| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | /* 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"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-24 15:18:32 +01:00
										 |  |  | DWORD RunSilent(const char* strCommand); | 
					
						
							|  |  |  | FILE *pt_popen(const char *cmd, const char *mode); | 
					
						
							|  |  |  | int pt_pclose(FILE *fd); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | DWORD RunSilent(const char* strCommand) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	STARTUPINFO StartupInfo; | 
					
						
							|  |  |  | 	PROCESS_INFORMATION ProcessInfo; | 
					
						
							|  |  |  | 	char Args[4096]; | 
					
						
							|  |  |  | 	char *pEnvCMD = NULL; | 
					
						
							|  |  |  | 	char *pDefaultCMD = "CMD.EXE"; | 
					
						
							|  |  |  | 	ULONG rc; | 
					
						
							| 
									
										
										
										
											2011-03-08 00:03:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | 	memset(&StartupInfo, 0, sizeof(StartupInfo)); | 
					
						
							|  |  |  | 	StartupInfo.cb = sizeof(STARTUPINFO); | 
					
						
							|  |  |  | 	StartupInfo.dwFlags = STARTF_USESHOWWINDOW; | 
					
						
							|  |  |  | 	StartupInfo.wShowWindow = SW_HIDE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Args[0] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pEnvCMD = getenv("COMSPEC"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-08 00:03:50 +00:00
										 |  |  | 	if(pEnvCMD){ | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | 		strcpy(Args, pEnvCMD); | 
					
						
							|  |  |  | 	} else{ | 
					
						
							|  |  |  | 		strcpy(Args, pDefaultCMD); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* "/c" option - Do the command then terminate the command window */ | 
					
						
							| 
									
										
										
										
											2011-03-08 00:03:50 +00:00
										 |  |  | 	strcat(Args, " /c "); | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | 	/*the application you would like to run from the command window */ | 
					
						
							| 
									
										
										
										
											2011-03-08 00:03:50 +00:00
										 |  |  | 	strcat(Args, strCommand); | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!CreateProcess( NULL, Args, NULL, NULL, FALSE, | 
					
						
							| 
									
										
										
										
											2011-03-08 00:03:50 +00:00
										 |  |  | 		CREATE_NEW_CONSOLE, | 
					
						
							|  |  |  | 		NULL, | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | 		NULL, | 
					
						
							|  |  |  | 		&StartupInfo, | 
					
						
							|  |  |  | 		&ProcessInfo)) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2011-03-08 00:03:50 +00:00
										 |  |  | 		return GetLastError(); | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	WaitForSingleObject(ProcessInfo.hProcess, INFINITE); | 
					
						
							|  |  |  | 	if(!GetExitCodeProcess(ProcessInfo.hProcess, &rc)) | 
					
						
							|  |  |  | 		rc = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CloseHandle(ProcessInfo.hThread); | 
					
						
							|  |  |  | 	CloseHandle(ProcessInfo.hProcess); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return rc; | 
					
						
							| 
									
										
										
										
											2011-03-08 00:03:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*------------------------------------------------------------------------------
 | 
					
						
							|  |  |  |   Globals for the Routines pt_popen() / pt_pclose() | 
					
						
							|  |  |  | ------------------------------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CRITICAL_SECTION lock; | 
					
						
							|  |  |  | #define LOCK()   EnterCriticalSection(&lock);
 | 
					
						
							|  |  |  | #define UNLOCK() LeaveCriticalSection(&lock);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2013-11-16 16:58:07 +00:00
										 |  |  | pt_init( void ) | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | { 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 * | 
					
						
							| 
									
										
										
										
											2013-11-16 16:58:07 +00:00
										 |  |  | allocPipeContext( void ) | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | { 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, | 
					
						
							| 
									
										
										
										
											2011-03-08 00:03:50 +00:00
										 |  |  | 			   wcmd,	// command line
 | 
					
						
							|  |  |  | 			   NULL,	// process security attributes
 | 
					
						
							|  |  |  | 			   NULL,	// primary thread security attributes
 | 
					
						
							|  |  |  | 			   TRUE,	// handles are inherited
 | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | 			   CREATE_NO_WINDOW,  // creation flags: without window (?)
 | 
					
						
							| 
									
										
										
										
											2011-03-08 00:03:50 +00:00
										 |  |  | 			   NULL,	// use parent's environment
 | 
					
						
							|  |  |  | 			   NULL,	// use parent's current directory
 | 
					
						
							|  |  |  | 			   &siStartInfo, // STARTUPINFO pointer
 | 
					
						
							|  |  |  | 			   &piProcInfo); // receives PROCESS_INFORMATION
 | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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' ) | 
					
						
							| 
									
										
										
										
											2013-01-19 14:35:11 +00:00
										 |  |  |     fptr = _fdopen(_open_osfhandle((intptr_t)pc->out[0],_O_BINARY),"r"); | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  |   else | 
					
						
							| 
									
										
										
										
											2013-01-19 14:35:11 +00:00
										 |  |  |     fptr = _fdopen(_open_osfhandle((intptr_t)pc->in[1],_O_BINARY),"w"); | 
					
						
							| 
									
										
										
										
											2009-05-02 12:33:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 |