/*
  util.c - Utility functions.
*/

#include "ansicon.h"
#include "version.h"


TCHAR	prog_path[MAX_PATH];
LPTSTR	prog;

int	log_level;

TCHAR	DllName[MAX_PATH];	// Dll file name
char	ansi_dll[MAX_PATH];
DWORD	ansi_len;
#ifdef _WIN64
char*	ansi_bits;
#endif


// Get just the name of the program: "C:\path\program.exe" -> "program".
// Returns a pointer within program; it is modified to remove the extension.
LPTSTR get_program_name( LPTSTR program )
{
  LPTSTR name, ext;

  if (program == NULL)
  {
    GetModuleFileName( NULL, prog_path, lenof(prog_path) );
    program = prog_path;
  }
  name = wcsrchr( program, '\\' );
  if (name != NULL)
    ++name;
  else
    name = program;
  ext = wcsrchr( name, '.' );
  if (ext != NULL && ext != name)
    *ext = '\0';

  return name;
}


// Get the ANSI path of the DLL for the import.  If it can't be converted,
// just use the name and hope it's on the PATH.
void set_ansi_dll( void )
{
  BOOL bad;

  ansi_len = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, DllName, -1,
				  NULL, 0, NULL, &bad );
  if (bad || ansi_len > MAX_PATH)
  {
#ifdef _WIN64
    ansi_bits = ansi_dll + 4;
    if (*DllNameType == '6')
      memcpy( ansi_dll, "ANSI64.dll\0", 12 );
    else
#endif
    memcpy( ansi_dll, "ANSI32.dll\0", 12 );
    ansi_len = 12;
  }
  else
  {
    WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, DllName, -1,
			 ansi_dll, MAX_PATH, NULL, NULL );
#ifdef _WIN64
    ansi_bits = ansi_dll + ansi_len - 7;
#endif
    ansi_len = (ansi_len + 3) & ~3;
  }
}


void DEBUGSTR( int level, LPTSTR szFormat, ... )
{
  static char  tempfile[MAX_PATH];
  static DWORD pid;

  TCHAR   szBuffer[1024], szEscape[1024];
  va_list pArgList;
  HANDLE  mutex;
  DWORD   wait;
  FILE*   file;

  if ((log_level & 3) < level && !(level & 4 & log_level))
    return;

  if (*tempfile == '\0')
  {
    _snprintf( tempfile, MAX_PATH, "%s\\ansicon.log", getenv( "TEMP" ) );
    pid = GetCurrentProcessId();
  }
  if (szFormat == NULL)
  {
    // Explicitly use 't', as _fmode might be binary.
    file = fopen( tempfile, (log_level & 8) ? "at" : "wt" );
    if (file != NULL)
    {
      SYSTEMTIME now;
      GetLocalTime( &now );
      fseek( file, 0, SEEK_END );
      if (ftell( file ) != 0)
	putc( '\n', file );
      fprintf( file, "ANSICON (" BITSA "-bit) v" PVERSA " log (%d) started "
		      "%d-%.2d-%.2d %d:%.2d:%.2d\n",
		     log_level,
		     now.wYear, now.wMonth, now.wDay,
		     now.wHour, now.wMinute, now.wSecond );
      fclose( file );
    }
    return;
  }

  va_start( pArgList, szFormat );
  _vsnwprintf( szBuffer, lenof(szBuffer), szFormat, pArgList );
  va_end( pArgList );

  szFormat = szBuffer;
  if (*szFormat == '\33')
  {
    BOOL first = TRUE;
    LPTSTR pos = szEscape;
    while (*++szFormat != '\0' && pos < szEscape + lenof(szEscape) - 4)
    {
      if (*szFormat < 32)
      {
	*pos++ = '\\';
	switch (*szFormat)
	{
	  case '\a': *pos++ = 'a'; break;
	  case '\b': *pos++ = 'b'; break;
	  case '\t': *pos++ = 't'; break;
	  case '\r': *pos++ = 'r'; break;
	  case '\n': *pos++ = 'n'; break;
	  case	27 : *pos++ = 'e'; break;
	  default:
	    pos += _snwprintf( pos, 32, L"%.*o",
			     (szFormat[1] >= '0' && szFormat[1] <= '7') ? 3 : 1,
			     *szFormat );
	}
      }
      else
      {
	if (*szFormat == '"')
	{
	  if (first)
	    first = FALSE;
	  else if (szFormat[1] != '\0')
	    *pos++ = '\\';
	}
	*pos++ = *szFormat;
      }
    }
    *pos = '\0';
    szFormat = szEscape;
  }

  mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" );
  wait	= WaitForSingleObject( mutex, 500 );
  file	= fopen( tempfile, "at" );
  if (file != NULL)
  {
    fwprintf( file, L"%s (%lu): %s\n", prog, pid, szFormat );
    fclose( file );
  }
  if (wait == WAIT_OBJECT_0)
    ReleaseMutex( mutex );
  CloseHandle( mutex );
}