Back to index

radiance  4R0+20100331
Defines | Functions | Variables
win_popen.c File Reference
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <io.h>
#include <fcntl.h>
#include "paths.h"
#include "rtio.h"
#include "rterror.h"

Go to the source code of this file.

Defines

#define RAD_MAX_PIPES   32 /* maximum number of pipes */
#define R_MODE   1
#define W_MODE   2
#define A_MODE   3

Functions

static int parse_pipes (char *s, char *lines[], char **infn, char **outfn, int *append, int maxl)
static BOOL createPipes (HANDLE *, HANDLE *, HANDLE *, HANDLE *)
static BOOL runChild (char *, char *, HANDLE, HANDLE, HANDLE)
static void resetStdHandles (HANDLE stdoutOrig, HANDLE stdinOrig)
HANDLE newFile (char *fn, int mode)
int win_pclose (FILE *p)
FILE * win_popen (char *command, char *type)

Variables

static const char RCSid [] = "$Id: win_popen.c,v 1.4 2004/10/04 10:14:22 schorsch Exp $"

Define Documentation

#define A_MODE   3

Definition at line 34 of file win_popen.c.

#define R_MODE   1

Definition at line 32 of file win_popen.c.

#define RAD_MAX_PIPES   32 /* maximum number of pipes */

Definition at line 30 of file win_popen.c.

#define W_MODE   2

Definition at line 33 of file win_popen.c.


Function Documentation

static BOOL createPipes ( HANDLE *  stdoutRd,
HANDLE *  stdoutWr,
HANDLE *  stdinRd,
HANDLE *  stdinWr 
) [static]

Definition at line 196 of file win_popen.c.

{
       HANDLE stdoutRdInh = NULL;
       HANDLE stdinWrInh = NULL;
       HANDLE curproc;
       SECURITY_ATTRIBUTES sAttr;
       
       curproc = GetCurrentProcess();
       
       /* The rules of inheritance for handles are a mess.
          Just to be safe, make all handles we pass to the
          child processes inheritable */
       sAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
       sAttr.bInheritHandle = TRUE;
       sAttr.lpSecurityDescriptor = NULL;
       
       if(*stdoutRd != NULL){
       /* if we have a previous stdout pipe,
          assign the other end to stdin for the new process */
              CloseHandle(*stdinRd);
              if(!DuplicateHandle(curproc, *stdoutRd,
                     curproc, stdinRd, 0,
                     TRUE, DUPLICATE_SAME_ACCESS))
                     return FALSE;
              CloseHandle(*stdoutRd);
              if(!SetStdHandle(STD_INPUT_HANDLE, *stdinRd))
                     return FALSE;
       } else {
              /* there's no previous stdout, create a new stdin pipe */
              if(!CreatePipe(stdinRd, &stdinWrInh, &sAttr, 0))
                     return FALSE;
              if(!SetStdHandle(STD_INPUT_HANDLE, *stdinRd))
                     return FALSE;
              CloseHandle(stdinWrInh);
       }
       
       /* create the stdout pipe for the new process */
       if(!CreatePipe(&stdoutRdInh, stdoutWr, &sAttr, 0))
              return FALSE;
       if(!SetStdHandle(STD_OUTPUT_HANDLE, *stdoutWr))
              return FALSE;
       if(!DuplicateHandle(curproc, stdoutRdInh,
              curproc, stdoutRd, 0,
              FALSE, DUPLICATE_SAME_ACCESS))
              return FALSE;
       CloseHandle(stdoutRdInh);
       
       return TRUE;
}

Here is the caller graph for this function:

HANDLE newFile ( char *  fn,
int  mode 
)

Definition at line 162 of file win_popen.c.

{
       SECURITY_ATTRIBUTES sAttr;
       HANDLE fh;

       sAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
       sAttr.bInheritHandle = TRUE;
       sAttr.lpSecurityDescriptor = NULL;

       if (mode == R_MODE) {
              fh = CreateFile(fn,
                            GENERIC_READ,
                            FILE_SHARE_READ,
                            &sAttr,
                            OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL);
       } else if (mode == W_MODE || mode == A_MODE) {
              fh = CreateFile(fn,
                            GENERIC_WRITE,
                            FILE_SHARE_WRITE,
                            &sAttr,
                            mode==W_MODE?CREATE_ALWAYS:OPEN_ALWAYS,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL);
       }
       if (fh == NULL) {
              int e = GetLastError();
       }
       return fh;
}

