home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / cvs-1.8.7-src.tgz / tar.out / fsf / cvs / os2 / popen.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  8KB  |  381 lines

  1. /* popen.c -- popen/pclose for OS/2. */
  2.  
  3. /* Set to 0 for distribution.
  4.    Search for "DIAGNOSTIC" in the code to see what it's for. */
  5. #define DIAGNOSTIC 0
  6.  
  7. #define INCL_DOSQUEUES
  8. #define INCL_DOSPROCESS
  9. #define INCL_DOSSESMGR
  10. #include    <os2.h>
  11. #include    <process.h>
  12.  
  13. #include    <stdio.h>
  14. #include    <stdlib.h>
  15. #include    <sys/types.h>
  16. #include    <sys/stat.h>
  17. #include    <ctype.h>
  18. #include    <string.h>
  19. #include    <fcntl.h>
  20.  
  21. #define LL_VAL ULONG
  22. #define LL_KEY PID    /* also ULONG, really */
  23.  
  24.  
  25. #define STDIN       0
  26. #define STDOUT      1
  27. #define STDERR      2
  28.  
  29. /* ********************************************************************* *
  30.  *                                                                       *
  31.  *   First, a little linked-list library to help keep track of pipes:    *
  32.  *                                                                       *
  33.  * ********************************************************************* */
  34.  
  35. /* Map integer PID's onto integer termination codes. */
  36. struct pid_list
  37. {
  38.   HFILE pid;              /* key */
  39.   ULONG term_code;        /* val */
  40.   struct pid_list *next;  /* duh */ 
  41. };
  42.  
  43. static struct pid_list *pid_ll = (struct pid_list *) NULL;
  44.  
  45. /* The ll_*() functions all make use of the global var `pid_ll'. */
  46.  
  47. void
  48. ll_insert (HFILE key, ULONG val)
  49. {
  50.   struct pid_list *new;
  51.   new = (struct pid_list *) malloc (sizeof (*new));
  52.  
  53.   new->pid       = key;
  54.   new->term_code = val;
  55.   new->next      = pid_ll;
  56.  
  57.   pid_ll = new;
  58. }
  59.  
  60.  
  61. void
  62. ll_delete (int key)
  63. {
  64.   struct pid_list *this, *last;
  65.  
  66.   this = pid_ll;
  67.   last = (struct pid_list *) NULL;
  68.  
  69.   while (this)
  70.     {
  71.       if (this->pid == key)
  72.         {
  73.           /* Delete this node and leave. */
  74.           if (last)
  75.             last->next = this->next;
  76.           else
  77.             pid_ll = this->next;
  78.           free (this);
  79.           return;
  80.         }
  81.  
  82.       /* Else no match, so try the next one. */
  83.       last = this;
  84.       this = this->next;
  85.     }
  86. }
  87.  
  88. ULONG
  89. ll_lookup (HFILE key)
  90. {
  91.   struct pid_list *this = pid_ll;
  92.  
  93.   while (this)
  94.     {
  95.       if (this->pid == key)
  96.         return this->term_code;
  97.  
  98.       /* Else no match, so try the next one. */
  99.       this = this->next;
  100.     }
  101.  
  102.   /* Zero is special in this context anyway. */
  103.   return 0;
  104. }
  105.  
  106. #if DIAGNOSTIC
  107. ULONG
  108. ll_length ()
  109. {
  110.   struct pid_list *this = pid_ll;
  111.   unsigned long int len;
  112.  
  113.   for (len = 0; this; len++)
  114.     this = this->next;
  115.  
  116.   return len;
  117. }
  118.  
  119. ULONG
  120. ll_print ()
  121. {
  122.   struct pid_list *this = pid_ll;
  123.   unsigned long int i;
  124.  
  125.   for (i = 0; this; i++)
  126.     {
  127.       printf ("pid_ll[%d] == (%5d --> %5d)\n",
  128.               i, this->pid, this->term_code);
  129.       this = this->next;
  130.     }
  131.  
  132.   if (i == 0)
  133.     printf ("No entries.\n");
  134.  
  135.   return i;
  136. }
  137. #endif /* DIAGNOSTIC */
  138.  
  139. /* ********************************************************************* *
  140.  *                                                                       *
  141.  *       End of linked-list library, beginning of popen/pclose:          *
  142.  *                                                                       *
  143.  * ********************************************************************* */
  144.  
  145. /*
  146.  *  Routine: popen
  147.  *  Returns: FILE pointer to pipe.
  148.  *  Action : Exec program connected via pipe, connect a FILE * to the
  149.  *           pipe and return it.
  150.  *  Params : Command - Program to run
  151.  *           Mode    - Mode to open pipe.  "r" implies pipe is connected
  152.  *                     to the programs stdout, "w" connects to stdin.
  153.  */
  154. FILE *
  155. popen (const char *Command, const char *Mode)
  156. {
  157.     HFILE End1, End2, Std, Old1, Old2, Tmp;
  158.  
  159.     FILE *File;
  160.  
  161.     char    Fail[256],
  162.             *Args,
  163.             CmdLine[256],
  164.             *CmdExe;
  165.  
  166.     RESULTCODES
  167.             Result;
  168.  
  169.     int     Rc;
  170.  
  171.     if (DosCreatePipe (&End1, &End2, 4096))
  172.         return NULL;
  173.  
  174.     Std = (*Mode == 'w') ? STDIN : STDOUT ;
  175.     if (Std == STDIN)
  176.     {
  177.         Tmp = End1; End1 = End2; End2 = Tmp;
  178.     }
  179.  
  180.     Old1 = -1; /* save stdin or stdout */
  181.     DosDupHandle (Std, &Old1);
  182.     DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT);
  183.     Tmp = Std; /* redirect stdin or stdout */
  184.     DosDupHandle (End2, &Tmp);
  185.  
  186.     if (Std == 1) 
  187.     {
  188.         Old2 = -1; /* save stderr */
  189.         DosDupHandle (STDERR, &Old2);
  190.         DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
  191.         Tmp = STDERR;
  192.         DosDupHandle (End2, &Tmp);
  193.     }
  194.  
  195.     DosClose (End2);
  196.     DosSetFHState (End1, OPEN_FLAGS_NOINHERIT);
  197.  
  198.     if ((CmdExe = getenv ("COMSPEC")) == NULL )
  199.         CmdExe = "cmd.exe";
  200.  
  201.     strcpy (CmdLine, CmdExe);
  202.     Args = CmdLine + strlen (CmdLine) + 1; /* skip zero */
  203.     strcpy (Args, "/c ");
  204.     strcat (Args, Command);
  205.     Args[strlen (Args) + 1] = '\0'; /* two zeroes */
  206.     Rc = DosExecPgm (Fail, sizeof (Fail), EXEC_ASYNCRESULT, 
  207.                      (unsigned char *) CmdLine, 0, &Result,
  208.                      (unsigned char *) CmdExe);
  209.  
  210.     Tmp = Std; /* restore stdin or stdout */
  211.     DosDupHandle (Old1, &Tmp);
  212.     DosClose (Old1);
  213.  
  214.     if (Std == STDOUT) 
  215.     {
  216.         Tmp = STDERR;   /* restore stderr */
  217.         DosDupHandle (Old2, &Tmp);
  218.         DosClose (Old2);
  219.     }
  220.  
  221.     if (Rc)
  222.     {
  223.         DosClose (End1);
  224.         return NULL;
  225.     }
  226.   
  227.     File = fdopen (End1, Mode);
  228.     ll_insert ((LL_KEY) End1, (LL_VAL) Result.codeTerminate);
  229.  
  230.     return File;
  231. }
  232.         
  233.  
  234. /*
  235.  *  Routine: popenRW
  236.  *  Returns: PID of child process
  237.  *  Action : Exec program connected via pipe, connect int fd's to 
  238.  *           both the stdin and stdout of the process.
  239.  *  Params : Command - Program to run
  240.  *           Pipes   - Array of 2 ints to store the pipe descriptors
  241.  *                     Pipe[0] writes to child's stdin,
  242.  *                     Pipe[1] reads from child's stdout/stderr
  243.  */
  244. int
  245. popenRW (const char **argv, int *pipes)
  246. {
  247.     HFILE Out1, Out2, In1, In2;
  248.     HFILE Old0 = -1, Old1 = -1, Old2 = -1, Tmp;
  249.  
  250.     PID pid;
  251.  
  252.     if (DosCreatePipe (&Out2, &Out1, 4096))
  253.         return FALSE;
  254.  
  255.     if (DosCreatePipe (&In1, &In2, 4096))
  256.     {
  257.         DosClose (Out1);
  258.         DosClose (Out2);
  259.         return FALSE;
  260.     }
  261.  
  262.     /* Save std{in,out,err} */
  263.     DosDupHandle (STDIN, &Old0);
  264.     DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT);
  265.     DosDupHandle (STDOUT, &Old1);
  266.     DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
  267.     DosDupHandle (STDERR, &Old2);
  268.     DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT);
  269.  
  270.     /* Redirect std{in,out,err} */
  271.     Tmp = STDIN;
  272.     DosDupHandle (In1, &Tmp);
  273.     Tmp = STDOUT;
  274.     DosDupHandle (Out1, &Tmp);
  275.     Tmp = STDERR;
  276.     DosDupHandle (Out1, &Tmp);
  277.  
  278.     /* Close file handles not needed in child */
  279.     
  280.     DosClose (In1);
  281.     DosClose (Out1);
  282.     DosSetFHState (In2, OPEN_FLAGS_NOINHERIT);
  283.     DosSetFHState (Out2, OPEN_FLAGS_NOINHERIT);
  284.  
  285.     /* Spawn we now our hoary brood. */
  286.     pid = spawnvp (P_NOWAIT, argv[0], argv);
  287.  
  288.     /* Restore std{in,out,err} */
  289.     Tmp = STDIN;
  290.     DosDupHandle (Old0, &Tmp);
  291.     DosClose (Old0);
  292.     Tmp = STDOUT;
  293.     DosDupHandle (Old1, &Tmp);
  294.     DosClose (Old1);
  295.     Tmp = STDERR;
  296.     DosDupHandle (Old2, &Tmp);
  297.     DosClose (Old2);
  298.  
  299.     if(pid < 0) 
  300.       {
  301.         DosClose (In2);
  302.         DosClose (Out2);
  303.         return -1;
  304.       }
  305.     
  306.     pipes[0] = In2;
  307.     _setmode (pipes[0], O_BINARY);
  308.     pipes[1] = Out2;
  309.     _setmode (pipes[1], O_BINARY);
  310.  
  311.     /* Save ID of write-to-child pipe for pclose() */
  312.     ll_insert ((LL_KEY) In2, (LL_VAL) pid);
  313.     
  314.     return pid;
  315. }
  316.  
  317.  
  318. /*
  319.  *  Routine: pclose
  320.  *  Returns: TRUE on success
  321.  *  Action : Close a pipe opened with popen();
  322.  *  Params : Pipe - pipe to close
  323.  */
  324. int
  325. pclose (FILE *Pipe) 
  326. {
  327.     RESULTCODES rc;
  328.     PID pid, pid1;
  329.     int Handle = fileno (Pipe);
  330.  
  331.     fclose (Pipe);
  332.  
  333.     rc.codeTerminate = -1;
  334.  
  335.     pid1 = (PID) ll_lookup ((LL_KEY) Handle);
  336.     /* if pid1 is zero, something's seriously wrong */
  337.     if (pid1 != 0)
  338.       {
  339.         DosWaitChild (DCWA_PROCESSTREE, DCWW_WAIT, &rc, &pid, pid1);
  340.         ll_delete ((LL_KEY) Handle);
  341.       }
  342.     return rc.codeTerminate == 0 ? rc.codeResult : -1;
  343. }
  344.  
  345.  
  346. #if DIAGNOSTIC
  347. void
  348. main ()
  349. {
  350.   FILE *fp1, *fp2, *fp3;
  351.   int c;
  352.  
  353.   ll_print ();
  354.   fp1 = popen ("gcc --version", "r");
  355.   ll_print ();
  356.   fp2 = popen ("link386 /?", "r");
  357.   ll_print ();
  358.   fp3 = popen ("dir", "r");
  359.   ll_print ();
  360.  
  361.   while ((c = getc (fp1)) != EOF)
  362.     printf ("%c", c);
  363.  
  364.   while ((c = getc (fp2)) != EOF)
  365.     printf ("%c", c);
  366.  
  367.   while ((c = getc (fp3)) != EOF)
  368.     printf ("%c", c);
  369.  
  370.   pclose (fp1);
  371.   ll_print ();
  372.   pclose (fp2);
  373.   ll_print ();
  374.   pclose (fp3);
  375.   ll_print ();
  376.  
  377.   return;
  378. }
  379.  
  380. #endif /* DIAGNOSTIC */
  381.