diff options
Diffstat (limited to 'generic/tclPipe.c')
-rw-r--r-- | generic/tclPipe.c | 410 |
1 files changed, 226 insertions, 184 deletions
diff --git a/generic/tclPipe.c b/generic/tclPipe.c index f7bc038..83fb818 100644 --- a/generic/tclPipe.c +++ b/generic/tclPipe.c @@ -1,4 +1,4 @@ -/* +/* * tclPipe.c -- * * This file contains the generic portion of the command channel driver @@ -8,8 +8,6 @@ * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tclPipe.c,v 1.12 2005/07/28 10:55:36 dkf Exp $ */ #include "tclInt.h" @@ -34,10 +32,10 @@ TCL_DECLARE_MUTEX(pipeMutex) /* Guard access to detList. */ * Declarations for local functions defined in this file: */ -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)); +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); /* *---------------------------------------------------------------------- @@ -61,34 +59,33 @@ static TclFile FileForRedirect _ANSI_ARGS_((Tcl_Interp *interp, */ static TclFile -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 +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 + 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: + const char *arg, /* Pointer to entire argument containing spec: * used for error reporting. */ - CONST char *nextArg; /* Next argument in argc/argv array, if needed + 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 + int flags, /* Flags to use for opening file or to specify * mode for channel. */ - int *skipPtr; /* Filled with 1 if redirection target was in + 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 + 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; @@ -97,17 +94,27 @@ FileForRedirect(interp, spec, atOK, arg, nextArg, flags, skipPtr, closePtr, } *skipPtr = 2; } - chan = Tcl_GetChannel(interp, spec, NULL); - if (chan == (Tcl_Channel) NULL) { - return NULL; - } + chan = Tcl_GetChannel(interp, spec, NULL); + if (chan == (Tcl_Channel) NULL) { + return NULL; + } file = TclpMakeFile(chan, writing ? TCL_WRITABLE : TCL_READABLE); - if (file == NULL) { - Tcl_AppendResult(interp, "channel \"", Tcl_GetChannelName(chan), - "\" wasn't opened for ", - ((writing) ? "writing" : "reading"), (char *) NULL); - return NULL; - } + if (file == NULL) { + Tcl_Obj *msg; + + Tcl_GetChannelError(chan, &msg); + if (msg) { + Tcl_SetObjResult(interp, msg); + } else { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "channel \"%s\" wasn't opened for %s", + Tcl_GetChannelName(chan), + ((writing) ? "writing" : "reading"))); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", + "BADCHAN", NULL); + } + return NULL; + } *releasePtr = 1; if (writing) { /* @@ -115,10 +122,10 @@ FileForRedirect(interp, spec, atOK, arg, nextArg, flags, skipPtr, closePtr, * by the child appears after stuff we've already written. */ - Tcl_Flush(chan); + Tcl_Flush(chan); } } else { - CONST char *name; + const char *name; Tcl_DString nameString; if (*spec == '\0') { @@ -129,25 +136,26 @@ FileForRedirect(interp, spec, atOK, arg, nextArg, flags, skipPtr, closePtr, *skipPtr = 2; } name = Tcl_TranslateFileName(interp, spec, &nameString); - if (name != NULL) { - file = TclpOpenFile(name, flags); - } else { - file = NULL; + if (name == NULL) { + return NULL; } + file = TclpOpenFile(name, flags); Tcl_DStringFree(&nameString); if (file == NULL) { - Tcl_AppendResult(interp, "couldn't ", - ((writing) ? "write" : "read"), " file \"", spec, "\": ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't %s file \"%s\": %s", + (writing ? "write" : "read"), spec, + Tcl_PosixError(interp))); return NULL; } - *closePtr = 1; + *closePtr = 1; } return file; badLastArg: - Tcl_AppendResult(interp, "can't specify \"", arg, - "\" as last word in command", (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't specify \"%s\" as last word in command", arg)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "SYNTAX", NULL); return NULL; } @@ -170,17 +178,17 @@ FileForRedirect(interp, spec, atOK, arg, nextArg, flags, skipPtr, closePtr, */ void -Tcl_DetachPids(numPids, pidPtr) - int numPids; /* Number of pids to detach: gives size of +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_Pid *pidPtr) /* Array of pids to detach. */ { register Detached *detPtr; int i; Tcl_MutexLock(&pipeMutex); for (i = 0; i < numPids; i++) { - detPtr = (Detached *) ckalloc(sizeof(Detached)); + detPtr = ckalloc(sizeof(Detached)); detPtr->pid = pidPtr[i]; detPtr->nextPtr = detList; detList = detPtr; @@ -209,7 +217,7 @@ Tcl_DetachPids(numPids, pidPtr) */ void -Tcl_ReapDetachedProcs() +Tcl_ReapDetachedProcs(void) { register Detached *detPtr; Detached *nextPtr, *prevPtr; @@ -230,7 +238,7 @@ Tcl_ReapDetachedProcs() } else { prevPtr->nextPtr = detPtr->nextPtr; } - ckfree((char *) detPtr); + ckfree(detPtr); detPtr = nextPtr; } Tcl_MutexUnlock(&pipeMutex); @@ -259,48 +267,48 @@ Tcl_ReapDetachedProcs() */ int -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 +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 * stderr output. */ { int result = TCL_OK; int i, abnormalExit, anyErrorInfo; Tcl_Pid pid; - WAIT_STATUS_TYPE waitStatus; - CONST char *msg; + int waitStatus; + const char *msg; unsigned long resolvedPid; abnormalExit = 0; for (i = 0; i < numPids; i++) { /* * We need to get the resolved pid before we wait on it as the windows - * implimentation of Tcl_WaitPid deletes the information such that any + * 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); + pid = Tcl_WaitPid(pidPtr[i], &waitStatus, 0); if (pid == (Tcl_Pid) -1) { result = TCL_ERROR; - if (interp != (Tcl_Interp *) NULL) { - msg = Tcl_PosixError(interp); - if (errno == ECHILD) { + if (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. - */ - - msg = - "child process lost (is SIGCHLD ignored or trapped?)"; - } - Tcl_AppendResult(interp, "error waiting for process to exit: ", - msg, (char *) NULL); - } + * 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_SetObjResult(interp, Tcl_ObjPrintf( + "error waiting for process to exit: %s", msg)); + } continue; } @@ -317,40 +325,32 @@ TclCleanupChildren(interp, numPids, pidPtr, errorChan) result = TCL_ERROR; sprintf(msg1, "%lu", resolvedPid); if (WIFEXITED(waitStatus)) { - if (interp != (Tcl_Interp *) NULL) { - sprintf(msg2, "%hu", WEXITSTATUS(waitStatus)); - Tcl_SetErrorCode(interp, "CHILDSTATUS", msg1, msg2, - (char *) NULL); - } + if (interp != NULL) { + sprintf(msg2, "%u", WEXITSTATUS(waitStatus)); + Tcl_SetErrorCode(interp, "CHILDSTATUS", msg1, msg2, NULL); + } abnormalExit = 1; - } 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, - (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, (char *) NULL); - Tcl_AppendResult(interp, "child suspended: ", p, "\n", - (char *) NULL); - } - } else { - if (interp != (Tcl_Interp *) NULL) { - Tcl_AppendResult(interp, - "child wait status didn't make sense\n", - (char *) NULL); - } + } else if (interp != NULL) { + const char *p; + + if (WIFSIGNALED(waitStatus)) { + p = Tcl_SignalMsg(WTERMSIG(waitStatus)); + Tcl_SetErrorCode(interp, "CHILDKILLED", msg1, + Tcl_SignalId(WTERMSIG(waitStatus)), p, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "child killed: %s\n", p)); + } else if (WIFSTOPPED(waitStatus)) { + p = Tcl_SignalMsg(WSTOPSIG(waitStatus)); + Tcl_SetErrorCode(interp, "CHILDSUSP", msg1, + Tcl_SignalId(WSTOPSIG(waitStatus)), p, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "child suspended: %s\n", p)); + } else { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "child wait status didn't make sense\n", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", + "ODDWAITRESULT", msg1, NULL); + } } } } @@ -366,10 +366,10 @@ TclCleanupChildren(interp, numPids, pidPtr, errorChan) * Make sure we start at the beginning of the file. */ - if (interp != NULL) { + 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); @@ -377,8 +377,9 @@ TclCleanupChildren(interp, numPids, pidPtr, errorChan) result = TCL_ERROR; Tcl_DecrRefCount(objPtr); Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "error reading stderr output file: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error reading stderr output file: %s", + Tcl_PosixError(interp))); } else if (count > 0) { anyErrorInfo = 1; Tcl_SetObjResult(interp, objPtr); @@ -396,8 +397,8 @@ TclCleanupChildren(interp, numPids, pidPtr, errorChan) */ if ((abnormalExit != 0) && (anyErrorInfo == 0) && (interp != NULL)) { - Tcl_AppendResult(interp, "child process exited abnormally", - (char *) NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "child process exited abnormally", -1)); } return result; } @@ -432,30 +433,29 @@ TclCleanupChildren(interp, numPids, pidPtr, errorChan) */ int -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 +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 + 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 + 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 + 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 + 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 @@ -472,7 +472,7 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, * *pidPtr right now. */ int cmdCount; /* Count of number of distinct commands found * in argc/argv. */ - CONST char *inputLiteral = NULL; + 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 @@ -481,22 +481,23 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, * first process in pipeline (specified via < * or <@). */ int inputClose = 0; /* If non-zero, then inputFile should be - * closed when cleaning up. */ + * 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 * means use stdout. */ int outputClose = 0; /* If non-zero, then outputFile should be - * closed when cleaning up. */ + * closed when cleaning up. */ int outputRelease = 0; TclFile errorFile = NULL; /* Writable file for error output from all * commands in pipeline. NULL means use * stderr. */ int errorClose = 0; /* If non-zero, then errorFile should be - * closed when cleaning up. */ + * closed when cleaning up. */ int errorRelease = 0; - CONST char *p; - int skip, lastBar, lastArg, i, j, atOK, flags, errorToOutput = 0; + const char *p; + const char *nextArg; + int skip, lastBar, lastArg, i, j, atOK, flags, needCmd, errorToOutput = 0; Tcl_DString execBuffer; TclFile pipeIn; TclFile curInFile, curOutFile, curErrFile; @@ -513,7 +514,7 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, } Tcl_DStringInit(&execBuffer); - + pipeIn = NULL; curInFile = NULL; curOutFile = NULL; @@ -534,6 +535,7 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, lastBar = -1; cmdCount = 1; + needCmd = 1; for (i = 0; i < argc; i++) { errorToOutput = 0; skip = 0; @@ -545,13 +547,16 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, } if (*p == '\0') { if ((i == (lastBar + 1)) || (i == (argc - 1))) { - Tcl_SetResult(interp, "illegal use of | or |& in command", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "illegal use of | or |& in command", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", + "PIPESYNTAX", NULL); goto error; } } lastBar = i; cmdCount++; + needCmd = 1; break; case '<': @@ -568,17 +573,21 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, inputLiteral = p + 1; skip = 1; if (*inputLiteral == '\0') { - inputLiteral = argv[i + 1]; + inputLiteral = ((i + 1) == argc) ? NULL : argv[i + 1]; if (inputLiteral == NULL) { - Tcl_AppendResult(interp, "can't specify \"", argv[i], - "\" as last word in command", (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't specify \"%s\" as last word in command", + argv[i])); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", + "PIPESYNTAX", NULL); goto error; } skip = 2; } } else { + nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; inputLiteral = NULL; - inputFile = FileForRedirect(interp, p, 1, argv[i], argv[i+1], + inputFile = FileForRedirect(interp, p, 1, argv[i], nextArg, O_RDONLY, &skip, &inputClose, &inputRelease); if (inputFile == NULL) { goto error; @@ -630,7 +639,8 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, TclpReleaseFile(outputFile); } } - outputFile = FileForRedirect(interp, p, atOK, argv[i], argv[i+1], + nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; + outputFile = FileForRedirect(interp, p, atOK, argv[i], nextArg, flags, &skip, &outputClose, &outputRelease); if (outputFile == NULL) { goto error; @@ -676,21 +686,33 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, */ if (i != argc-1) { - Tcl_AppendResult(interp, "must specify \"", argv[i], - "\" as last word in command", (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "must specify \"%s\" as last word in command", + argv[i])); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", + "PIPESYNTAX", NULL); goto error; } errorFile = outputFile; errorToOutput = 2; skip = 1; } else { - errorFile = FileForRedirect(interp, p, atOK, argv[i], - argv[i+1], flags, &skip, &errorClose, &errorRelease); + nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; + errorFile = FileForRedirect(interp, p, atOK, argv[i], + nextArg, flags, &skip, &errorClose, &errorRelease); if (errorFile == NULL) { goto error; } } break; + + default: + /* + * Got a command word, not a redirection. + */ + + needCmd = 0; + break; } if (skip != 0) { @@ -702,6 +724,18 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, } } + if (needCmd) { + /* + * We had a bar followed only by redirections. + */ + + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "illegal use of | or |& in command", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "PIPESYNTAX", + NULL); + goto error; + } + if (inputFile == NULL) { if (inputLiteral != NULL) { /* @@ -712,9 +746,9 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, inputFile = TclpCreateTempFile(inputLiteral); if (inputFile == NULL) { - Tcl_AppendResult(interp, - "couldn't create input file for command: ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create input file for command: %s", + Tcl_PosixError(interp))); goto error; } inputClose = 1; @@ -725,9 +759,9 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, */ if (TclpCreatePipe(&inputFile, inPipePtr) == 0) { - Tcl_AppendResult(interp, - "couldn't create input pipe for command: ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create input pipe for command: %s", + Tcl_PosixError(interp))); goto error; } inputClose = 1; @@ -754,9 +788,9 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, */ if (TclpCreatePipe(outPipePtr, &outputFile) == 0) { - Tcl_AppendResult(interp, - "couldn't create output pipe for command: ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create output pipe for command: %s", + Tcl_PosixError(interp))); goto error; } outputClose = 1; @@ -794,9 +828,9 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, errorFile = TclpCreateTempFile(NULL); if (errorFile == NULL) { - Tcl_AppendResult(interp, - "couldn't create error file for command: ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create error file for command: %s", + Tcl_PosixError(interp))); goto error; } *errFilePtr = errorFile; @@ -814,24 +848,24 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, } } } - + /* * Scan through the argc array, creating a process for each group of * arguments between the "|" characters. */ Tcl_ReapDetachedProcs(); - pidPtr = (Tcl_Pid *) ckalloc((unsigned) (cmdCount * sizeof(Tcl_Pid))); + pidPtr = ckalloc(cmdCount * sizeof(Tcl_Pid)); 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; + 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) { @@ -844,17 +878,17 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, joinThisError = 0; for (lastArg = i; lastArg < argc; lastArg++) { - if (argv[lastArg][0] == '|') { - if (argv[lastArg][1] == '\0') { - break; - } - if ((argv[lastArg][1] == '&') && (argv[lastArg][2] == '\0')) { - joinThisError = 1; - break; - } + if (argv[lastArg][0] != '|') { + continue; + } + if (argv[lastArg][1] == '\0') { + break; + } + if ((argv[lastArg][1] == '&') && (argv[lastArg][2] == '\0')) { + joinThisError = 1; + break; } } - argv[lastArg] = NULL; /* * If this is the last segment, use the specified outputFile. @@ -862,12 +896,13 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, * curInFile for the next segment of the pipe. */ - if (lastArg == argc) { + if (lastArg == argc) { curOutFile = outputFile; } else { + argv[lastArg] = NULL; if (TclpCreatePipe(&pipeIn, &curOutFile) == 0) { - Tcl_AppendResult(interp, "couldn't create pipe: ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create pipe: %s", Tcl_PosixError(interp))); goto error; } } @@ -882,7 +917,7 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, * 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, @@ -973,7 +1008,7 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, Tcl_DetachPids(1, &pidPtr[i]); } } - ckfree((char *) pidPtr); + ckfree(pidPtr); } numPids = -1; goto cleanup; @@ -1012,12 +1047,12 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, */ Tcl_Channel -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_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_STDERR, and TCL_ENFORCE_MODE. */ { TclFile *inPipePtr, *outPipePtr, *errFilePtr; @@ -1031,9 +1066,9 @@ Tcl_OpenCommandChannel(interp, argc, argv, flags) 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); + outPipePtr, errFilePtr); if (numPids < 0) { goto error; @@ -1046,23 +1081,30 @@ Tcl_OpenCommandChannel(interp, argc, argv, flags) if (flags & TCL_ENFORCE_MODE) { if ((flags & TCL_STDOUT) && (outPipe == NULL)) { - Tcl_AppendResult(interp, "can't read output from command:", - " standard output was redirected", (char *) NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can't read output from command:" + " standard output was redirected", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", + "BADREDIRECT", NULL); goto error; } if ((flags & TCL_STDIN) && (inPipe == NULL)) { - Tcl_AppendResult(interp, "can't write input to command:", - " standard input was redirected", (char *) NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can't write input to command:" + " standard input was redirected", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", + "BADREDIRECT", 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", - (char *) NULL); + if (channel == NULL) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "pipe for command could not be created", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "NOPIPE", NULL); goto error; } return channel; @@ -1070,7 +1112,7 @@ Tcl_OpenCommandChannel(interp, argc, argv, flags) error: if (numPids > 0) { Tcl_DetachPids(numPids, pidPtr); - ckfree((char *) pidPtr); + ckfree(pidPtr); } if (inPipe != NULL) { TclpCloseFile(inPipe); |