Here is the caller graph for this function:

static int parse_pipes ( char *  s,
char *  lines[],
char **  infn,
char **  outfn,
int *  append,
int  maxl 
) [static]

Definition at line 264 of file win_popen.c.

{
       int n = 0, i;
       char *se, *ws;
       char *curs;
       int llen = 0;
       int quote = 0;
       int last = 0;

       if (maxl<= 0) return 0;
       if (s == NULL) {
              return 0;
       }
       *infn = *outfn = NULL;
       while (isspace(*s)) s++; /* leading whitespace */
       se = s;
       while (n < maxl) {
              switch (*se) {
                     case '"':
                            if (quote == '"') quote = 0;
                            else if (quote == 0) quote = '"';
                            break;
                     case '\'':
                            if (quote == '\'') quote = 0;
                            else if (quote == 0) quote = '\'';
                            break;
                     case '<':
                     case '>':
                     case '|':
                     case '\0':
                            if (*se != '\0' && quote)
                                   break;
                            llen = se - s;
                            curs = malloc(llen+1);
                            strncpy(curs, s, llen);
                            /* remove unix style line-end escapes */
                            while((ws = strstr(curs, "\\\n")) != NULL)
                                   *ws = *(ws+1) = ' ';
                            /* remove DOS style line-end escapes */
                            while((ws = strstr(curs, "\\\r\n")) != NULL)
                                   *ws = *(ws+1) = *(ws+2) = ' ';
                            while (isspace(*(curs + llen - 1)))
                                   llen--; /* trailing whitespace */
                            curs[llen] = '\0';

                            if (last == '|' || last == 0) { /* first or pipe */
                                   lines[n] = curs;
                                   n++;
                                   curs = NULL;
                            } else if (last == '<') { /* input file */
                                   if (*infn != NULL) {
                                          eputs("win_popen(): ambiguous input redirection");
                                          goto error;
                                   }
                                   *infn = curs;
                                   curs = NULL;
                            } else if (last == '>') { /* output file */
                                   if (*outfn != NULL) {
                                          eputs("win_popen(): ambiguous output redirection");
                                          goto error;
                                   }
                                   *outfn = curs;
                                   curs = NULL;
                                   if (*se != '\0' && *se+1 == '>') { /* >> */
                                          *append = 1;
                                          se++;
                                   }
                            }
                            last = *se;

                            if (*se == '\0') return n;
                            s = se + 1;
                            while (isspace(*s)) s++; /* leading whitespace */
                            se = s;
                            break;
                     default:
                            break;
              }
              se++;
       }
       /* more jobs than slots */
error:
       for (i = 0; i < n; i++) free(lines[i]);
       if (*infn != NULL) free(*infn);
       if (*outfn != NULL) free(*outfn);
       if (curs != NULL) free(curs);
       return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void resetStdHandles ( HANDLE  stdoutOrig,
HANDLE  stdinOrig 
) [static]

Definition at line 253 of file win_popen.c.

{
       SetStdHandle(STD_OUTPUT_HANDLE, stdoutOrig);
       SetStdHandle(STD_INPUT_HANDLE, stdinOrig);
}

Here is the caller graph for this function:

static BOOL runChild ( char *  executable,
char *  cmdline,
HANDLE  stdinRd,
HANDLE  stdoutWr,
HANDLE  stderrWr 
) [static]

Definition at line 362 of file win_popen.c.

{
       PROCESS_INFORMATION procInfo;
       STARTUPINFO startupInfo;

       /* use the given handles and don't display the console window */
       ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
       startupInfo.cb = sizeof(STARTUPINFO);
       startupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
       startupInfo.wShowWindow = SW_HIDE;
       startupInfo.hStdInput = stdinRd;
       startupInfo.hStdOutput = stdoutWr;
       startupInfo.hStdError = stderrWr;

       return CreateProcess(executable, cmdline, NULL, NULL,
              TRUE, 0,
              NULL, NULL, &startupInfo, &procInfo);
}

Here is the caller graph for this function:

int win_pclose ( FILE *  p)

Definition at line 45 of file win_popen.c.

{
       fclose(p);
       /* not sure if it's useful to wait for anything on Windows */
       return 0;
}
FILE* win_popen ( char *  command,
char *  type 
)

Definition at line 56 of file win_popen.c.

{
       char *execfile, *args;
       char *cmdlines[RAD_MAX_PIPES];
       char *infn = NULL, *outfn = NULL;
       char executable[512], estr[512];
       int n, i, mode = 0, append = 0;
       int ncmds = 0;
       FILE *inf = NULL;
       HANDLE stdoutRd = NULL, stdoutWr = NULL;
       HANDLE stdinRd = NULL, stdinWr = NULL;
       HANDLE stderrWr = NULL;
       HANDLE stdoutOrig, stdinOrig;

       if (strchr(type, 'w')) {
              mode = W_MODE;
       } else if (strchr(type, 'r')) {
              mode = R_MODE;
       } else {
              _snprintf(estr, sizeof(estr),
                            "Invalid mode \"%s\" for win_popen().", type);
              eputs(estr);
              return NULL;
       }

       stdoutOrig = GetStdHandle(STD_OUTPUT_HANDLE);
       stdinOrig = GetStdHandle(STD_INPUT_HANDLE);
       /* if we have a console, use it for error output */
       stderrWr = GetStdHandle(STD_ERROR_HANDLE);

       ncmds = parse_pipes(command,cmdlines,&infn,&outfn,&append,RAD_MAX_PIPES);
       if(ncmds <= 0) {
              eputs("Too many pipes or malformed command.");
              goto error;
       }

       if (infn != NULL) {
              stdoutRd = newFile(infn, mode);
       }

       for(n = 0; n < ncmds; ++n) {
              if(!createPipes(&stdoutRd, &stdoutWr,
                     &stdinRd, &stdinWr)) {
                     eputs("Error creating pipe");
                     goto error;
              }
              if (outfn != NULL && n == ncmds - 1) {
                     CloseHandle(stdoutWr);
                     CloseHandle(stdoutRd);
                     stdoutWr = newFile(outfn, mode);
              }
              if (n == 0 && mode == W_MODE) {
                     /* create a standard C file pointer for writing to the input */
                     inf = _fdopen(_open_osfhandle((long)stdinWr, _O_RDONLY), "w");
              }
              /* find the executable on the PATH */
              args = nextword(executable, sizeof(executable), cmdlines[n]);
              if (args == NULL) {
                     eputs("Empty command.");
                     goto error;
              }
              execfile = getpath(executable, getenv("PATH"), X_OK);
              if(execfile == NULL) {
                     _snprintf(estr, sizeof(estr),
                                   "Can't find executable for \"%s\".", executable);
                     eputs(estr);
                     goto error;
              }
              if(!runChild(execfile, cmdlines[n], stdinRd, stdoutWr, stderrWr)) {
                     _snprintf(estr, sizeof(estr),
                                   "Unable to execute executable \"%s\".", executable);
                     eputs(estr);
                     goto error;
              }
              /* close the stdout end just passed to the last process,
                 or the final read will block */
              CloseHandle(stdoutWr);
       }

       /* clean up */
       resetStdHandles(stdinOrig, stdoutOrig);
       for (i = 0; i < ncmds; i++) free(cmdlines[i]);
       if (infn != NULL) free(infn);
       if (outfn != NULL) free(outfn);

       if (mode == R_MODE) {
              /* return a standard C file pointer for reading the output */
              return _fdopen(_open_osfhandle((long)stdoutRd, _O_RDONLY), "r");
       } else if (mode == W_MODE) {
              /* return a standard C file pointer for writing to the input */
              return inf;
       }

error:
       resetStdHandles(stdinOrig, stdoutOrig);
       for (i = 0; i < ncmds; i++) free(cmdlines[i]);
       if (infn != NULL) free(infn);
       if (outfn != NULL) free(outfn);
       return NULL;
}

Here is the call graph for this function:


Variable Documentation

const char RCSid[] = "$Id: win_popen.c,v 1.4 2004/10/04 10:14:22 schorsch Exp $" [static]

Definition at line 2 of file win_popen.c.