#include <time.h>
#include <stdio.h>
#include <windows.h>

static  char * prefix = "real";
static  char * logfile = "c:\\temp\\logrun.log";

/*
  Run a different command, obtain by inserting <prefix>
  before the file name used to invoke this command.

  Wait for that different command to complete,
  and then return its exit code.
  */

static char * executableName() 
{
  HANDLE h = GetModuleHandle(NULL);
  int buffer_len = 4;
  TCHAR * buffer = (TCHAR *) malloc (sizeof(TCHAR) * buffer_len);
  int rc = GetModuleFileName(h,buffer,buffer_len);
  while (rc > 0 && rc == buffer_len) {
    buffer_len *= 2;
    free(buffer);
    buffer = (TCHAR *) malloc (sizeof(TCHAR) * buffer_len);
    rc = GetModuleFileName(h,buffer,buffer_len);
  }
  
  return rc > 0 ? buffer : NULL;
}

/* Link with /subsystem:windows for a non-console runner. */
int WINAPI WinMain  (HINSTANCE hinstExe, HINSTANCE hinstExePrev, LPSTR cmdline, int nCmdShow) {
  return main(__argc, __argv, _environ);
}

/* Entrypoint for console runner. */
int main(int argc, char ** argv, char ** envp) {
  int rc;
  FILE * f = fopen(logfile, "a");
  int i = 0;
  int length = 0;
  HANDLE hsi = GetStdHandle(STD_INPUT_HANDLE);
  HANDLE hso = GetStdHandle(STD_OUTPUT_HANDLE);
  HANDLE hse = GetStdHandle(STD_ERROR_HANDLE);
  char * actual_name = executableName();
  time_t ltime;

  time( &ltime );

  fprintf(f,"logging run of %s at %s", actual_name, ctime(&ltime));

  /* If the command name is missing, pick one likely to work. */
  if (argv[0][0] == 0) {
    fprintf(f, "Program name was empty.\n");
    argv[0] = actual_name;
  }

  while (envp[i] != 0) {
    fprintf(f, "env[%d] '%s'\n", i, envp[i]);    
    i++;
  }

  i = 0;
  while (i < argc) {
    fprintf(f, "argv[%d] '%s'\n", i, argv[i]);

    if (i == 0) {
      /* Treat the first (command name) parameter specially. */
      char * last_bs = strrchr(argv[0], '\\');
      char * last_sl = strrchr(argv[0], '/');
      char * new_arg;
      int last_index = -1;

      if (last_bs != NULL) {
	if (last_sl != NULL) {
	  if (last_bs - argv[0] > last_sl - argv[0]) {
	    last_index = last_bs - argv[0];
	  } else {
	    last_index = last_sl - argv[0];
	  }
	} else {
	  last_index = last_bs - argv[0];
	}      
      } else if (last_sl != NULL) {
	last_index = last_sl - argv[0];
      } else {
	last_index = -1;
      }

      /* drive:/directory/whatever.exe
	                 ^
			 last_index
      */

      /* Construct aaaa/PREFIXbbb */

      new_arg = (char *) malloc(strlen(argv[0]) + strlen(prefix) + 1);
      strcpy(new_arg, argv[0]);
      strcpy(new_arg+last_index+1, prefix);
      strcpy(new_arg+last_index+strlen(prefix)+1, argv[0]+last_index+1);

      argv[0] = new_arg;
      fprintf(f,"Constructing new argv[0] '%s'\n", new_arg);
    } else {
      /* Add quotes to everything */
      char * a = argv[i];
      int l = strlen(a);
      char * new_arg = (char *) malloc(l+3);
      strcpy(new_arg+1, a);
      new_arg[0] = '"';
      new_arg[l+1] = '"';
      new_arg[l+2] = 0;
      argv[i] = new_arg;
    }
    length += strlen(argv[i] + 1);
    i++;
  }
  fprintf(f, "------------------\n");
  fclose(f);
  {
    STARTUPINFO si;
    SECURITY_ATTRIBUTES saProcess, saThread;
    PROCESS_INFORMATION pi;

    /* Assemble a command line */
    char * commandBuffer = (char *) malloc(length + 1);
    int at = 0;
    i = 0;
    while (i < argc) {
      strcpy(commandBuffer + at, argv[i]);
      at += strlen(argv[i]);
      commandBuffer[at] = ' ';
      at ++;
      i++;
    }
    commandBuffer[at] = 0;

    /* Process creation boilerplate. */
#define Z(x) ZeroMemory(&x, sizeof(x))
    Z(si);
    Z(saProcess);
    Z(saThread);
    si.cb = sizeof(si);
    saProcess.nLength = sizeof(saProcess);
    saProcess.lpSecurityDescriptor = NULL;
    saProcess.bInheritHandle = TRUE;
    saThread.nLength = sizeof(saThread);
    saThread.lpSecurityDescriptor = NULL;
    saThread.bInheritHandle = FALSE;
    rc = CreateProcess(
		       NULL,          /* name */
		       commandBuffer, /* command */
		       NULL,          /* process security attr */
		       NULL,          /* thread security attr */
		       TRUE,          /* inherit handles */
		       NORMAL_PRIORITY_CLASS /* flags */
		       | CREATE_UNICODE_ENVIRONMENT
		       ,
		       NULL,          /* environment block */
		       NULL,          /* current directory */
		       &si,           /* startup info */
		       &pi);          /* process info */

    /* rc != 0 === success */
    if (rc != 0) {

      DWORD exit_code;

      /* Close handles we won't need; our child process has own copies. */

      CloseHandle(hsi);
      CloseHandle(hso);
      CloseHandle(hse);
      CloseHandle(pi.hThread);
      
      /* Wait for completion, relay error code. */
      WaitForSingleObject(pi.hProcess, INFINITE);
      GetExitCodeProcess(pi.hProcess, &exit_code);
      CloseHandle(pi.hProcess);

      return exit_code;
    }
    return GetLastError();
  }
}

