home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tkisrc04.zip / tcl / os2 / tclOS2Pipe.c < prev    next >
C/C++ Source or Header  |  1998-08-07  |  21KB  |  659 lines

  1. /* 
  2.  * tclOS2Pipe.c -- This file implements the OS/2-specific pipeline exec
  3.  *                 functions.
  4.  *      
  5.  *
  6.  * Copyright (c) 1996 Sun Microsystems, Inc.
  7.  * Copyright (c) 1996-1997 Illya Vaes
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  */
  12.  
  13.  
  14. #include "tclInt.h"
  15. #include "tclPort.h"
  16.  
  17. #ifndef __IBMC__
  18. #include <dos.h>
  19. #endif
  20.  
  21. #define HF_STDIN  0
  22. #define HF_STDOUT 1
  23. #define HF_STDERR 2
  24.  
  25.  
  26. /*
  27.  *----------------------------------------------------------------------
  28.  *
  29.  * TclSpawnPipeline --
  30.  *
  31.  *      Given an argc/argv array, instantiate a pipeline of processes
  32.  *      as described by the argv.
  33.  *
  34.  * Results:
  35.  *      The return value is 1 on success, 0 on error
  36.  *
  37.  * Side effects:
  38.  *      Processes and pipes are created.
  39.  *
  40.  *----------------------------------------------------------------------
  41.  */
  42.  
  43. int
  44. TclSpawnPipeline(interp, pidPtr, numPids, argc, argv, inputFile, outputFile,
  45.         errorFile, intIn, finalOut)
  46.     Tcl_Interp *interp;         /* Interpreter in which to process pipeline. */
  47.     int *pidPtr;                /* Array of pids which are created. */
  48.     int *numPids;               /* Number of pids created. */
  49.     int argc;                   /* Number of entries in argv. */
  50.     char **argv;                /* Array of strings describing commands in
  51.                                  * pipeline plus I/O redirection with <,
  52.                                  * <<, >, etc. argv[argc] must be NULL. */
  53.     Tcl_File inputFile; /* If >=0, gives file id to use as input for
  54.                                  * first process in pipeline (specified via <
  55.                                  * or <@). */
  56.     Tcl_File outputFile;        /* Writable file id for output from last
  57.                                  * command in pipeline (could be file or
  58.                                  * pipe). NULL means use stdout. */
  59.     Tcl_File errorFile; /* Writable file id for error output from all
  60.                                  * commands in the pipeline. NULL means use
  61.                                  * stderr */
  62.     char *intIn;                /* File name for initial input (for Win32s). */
  63.     char *finalOut;             /* File name for final output (for Win32s). */
  64. {
  65.     Tcl_Channel channel;
  66.     UCHAR toBeFound[MAXPATHLEN];    /* Buffer for full path of program */
  67.     UCHAR fullPath[MAXPATHLEN];    /* Buffer for full path of program */
  68.     PSZ path;                      /* Pointer to environment variable value */
  69.     ULONG pid;                     /* Child process ID */
  70.     int firstArg, lastArg;         /* Indices of first and last arguments
  71.                     * in current command. */
  72.     int i, type;
  73.     APIRET rc;
  74.     Tcl_DString buffer;
  75.     char *execName;
  76.     int joinThisError;
  77.     Tcl_File pipeIn = NULL;
  78.     Tcl_File curOutFile = NULL;
  79.     Tcl_File curInFile = inputFile;
  80.     Tcl_File stdInFile = NULL, stdOutFile = NULL, stdErrFile = NULL;
  81.     HFILE stdIn = HF_STDIN, stdOut = HF_STDOUT, stdErr = HF_STDERR;
  82.     HFILE orgIn = -1, orgOut = -1, orgErr = -1;
  83.     HFILE tmp;
  84.     ULONG action;
  85.     BOOL hStdInput, hStdOutput, hStdError;
  86.     char *cmdLine[256];
  87.     int cmdLineCount = 0;
  88.     char *cmdexe = "CMD";
  89.     char *cmdarg = "/C";
  90. #ifdef DEBUG
  91.     printf("curInFile [%x]\n", curInFile);
  92. #endif
  93.  
  94.     /* Backup original stdin, stdout, stderr by Dup-ing to new handle */
  95.     rc = DosDupHandle(stdIn, &orgIn);
  96. #ifdef DEBUG
  97.     printf("DosDupHandle stdIn %d returns %d orgIn %d\n", stdIn, rc, orgIn);
  98. #endif
  99.     rc = DosDupHandle(stdOut, &orgOut);
  100. #ifdef DEBUG
  101.     printf("DosDupHandle stdOut %d returns %d, orgOut %d\n", stdOut, rc, orgOut);
  102. #endif
  103.     rc = DosDupHandle(stdErr, &orgErr);
  104. #ifdef DEBUG
  105.     printf("DosDupHandle stdErr %x returns %d orgErr %d\n", stdErr, rc, orgErr);
  106. #endif
  107.  
  108.     /*
  109.      * Fetch the current standard channels.  Note that we have to check the
  110.      * type of each file, since we cannot duplicate some file types.
  111.      */
  112.  
  113.     channel = Tcl_GetStdChannel(TCL_STDIN);
  114. #ifdef DEBUG
  115.     printf("channel [%x]\n", channel);
  116. #endif
  117.     if (channel) {
  118.         stdInFile = Tcl_GetChannelFile(channel, TCL_READABLE);
  119. #ifdef DEBUG
  120.         printf("stdInFile [%x]\n", stdInFile);
  121. #endif
  122.         if (stdInFile) {
  123.             Tcl_GetFileInfo(stdInFile, &type);
  124. #ifdef DEBUG
  125.             printf("filetype [%x]\n", type);
  126. #endif
  127.             if ((type < TCL_OS2_PIPE) || (type > TCL_OS2_CONSOLE)) {
  128.                 stdInFile = NULL;
  129. #ifdef DEBUG
  130.                 printf("stdInFile NULL [%x]\n", stdInFile);
  131. #endif
  132.             }
  133.         }
  134.     }
  135.     channel = Tcl_GetStdChannel(TCL_STDOUT);
  136.     if (channel) {
  137.         stdOutFile = Tcl_GetChannelFile(channel, TCL_WRITABLE);
  138.         if (stdOutFile) {
  139.             Tcl_GetFileInfo(stdOutFile, &type);
  140.             if ((type < TCL_OS2_PIPE) || (type > TCL_OS2_CONSOLE)) {
  141.                 stdOutFile = NULL;
  142.             }
  143.         }
  144.     }
  145.     channel = Tcl_GetStdChannel(TCL_STDERR);
  146.     if (channel) {
  147.         stdErrFile = Tcl_GetChannelFile(channel, TCL_WRITABLE);
  148.         if (stdErrFile) {
  149.             Tcl_GetFileInfo(stdErrFile, &type);
  150.             if ((type < TCL_OS2_PIPE) || (type > TCL_OS2_CONSOLE)) {
  151.                 stdErrFile = NULL;
  152.             }
  153.         }
  154.     }
  155.  
  156.     /*
  157.      * If the current process has a console attached, let the child inherit
  158.      * it.  Otherwise, create the child as a detached process.
  159.      */
  160.  
  161.     Tcl_DStringInit(&buffer);
  162.  
  163.     for (firstArg = 0; firstArg < argc; firstArg = lastArg+1) { 
  164.  
  165.         cmdLineCount = 0;
  166.         hStdInput = FALSE;
  167.         hStdOutput = FALSE;
  168.         hStdError = FALSE;
  169.  
  170.         /*
  171.          * Convert the program name into native form.  Also, ensure that
  172.          * the argv entry was copied into the DString.
  173.          */
  174.  
  175.         Tcl_DStringFree(&buffer);
  176.         execName = Tcl_TranslateFileName(interp, argv[firstArg], &buffer);
  177.         if (execName == NULL) {
  178.             goto error;
  179.         } else if (execName == argv[firstArg]) {
  180.             Tcl_DStringAppend(&buffer, argv[firstArg], -1);
  181.         }
  182.         cmdLine[cmdLineCount] = argv[firstArg];
  183.         cmdLineCount++;
  184.  
  185.         /*
  186.          * Find the end of the current segment of the pipeline.
  187.          */
  188.  
  189.     joinThisError = 0;
  190.     for (lastArg = firstArg; lastArg < argc; lastArg++) {
  191.         if (argv[lastArg][0] == '|') { 
  192.         if (argv[lastArg][1] == 0) { 
  193.             break;
  194.         }
  195.         if ((argv[lastArg][1] == '&') && (argv[lastArg][2] == 0)) {
  196.             joinThisError = 1;
  197.             break;
  198.         }
  199.         }
  200.     }
  201.  
  202.        /*
  203.         * Now append the rest of the command line arguments.
  204.         */
  205.  
  206.        for (i = firstArg + 1; i < lastArg; i++) {
  207.            cmdLine[cmdLineCount] = argv[i];
  208.            cmdLineCount++;
  209.            Tcl_DStringAppend(&buffer, " ", -1);
  210.            Tcl_DStringAppend(&buffer, argv[i], -1);
  211.        }
  212.  
  213.        /*
  214.         * If this is the last segment, use the specified outputFile.
  215.         * Otherwise create an intermediate pipe.
  216.         */
  217.  
  218.     if (lastArg == argc) { 
  219.         curOutFile = outputFile;
  220.     } else {
  221. #ifdef DEBUG
  222.             printf("Creating pipe\n");
  223. #endif
  224.         if (!TclCreatePipe(&pipeIn, &curOutFile)) {
  225.         Tcl_AppendResult(interp, "couldn't create pipe: ",
  226.             Tcl_PosixError(interp), (char *) NULL);
  227.         goto error;
  228.         }
  229.     }
  230.  
  231.         /*
  232.          * In the absence of any redirections, use the standard handles.
  233.          */
  234.  
  235. #ifdef DEBUG
  236.         printf("curInFile [%x], curOutFile [%x]\n", curInFile, curOutFile);
  237. #endif
  238.         if (!curInFile) {
  239. #ifdef DEBUG
  240.             printf("Making curInFile stdin\n");
  241. #endif
  242.             curInFile = stdInFile;
  243.         }
  244.         if (!curOutFile) {
  245. #ifdef DEBUG
  246.             printf("Making curInFile stderr\n");
  247. #endif
  248.             curOutFile = stdOutFile;
  249.         }
  250.         if (!curOutFile) {
  251. #ifdef DEBUG
  252.             printf("Making curInFile stderr\n");
  253. #endif
  254.             errorFile = stdErrFile;
  255.         }
  256. #ifdef DEBUG
  257.         printf("curInFile [%x], curOutFile [%x]\n", curInFile, curOutFile);
  258. #endif
  259.  
  260.         /*
  261.          * Duplicate all the handles which will be passed off as stdin, stdout
  262.          * and stderr of the child process. The duplicate handles are set to
  263.          * be inheritable, so the child process can use them.
  264.          */
  265.  
  266.         if (curInFile) {
  267.             tmp = (HFILE) Tcl_GetFileInfo(curInFile, NULL);
  268.             if (tmp != (HFILE)0) {
  269.                 /* Duplicate standard input handle */
  270.                 rc = DosDupHandle(tmp, &stdIn);
  271. #ifdef DEBUG
  272.                 printf("DosDupHandle curInFile [%x] returned [%d], handle [%d]\n",
  273.                        tmp, rc, stdIn);
  274. #endif
  275.                 if (rc != NO_ERROR) {
  276.                     TclOS2ConvertError(rc);
  277.                     Tcl_AppendResult(interp, "couldn't duplicate input handle: ",
  278.                             Tcl_PosixError(interp), (char *) NULL);
  279.                     goto error;
  280.                 }
  281.                 hStdInput = TRUE;
  282.             }
  283.         }
  284. #ifdef DEBUG
  285.         printf("before curOutFile\n");
  286. #endif
  287.         if (curOutFile) {
  288.             tmp = (HFILE) Tcl_GetFileInfo(curOutFile, NULL);
  289.             if (tmp != (HFILE)1) {
  290.                 /* Duplicate standard output handle */
  291.                 rc = DosDupHandle(tmp, &stdOut);
  292. #ifdef DEBUG
  293.                 printf("DosDupHandle curOutFile [%x] returned [%d], handle [%d]\n",
  294.                        tmp, rc, stdOut);
  295. #endif
  296.                 if (rc != NO_ERROR) {
  297.                     TclOS2ConvertError(rc);
  298.                     Tcl_AppendResult(interp, "couldn't duplicate output handle: ",
  299.                             Tcl_PosixError(interp), (char *) NULL);
  300.                     goto error;
  301.                 }
  302.                 hStdOutput = TRUE;
  303.             }
  304.         }
  305. #ifdef DEBUG
  306.         printf("before joinThisError\n");
  307. #endif
  308.         if (joinThisError) {
  309.             tmp = (HFILE) Tcl_GetFileInfo(curOutFile, NULL);
  310.             if (tmp != (HFILE)1) {
  311.                 /* Duplicate standard output handle */
  312.                 rc = DosDupHandle(tmp, &stdOut);
  313. #ifdef DEBUG
  314.                 printf("DosDupHandle curOutFile [%x] returned [%d], handle [%d]\n",
  315.                        tmp, rc, stdErr);
  316. #endif
  317.                 if (rc != NO_ERROR) {
  318.                     TclOS2ConvertError(rc);
  319.                     Tcl_AppendResult(interp, "couldn't duplicate output handle: ",
  320.                             Tcl_PosixError(interp), (char *) NULL);
  321.                     goto error;
  322.                 }
  323.                 hStdOutput = TRUE;
  324.             }
  325.         } else {
  326.             if (errorFile) {
  327.                 tmp = (HFILE) Tcl_GetFileInfo(errorFile, NULL);
  328.                 if (tmp != (HFILE)2) {
  329.                     /* Duplicate standard error handle */
  330.                     rc = DosDupHandle(tmp, &stdErr);
  331. #ifdef DEBUG
  332.                     printf("DosDupHandle errorFile [%x] returned [%d], handle [%d]\n",
  333.                            tmp, rc, stdErr);
  334. #endif
  335.                     if (rc != NO_ERROR) {
  336.                         TclOS2ConvertError(rc);
  337.                         Tcl_AppendResult(interp, "couldn't duplicate error handle: ",
  338.                                 Tcl_PosixError(interp), (char *) NULL);
  339.                         goto error;
  340.                     }
  341.                     hStdError = TRUE;
  342.                 }
  343.             }
  344.         }
  345.  
  346.        /*
  347.         * If any handle was not set, open the null device instead.
  348.         */
  349.  
  350.        if (!hStdInput) {
  351. #ifdef DEBUG
  352.            printf("opening NUL as stdin\n");
  353. #endif
  354.            rc = DosOpen((PSZ)"NUL", &tmp, &action, 0, FILE_NORMAL,
  355.                         OPEN_ACTION_CREATE_IF_NEW,
  356.                         OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, NULL);
  357. #ifdef DEBUG
  358.            printf("DosOpen NUL returned %d\n", rc);
  359. #endif
  360.            /* Duplicate standard input handle */
  361.            rc = DosDupHandle(tmp, &stdIn);
  362. #ifdef DEBUG
  363.            printf("DosDupHandle NUL returned %d\n", rc);
  364. #endif
  365.        }
  366.        if (!hStdOutput) {
  367. #ifdef DEBUG
  368.            printf("opening NUL as stdout\n");
  369. #endif
  370.            rc = DosOpen((PSZ)"NUL", &tmp, &action, 0, FILE_NORMAL,
  371.                         OPEN_ACTION_CREATE_IF_NEW,
  372.                         OPEN_SHARE_DENYNONE | OPEN_ACCESS_WRITEONLY, NULL);
  373. #ifdef DEBUG
  374.            printf("DosOpen NUL returned %d\n", rc);
  375. #endif
  376.            /* Duplicate standard output handle */
  377.            rc = DosDupHandle(tmp, &stdOut);
  378. #ifdef DEBUG
  379.            printf("DosDupHandle NUL returned %d\n", rc);
  380. #endif
  381.        }
  382.        if (!hStdError) {
  383. #ifdef DEBUG
  384.            printf("opening NUL as stderr\n");
  385. #endif
  386.            rc = DosOpen((PSZ)"NUL", &tmp, &action, 0, FILE_NORMAL,
  387.                         OPEN_ACTION_CREATE_IF_NEW,
  388.                         OPEN_SHARE_DENYNONE | OPEN_ACCESS_WRITEONLY, NULL);
  389. #ifdef DEBUG
  390.            printf("DosOpen NUL returned %d\n", rc);
  391. #endif
  392.            /* Duplicate standard error handle */
  393.            rc = DosDupHandle(tmp, &stdErr);
  394. #ifdef DEBUG
  395.            printf("DosDupHandle NUL returned %d\n", rc);
  396. #endif
  397.        }
  398.  
  399.        /*
  400.         * Start the subprocess by invoking the executable directly.  If that
  401.         * fails, then attempt to use cmd.exe.
  402.         */
  403.  
  404.         cmdLine[cmdLineCount] = NULL;
  405.         cmdLineCount++;
  406.         /* See if we can find the program as a "real" executable */
  407.         rc = DosScanEnv("PATH", &path);
  408. #ifdef DEBUG
  409.         printf("DosScanEnv PATH returned %x (%s)\n", rc, path);
  410. #endif
  411.         strcpy(toBeFound, cmdLine[0]);
  412.         rc = DosSearchPath(SEARCH_CUR_DIRECTORY | SEARCH_IGNORENETERRS, path,
  413.                            toBeFound, (PBYTE)&fullPath, (ULONG) sizeof(fullPath));
  414.         if (rc != NO_ERROR) {
  415.             /* Couldn't find it "literally" */
  416. #ifdef DEBUG
  417.             printf("DosSearchPath %s ERROR %d\n", toBeFound, rc);
  418. #endif
  419.             strcpy(toBeFound, cmdLine[0]);
  420.             strcat(toBeFound, ".EXE");
  421.             rc = DosSearchPath(SEARCH_CUR_DIRECTORY | SEARCH_IGNORENETERRS,
  422.                                path, toBeFound, (PBYTE)&fullPath,
  423.                                (ULONG) sizeof(fullPath));
  424. #ifdef DEBUG
  425.             if (rc != NO_ERROR) {
  426.                 printf("DosSearchPath %s ERROR %d\n", toBeFound, rc);
  427.             } else {
  428.                 printf("DosSearchPath %s OK: %s\n", toBeFound, fullPath);
  429.             }
  430. #endif
  431.         }
  432. #ifdef DEBUG
  433.           else {
  434.              printf("DosSearchPath %s OK (%s)\n", toBeFound, fullPath);
  435.         }
  436. #endif
  437.         if (rc == NO_ERROR) {
  438.             cmdLine[0] = fullPath;
  439. #ifdef DEBUG
  440.             printf("before spawnv, cmdLine[0] [%s] cmdLine[1] [%s]\n",
  441.                    cmdLine[0], cmdLine[1]);
  442. #endif
  443. /* *MM* created ifdef */
  444. #ifdef __IBMC__
  445.             pid = spawnv(P_WAIT,
  446.                          cmdLine[0], cmdLine);
  447. #else
  448.             pid = spawnv(P_SESSION | P_DEFAULT | P_MINIMIZE | P_BACKGROUND,
  449.                          cmdLine[0], cmdLine);
  450. #endif
  451. #ifdef DEBUG
  452.             printf("after spawnv, pid [%d]\n", pid);
  453. #endif
  454.     }
  455.     if (rc != NO_ERROR || pid == -1) {
  456.             /*
  457.              * DosSearchPath didn't find match in path, have the system command
  458.              * processor (in environment variable COMSPEC) try it in case
  459.              * it's an internal command.
  460.              */
  461. /* *MM* added ifdef - IBMC doesn't support variable length local arrays */
  462. #ifdef __IBMC__
  463.         char buffer[MAXPATHLEN];
  464. #else
  465.         char buffer[maxPath];
  466. #endif
  467.         PSZ comspec = buffer;
  468.         char *cmdcmdLine[258];
  469.         int i;
  470.  
  471.             rc = DosScanEnv("COMSPEC", &comspec);
  472.             if (rc != NO_ERROR) {
  473. #ifdef DEBUG
  474.                 printf("DosScanEnv COMSPEC ERROR %d (203=Var not found)\n", rc);
  475. #endif
  476.                 cmdcmdLine[0] = cmdexe;
  477.             } else {
  478. #ifdef DEBUG
  479.                 printf("DosScanEnv COMSPEC OK: %s\n", (char *)comspec);
  480. #endif
  481.                 cmdcmdLine[0] = comspec;
  482.             }
  483.             cmdcmdLine[1] = cmdarg;
  484.             for (i= 0; i<cmdLineCount; i++) {
  485.                 cmdcmdLine[i+2] = cmdLine[i];
  486.             }
  487.             /* Spawn, with CMD /C at beginning */
  488. #ifdef DEBUG
  489.             printf("before spawnv cmdcmdLine [%s] [%s] [%s]\n",
  490.                    cmdcmdLine[0], cmdcmdLine[1], cmdcmdLine[2]);
  491. #endif
  492. /* *MM* created ifdef */
  493. #ifdef __IBMC__
  494.             pid = spawnv(P_WAIT,
  495.                          cmdexe, cmdcmdLine);
  496. #else
  497.             pid = spawnv(P_SESSION | P_DEFAULT | P_MINIMIZE | P_BACKGROUND,
  498.                          cmdexe, cmdcmdLine);
  499. #endif
  500. #ifdef DEBUG
  501.             printf("after spawnv, pid [%d]\n", pid);
  502. #endif
  503.         if (pid == -1) {
  504.                 Tcl_AppendResult(interp, "couldn't execute \"", argv[firstArg],
  505.                         "\": ", Tcl_PosixError(interp), (char *) NULL);
  506.                 goto error;
  507.         }
  508.     }
  509.         Tcl_DStringFree(&buffer);
  510.  
  511.         /*
  512.          * Add the child process to the list of those to be reaped.
  513.          */
  514.  
  515. #ifdef DEBUG
  516.         printf("numPids: %d\n", *numPids);
  517. #endif
  518.         pidPtr[*numPids] = pid;
  519.         (*numPids)++;
  520. #ifdef DEBUG
  521.         printf("    now: %d\n", *numPids);
  522. #endif
  523.  
  524.         /*
  525.          * Close off our copies of file descriptors that were set up for
  526.          * this child, then set up the input for the next child.
  527.          */
  528.  
  529.         if (curInFile && (curInFile != inputFile)
  530.                 && (curInFile != stdInFile)) {
  531.             TclCloseFile(curInFile);
  532.         }
  533.         curInFile = pipeIn;
  534.         pipeIn = NULL;
  535.  
  536.         if (curOutFile && (curOutFile != outputFile)
  537.                 && (curOutFile != stdOutFile)) {
  538.             TclCloseFile(curOutFile);
  539.         }
  540.         curOutFile = NULL;
  541.  
  542.     }
  543.  
  544.     /* Restore original stdin, stdout, stderr by Dup-ing from new handle */
  545.     stdIn = HF_STDIN; stdOut = HF_STDOUT; stdErr = HF_STDERR;
  546.     rc = DosDupHandle(orgIn, &stdIn);
  547. #ifdef DEBUG
  548.     printf("DosDupHandle orgIn [%x] returned [%d]\n", orgIn, rc);
  549. #endif
  550.     rc = DosDupHandle(orgOut, &stdOut);
  551. #ifdef DEBUG
  552.     printf("DosDupHandle orgOut [%x] returned [%d]\n", orgOut, rc);
  553. #endif
  554.     rc = DosDupHandle(orgErr, &stdErr);
  555. #ifdef DEBUG
  556.     printf("DosDupHandle orgErr [%x] returned [%d]\n", orgErr, rc);
  557. #endif
  558.     rc = DosClose(orgIn);
  559.     rc = DosClose(orgOut);
  560.     rc = DosClose(orgErr);
  561.  
  562.     return 1;
  563.  
  564.     /*
  565.      * An error occured, so we need to clean up any open pipes.
  566.      */
  567.  
  568. error:
  569.     Tcl_DStringFree(&buffer);
  570.     if (pipeIn) {
  571.         TclCloseFile(pipeIn);
  572.     }
  573.     if (curOutFile && (curOutFile != outputFile)
  574.                 && (curOutFile != stdOutFile)) {
  575.         TclCloseFile(curOutFile);
  576.     }
  577.     if (curInFile && (curInFile != inputFile)
  578.                 && (curInFile != stdInFile)) {
  579.         TclCloseFile(curInFile);
  580.     }
  581.     /* Restore original stdin, stdout, stderr by Dup-ing from new handle */
  582.     stdIn = HF_STDIN; stdOut = HF_STDOUT; stdErr = HF_STDERR;
  583.     rc = DosDupHandle(orgIn, &stdIn);
  584. #ifdef DEBUG
  585.     printf("DosDupHandle orgIn [%x] returned [%d]\n", orgIn, rc);
  586. #endif
  587.     rc = DosDupHandle(orgOut, &stdOut);
  588. #ifdef DEBUG
  589.     printf("DosDupHandle orgOut [%x] returned [%d]\n", orgOut, rc);
  590. #endif
  591.     rc = DosDupHandle(orgErr, &stdErr);
  592. #ifdef DEBUG
  593.     printf("DosDupHandle orgErr [%x] returned [%d]\n", orgErr, rc);
  594. #endif
  595.     rc = DosClose(orgIn);
  596.     rc = DosClose(orgOut);
  597.     rc = DosClose(orgErr);
  598.     return 0;
  599. }
  600.  
  601. /*
  602.  *----------------------------------------------------------------------
  603.  *
  604.  * TclHasPipes --
  605.  *
  606.  *      Determines if pipes are available.
  607.  *
  608.  * Results:
  609.  *      Returns 1 if pipes are available.
  610.  *
  611.  * Side effects:
  612.  *      None.
  613.  *
  614.  *----------------------------------------------------------------------
  615.  */
  616.  
  617. int
  618. TclHasPipes(void)
  619. {
  620.     return 1;
  621. }
  622.  
  623. /*
  624.  *----------------------------------------------------------------------
  625.  *
  626.  * TclCreatePipe --
  627.  *
  628.  *      Creates an anonymous pipe.
  629.  *
  630.  * Results:
  631.  *      Returns 1 on success, 0 on failure. 
  632.  *
  633.  * Side effects:
  634.  *      Creates a pipe.
  635.  *
  636.  *----------------------------------------------------------------------
  637.  */
  638.  
  639. int
  640. TclCreatePipe(readPipe, writePipe)
  641.     Tcl_File *readPipe; /* Location to store file handle for
  642.                                  * read side of pipe. */
  643.     Tcl_File *writePipe;        /* Location to store file handle for
  644.                                  * write side of pipe. */
  645. {
  646.     HFILE readHandle, writeHandle;
  647.     APIRET rc;
  648.  
  649.     rc = DosCreatePipe(&readHandle, &writeHandle, 1024);
  650. #ifdef DEBUG
  651.     printf("DosCreatePipe returned [%x], read [%x], write [%x]\n",
  652.            rc, readHandle, writeHandle);
  653. #endif
  654.  
  655.     *readPipe = Tcl_GetFile((ClientData)readHandle, TCL_OS2_PIPE);
  656.     *writePipe = Tcl_GetFile((ClientData)writeHandle, TCL_OS2_PIPE);
  657.     return 1;
  658. }
  659.