diff options
Diffstat (limited to 'os2/popen.c')
-rw-r--r-- | os2/popen.c | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/os2/popen.c b/os2/popen.c new file mode 100644 index 0000000..12de183 --- /dev/null +++ b/os2/popen.c @@ -0,0 +1,385 @@ +/* popen.c -- popen/pclose for OS/2. */ + +/* Set to 0 for distribution. + Search for "DIAGNOSTIC" in the code to see what it's for. */ +#define DIAGNOSTIC 0 + +#include <process.h> + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <string.h> +#include <fcntl.h> + +#include "config.h" +#include "os2inc.h" + +#define LL_VAL ULONG +#define LL_KEY PID /* also ULONG, really */ + +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 + +/* ********************************************************************* * + * * + * First, a little linked-list library to help keep track of pipes: * + * * + * ********************************************************************* */ + +/* Map integer PID's onto integer termination codes. */ +struct pid_list +{ + HFILE pid; /* key */ + ULONG term_code; /* val */ + struct pid_list *next; /* duh */ +}; + +static struct pid_list *pid_ll = (struct pid_list *) NULL; + +/* The ll_*() functions all make use of the global var `pid_ll'. */ + +void +ll_insert (HFILE key, ULONG val) +{ + struct pid_list *new; + new = (struct pid_list *) xmalloc (sizeof (*new)); + + new->pid = key; + new->term_code = val; + new->next = pid_ll; + + pid_ll = new; +} + + +void +ll_delete (int key) +{ + struct pid_list *this, *last; + + this = pid_ll; + last = (struct pid_list *) NULL; + + while (this) + { + if (this->pid == key) + { + /* Delete this node and leave. */ + if (last) + last->next = this->next; + else + pid_ll = this->next; + free (this); + return; + } + + /* Else no match, so try the next one. */ + last = this; + this = this->next; + } +} + +ULONG +ll_lookup (HFILE key) +{ + struct pid_list *this = pid_ll; + + while (this) + { + if (this->pid == key) + return this->term_code; + + /* Else no match, so try the next one. */ + this = this->next; + } + + /* Zero is special in this context anyway. */ + return 0; +} + +#if DIAGNOSTIC +ULONG +ll_length () +{ + struct pid_list *this = pid_ll; + unsigned long int len; + + for (len = 0; this; len++) + this = this->next; + + return len; +} + +ULONG +ll_print () +{ + struct pid_list *this = pid_ll; + unsigned long int i; + + for (i = 0; this; i++) + { + printf ("pid_ll[%d] == (%5d --> %5d)\n", + i, this->pid, this->term_code); + this = this->next; + } + + if (i == 0) + printf ("No entries.\n"); + + return i; +} +#endif /* DIAGNOSTIC */ + +/* ********************************************************************* * + * * + * End of linked-list library, beginning of popen/pclose: * + * * + * ********************************************************************* */ + +/* + * Routine: popen + * Returns: FILE pointer to pipe. + * Action : Exec program connected via pipe, connect a FILE * to the + * pipe and return it. + * Params : Command - Program to run + * Mode - Mode to open pipe. "r" implies pipe is connected + * to the programs stdout, "w" connects to stdin. + */ +FILE * +popen (const char *Command, const char *Mode) +{ + HFILE End1, End2, Std, Old1, Old2, Tmp; + + FILE *File; + + char Fail[256], + *Args, + CmdLine[256], + *CmdExe; + + RESULTCODES + Result; + + int Rc; + + if (DosCreatePipe (&End1, &End2, 4096)) + return NULL; + + Std = (*Mode == 'w') ? STDIN : STDOUT ; + if (Std == STDIN) + { + Tmp = End1; End1 = End2; End2 = Tmp; + } + + Old1 = -1; /* save stdin or stdout */ + DosDupHandle (Std, &Old1); + DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT); + Tmp = Std; /* redirect stdin or stdout */ + DosDupHandle (End2, &Tmp); + + if (Std == 1) + { + Old2 = -1; /* save stderr */ + DosDupHandle (STDERR, &Old2); + DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT); + Tmp = STDERR; + DosDupHandle (End2, &Tmp); + } + + DosClose (End2); + DosSetFHState (End1, OPEN_FLAGS_NOINHERIT); + + if ((CmdExe = getenv ("COMSPEC")) == NULL ) + CmdExe = "cmd.exe"; + + strcpy (CmdLine, CmdExe); + Args = CmdLine + strlen (CmdLine) + 1; /* skip zero */ + strcpy (Args, "/c "); + strcat (Args, Command); + Args[strlen (Args) + 1] = '\0'; /* two zeroes */ + Rc = DosExecPgm (Fail, sizeof (Fail), EXEC_ASYNCRESULT, + (unsigned char *) CmdLine, 0, &Result, + (unsigned char *) CmdExe); + + Tmp = Std; /* restore stdin or stdout */ + DosDupHandle (Old1, &Tmp); + DosClose (Old1); + + if (Std == STDOUT) + { + Tmp = STDERR; /* restore stderr */ + DosDupHandle (Old2, &Tmp); + DosClose (Old2); + } + + if (Rc) + { + DosClose (End1); + return NULL; + } + +#ifdef __WATCOMC__ + /* Watcom does not allow mixing operating system handles and + * C library handles, so we have to convert. + */ + File = fdopen (_hdopen (End1, *Mode == 'w'? O_WRONLY : O_RDONLY), Mode); +#else + File = fdopen (End1, Mode); +#endif + ll_insert ((LL_KEY) End1, (LL_VAL) Result.codeTerminate); + + return File; +} + + +/* + * Routine: popenRW + * Returns: PID of child process + * Action : Exec program connected via pipe, connect int fd's to + * both the stdin and stdout of the process. + * Params : Command - Program to run + * Pipes - Array of 2 ints to store the pipe descriptors + * Pipe[0] writes to child's stdin, + * Pipe[1] reads from child's stdout/stderr + */ +int +popenRW (const char **argv, int *pipes) +{ + HFILE Out1, Out2, In1, In2; + HFILE Old0 = -1, Old1 = -1, Old2 = -1, Tmp; + + int pid; + + if (DosCreatePipe (&Out2, &Out1, 4096)) + return FALSE; + + if (DosCreatePipe (&In1, &In2, 4096)) + { + DosClose (Out1); + DosClose (Out2); + return FALSE; + } + + /* Save std{in,out,err} */ + DosDupHandle (STDIN, &Old0); + DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT); + DosDupHandle (STDOUT, &Old1); + DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT); + DosDupHandle (STDERR, &Old2); + DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT); + + /* Redirect std{in,out,err} */ + Tmp = STDIN; + DosDupHandle (In1, &Tmp); + Tmp = STDOUT; + DosDupHandle (Out1, &Tmp); + Tmp = STDERR; + DosDupHandle (Out1, &Tmp); + + /* Close file handles not needed in child */ + + DosClose (In1); + DosClose (Out1); + DosSetFHState (In2, OPEN_FLAGS_NOINHERIT); + DosSetFHState (Out2, OPEN_FLAGS_NOINHERIT); + + /* Spawn we now our hoary brood. */ + pid = spawnvp (P_NOWAIT, argv[0], argv); + + /* Restore std{in,out,err} */ + Tmp = STDIN; + DosDupHandle (Old0, &Tmp); + DosClose (Old0); + Tmp = STDOUT; + DosDupHandle (Old1, &Tmp); + DosClose (Old1); + Tmp = STDERR; + DosDupHandle (Old2, &Tmp); + DosClose (Old2); + + if(pid < 0) + { + DosClose (In2); + DosClose (Out2); + return -1; + } + + pipes[0] = In2; + _setmode (pipes[0], O_BINARY); + pipes[1] = Out2; + _setmode (pipes[1], O_BINARY); + + /* Save ID of write-to-child pipe for pclose() */ + ll_insert ((LL_KEY) In2, (LL_VAL) pid); + + return pid; +} + + +/* + * Routine: pclose + * Returns: TRUE on success + * Action : Close a pipe opened with popen(); + * Params : Pipe - pipe to close + */ +int +pclose (FILE *Pipe) +{ + RESULTCODES rc; + PID pid, pid1; + int Handle = fileno (Pipe); + + fclose (Pipe); + + rc.codeTerminate = -1; + + pid1 = (PID) ll_lookup ((LL_KEY) Handle); + /* if pid1 is zero, something's seriously wrong */ + if (pid1 != 0) + { + DosWaitChild (DCWA_PROCESSTREE, DCWW_WAIT, &rc, &pid, pid1); + ll_delete ((LL_KEY) Handle); + } + return rc.codeTerminate == 0 ? rc.codeResult : -1; +} + + +#if DIAGNOSTIC +void +main () +{ + FILE *fp1, *fp2, *fp3; + int c; + + ll_print (); + fp1 = popen ("gcc --version", "r"); + ll_print (); + fp2 = popen ("link386 /?", "r"); + ll_print (); + fp3 = popen ("dir", "r"); + ll_print (); + + while ((c = getc (fp1)) != EOF) + printf ("%c", c); + + while ((c = getc (fp2)) != EOF) + printf ("%c", c); + + while ((c = getc (fp3)) != EOF) + printf ("%c", c); + + pclose (fp1); + ll_print (); + pclose (fp2); + ll_print (); + pclose (fp3); + ll_print (); + + return; +} + +#endif /* DIAGNOSTIC */ |