365 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			365 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/* popen.c
 | 
						|
  RunSilent() is by Steven Szelei,
 | 
						|
  and pt_popen()/pt_pclose() is by Kurt Keller
 | 
						|
  Modified and comments translated by Steve Donovan
 | 
						|
 | 
						|
  Please note an extension; if your commmand contains '2>&1'
 | 
						|
  then any error output will be redirected as well to the pipe.
 | 
						|
 | 
						|
  Put this file in scite\lua\src\lib and add to your project
 | 
						|
 | 
						|
  to modify liolib.c in the same dir,
 | 
						|
  replace conditional at line 47 with:
 | 
						|
 | 
						|
  #ifndef USE_POPEN
 | 
						|
  #ifdef __WINDOWS__
 | 
						|
  #define USE_POPEN 1
 | 
						|
  FILE* pt_popen(const char *cmd, const char*mode);
 | 
						|
  int pt_pclose(FILE *file);
 | 
						|
  uintptr_t RunSilent(const char* strCommand);
 | 
						|
  #define popen pt_popen
 | 
						|
  #define pclose pt_pclose
 | 
						|
  #define system RunSilent
 | 
						|
  #endif
 | 
						|
  #else
 | 
						|
  #define USE_POPEN	0
 | 
						|
  #endif
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
SWI-Prolog note:
 | 
						|
 | 
						|
This        file        is         copied          verbatim         from
 | 
						|
http://lua-users.org/wiki/PipesOnWindows, where it is   contributed  for
 | 
						|
using pipes with the LUA programming  language. LUA is distributed under
 | 
						|
the MIT licence which is claimed to be compatible (but less restrictive)
 | 
						|
with the LGPL license. We  therefore  assume   we  can  use this file in
 | 
						|
SWI-Prolog without introducing new license problems.
 | 
						|
 | 
						|
This version is heavily modified:
 | 
						|
 | 
						|
	* Support Unicode commands (commands are specified in UTF-8)
 | 
						|
	* make popen()/pclose() thread-safe.
 | 
						|
	* Fix leak process-handles
 | 
						|
 | 
						|
If you find this file and know better, please contact info@swi-prolog.org.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
#include <windows.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#include <string.h>
 | 
						|
#include <io.h>
 | 
						|
#include "pl-utf8.h"
 | 
						|
 | 
						|
DWORD RunSilent(const char* strCommand);
 | 
						|
FILE *pt_popen(const char *cmd, const char *mode);
 | 
						|
int pt_pclose(FILE *fd);
 | 
						|
 | 
						|
 | 
						|
DWORD RunSilent(const char* strCommand)
 | 
						|
{
 | 
						|
	STARTUPINFO StartupInfo;
 | 
						|
	PROCESS_INFORMATION ProcessInfo;
 | 
						|
	char Args[4096];
 | 
						|
	char *pEnvCMD = NULL;
 | 
						|
	char *pDefaultCMD = "CMD.EXE";
 | 
						|
	ULONG rc;
 | 
						|
 | 
						|
	memset(&StartupInfo, 0, sizeof(StartupInfo));
 | 
						|
	StartupInfo.cb = sizeof(STARTUPINFO);
 | 
						|
	StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
 | 
						|
	StartupInfo.wShowWindow = SW_HIDE;
 | 
						|
 | 
						|
	Args[0] = 0;
 | 
						|
 | 
						|
	pEnvCMD = getenv("COMSPEC");
 | 
						|
 | 
						|
	if(pEnvCMD){
 | 
						|
		strcpy(Args, pEnvCMD);
 | 
						|
	} else{
 | 
						|
		strcpy(Args, pDefaultCMD);
 | 
						|
	}
 | 
						|
 | 
						|
	/* "/c" option - Do the command then terminate the command window */
 | 
						|
	strcat(Args, " /c ");
 | 
						|
	/*the application you would like to run from the command window */
 | 
						|
	strcat(Args, strCommand);
 | 
						|
 | 
						|
	if (!CreateProcess( NULL, Args, NULL, NULL, FALSE,
 | 
						|
		CREATE_NEW_CONSOLE,
 | 
						|
		NULL,
 | 
						|
		NULL,
 | 
						|
		&StartupInfo,
 | 
						|
		&ProcessInfo))
 | 
						|
	{
 | 
						|
		return GetLastError();
 | 
						|
	}
 | 
						|
 | 
						|
	WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
 | 
						|
	if(!GetExitCodeProcess(ProcessInfo.hProcess, &rc))
 | 
						|
		rc = 0;
 | 
						|
 | 
						|
	CloseHandle(ProcessInfo.hThread);
 | 
						|
	CloseHandle(ProcessInfo.hProcess);
 | 
						|
 | 
						|
	return rc;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/*------------------------------------------------------------------------------
 | 
						|
  Globals for the Routines pt_popen() / pt_pclose()
 | 
						|
------------------------------------------------------------------------------*/
 | 
						|
 | 
						|
