#define _Noreturn #if defined(__WIN32__) #define WIN32_LEAN_AND_MEAN #define UNICODE #include #else #include #include #include #include #include #include #endif #include #include #include #include #define POM_output 1 #define POM_error 2 #define POM_input 4 #define POM_showWindow 8 #define FSM_start 0 #define FSM_current 1 #define FSM_end 2 #define false 0 #define true 1 #define null ((void *)0) typedef unsigned int FileSeekMode; typedef unsigned int PipeOpenMode; typedef unsigned char byte; typedef unsigned short uint16; typedef unsigned int uint; typedef int bool; #define forArgsPassing 2 int __ecereNameSpace__ecere__sys__Tokenize(char * string, int maxTokens, char * tokens[], unsigned int esc); char * __ecereNameSpace__ecere__sys__CopyString(const char * string); void __ecereNameSpace__ecere__com__eSystem_Delete(void * memory); unsigned short * __ecereNameSpace__ecere__sys__UTF8toUTF16(const char * source, int * wordCount); typedef struct { #if defined(__WIN32__) HANDLE inputHandle, outputHandle; HANDLE hProcess; #else FILE * input, * output; int exitCode; #endif int pid; bool eof:1, gotExitCode:1; } _DualPipe; void DualPipe_Destructor(_DualPipe * dp) { #if defined(__WIN32__) if(dp->outputHandle) { CloseHandle(dp->outputHandle); dp->outputHandle = null; } if(dp->inputHandle) { CloseHandle(dp->inputHandle); dp->inputHandle = null; } if(dp->hProcess) CloseHandle(dp->hProcess); #endif free(dp); } void DualPipe_CloseInput(_DualPipe * dp) { #if defined(__WIN32__) if(dp->inputHandle) { CloseHandle(dp->inputHandle); dp->inputHandle = null; } #endif } void DualPipe_CloseOutput(_DualPipe * dp) { #if defined(__WIN32__) if(dp->outputHandle) { CloseHandle(dp->outputHandle); dp->outputHandle = null; } #endif } int DualPipe_Read(_DualPipe * dp, byte * buffer, uint size, uint count) { #if defined(__WIN32__) unsigned int read; dp->eof = !ReadFile(dp->inputHandle, buffer, size*count, (DWORD *)&read, null); return read / size; #else int result; result = read(fileno(dp->input), buffer, size * count); if(!result || (result < 0 && errno != EAGAIN)) dp->eof = true; return (result > 0) ? (result / size) : 0; #endif } int DualPipe_Write(_DualPipe * dp, const byte * buffer, uint size, uint count) { #if defined(__WIN32__) unsigned int written; WriteFile(dp->outputHandle, buffer, size * count, (DWORD *)&written, null); return written / size; #endif return 0; } bool DualPipe_Getc(_DualPipe * dp, char * ch) { #if defined(__WIN32__) unsigned int read; dp->eof = !ReadFile(dp->inputHandle, ch, 1, (DWORD *)&read, null); return !dp->eof && read != 0; #endif return false; } bool DualPipe_Putc(_DualPipe * dp, char ch) { #if defined(__WIN32__) unsigned int written; WriteFile(dp->outputHandle, &ch, 1, (DWORD *)&written, null); return written != 0; #endif return false; } bool DualPipe_Puts(_DualPipe * dp, const char * string) { #if defined(__WIN32__) unsigned int written; int len = strlen(string); WriteFile(dp->outputHandle, string, len, (DWORD *)&written, null); return written == len; #endif return false; } bool DualPipe_Seek(_DualPipe * dp, int pos, FileSeekMode mode) { #if defined(__WIN32__) bool result = false; switch(mode) { case FSM_start: result = SetFilePointer(dp->inputHandle, pos, null, FILE_BEGIN) != -1; break; case FSM_current: result = SetFilePointer(dp->inputHandle, pos, null, FILE_CURRENT) != -1; break; case FSM_end: result = SetFilePointer(dp->inputHandle, pos, null, FILE_END) != -1; break; } return result; #endif return false; } uint DualPipe_Tell(_DualPipe * dp) { #if defined(__WIN32__) return (uint)SetFilePointer(dp->inputHandle, 0, null, FILE_CURRENT); #endif return 0; } bool DualPipe_Eof(_DualPipe * dp) { #if defined(__WIN32__) return dp->eof; #else return !dp->input || dp->eof || feof(dp->input); #endif } // Not yet supported... Will ever be? bool DualPipe_GetSize(_DualPipe * dp) { return 0; } bool DualPipe_Peek(_DualPipe * dp) { #if defined(__WIN32__) uint avail = 0; int result = PeekNamedPipe(dp->inputHandle, null, 0, null, (DWORD *)&avail, null); if(!result) { unsigned int read; char buffer[1]; dp->eof = !ReadFile(dp->inputHandle, buffer, 0, (DWORD *)&read, null); } return avail ? true : false; #else bool result = false; //true; // false if(!DualPipe_Eof(dp)) { fd_set rs; struct timeval tv; int fd = fileno(dp->input); FD_ZERO(&rs); FD_SET(fd, &rs); tv.tv_sec = 0; tv.tv_usec = 0; return select(fd+1, &rs, null, null, &tv) > 0; } return result; #endif } void DualPipe_Terminate(_DualPipe * dp) { #if defined(__WIN32__) TerminateProcess(dp->hProcess, 0); #else if(dp->pid) kill(dp->pid, SIGTERM); #endif } int DualPipe_GetExitCode(_DualPipe * dp) { #if !defined(__WIN32__) if(!dp->gotExitCode) { int status = 0; waitpid(dp->pid, &status, 0); dp->exitCode = WEXITSTATUS(status); dp->gotExitCode = true; } /*#if defined(__linux__) // Until we support this _extension_ syntax: (moved this to a C file...) // return (((( _extension_ (((union { __typeof(status) __in; int __i; }) { .__in = (status) }).__i))) & 0xff00) >> 8); // return ((__extension__({ union { __typeof(status) __in; int __i; } __u; __u.__in = (status); __u.__i; }) ) & 0xFF00) >> 8; #else*/ return dp->exitCode; //#endif //return __WEXITSTATUS(status); #else int exitCode = 0; // NOTE: This was inconsistent with Linux version waiting... Testing Suite would not return proper values WaitForSingleObject(dp->hProcess, INFINITE); GetExitCodeProcess(dp->hProcess, (DWORD *)&exitCode); return exitCode; #endif } int DualPipe_GetProcessID(_DualPipe * dp) { return dp->pid; // Requires Windows Vista or Windows XP SP1. // return GetProcessId(hProcess); } void DualPipe_Wait(_DualPipe * dp) { #if defined(__WIN32__) WaitForSingleObject(dp->hProcess, INFINITE); #else if(dp->pid) { int status = 0; waitpid(dp->pid, &status, 0); dp->exitCode = WEXITSTATUS(status); dp->gotExitCode = true; } #endif } _DualPipe * _DualPipeOpen(PipeOpenMode mode, const char * commandLine, const char * env, void ** inputPtr, void ** outputPtr) { _DualPipe * f = null; #define PIPE_READ 0 #define PIPE_WRITE 1 #if !defined(__WIN32__) { FILE * input = null, * output = null; int hInput[2] = { 0 }, hOutput[2] = { 0 }; pid_t pid; bool result = true; if((mode & POM_error) || (mode & POM_output)) if(pipe(hOutput)) result = false; if((mode & POM_input)) if(pipe(hInput)) result = false; if(result) { pid = fork(); if(pid > 0) { // This process if(hInput[PIPE_READ]) { close(hInput[PIPE_READ]); output = fdopen(hInput[PIPE_WRITE],"w"); } if(hOutput[PIPE_WRITE]) { close(hOutput[PIPE_WRITE]); input = fdopen(hOutput[PIPE_READ],"r"); } } else if(pid == 0) { // Child process char * tokens[129]; int numTokens; char * commandLineCopy = __ecereNameSpace__ecere__sys__CopyString(commandLine); if(hInput[PIPE_WRITE]) close(hInput[PIPE_WRITE]); if(hOutput[PIPE_READ]) close(hOutput[PIPE_READ]); if((mode & POM_error) && hOutput[PIPE_WRITE] != STDERR_FILENO) dup2(hOutput[PIPE_WRITE], STDERR_FILENO); if((mode & POM_output) && hOutput[PIPE_WRITE] != STDOUT_FILENO) dup2(hOutput[PIPE_WRITE], STDOUT_FILENO); if(hOutput[PIPE_WRITE] && hOutput[PIPE_WRITE] != STDOUT_FILENO) close(hOutput[PIPE_WRITE]); if((mode & POM_input) && hInput[PIPE_READ] != STDIN_FILENO) { dup2(hInput[PIPE_READ], STDIN_FILENO); close(hInput[PIPE_READ]); } #if 0 //#ifdef _DEBUG fprintf(stderr, "\n_DualPipeOpen (in child): %s\n\n", commandLineCopy); #endif numTokens = __ecereNameSpace__ecere__sys__Tokenize(commandLineCopy, sizeof(tokens) / sizeof(tokens[0]) - 1, tokens, forArgsPassing); #if 0 //#ifdef _DEBUG { int c; for(c=0; cinput = input; *outputPtr = f->output = output; f->pid = pid; } } else { if(hInput[PIPE_READ]) close(hInput[PIPE_READ]); if(hInput[PIPE_WRITE]) close(hInput[PIPE_WRITE]); if(hOutput[PIPE_WRITE]) close(hOutput[PIPE_WRITE]); if(hOutput[PIPE_READ]) close(hOutput[PIPE_READ]); } } #else { HANDLE hOutput[2] = { 0 },hOutputRead = 0; HANDLE hInput[2] = { 0 }, hInputWrite = 0; HANDLE hError[2] = { 0 }, hErrorRead = 0; HANDLE hStdErr = 0, hStdIn = 0, hStdOut = 0; SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi = { 0 }; STARTUPINFO si = { 0 }; uint16 * _wcommandLine = __ecereNameSpace__ecere__sys__UTF8toUTF16(commandLine, null); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = null; sa.bInheritHandle = TRUE; // Force redirecting if GUI application if(!(mode & POM_error)) hStdErr = GetStdHandle(STD_ERROR_HANDLE); if(!(mode & POM_input)) hStdIn = GetStdHandle(STD_INPUT_HANDLE); if(!(mode & POM_output)) hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if((mode & POM_output) || !hStdOut) CreatePipe(&hOutput[PIPE_READ],&hOutput[PIPE_WRITE],&sa,0); if(( (mode & POM_error) && !(mode & POM_output)) || (!(mode & POM_error) && !hStdErr)) CreatePipe(&hError[PIPE_READ], &hError[PIPE_WRITE],&sa,0); if((mode & POM_input) || !hStdIn) CreatePipe(&hInput[PIPE_READ], &hInput[PIPE_WRITE], &sa,0); if(hInput[PIPE_READ]) DuplicateHandle(GetCurrentProcess(),hInput[PIPE_WRITE],GetCurrentProcess(),&hInputWrite,0,FALSE,DUPLICATE_SAME_ACCESS); if((mode & POM_error) && (mode & POM_output)) { DuplicateHandle(GetCurrentProcess(),hOutput[PIPE_READ],GetCurrentProcess(),&hOutputRead,0,FALSE,DUPLICATE_SAME_ACCESS); DuplicateHandle(GetCurrentProcess(),hOutput[PIPE_WRITE],GetCurrentProcess(),&hError[PIPE_WRITE],0,TRUE,DUPLICATE_SAME_ACCESS); } else { if(hOutput[PIPE_WRITE]) DuplicateHandle(GetCurrentProcess(),hOutput[PIPE_READ],GetCurrentProcess(),&hOutputRead,0,FALSE,DUPLICATE_SAME_ACCESS); if(hError[PIPE_WRITE]) DuplicateHandle(GetCurrentProcess(),hError[PIPE_READ],GetCurrentProcess(),&hErrorRead,0,FALSE,DUPLICATE_SAME_ACCESS); } if(hOutput[PIPE_READ]) CloseHandle(hOutput[PIPE_READ]); if(hError[PIPE_READ]) CloseHandle(hError[PIPE_READ]); if(hInput[PIPE_WRITE]) CloseHandle(hInput[PIPE_WRITE]); // Set up the start up info struct. si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.wShowWindow = (mode & POM_showWindow) ? SW_SHOW : SW_HIDE; si.hStdOutput = hOutput[PIPE_WRITE] ? hOutput[PIPE_WRITE] : hStdOut; si.hStdInput = hInput [PIPE_READ] ? hInput [PIPE_READ] : hStdIn; if((mode & POM_error) && (mode & POM_output)) si.hStdError = hOutput[PIPE_WRITE]; else if((mode & POM_error)) si.hStdError = hError[PIPE_WRITE]; else si.hStdError = hError[PIPE_WRITE] ? hError[PIPE_WRITE] : hStdErr; if(CreateProcess(null,_wcommandLine,null,null,TRUE, 0,(void *)env,null ,&si,&pi)) { CloseHandle(pi.hThread); f = calloc(1, sizeof(_DualPipe)); f->inputHandle = hOutputRead; f->outputHandle = hInputWrite; f->hProcess = pi.hProcess; f->pid = pi.dwProcessId; *inputPtr = null; *outputPtr = null; } else { if(hOutputRead) CloseHandle(hOutputRead); if(hInputWrite) CloseHandle(hInputWrite); if(hErrorRead) CloseHandle(hErrorRead); } if(hInput [PIPE_READ]) CloseHandle(hInput [PIPE_READ]); if(hOutput[PIPE_WRITE]) CloseHandle(hOutput[PIPE_WRITE]); if(hError [PIPE_WRITE]) CloseHandle(hError [PIPE_WRITE]); __ecereNameSpace__ecere__com__eSystem_Delete(_wcommandLine); } #endif return f; }