home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / rcs57pc3.zip / diff / pc / popen.c < prev    next >
C/C++ Source or Header  |  1999-01-17  |  11KB  |  534 lines

  1. /* popen.c
  2.  *
  3.  * Author:  Kai Uwe Rommel <rommel@ars.de>
  4.  * Created: Wed Aug 23 1995
  5.  */
  6.  
  7. static char *rcsid =
  8. "$Id$";
  9. static char *rcsrev = "$Revision$";
  10.  
  11. /*
  12.  * $Log$ 
  13.  */
  14.  
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <io.h>
  18. #include <fcntl.h>
  19. #include <string.h>
  20.  
  21. #ifdef __EMX__
  22. #include <alloca.h>
  23. #endif
  24. #ifdef __IBMC__
  25. #define alloca _alloca
  26. #endif
  27. #ifdef __WATCOMC__
  28. #include <malloc.h>
  29. #define tempnam _tempnam
  30. #endif
  31.  
  32. #include "popen.h"
  33.  
  34. #if defined(__OS2__) && !defined(OS2)
  35. #define OS2
  36. #endif
  37.  
  38. #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
  39. #define WIN32
  40. #endif
  41.  
  42. #ifdef M_I86
  43.  
  44. FILE *popen(const char *cmd, const char *mode)
  45. {
  46.   return (_osmode == DOS_MODE) ? fake_popen(cmd, mode) : _popen(cmd, mode);
  47. }
  48.  
  49. int pclose(FILE *ptr)
  50. {
  51.   return (_osmode == DOS_MODE) ? fake_pclose(ptr) : _pclose(ptr);
  52. }
  53.  
  54. int pipe(int *handles)
  55. {
  56.   return _pipe(handles, 4096, O_BINARY);
  57. }
  58.  
  59. #else
  60.  
  61. #ifdef OS2
  62.  
  63. #define INCL_DOS
  64. #define INCL_NOPM
  65. #include <os2.h>
  66.  
  67. static int pids[MAXPIPES];
  68.  
  69. FILE *popen(const char *cmd, const char *mode) 
  70. {
  71.   HFILE end1, end2, std, old1, old2, temp;
  72.   FILE *file;
  73.   RESULTCODES res;
  74.   char fail[256], cmdline[256], *args, *shell;
  75.   const char *ptr;
  76.   int fmode, rc;
  77.  
  78.   for (ptr = mode; *ptr; ptr++)
  79.     switch (*ptr)
  80.     {
  81.     case 'r':
  82.       std = 1;
  83.       break;
  84.     case 'w':
  85.       std = 0;
  86.       break;
  87.     case 't':
  88.       fmode = O_TEXT;
  89.       break;
  90.     case 'b':
  91.       fmode = O_BINARY;
  92.       break;
  93.     }
  94.   
  95.   if (DosCreatePipe(&end1, &end2, 4096))
  96.     return NULL;
  97.  
  98.   if (std == 0) 
  99.   {
  100.     temp = end1; end1 = end2; end2 = temp;
  101.   }
  102.  
  103.   old1 = -1; /* save stdin or stdout */
  104.   DosDupHandle(std, &old1);
  105.   DosSetFHState(old1, OPEN_FLAGS_NOINHERIT);
  106.   temp = std; /* redirect stdin or stdout */
  107.   DosDupHandle(end2, &temp);
  108.  
  109.   if (std == 1) 
  110.   {
  111.     old2 = -1; /* save stderr */
  112.     DosDupHandle(2, &old2);
  113.     DosSetFHState(old2, OPEN_FLAGS_NOINHERIT);
  114.     temp = 2;   /* redirect stderr */
  115.     DosDupHandle(end2, &temp);
  116.   }
  117.  
  118.   DosClose(end2);
  119.   DosSetFHState(end1, OPEN_FLAGS_NOINHERIT);
  120.  
  121.   if ((shell = getenv("COMSPEC")) == NULL)
  122.     shell = "cmd.exe";
  123.  
  124.   strcpy(cmdline, shell);
  125.   args = cmdline + strlen(cmdline) + 1; /* skip zero */
  126.   strcpy(args, "/c ");
  127.   strcat(args, cmd);
  128.   args[strlen(args) + 1] = '\0'; /* two zeroes */
  129.  
  130.   rc = DosExecPgm(fail, sizeof(fail), EXEC_ASYNCRESULT, cmdline, 0, &res, shell);
  131.  
  132.   temp = std; /* restore stdin or stdout */
  133.   DosDupHandle(old1, &temp);
  134.   DosClose(old1);
  135.  
  136.   if (std == 1) 
  137.   {
  138.     temp = 2;   /* restore stderr */
  139.     DosDupHandle(old2, &temp);
  140.     DosClose(old2);
  141.   }
  142.  
  143.   if (rc) 
  144.   {
  145.     DosClose(end1);
  146.     return NULL;
  147.   }
  148.   
  149. #ifdef __IBMC__
  150.   _setmode(end1, fmode);
  151. #endif
  152.  
  153.   file = fdopen(end1, mode);
  154.   pids[end1] = res.codeTerminate;
  155.  
  156.   return file;
  157. }
  158.  
  159. int pclose(FILE *pipe) 
  160. {
  161.   RESULTCODES rc;
  162.   PID pid;
  163.   int handle = fileno(pipe);
  164.  
  165.   fclose(pipe);
  166.  
  167.   if (pids[handle])
  168.     DosWaitChild(DCWA_PROCESSTREE, DCWW_WAIT, &rc, &pid, pids[handle]);
  169.  
  170.   pids[handle] = 0;
  171.  
  172. #ifdef __EMX__
  173.   return rc.codeTerminate == 0 ? (rc.codeResult << 8) : -1;
  174. #else
  175.   return rc.codeTerminate == 0 ? rc.codeResult : -1;
  176. #endif
  177. }
  178.  
  179. int pipe(int *handles)
  180. {
  181.   HFILE end1, end2;
  182.  
  183.   if (DosCreatePipe(&end1, &end2, 4096))
  184.     return -1;
  185.  
  186. #ifdef __IBMC__
  187.   _setmode(end1, O_TEXT);
  188.   _setmode(end2, O_TEXT);
  189. #endif
  190.  
  191.   handles[0] = (int) end1;
  192.   handles[1] = (int) end2;
  193.  
  194.   return 0;
  195. }
  196.  
  197. #else
  198.  
  199. #ifdef WIN32
  200.  
  201. #include <windows.h>
  202. #ifdef __EMX__
  203. /* #define _open_osfhandle(h, m) _imphandle(h) 
  204.    nolonger needed with RSXNT 1.42 */
  205. #include <mscompat.h>
  206. #endif
  207.  
  208. PROCESS_INFORMATION pid[MAXPIPES];
  209.  
  210. FILE *popen(const char *cmd, const char *mode) 
  211. {
  212.   HANDLE rpipe, wpipe, handle, other;
  213. #ifdef VERSION2
  214.   HANDLE old0, old1, old2;
  215. #endif
  216.   SECURITY_ATTRIBUTES security;
  217.   STARTUPINFO si;
  218.   PROCESS_INFORMATION pi;
  219.   char buffer[8192];
  220.   const char *ptr;
  221.   int fhandle, fmode, rc;
  222.   OSVERSIONINFO osvi;
  223.   static int WindowsNT = -1;
  224.  
  225.   if (WindowsNT == -1)
  226.   {
  227.     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  228.     GetVersionEx(&osvi);
  229.     WindowsNT = (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT);
  230.   }
  231.  
  232.   for (fmode = 0, ptr = mode; *ptr; ptr++)
  233.     switch (*ptr)
  234.     {
  235.     case 'r':
  236.       fmode |= O_RDONLY;
  237.       break;
  238.     case 'w':
  239.       fmode |= O_WRONLY;
  240.       break;
  241.     case 't':
  242.       fmode |= O_TEXT;
  243.       break;
  244.     case 'b':
  245.       fmode |= O_BINARY;
  246.       break;
  247.     }
  248.   
  249.   security.nLength = sizeof(security);
  250.   security.bInheritHandle = TRUE;
  251.   security.lpSecurityDescriptor = NULL;
  252.  
  253.   if (!CreatePipe(&rpipe, &wpipe, &security, 0))
  254.     return NULL;
  255.  
  256.   handle = (fmode & O_WRONLY) ? wpipe : rpipe;
  257.   other  = (fmode & O_WRONLY) ? rpipe : wpipe;
  258.  
  259.   SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
  260.   fhandle = _open_osfhandle((long) handle, fmode);
  261.  
  262.   if (fhandle < 0 || MAXPIPES <= fhandle)
  263.   {
  264.     CloseHandle(rpipe);
  265.     CloseHandle(wpipe);
  266.     return NULL;
  267.   }
  268.   
  269.   memset(&si, 0, sizeof(si));
  270.   si.cb = sizeof(si);
  271.  
  272.   /* Both of the two following versions of redirection work fine. We keep
  273.    * them both here just for reference. The one #ifdef'ed VERSION2 is the
  274.    * more common one but the other one is (fail-) safer.
  275.    */
  276.  
  277. #ifdef VERSION2
  278.   if (fmode & O_WRONLY) 
  279.   {
  280.     old0 = GetStdHandle(STD_INPUT_HANDLE);
  281.     SetStdHandle(STD_INPUT_HANDLE, rpipe);
  282.   }
  283.   else
  284.   {
  285.     old1 = GetStdHandle(STD_OUTPUT_HANDLE);
  286.     old2 = GetStdHandle(STD_ERROR_HANDLE);
  287.     SetStdHandle(STD_OUTPUT_HANDLE, wpipe);
  288.     SetStdHandle(STD_ERROR_HANDLE, wpipe);
  289.   }
  290. #else
  291.   si.dwFlags = STARTF_USESTDHANDLES;
  292.  
  293.   if (fmode & O_WRONLY) 
  294.   {
  295.     si.hStdInput  = rpipe;
  296.     si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  297.     si.hStdError  = GetStdHandle(STD_ERROR_HANDLE);
  298.   }
  299.   else
  300.   {
  301.     si.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
  302.     si.hStdOutput = wpipe;
  303.     si.hStdError  = wpipe;
  304.   }
  305. #endif
  306.  
  307.   /* Using anonymous pipes and CreateProcess to redirect stdin or stdout does
  308.    * only work without any restrictions on Windows NT. On Windows 95, it
  309.    * does only work if the child process is also a Win32 application and not
  310.    * an old 16-bit executable. The problem is, that the Windows 95 command
  311.    * line interpreter or shell (command.com) is also an old 16-bit program.
  312.    * The semantics of popen() normally require execution through a shell
  313.    * but that can never work on Windows 95 because of this restriction.
  314.    * Therefore, if we do not run on Windows NT, we must try to run the command
  315.    * without a shell to at least cover _some_ cases. Otherwise we just fail.
  316.    */
  317.  
  318.   if (!WindowsNT)
  319.     rc = CreateProcess(NULL, (char *) cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
  320.   else
  321.   {
  322.     if ((ptr = getenv("COMSPEC")) == NULL)
  323.       ptr = "cmd.exe";
  324.  
  325.     strcpy(buffer, ptr);
  326.     strcat(buffer, " /c ");
  327.     strcat(buffer, cmd);
  328.  
  329.     rc = CreateProcess(ptr, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
  330.   }
  331.  
  332. #ifdef VERSION2
  333.   if (fmode & O_WRONLY)
  334.     SetStdHandle(STD_INPUT_HANDLE, old0);
  335.   else
  336.   {
  337.     SetStdHandle(STD_OUTPUT_HANDLE, old1);
  338.     SetStdHandle(STD_ERROR_HANDLE, old2);
  339.   }
  340. #endif
  341.  
  342.   if (rc == 0)
  343.   {
  344.     CloseHandle(rpipe);
  345.     CloseHandle(wpipe);
  346.     return NULL;
  347.   }
  348.   
  349.   CloseHandle(other);
  350.  
  351.   pid[fhandle] = pi;
  352.  
  353.   return fdopen(fhandle, (char *) mode);
  354. }
  355.  
  356. int pclose(FILE *pipe) 
  357. {
  358.   PROCESS_INFORMATION pi;
  359.   DWORD rc;
  360.   int fhandle = fileno(pipe);
  361.  
  362.   if (fhandle < 0 || MAXPIPES <= fhandle)
  363.     return -1;
  364.  
  365.   fclose(pipe);
  366.  
  367.   pi = pid[fhandle];
  368.  
  369.   WaitForSingleObject(pi.hProcess, INFINITE);
  370.   GetExitCodeProcess(pi.hProcess, &rc);
  371.  
  372.   CloseHandle(pi.hProcess);
  373.   CloseHandle(pi.hThread);
  374.  
  375. #ifdef __EMX__
  376.   return rc << 8;
  377. #else
  378.   return rc;
  379. #endif
  380. }
  381.  
  382. int pipe(int *handles)
  383. {
  384.   HANDLE rpipe, wpipe;
  385.   SECURITY_ATTRIBUTES security;
  386.  
  387.   security.nLength = sizeof(security);
  388.   security.bInheritHandle = TRUE;
  389.   security.lpSecurityDescriptor = NULL;
  390.  
  391.   if (!CreatePipe(&rpipe, &wpipe, &security, 0))
  392.     return -1;
  393.  
  394.   handles[0] = _open_osfhandle((long) rpipe, O_RDONLY);
  395.   handles[1] = _open_osfhandle((long) wpipe, O_WRONLY);
  396.  
  397.   return 0;
  398. }
  399.  
  400. #else
  401.  
  402. FILE *popen(const char *cmd, const char *mode)
  403. {
  404.   return fake_popen(cmd, mode);
  405. }
  406.  
  407. int pclose(FILE *pipe)
  408. {
  409.   return fake_pclose(pipe);
  410. }
  411.  
  412. int pipe(int *handles)
  413. {
  414.   return -1;
  415. }
  416.  
  417. #endif
  418. #endif
  419. #endif
  420.  
  421. typedef enum { unopened = 0, reading, writing } pipemode;
  422.  
  423. static struct
  424. {
  425.   char *name;
  426.   char *cmd;
  427.   pipemode pmode;
  428. }
  429. pipes[MAXPIPES];
  430.  
  431. FILE *fake_popen(const char *cmd, const char *mode)
  432. {
  433.   FILE *current;
  434.   char *name;
  435.   int cur;
  436.   pipemode curmode;
  437.  
  438.   if(strchr(mode, 'r') != NULL)
  439.     curmode = reading;
  440.   else if(strchr(mode, 'w') != NULL)
  441.     curmode = writing;
  442.   else
  443.     return NULL;
  444.  
  445.   if ((name = tempnam(NULL, "pi")) == NULL)
  446.     return NULL;
  447.  
  448.   if(curmode == reading)
  449.   {
  450.     char *line = alloca(strlen(cmd) + strlen(name) + 4);
  451.     sprintf(line, "%s > %s", cmd, name);
  452.     system(line);
  453.  
  454.     if((current = fopen(name, mode)) == NULL)
  455.       return NULL;
  456.   }
  457.   else
  458.   {
  459.     if((current = fopen(name, mode)) == NULL)
  460.       return NULL;
  461.   }
  462.  
  463.   cur = fileno(current);
  464.   pipes[cur].name = name;
  465.   pipes[cur].cmd = strdup(cmd);
  466.   pipes[cur].pmode = curmode;
  467.  
  468.   return current;
  469. }
  470.  
  471. int fake_pclose(FILE *pipe)
  472. {
  473.   int cur = fileno(pipe), rval;
  474.  
  475.   if(pipes[cur].pmode == unopened)
  476.     return -1;
  477.  
  478.   if(pipes[cur].pmode == reading)
  479.   {
  480.     rval = fclose(pipe);
  481.     unlink(pipes[cur].name);
  482.   }
  483.   else
  484.   {
  485.     char *line = alloca(strlen(pipes[cur].cmd) + strlen(pipes[cur].name) + 4);
  486.     fclose(pipe);
  487.     sprintf(line, "%s < %s", pipes[cur].cmd, pipes[cur].name);
  488.     rval = system(line);
  489.     unlink(pipes[cur].name);
  490.   }
  491.  
  492.   free(pipes[cur].name);
  493.   free(pipes[cur].cmd);
  494.   pipes[cur].pmode = unopened;
  495.  
  496.   return rval;
  497. }
  498.  
  499. #ifdef TEST
  500.  
  501. #include <conio.h>
  502.  
  503. int main(void)
  504. {
  505.   FILE *pipe;
  506.   int x = 0;
  507.   char line[256];
  508.  
  509.   pipe = popen("diff.exe", "r");
  510.  
  511.   while (fgets(line, sizeof(line), pipe))
  512.   {
  513.     fputs(line, stdout);
  514.     x++;
  515.   }
  516.  
  517.   printf("%d lines, rc = %d\n", x, pclose(pipe));
  518.   fflush(stdout);
  519.   getch();
  520.  
  521.   pipe = popen("more.com", "w");
  522.  
  523.   for (x = 0; x < 32; x++)
  524.     fprintf(pipe, "line %d\n", x);
  525.  
  526.   printf("rc = %d\n", pclose(pipe));
  527.  
  528.   return 0;
  529. }
  530.  
  531. #endif
  532.  
  533. /* end of popen.c */
  534.