CRITICAL_SECTION lock;
 | 
						|
#define LOCK()   EnterCriticalSection(&lock);
 | 
						|
#define UNLOCK() LeaveCriticalSection(&lock);
 | 
						|
 | 
						|
static void
 | 
						|
pt_init( void )
 | 
						|
{ InitializeCriticalSection(&lock);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
typedef struct pipe_context
 | 
						|
{ struct pipe_context *next;
 | 
						|
  FILE   *fd;
 | 
						|
  HANDLE in[2];
 | 
						|
  HANDLE out[2];
 | 
						|
  HANDLE err[2];
 | 
						|
  char   mode;				/* 'r' or 'w' */
 | 
						|
} pipe_context;
 | 
						|
 | 
						|
 | 
						|
static pipe_context *pipes = NULL;
 | 
						|
 | 
						|
static pipe_context *
 | 
						|
allocPipeContext( void )
 | 
						|
{ pipe_context *pc = malloc(sizeof(*pc));
 | 
						|
 | 
						|
  if ( !pc )
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  pc->in[0]   = INVALID_HANDLE_VALUE;
 | 
						|
  pc->in[1]   = INVALID_HANDLE_VALUE;
 | 
						|
  pc->out[0]  = INVALID_HANDLE_VALUE;
 | 
						|
  pc->out[1]  = INVALID_HANDLE_VALUE;
 | 
						|
  pc->err[0]  = INVALID_HANDLE_VALUE;
 | 
						|
  pc->err[1]  = INVALID_HANDLE_VALUE;
 | 
						|
 | 
						|
  return pc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
discardPipeContext(pipe_context *pc)
 | 
						|
{ if (pc->in[0]  != INVALID_HANDLE_VALUE)
 | 
						|
    CloseHandle(pc->in[0]);
 | 
						|
  if (pc->in[1]  != INVALID_HANDLE_VALUE)
 | 
						|
    CloseHandle(pc->in[1]);
 | 
						|
  if (pc->out[0] != INVALID_HANDLE_VALUE)
 | 
						|
    CloseHandle(pc->out[0]);
 | 
						|
  if (pc->out[1] != INVALID_HANDLE_VALUE)
 | 
						|
    CloseHandle(pc->out[1]);
 | 
						|
  if (pc->err[0] != INVALID_HANDLE_VALUE)
 | 
						|
    CloseHandle(pc->err[0]);
 | 
						|
  if (pc->err[1] != INVALID_HANDLE_VALUE)
 | 
						|
    CloseHandle(pc->err[1]);
 | 
						|
 | 
						|
  free(pc);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
linkPipeContext(pipe_context *pc)
 | 
						|
{ LOCK();
 | 
						|
  pc->next = pipes;
 | 
						|
  pipes = pc;
 | 
						|
  UNLOCK();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
my_pipe(HANDLE *readwrite)
 | 
						|
{
 | 
						|
  SECURITY_ATTRIBUTES sa;
 | 
						|
 | 
						|
  sa.nLength = sizeof(sa);          /* Length in bytes */
 | 
						|
  sa.bInheritHandle = 1;            /* the child must inherit these handles */
 | 
						|
  sa.lpSecurityDescriptor = NULL;
 | 
						|
 | 
						|
  if (! CreatePipe (&readwrite[0],&readwrite[1],&sa,1 << 13))
 | 
						|
  {
 | 
						|
    errno = -1; /* EMFILE; que? */
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*------------------------------------------------------------------------------
 | 
						|
  Replacement for 'popen()' under Windows.
 | 
						|
 | 
						|
  cmd is taken to be encoded in UTF-8 for compatibility with the Unix
 | 
						|
  version.
 | 
						|
 | 
						|
  NOTE: if cmd contains '2>&1', we connect the standard error file handle
 | 
						|
    to the standard output file handle.
 | 
						|
------------------------------------------------------------------------------*/
 | 
						|
 | 
						|
static void
 | 
						|
utf8towcs(wchar_t *o, const char *src)
 | 
						|
{ for( ; *src; )
 | 
						|
  { int wc;
 | 
						|
 | 
						|
    src = utf8_get_char(src, &wc);
 | 
						|
    *o++ = wc;
 | 
						|
  }
 | 
						|
  *o = 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
FILE *
 | 
						|
pt_popen(const char *cmd, const char *mode)
 | 
						|
{ FILE *fptr = NULL;
 | 
						|
  PROCESS_INFORMATION piProcInfo;
 | 
						|
  STARTUPINFOW siStartInfo;
 | 
						|
  int success, redirect_error = 0;
 | 
						|
  wchar_t *wcmd = NULL;
 | 
						|
  wchar_t *err2out;
 | 
						|
  pipe_context *pc;
 | 
						|
 | 
						|
  size_t utf8len = utf8_strlen(cmd, strlen(cmd));
 | 
						|
  if ( !(wcmd = malloc((utf8len+1)*sizeof(wchar_t))) )
 | 
						|
  { return NULL;
 | 
						|
  }
 | 
						|
  utf8towcs(wcmd, cmd);
 | 
						|
 | 
						|
  if ( !(pc=allocPipeContext()) )
 | 
						|
    goto finito;
 | 
						|
  if ( !mode || !*mode )
 | 
						|
    goto finito;
 | 
						|
  pc->mode = *mode;
 | 
						|
  if ( pc->mode != 'r' && pc->mode != 'w' )
 | 
						|
    goto finito;
 | 
						|
 | 
						|
  /*
 | 
						|
   * Shall we redirect stderr to stdout ? */
 | 
						|
  if ( (err2out=wcsstr(wcmd, L"2>&1")) != NULL)
 | 
						|
  { /* this option doesn't apply to win32 shells, so we clear it out! */
 | 
						|
     wcsncpy(err2out, L"    ", 4);
 | 
						|
     redirect_error = 1;
 | 
						|
  }
 | 
						|
 | 
						|
  /*
 | 
						|
   * Create the Pipes... */
 | 
						|
  if (my_pipe(pc->in)  == -1 ||
 | 
						|
      my_pipe(pc->out) == -1)
 | 
						|
    goto finito;
 | 
						|
  if ( !redirect_error )
 | 
						|
  { if ( my_pipe(pc->err) == -1)
 | 
						|
      goto finito;
 | 
						|
  }
 | 
						|
 | 
						|
  /*
 | 
						|
   * Now create the child process */
 | 
						|
  ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
 | 
						|
  siStartInfo.cb           = sizeof(STARTUPINFO);
 | 
						|
  siStartInfo.hStdInput    = pc->in[0];
 | 
						|
  siStartInfo.hStdOutput   = pc->out[1];
 | 
						|
  if ( redirect_error )
 | 
						|
    siStartInfo.hStdError  = pc->out[1];
 | 
						|
  else
 | 
						|
    siStartInfo.hStdError  = pc->err[1];
 | 
						|
  siStartInfo.dwFlags      = STARTF_USESTDHANDLES;
 | 
						|
 | 
						|
  success = CreateProcessW(NULL,
 | 
						|
			   wcmd,	// command line
 | 
						|
			   NULL,	// process security attributes
 | 
						|
			   NULL,	// primary thread security attributes
 | 
						|
			   TRUE,	// handles are inherited
 | 
						|
			   CREATE_NO_WINDOW,  // creation flags: without window (?)
 | 
						|
			   NULL,	// use parent's environment
 | 
						|
			   NULL,	// use parent's current directory
 | 
						|
			   &siStartInfo, // STARTUPINFO pointer
 | 
						|
			   &piProcInfo); // receives PROCESS_INFORMATION
 | 
						|
 | 
						|
  if ( !success )
 | 
						|
    goto finito;
 | 
						|
 | 
						|
  CloseHandle(piProcInfo.hThread);
 | 
						|
  CloseHandle(piProcInfo.hProcess);
 | 
						|
 | 
						|
  /*
 | 
						|
   * These handles listen to the Child process */
 | 
						|
  CloseHandle(pc->in[0]);  pc->in[0]  = INVALID_HANDLE_VALUE;
 | 
						|
  CloseHandle(pc->out[1]); pc->out[1] = INVALID_HANDLE_VALUE;
 | 
						|
  if ( pc->err[1] != INVALID_HANDLE_VALUE )
 | 
						|
  { CloseHandle(pc->err[1]);
 | 
						|
    pc->err[1] = INVALID_HANDLE_VALUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( pc->mode == 'r' )
 | 
						|
    fptr = _fdopen(_open_osfhandle((intptr_t)pc->out[0],_O_BINARY),"r");
 | 
						|
  else
 | 
						|
    fptr = _fdopen(_open_osfhandle((intptr_t)pc->in[1],_O_BINARY),"w");
 | 
						|
 | 
						|
finito:
 | 
						|
  if ( fptr )
 | 
						|
  { pc->fd = fptr;
 | 
						|
    linkPipeContext(pc);
 | 
						|
  } else
 | 
						|
  { if ( pc )
 | 
						|
      discardPipeContext(pc);
 | 
						|
  }
 | 
						|
  if ( wcmd )
 | 
						|
    free(wcmd);
 | 
						|
 | 
						|
  return fptr;
 | 
						|
}
 | 
						|
 | 
						|
/*------------------------------------------------------------------------------
 | 
						|
  Replacement for 'pclose()' under Win32
 | 
						|
------------------------------------------------------------------------------*/
 | 
						|
int
 | 
						|
pt_pclose(FILE *fd)
 | 
						|
{ pipe_context **ppc;
 | 
						|
  int rc;
 | 
						|
 | 
						|
  if ( !fd )
 | 
						|
  { errno = EINVAL;
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  rc = fclose(fd);
 | 
						|
  LOCK();
 | 
						|
  for(ppc = &pipes; *ppc; ppc=&(*ppc)->next)
 | 
						|
  { pipe_context *pc = *ppc;
 | 
						|
 | 
						|
    if ( pc->fd == fd )
 | 
						|
    { *ppc = pc->next;
 | 
						|
 | 
						|
      UNLOCK();
 | 
						|
      if ( pc->err[0] != INVALID_HANDLE_VALUE )
 | 
						|
	CloseHandle(pc->err[0]);
 | 
						|
      if ( pc->mode == 'r' )
 | 
						|
      { CloseHandle(pc->in[1]);
 | 
						|
      } else
 | 
						|
      { CloseHandle(pc->out[0]);
 | 
						|
      }
 | 
						|
 | 
						|
      free(pc);
 | 
						|
 | 
						|
      return rc;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  UNLOCK();
 | 
						|
  errno = EINVAL;
 | 
						|
  return -1;
 | 
						|
}
 | 
						|
 | 
						|
 |