diff options
Diffstat (limited to 'generic/tclPipe.c')
| -rw-r--r-- | generic/tclPipe.c | 588 |
1 files changed, 298 insertions, 290 deletions
diff --git a/generic/tclPipe.c b/generic/tclPipe.c index 698f85d..6e7029e 100644 --- a/generic/tclPipe.c +++ b/generic/tclPipe.c @@ -1,56 +1,60 @@ -/* +/* * tclPipe.c -- * - * This file contains the generic portion of the command channel driver - * as well as various utility routines used in managing subprocesses. + * This file contains the generic portion of the command channel + * driver as well as various utility routines used in managing + * subprocesses. * * Copyright (c) 1997 by Sun Microsystems, Inc. * - * See the file "license.terms" for information on usage and redistribution of - * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" +#include "tclPort.h" /* - * A linked list of the following structures is used to keep track of child - * processes that have been detached but haven't exited yet, so we can make - * sure that they're properly "reaped" (officially waited for) and don't lie - * around as zombies cluttering the system. + * A linked list of the following structures is used to keep track + * of child processes that have been detached but haven't exited + * yet, so we can make sure that they're properly "reaped" (officially + * waited for) and don't lie around as zombies cluttering the + * system. */ typedef struct Detached { - Tcl_Pid pid; /* Id of process that's been detached but - * isn't known to have exited. */ - struct Detached *nextPtr; /* Next in list of all detached processes. */ + Tcl_Pid pid; /* Id of process that's been detached + * but isn't known to have exited. */ + struct Detached *nextPtr; /* Next in list of all detached + * processes. */ } Detached; -static Detached *detList = NULL;/* List of all detached proceses. */ -TCL_DECLARE_MUTEX(pipeMutex) /* Guard access to detList. */ +static Detached *detList = NULL; /* List of all detached proceses. */ +TCL_DECLARE_MUTEX(pipeMutex) /* Guard access to detList. */ /* - * Declarations for local functions defined in this file: + * Declarations for local procedures defined in this file: */ -static TclFile FileForRedirect(Tcl_Interp *interp, CONST char *spec, - int atOk, CONST char *arg, CONST char *nextArg, - int flags, int *skipPtr, int *closePtr, - int *releasePtr); +static TclFile FileForRedirect _ANSI_ARGS_((Tcl_Interp *interp, + CONST char *spec, int atOk, CONST char *arg, + CONST char *nextArg, int flags, int *skipPtr, + int *closePtr, int *releasePtr)); /* *---------------------------------------------------------------------- * * FileForRedirect -- * - * This function does much of the work of parsing redirection operators. - * It handles "@" if specified and allowed, and a file name, and opens - * the file if necessary. + * This procedure does much of the work of parsing redirection + * operators. It handles "@" if specified and allowed, and a file + * name, and opens the file if necessary. * * Results: - * The return value is the descriptor number for the file. If an error - * occurs then NULL is returned and an error message is left in the - * interp's result. Several arguments are side-effected; see the argument - * list below for details. + * The return value is the descriptor number for the file. If an + * error occurs then NULL is returned and an error message is left + * in the interp's result. Several arguments are side-effected; see + * the argument list below for details. * * Side effects: * None. @@ -59,33 +63,34 @@ static TclFile FileForRedirect(Tcl_Interp *interp, CONST char *spec, */ static TclFile -FileForRedirect( - Tcl_Interp *interp, /* Intepreter to use for error reporting. */ - CONST char *spec, /* Points to character just after redirection - * character. */ - int atOK, /* Non-zero means that '@' notation can be +FileForRedirect(interp, spec, atOK, arg, nextArg, flags, skipPtr, closePtr, + releasePtr) + Tcl_Interp *interp; /* Intepreter to use for error reporting. */ + CONST char *spec; /* Points to character just after + * redirection character. */ + int atOK; /* Non-zero means that '@' notation can be * used to specify a channel, zero means that * it isn't. */ - CONST char *arg, /* Pointer to entire argument containing spec: - * used for error reporting. */ - CONST char *nextArg, /* Next argument in argc/argv array, if needed - * for file name or channel name. May be + CONST char *arg; /* Pointer to entire argument containing + * spec: used for error reporting. */ + CONST char *nextArg; /* Next argument in argc/argv array, if needed + * for file name or channel name. May be * NULL. */ - int flags, /* Flags to use for opening file or to specify - * mode for channel. */ - int *skipPtr, /* Filled with 1 if redirection target was in - * spec, 2 if it was in nextArg. */ - int *closePtr, /* Filled with one if the caller should close - * the file when done with it, zero + int flags; /* Flags to use for opening file or to + * specify mode for channel. */ + int *skipPtr; /* Filled with 1 if redirection target was + * in spec, 2 if it was in nextArg. */ + int *closePtr; /* Filled with one if the caller should + * close the file when done with it, zero * otherwise. */ - int *releasePtr) + int *releasePtr; { int writing = (flags & O_WRONLY); Tcl_Channel chan; TclFile file; *skipPtr = 1; - if ((atOK != 0) && (*spec == '@')) { + if ((atOK != 0) && (*spec == '@')) { spec++; if (*spec == '\0') { spec = nextArg; @@ -100,22 +105,18 @@ FileForRedirect( } file = TclpMakeFile(chan, writing ? TCL_WRITABLE : TCL_READABLE); if (file == NULL) { - Tcl_Obj* msg; - Tcl_GetChannelError(chan, &msg); - if (msg) { - Tcl_SetObjResult (interp, msg); - } else { - Tcl_AppendResult(interp, "channel \"", Tcl_GetChannelName(chan), - "\" wasn't opened for ", - ((writing) ? "writing" : "reading"), NULL); - } + Tcl_AppendResult(interp, "channel \"", Tcl_GetChannelName(chan), + "\" wasn't opened for ", + ((writing) ? "writing" : "reading"), (char *) NULL); return NULL; } *releasePtr = 1; if (writing) { + /* - * Be sure to flush output to the file, so that anything written - * by the child appears after stuff we've already written. + * Be sure to flush output to the file, so that anything + * written by the child appears after stuff we've already + * written. */ Tcl_Flush(chan); @@ -140,16 +141,16 @@ FileForRedirect( if (file == NULL) { Tcl_AppendResult(interp, "couldn't ", ((writing) ? "write" : "read"), " file \"", spec, "\": ", - Tcl_PosixError(interp), NULL); + Tcl_PosixError(interp), (char *) NULL); return NULL; } *closePtr = 1; } return file; - badLastArg: + badLastArg: Tcl_AppendResult(interp, "can't specify \"", arg, - "\" as last word in command", NULL); + "\" as last word in command", (char *) NULL); return NULL; } @@ -158,9 +159,10 @@ FileForRedirect( * * Tcl_DetachPids -- * - * This function is called to indicate that one or more child processes - * have been placed in background and will never be waited for; they - * should eventually be reaped by Tcl_ReapDetachedProcs. + * This procedure is called to indicate that one or more child + * processes have been placed in background and will never be + * waited for; they should eventually be reaped by + * Tcl_ReapDetachedProcs. * * Results: * None. @@ -172,10 +174,10 @@ FileForRedirect( */ void -Tcl_DetachPids( - int numPids, /* Number of pids to detach: gives size of - * array pointed to by pidPtr. */ - Tcl_Pid *pidPtr) /* Array of pids to detach. */ +Tcl_DetachPids(numPids, pidPtr) + int numPids; /* Number of pids to detach: gives size + * of array pointed to by pidPtr. */ + Tcl_Pid *pidPtr; /* Array of pids to detach. */ { register Detached *detPtr; int i; @@ -196,22 +198,23 @@ Tcl_DetachPids( * * Tcl_ReapDetachedProcs -- * - * This function checks to see if any detached processes have exited and, - * if so, it "reaps" them by officially waiting on them. It should be - * called "occasionally" to make sure that all detached processes are - * eventually reaped. + * This procedure checks to see if any detached processes have + * exited and, if so, it "reaps" them by officially waiting on + * them. It should be called "occasionally" to make sure that + * all detached processes are eventually reaped. * * Results: * None. * * Side effects: - * Processes are waited on, so that they can be reaped by the system. + * Processes are waited on, so that they can be reaped by the + * system. * *---------------------------------------------------------------------- */ void -Tcl_ReapDetachedProcs(void) +Tcl_ReapDetachedProcs() { register Detached *detPtr; Detached *nextPtr, *prevPtr; @@ -243,30 +246,30 @@ Tcl_ReapDetachedProcs(void) * * TclCleanupChildren -- * - * This is a utility function used to wait for child processes to exit, - * record information about abnormal exits, and then collect any stderr - * output generated by them. + * This is a utility procedure used to wait for child processes + * to exit, record information about abnormal exits, and then + * collect any stderr output generated by them. * * Results: - * The return value is a standard Tcl result. If anything at weird - * happened with the child processes, TCL_ERROR is returned and a message - * is left in the interp's result. + * The return value is a standard Tcl result. If anything at + * weird happened with the child processes, TCL_ERROR is returned + * and a message is left in the interp's result. * * Side effects: - * If the last character of the interp's result is a newline, then it is - * removed unless keepNewline is non-zero. File errorId gets closed, and - * pidPtr is freed back to the storage allocator. + * If the last character of the interp's result is a newline, then it + * is removed unless keepNewline is non-zero. File errorId gets + * closed, and pidPtr is freed back to the storage allocator. * *---------------------------------------------------------------------- */ int -TclCleanupChildren( - Tcl_Interp *interp, /* Used for error messages. */ - int numPids, /* Number of entries in pidPtr array. */ - Tcl_Pid *pidPtr, /* Array of process ids of children. */ - Tcl_Channel errorChan) /* Channel for file containing stderr output - * from pipeline. NULL means there isn't any +TclCleanupChildren(interp, numPids, pidPtr, errorChan) + Tcl_Interp *interp; /* Used for error messages. */ + int numPids; /* Number of entries in pidPtr array. */ + Tcl_Pid *pidPtr; /* Array of process ids of children. */ + Tcl_Channel errorChan; /* Channel for file containing stderr output + * from pipeline. NULL means there isn't any * stderr output. */ { int result = TCL_OK; @@ -279,83 +282,93 @@ TclCleanupChildren( abnormalExit = 0; for (i = 0; i < numPids; i++) { /* - * We need to get the resolved pid before we wait on it as the windows - * implementation of Tcl_WaitPid deletes the information such that any - * following calls to TclpGetPid fail. + * We need to get the resolved pid before we wait on it as + * the windows implementation of Tcl_WaitPid deletes the + * information such that any following calls to TclpGetPid + * fail. */ - resolvedPid = TclpGetPid(pidPtr[i]); pid = Tcl_WaitPid(pidPtr[i], (int *) &waitStatus, 0); if (pid == (Tcl_Pid) -1) { result = TCL_ERROR; - if (interp != NULL) { + if (interp != (Tcl_Interp *) NULL) { msg = Tcl_PosixError(interp); if (errno == ECHILD) { /* - * This changeup in message suggested by Mark Diekhans to - * remind people that ECHILD errors can occur on some - * systems if SIGCHLD isn't in its default state. + * This changeup in message suggested by Mark Diekhans + * to remind people that ECHILD errors can occur on + * some systems if SIGCHLD isn't in its default state. */ msg = "child process lost (is SIGCHLD ignored or trapped?)"; } Tcl_AppendResult(interp, "error waiting for process to exit: ", - msg, NULL); + msg, (char *) NULL); } continue; } /* - * Create error messages for unusual process exits. An extra newline - * gets appended to each error message, but it gets removed below (in - * the same fashion that an extra newline in the command's output is - * removed). + * Create error messages for unusual process exits. An + * extra newline gets appended to each error message, but + * it gets removed below (in the same fashion that an + * extra newline in the command's output is removed). */ if (!WIFEXITED(waitStatus) || (WEXITSTATUS(waitStatus) != 0)) { char msg1[TCL_INTEGER_SPACE], msg2[TCL_INTEGER_SPACE]; result = TCL_ERROR; - sprintf(msg1, "%lu", resolvedPid); + TclFormatInt(msg1, (long) resolvedPid); if (WIFEXITED(waitStatus)) { if (interp != (Tcl_Interp *) NULL) { - sprintf(msg2, "%lu", - (unsigned long) WEXITSTATUS(waitStatus)); - Tcl_SetErrorCode(interp, "CHILDSTATUS", msg1, msg2, NULL); + TclFormatInt(msg2, WEXITSTATUS(waitStatus)); + Tcl_SetErrorCode(interp, "CHILDSTATUS", msg1, msg2, + (char *) NULL); } abnormalExit = 1; - } else if (interp != NULL) { - CONST char *p; - - if (WIFSIGNALED(waitStatus)) { + } else if (WIFSIGNALED(waitStatus)) { + if (interp != (Tcl_Interp *) NULL) { + CONST char *p; + p = Tcl_SignalMsg((int) (WTERMSIG(waitStatus))); Tcl_SetErrorCode(interp, "CHILDKILLED", msg1, Tcl_SignalId((int) (WTERMSIG(waitStatus))), p, - NULL); - Tcl_AppendResult(interp, "child killed: ", p, "\n", NULL); - } else if (WIFSTOPPED(waitStatus)) { + (char *) NULL); + Tcl_AppendResult(interp, "child killed: ", p, "\n", + (char *) NULL); + } + } else if (WIFSTOPPED(waitStatus)) { + if (interp != (Tcl_Interp *) NULL) { + CONST char *p; + p = Tcl_SignalMsg((int) (WSTOPSIG(waitStatus))); Tcl_SetErrorCode(interp, "CHILDSUSP", msg1, - Tcl_SignalId((int) (WSTOPSIG(waitStatus))), p, - NULL); + Tcl_SignalId((int) (WSTOPSIG(waitStatus))), + p, (char *) NULL); Tcl_AppendResult(interp, "child suspended: ", p, "\n", - NULL); - } else { + (char *) NULL); + } + } else { + if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, - "child wait status didn't make sense\n", NULL); + "child wait status didn't make sense\n", + (char *) NULL); } } } } /* - * Read the standard error file. If there's anything there, then return an - * error and add the file's contents to the result string. + * Read the standard error file. If there's anything there, + * then return an error and add the file's contents to the result + * string. */ anyErrorInfo = 0; if (errorChan != NULL) { + /* * Make sure we start at the beginning of the file. */ @@ -363,7 +376,7 @@ TclCleanupChildren( if (interp != NULL) { int count; Tcl_Obj *objPtr; - + Tcl_Seek(errorChan, (Tcl_WideInt)0, SEEK_SET); objPtr = Tcl_NewObj(); count = Tcl_ReadChars(errorChan, objPtr, -1, 0); @@ -385,12 +398,13 @@ TclCleanupChildren( } /* - * If a child exited abnormally but didn't output any error information at - * all, generate an error message here. + * If a child exited abnormally but didn't output any error information + * at all, generate an error message here. */ if ((abnormalExit != 0) && (anyErrorInfo == 0) && (interp != NULL)) { - Tcl_AppendResult(interp, "child process exited abnormally", NULL); + Tcl_AppendResult(interp, "child process exited abnormally", + (char *) NULL); } return result; } @@ -400,23 +414,25 @@ TclCleanupChildren( * * TclCreatePipeline -- * - * Given an argc/argv array, instantiate a pipeline of processes as - * described by the argv. + * Given an argc/argv array, instantiate a pipeline of processes + * as described by the argv. * - * This function is unofficially exported for use by BLT. + * This procedure is unofficially exported for use by BLT. * * Results: - * The return value is a count of the number of new processes created, or - * -1 if an error occurred while creating the pipeline. *pidArrayPtr is - * filled in with the address of a dynamically allocated array giving the - * ids of all of the processes. It is up to the caller to free this array - * when it isn't needed anymore. If inPipePtr is non-NULL, *inPipePtr is - * filled in with the file id for the input pipe for the pipeline (if - * any): the caller must eventually close this file. If outPipePtr isn't - * NULL, then *outPipePtr is filled in with the file id for the output - * pipe from the pipeline: the caller must close this file. If errFilePtr - * isn't NULL, then *errFilePtr is filled with a file id that may be used - * to read error output after the pipeline completes. + * The return value is a count of the number of new processes + * created, or -1 if an error occurred while creating the pipeline. + * *pidArrayPtr is filled in with the address of a dynamically + * allocated array giving the ids of all of the processes. It + * is up to the caller to free this array when it isn't needed + * anymore. If inPipePtr is non-NULL, *inPipePtr is filled in + * with the file id for the input pipe for the pipeline (if any): + * the caller must eventually close this file. If outPipePtr + * isn't NULL, then *outPipePtr is filled in with the file id + * for the output pipe from the pipeline: the caller must close + * this file. If errFilePtr isn't NULL, then *errFilePtr is filled + * with a file id that may be used to read error output after the + * pipeline completes. * * Side effects: * Processes and pipes are created. @@ -425,66 +441,67 @@ TclCleanupChildren( */ int -TclCreatePipeline( - Tcl_Interp *interp, /* Interpreter to use for error reporting. */ - int argc, /* Number of entries in argv. */ - CONST char **argv, /* Array of strings describing commands in - * pipeline plus I/O redirection with <, <<, - * >, etc. Argv[argc] must be NULL. */ - Tcl_Pid **pidArrayPtr, /* Word at *pidArrayPtr gets filled in with - * address of array of pids for processes in - * pipeline (first pid is first process in - * pipeline). */ - TclFile *inPipePtr, /* If non-NULL, input to the pipeline comes +TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, + outPipePtr, errFilePtr) + Tcl_Interp *interp; /* Interpreter to use for error reporting. */ + int argc; /* Number of entries in argv. */ + CONST char **argv; /* Array of strings describing commands in + * pipeline plus I/O redirection with <, + * <<, >, etc. Argv[argc] must be NULL. */ + Tcl_Pid **pidArrayPtr; /* Word at *pidArrayPtr gets filled in with + * address of array of pids for processes + * in pipeline (first pid is first process + * in pipeline). */ + TclFile *inPipePtr; /* If non-NULL, input to the pipeline comes * from a pipe (unless overridden by - * redirection in the command). The file id - * with which to write to this pipe is stored - * at *inPipePtr. NULL means command specified - * its own input source. */ - TclFile *outPipePtr, /* If non-NULL, output to the pipeline goes to - * a pipe, unless overriden by redirection in - * the command. The file id with which to read - * frome this pipe is stored at *outPipePtr. - * NULL means command specified its own output - * sink. */ - TclFile *errFilePtr) /* If non-NULL, all stderr output from the + * redirection in the command). The file + * id with which to write to this pipe is + * stored at *inPipePtr. NULL means command + * specified its own input source. */ + TclFile *outPipePtr; /* If non-NULL, output to the pipeline goes + * to a pipe, unless overriden by redirection + * in the command. The file id with which to + * read frome this pipe is stored at + * *outPipePtr. NULL means command specified + * its own output sink. */ + TclFile *errFilePtr; /* If non-NULL, all stderr output from the * pipeline will go to a temporary file - * created here, and a descriptor to read the - * file will be left at *errFilePtr. The file - * will be removed already, so closing this - * descriptor will be the end of the file. If - * this is NULL, then all stderr output goes - * to our stderr. If the pipeline specifies - * redirection then the file will still be - * created but it will never get any data. */ + * created here, and a descriptor to read + * the file will be left at *errFilePtr. + * The file will be removed already, so + * closing this descriptor will be the end + * of the file. If this is NULL, then + * all stderr output goes to our stderr. + * If the pipeline specifies redirection + * then the file will still be created + * but it will never get any data. */ { - Tcl_Pid *pidPtr = NULL; /* Points to malloc-ed array holding all the - * pids of child processes. */ - int numPids; /* Actual number of processes that exist at - * *pidPtr right now. */ - int cmdCount; /* Count of number of distinct commands found - * in argc/argv. */ - CONST char *inputLiteral = NULL; - /* If non-null, then this points to a string - * containing input data (specified via <<) to - * be piped to the first process in the - * pipeline. */ + Tcl_Pid *pidPtr = NULL; /* Points to malloc-ed array holding all + * the pids of child processes. */ + int numPids; /* Actual number of processes that exist + * at *pidPtr right now. */ + int cmdCount; /* Count of number of distinct commands + * found in argc/argv. */ + CONST char *inputLiteral = NULL; /* If non-null, then this points to a + * string containing input data (specified + * via <<) to be piped to the first process + * in the pipeline. */ TclFile inputFile = NULL; /* If != NULL, gives file to use as input for * first process in pipeline (specified via < * or <@). */ - int inputClose = 0; /* If non-zero, then inputFile should be + int inputClose = 0; /* If non-zero, then inputFile should be * closed when cleaning up. */ int inputRelease = 0; TclFile outputFile = NULL; /* Writable file for output from last command - * in pipeline (could be file or pipe). NULL + * in pipeline (could be file or pipe). NULL * means use stdout. */ - int outputClose = 0; /* If non-zero, then outputFile should be + int outputClose = 0; /* If non-zero, then outputFile should be * closed when cleaning up. */ int outputRelease = 0; TclFile errorFile = NULL; /* Writable file for error output from all - * commands in pipeline. NULL means use + * commands in pipeline. NULL means use * stderr. */ - int errorClose = 0; /* If non-zero, then errorFile should be + int errorClose = 0; /* If non-zero, then errorFile should be * closed when cleaning up. */ int errorRelease = 0; CONST char *p; @@ -506,23 +523,23 @@ TclCreatePipeline( } Tcl_DStringInit(&execBuffer); - + pipeIn = NULL; curInFile = NULL; curOutFile = NULL; numPids = 0; /* - * First, scan through all the arguments to figure out the structure of - * the pipeline. Process all of the input and output redirection arguments - * and remove them from the argument list in the pipeline. Count the - * number of distinct processes (it's the number of "|" arguments plus - * one) but don't remove the "|" arguments because they'll be used in the - * second pass to seperate the individual child processes. Cannot start - * the child processes in this pass because the redirection symbols may - * appear anywhere in the command line - e.g., the '<' that specifies the - * input to the entire pipe may appear at the very end of the argument - * list. + * First, scan through all the arguments to figure out the structure + * of the pipeline. Process all of the input and output redirection + * arguments and remove them from the argument list in the pipeline. + * Count the number of distinct processes (it's the number of "|" + * arguments plus one) but don't remove the "|" arguments because + * they'll be used in the second pass to seperate the individual + * child processes. Cannot start the child processes in this pass + * because the redirection symbols may appear anywhere in the + * command line -- e.g., the '<' that specifies the input to the + * entire pipe may appear at the very end of the argument list. */ lastBar = -1; @@ -539,7 +556,8 @@ TclCreatePipeline( } if (*p == '\0') { if ((i == (lastBar + 1)) || (i == (argc - 1))) { - Tcl_SetResult(interp, "illegal use of | or |& in command", + Tcl_SetResult(interp, + "illegal use of | or |& in command", TCL_STATIC); goto error; } @@ -566,7 +584,7 @@ TclCreatePipeline( inputLiteral = ((i + 1) == argc) ? NULL : argv[i + 1]; if (inputLiteral == NULL) { Tcl_AppendResult(interp, "can't specify \"", argv[i], - "\" as last word in command", NULL); + "\" as last word in command", (char *) NULL); goto error; } skip = 2; @@ -574,8 +592,8 @@ TclCreatePipeline( } else { nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; inputLiteral = NULL; - inputFile = FileForRedirect(interp, p, 1, argv[i], nextArg, - O_RDONLY, &skip, &inputClose, &inputRelease); + inputFile = FileForRedirect(interp, p, 1, argv[i], + nextArg, O_RDONLY, &skip, &inputClose, &inputRelease); if (inputFile == NULL) { goto error; } @@ -606,8 +624,8 @@ TclCreatePipeline( } /* - * Close the old output file, but only if the error file is not - * also using it. + * Close the old output file, but only if the error file is + * not also using it. */ if (outputClose != 0) { @@ -627,8 +645,8 @@ TclCreatePipeline( } } nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; - outputFile = FileForRedirect(interp, p, atOK, argv[i], nextArg, - flags, &skip, &outputClose, &outputRelease); + outputFile = FileForRedirect(interp, p, atOK, argv[i], + nextArg, flags, &skip, &outputClose, &outputRelease); if (outputFile == NULL) { goto error; } @@ -668,13 +686,12 @@ TclCreatePipeline( if (atOK && p[0] == '@' && p[1] == '1' && p[2] == '\0') { /* * Special case handling of 2>@1 to redirect stderr to the - * exec/open output pipe as well. This is meant for the end of - * the command string, otherwise use |& between commands. + * exec/open output pipe as well. This is meant for the end + * of the command string, otherwise use |& between commands. */ - - if (i != argc-1) { + if (i != argc - 1) { Tcl_AppendResult(interp, "must specify \"", argv[i], - "\" as last word in command", NULL); + "\" as last word in command", (char *) NULL); goto error; } errorFile = outputFile; @@ -682,7 +699,7 @@ TclCreatePipeline( skip = 1; } else { nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; - errorFile = FileForRedirect(interp, p, atOK, argv[i], + errorFile = FileForRedirect(interp, p, atOK, argv[i], nextArg, flags, &skip, &errorClose, &errorRelease); if (errorFile == NULL) { goto error; @@ -706,7 +723,7 @@ TclCreatePipeline( } if (needCmd) { - /* We had a bar followed only by redirections. */ + /* We had a bar followed only by redirections. */ Tcl_SetResult(interp, "illegal use of | or |& in command", @@ -718,28 +735,27 @@ TclCreatePipeline( if (inputLiteral != NULL) { /* * The input for the first process is immediate data coming from - * Tcl. Create a temporary file for it and put the data into the + * Tcl. Create a temporary file for it and put the data into the * file. */ - inputFile = TclpCreateTempFile(inputLiteral); if (inputFile == NULL) { Tcl_AppendResult(interp, "couldn't create input file for command: ", - Tcl_PosixError(interp), NULL); + Tcl_PosixError(interp), (char *) NULL); goto error; } inputClose = 1; } else if (inPipePtr != NULL) { /* - * The input for the first process in the pipeline is to come from - * a pipe that can be written from by the caller. + * The input for the first process in the pipeline is to + * come from a pipe that can be written from by the caller. */ if (TclpCreatePipe(&inputFile, inPipePtr) == 0) { - Tcl_AppendResult(interp, + Tcl_AppendResult(interp, "couldn't create input pipe for command: ", - Tcl_PosixError(interp), NULL); + Tcl_PosixError(interp), (char *) NULL); goto error; } inputClose = 1; @@ -761,14 +777,14 @@ TclCreatePipeline( if (outputFile == NULL) { if (outPipePtr != NULL) { /* - * Output from the last process in the pipeline is to go to a pipe - * that can be read by the caller. + * Output from the last process in the pipeline is to go to a + * pipe that can be read by the caller. */ if (TclpCreatePipe(outPipePtr, &outputFile) == 0) { - Tcl_AppendResult(interp, + Tcl_AppendResult(interp, "couldn't create output pipe for command: ", - Tcl_PosixError(interp), NULL); + Tcl_PosixError(interp), (char *) NULL); goto error; } outputClose = 1; @@ -790,17 +806,16 @@ TclCreatePipeline( if (errorFile == NULL) { if (errorToOutput == 2) { /* - * Handle 2>@1 special case at end of cmd line. + * Handle 2>@1 special case at end of cmd line */ - errorFile = outputFile; } else if (errFilePtr != NULL) { /* * Set up the standard error output sink for the pipeline, if - * requested. Use a temporary file which is opened, then deleted. + * requested. Use a temporary file which is opened, then deleted. * Could potentially just use pipe, but if it filled up it could - * cause the pipeline to deadlock: we'd be waiting for processes - * to complete before reading stderr, and processes couldn't + * cause the pipeline to deadlock: we'd be waiting for processes + * to complete before reading stderr, and processes couldn't * complete because stderr was backed up. */ @@ -808,7 +823,7 @@ TclCreatePipeline( if (errorFile == NULL) { Tcl_AppendResult(interp, "couldn't create error file for command: ", - Tcl_PosixError(interp), NULL); + Tcl_PosixError(interp), (char *) NULL); goto error; } *errFilePtr = errorFile; @@ -826,10 +841,10 @@ TclCreatePipeline( } } } - + /* - * Scan through the argc array, creating a process for each group of - * arguments between the "|" characters. + * Scan through the argc array, creating a process for each + * group of arguments between the "|" characters. */ Tcl_ReapDetachedProcs(); @@ -837,13 +852,13 @@ TclCreatePipeline( curInFile = inputFile; - for (i = 0; i < argc; i = lastArg + 1) { + for (i = 0; i < argc; i = lastArg + 1) { int result, joinThisError; Tcl_Pid pid; CONST char *oldName; /* - * Convert the program name into native form. + * Convert the program name into native form. */ if (Tcl_TranslateFileName(interp, argv[i], &execBuffer) == NULL) { @@ -856,21 +871,20 @@ TclCreatePipeline( joinThisError = 0; for (lastArg = i; lastArg < argc; lastArg++) { - if (argv[lastArg][0] != '|') { - continue; - } - if (argv[lastArg][1] == '\0') { - break; - } - if ((argv[lastArg][1] == '&') && (argv[lastArg][2] == '\0')) { - joinThisError = 1; - break; + if (argv[lastArg][0] == '|') { + if (argv[lastArg][1] == '\0') { + break; + } + if ((argv[lastArg][1] == '&') && (argv[lastArg][2] == '\0')) { + joinThisError = 1; + break; + } } } /* * If this is the last segment, use the specified outputFile. - * Otherwise create an intermediate pipe. pipeIn will become the + * Otherwise create an intermediate pipe. pipeIn will become the * curInFile for the next segment of the pipe. */ @@ -880,7 +894,7 @@ TclCreatePipeline( argv[lastArg] = NULL; if (TclpCreatePipe(&pipeIn, &curOutFile) == 0) { Tcl_AppendResult(interp, "couldn't create pipe: ", - Tcl_PosixError(interp), NULL); + Tcl_PosixError(interp), (char *) NULL); goto error; } } @@ -895,7 +909,7 @@ TclCreatePipeline( * Restore argv[i], since a caller wouldn't expect the contents of * argv to be modified. */ - + oldName = argv[i]; argv[i] = Tcl_DStringValue(&execBuffer); result = TclpCreateProcess(interp, lastArg - i, argv + i, @@ -910,8 +924,8 @@ TclCreatePipeline( numPids++; /* - * Close off our copies of file descriptors that were set up for this - * child, then set up the input for the next child. + * Close off our copies of file descriptors that were set up for + * this child, then set up the input for the next child. */ if ((curInFile != NULL) && (curInFile != inputFile)) { @@ -929,10 +943,10 @@ TclCreatePipeline( *pidArrayPtr = pidPtr; /* - * All done. Cleanup open files lying around and then return. + * All done. Cleanup open files lying around and then return. */ - cleanup: +cleanup: Tcl_DStringFree(&execBuffer); if (inputClose) { @@ -953,12 +967,12 @@ TclCreatePipeline( return numPids; /* - * An error occurred. There could have been extra files open, such as - * pipes between children. Clean them all up. Detach any child processes - * that have been created. + * An error occurred. There could have been extra files open, such + * as pipes between children. Clean them all up. Detach any child + * processes that have been created. */ - error: +error: if (pipeIn != NULL) { TclpCloseFile(pipeIn); } @@ -997,26 +1011,28 @@ TclCreatePipeline( * * Tcl_OpenCommandChannel -- * - * Opens an I/O channel to one or more subprocesses specified by argc and - * argv. The flags argument determines the disposition of the stdio - * handles. If the TCL_STDIN flag is set then the standard input for the - * first subprocess will be tied to the channel: writing to the channel - * will provide input to the subprocess. If TCL_STDIN is not set, then - * standard input for the first subprocess will be the same as this - * application's standard input. If TCL_STDOUT is set then standard - * output from the last subprocess can be read from the channel; - * otherwise it goes to this application's standard output. If TCL_STDERR - * is set, standard error output for all subprocesses is returned to the - * channel and results in an error when the channel is closed; otherwise - * it goes to this application's standard error. If TCL_ENFORCE_MODE is - * not set, then argc and argv can redirect the stdio handles to override - * TCL_STDIN, TCL_STDOUT, and TCL_STDERR; if it is set, then it is an - * error for argc and argv to override stdio channels for which - * TCL_STDIN, TCL_STDOUT, and TCL_STDERR have been set. + * Opens an I/O channel to one or more subprocesses specified + * by argc and argv. The flags argument determines the + * disposition of the stdio handles. If the TCL_STDIN flag is + * set then the standard input for the first subprocess will + * be tied to the channel: writing to the channel will provide + * input to the subprocess. If TCL_STDIN is not set, then + * standard input for the first subprocess will be the same as + * this application's standard input. If TCL_STDOUT is set then + * standard output from the last subprocess can be read from the + * channel; otherwise it goes to this application's standard + * output. If TCL_STDERR is set, standard error output for all + * subprocesses is returned to the channel and results in an error + * when the channel is closed; otherwise it goes to this + * application's standard error. If TCL_ENFORCE_MODE is not set, + * then argc and argv can redirect the stdio handles to override + * TCL_STDIN, TCL_STDOUT, and TCL_STDERR; if it is set, then it + * is an error for argc and argv to override stdio channels for + * which TCL_STDIN, TCL_STDOUT, and TCL_STDERR have been set. * * Results: - * A new command channel, or NULL on failure with an error message left - * in interp. + * A new command channel, or NULL on failure with an error + * message left in interp. * * Side effects: * Creates processes, opens pipes. @@ -1025,12 +1041,12 @@ TclCreatePipeline( */ Tcl_Channel -Tcl_OpenCommandChannel( - Tcl_Interp *interp, /* Interpreter for error reporting. Can NOT be - * NULL. */ - int argc, /* How many arguments. */ - CONST char **argv, /* Array of arguments for command pipe. */ - int flags) /* Or'ed combination of TCL_STDIN, TCL_STDOUT, +Tcl_OpenCommandChannel(interp, argc, argv, flags) + Tcl_Interp *interp; /* Interpreter for error reporting. Can + * NOT be NULL. */ + int argc; /* How many arguments. */ + CONST char **argv; /* Array of arguments for command pipe. */ + int flags; /* Or'ed combination of TCL_STDIN, TCL_STDOUT, * TCL_STDERR, and TCL_ENFORCE_MODE. */ { TclFile *inPipePtr, *outPipePtr, *errFilePtr; @@ -1044,7 +1060,7 @@ Tcl_OpenCommandChannel( inPipePtr = (flags & TCL_STDIN) ? &inPipe : NULL; outPipePtr = (flags & TCL_STDOUT) ? &outPipe : NULL; errFilePtr = (flags & TCL_STDERR) ? &errFile : NULL; - + numPids = TclCreatePipeline(interp, argc, argv, &pidPtr, inPipePtr, outPipePtr, errFilePtr); @@ -1053,34 +1069,34 @@ Tcl_OpenCommandChannel( } /* - * Verify that the pipes that were created satisfy the readable/writable - * constraints. + * Verify that the pipes that were created satisfy the + * readable/writable constraints. */ if (flags & TCL_ENFORCE_MODE) { if ((flags & TCL_STDOUT) && (outPipe == NULL)) { - Tcl_AppendResult(interp, "can't read output from command:" - " standard output was redirected", NULL); + Tcl_AppendResult(interp, "can't read output from command:", + " standard output was redirected", (char *) NULL); goto error; } if ((flags & TCL_STDIN) && (inPipe == NULL)) { - Tcl_AppendResult(interp, "can't write input to command:" - " standard input was redirected", NULL); + Tcl_AppendResult(interp, "can't write input to command:", + " standard input was redirected", (char *) NULL); goto error; } } - + channel = TclpCreateCommandChannel(outPipe, inPipe, errFile, numPids, pidPtr); if (channel == (Tcl_Channel) NULL) { Tcl_AppendResult(interp, "pipe for command could not be created", - NULL); + (char *) NULL); goto error; } return channel; - error: +error: if (numPids > 0) { Tcl_DetachPids(numPids, pidPtr); ckfree((char *) pidPtr); @@ -1096,11 +1112,3 @@ Tcl_OpenCommandChannel( } return NULL; } - -/* - * Local Variables: - * mode: c - * c-basic-offset: 4 - * fill-column: 78 - * End: - */ |
