From 3603c6eb07309cc57d856b7da7108c6d7c2f1fd0 Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Sat, 2 May 2009 12:33:36 -0500 Subject: [PATCH] include popen for mingw compilation simplify Makefile a tiny bit. --- packages/PLStream/Makefile.in | 47 +---- packages/PLStream/popen.c | 359 ++++++++++++++++++++++++++++++++++ 2 files changed, 368 insertions(+), 38 deletions(-) create mode 100644 packages/PLStream/popen.c diff --git a/packages/PLStream/Makefile.in b/packages/PLStream/Makefile.in index efd03dc51..64f086481 100644 --- a/packages/PLStream/Makefile.in +++ b/packages/PLStream/Makefile.in @@ -49,11 +49,11 @@ C_SOURCES=$(srcdir)/pl-buffer.c $(srcdir)/pl-ctype.c \ $(srcdir)/pl-stream.c $(srcdir)/pl-string.c \ $(srcdir)/pl-table.c \ $(srcdir)/pl-text.c $(srcdir)/pl-utf8.c \ - $(srcdir)/pl-yap.c @ENABLE_WINCONSOLE@ $(srcdir)/uxnt/utf8.c $(srcdir)/uxnt/uxnt.c + $(srcdir)/pl-yap.c @ENABLE_WINCONSOLE@ $(srcdir)/popen.c $(srcdir)/uxnt/utf8.c $(srcdir)/uxnt/uxnt.c OBJS=pl-buffer.o pl-ctype.o pl-error.o pl-feature.o \ pl-file.o pl-os.o \ pl-stream.o pl-string.o pl-table.o pl-text.o pl-utf8.o \ - pl-yap.o @ENABLE_WINCONSOLE@ utf8.o uxnt.o + pl-yap.o @ENABLE_WINCONSOLE@ popen.o utf8.o uxnt.o SOBJS=plstream@SHLIB_SUFFIX@ #in some systems we just create a single object, in others we need to @@ -61,48 +61,16 @@ SOBJS=plstream@SHLIB_SUFFIX@ all: $(SOBJS) -pl-buffer.o: $(srcdir)/pl-buffer.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-buffer.c -o pl-buffer.o - -pl-ctype.o: $(srcdir)/pl-ctype.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-ctype.c -o pl-ctype.o - -pl-error.o: $(srcdir)/pl-error.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-error.c -o pl-error.o - -pl-feature.o: $(srcdir)/pl-feature.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-feature.c -o pl-feature.o - -pl-file.o: $(srcdir)/pl-file.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-file.c -o pl-file.o - -pl-os.o: $(srcdir)/pl-os.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-os.c -o pl-os.o - -pl-stream.o: $(srcdir)/pl-stream.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-stream.c -o pl-stream.o - -pl-string.o: $(srcdir)/pl-string.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-string.c -o pl-string.o - -pl-table.o: $(srcdir)/pl-table.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-table.c -o pl-table.o - -pl-text.o: $(srcdir)/pl-text.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-text.c -o pl-text.o - -pl-utf8.o: $(srcdir)/pl-utf8.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-utf8.c -o pl-utf8.o - -pl-yap.o: $(srcdir)/pl-yap.c - $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/pl-yap.c -o pl-yap.o - uxnt.o: $(srcdir)/uxnt/uxnt.c $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/uxnt/uxnt.c -o uxnt.o utf8.o: $(srcdir)/uxnt/utf8.c $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/uxnt/utf8.c -o utf8.o +# default rule +%.o : $(srcdir)/C/%.c + $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $< -o $@ + @DO_SECOND_LD@%@SHLIB_SUFFIX@: %.o @DO_SECOND_LD@ @SHLIB_LD@ -o $@ $< @@ -123,3 +91,6 @@ depend: $(HEADERS) $(C_SOURCES) makedepend -f - -- $(CFLAGS) -I$(srcdir)/../../H -I$(srcdir)/../../include -- $(C_SOURCES) |\ sed 's|.*/\([^:]*\):|\1:|' >> Makefile ;\ fi + +# DO NOT DELETE THIS LINE -- make depend depends on it. + diff --git a/packages/PLStream/popen.c b/packages/PLStream/popen.c new file mode 100644 index 000000000..e18b67956 --- /dev/null +++ b/packages/PLStream/popen.c @@ -0,0 +1,359 @@ +/* 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 +#include +#include +#include +#include +#include "pl-utf8.h" + +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() +{ 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() +{ 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((long)pc->out[0],_O_BINARY),"r"); + else + fptr = _fdopen(_open_osfhandle((long)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; +} + +