summaryrefslogtreecommitdiff
path: root/contrib/tcl/generic/tclIOUtil.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tcl/generic/tclIOUtil.c')
-rw-r--r--contrib/tcl/generic/tclIOUtil.c917
1 files changed, 4 insertions, 913 deletions
diff --git a/contrib/tcl/generic/tclIOUtil.c b/contrib/tcl/generic/tclIOUtil.c
index f42e16bbd634f..cb2bd94c017fe 100644
--- a/contrib/tcl/generic/tclIOUtil.c
+++ b/contrib/tcl/generic/tclIOUtil.c
@@ -13,151 +13,12 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * SCCS: @(#) tclIOUtil.c 1.123 96/04/29 14:08:24
+ * SCCS: @(#) tclIOUtil.c 1.132 97/04/23 16:21:42
*/
#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.
- */
-
-typedef struct Detached {
- int 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. */
-
-/*
- * Declarations for local procedures defined in this file:
- */
-
-static Tcl_File FileForRedirect _ANSI_ARGS_((Tcl_Interp *interp,
- char *spec, int atOk, char *arg, int flags,
- char *nextArg, int *skipPtr, int *closePtr));
-
-/*
- *----------------------------------------------------------------------
- *
- * FileForRedirect --
- *
- * 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 interp->result. Several arguments are side-effected; see
- * the argument list below for details.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static Tcl_File
-FileForRedirect(interp, spec, atOk, arg, flags, nextArg, skipPtr, closePtr)
- Tcl_Interp *interp; /* Intepreter to use for error
- * reporting. */
- register char *spec; /* Points to character just after
- * redirection character. */
- int atOk; /* Non-zero means '@' notation is
- * OK, zero means it isn't. */
- char *arg; /* Pointer to entire argument
- * containing spec: used for error
- * reporting. */
- int flags; /* Flags to use for opening file. */
- char *nextArg; /* Next argument in argc/argv
- * array, if needed for file name.
- * May be NULL. */
- int *skipPtr; /* This value is incremented if
- * nextArg is used for redirection
- * spec. */
- int *closePtr; /* This value is set to 1 if the file
- * that's returned must be closed, 0
- * if it was specified with "@" so
- * it must be left open. */
-{
- int writing = (flags & O_WRONLY);
- Tcl_Channel chan;
- Tcl_File file;
-
- if (atOk && (*spec == '@')) {
- spec++;
- if (*spec == 0) {
- spec = nextArg;
- if (spec == NULL) {
- goto badLastArg;
- }
- *skipPtr += 1;
- }
- chan = Tcl_GetChannel(interp, spec, NULL);
- if (chan == (Tcl_Channel) NULL) {
- return NULL;
- }
- *closePtr = 0;
- file = Tcl_GetChannelFile(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 (writing) {
-
- /*
- * 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);
- }
- } else {
- Tcl_DString buffer;
- char *name;
-
- if (*spec == 0) {
- spec = nextArg;
- if (spec == NULL) {
- goto badLastArg;
- }
- *skipPtr += 1;
- }
- name = Tcl_TranslateFileName(interp, spec, &buffer);
- if (name) {
- file = TclOpenFile(name, flags);
- } else {
- file = NULL;
- }
- Tcl_DStringFree(&buffer);
- if (file == NULL) {
- Tcl_AppendResult(interp, "couldn't ",
- (writing) ? "write" : "read", " file \"", spec, "\": ",
- Tcl_PosixError(interp), (char *) NULL);
- return NULL;
- }
- *closePtr = 1;
- }
- return file;
-
- badLastArg:
- Tcl_AppendResult(interp, "can't specify \"", arg,
- "\" as last word in command", (char *) NULL);
- return NULL;
-}
/*
*----------------------------------------------------------------------
@@ -354,11 +215,11 @@ Tcl_EvalFile(interp, fileName)
int result;
struct stat statBuf;
char *cmdBuffer = (char *) NULL;
- char *oldScriptFile = (char *) NULL;
+ char *oldScriptFile;
Interp *iPtr = (Interp *) interp;
Tcl_DString buffer;
- char *nativeName = (char *) NULL;
- Tcl_Channel chan = (Tcl_Channel) NULL;
+ char *nativeName;
+ Tcl_Channel chan;
Tcl_ResetResult(interp);
oldScriptFile = iPtr->scriptFile;
@@ -438,670 +299,6 @@ error:
/*
*----------------------------------------------------------------------
*
- * Tcl_DetachPids --
- *
- * 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.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_DetachPids(numPids, pidPtr)
- int numPids; /* Number of pids to detach: gives size
- * of array pointed to by pidPtr. */
- int *pidPtr; /* Array of pids to detach. */
-{
- register Detached *detPtr;
- int i;
-
- for (i = 0; i < numPids; i++) {
- detPtr = (Detached *) ckalloc(sizeof(Detached));
- detPtr->pid = pidPtr[i];
- detPtr->nextPtr = detList;
- detList = detPtr;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_ReapDetachedProcs --
- *
- * 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.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_ReapDetachedProcs()
-{
- register Detached *detPtr;
- Detached *nextPtr, *prevPtr;
- int status;
- int pid;
-
- for (detPtr = detList, prevPtr = NULL; detPtr != NULL; ) {
- pid = (int) Tcl_WaitPid(detPtr->pid, &status, WNOHANG);
- if ((pid == 0) || ((pid == -1) && (errno != ECHILD))) {
- prevPtr = detPtr;
- detPtr = detPtr->nextPtr;
- continue;
- }
- nextPtr = detPtr->nextPtr;
- if (prevPtr == NULL) {
- detList = detPtr->nextPtr;
- } else {
- prevPtr->nextPtr = detPtr->nextPtr;
- }
- ckfree((char *) detPtr);
- detPtr = nextPtr;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCleanupChildren --
- *
- * 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 interp->result.
- *
- * Side effects:
- * If the last character of interp->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(interp, numPids, pidPtr, errorChan)
- Tcl_Interp *interp; /* Used for error messages. */
- int numPids; /* Number of entries in pidPtr array. */
- int *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, pid, abnormalExit, anyErrorInfo;
- WAIT_STATUS_TYPE waitStatus;
- char *msg;
-
- abnormalExit = 0;
- for (i = 0; i < numPids; i++) {
- pid = (int) Tcl_WaitPid(pidPtr[i], (int *) &waitStatus, 0);
- if (pid == -1) {
- result = TCL_ERROR;
- 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.
- */
-
- msg =
- "child process lost (is SIGCHLD ignored or trapped?)";
- }
- Tcl_AppendResult(interp, "error waiting for process to exit: ",
- 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).
- */
-
- if (!WIFEXITED(waitStatus) || (WEXITSTATUS(waitStatus) != 0)) {
- char msg1[20], msg2[20];
-
- result = TCL_ERROR;
- sprintf(msg1, "%d", pid);
- if (WIFEXITED(waitStatus)) {
- if (interp != (Tcl_Interp *) NULL) {
- sprintf(msg2, "%d", WEXITSTATUS(waitStatus));
- Tcl_SetErrorCode(interp, "CHILDSTATUS", msg1, msg2,
- (char *) NULL);
- }
- abnormalExit = 1;
- } else if (WIFSIGNALED(waitStatus)) {
- if (interp != (Tcl_Interp *) NULL) {
- 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) {
- 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);
- }
- }
- }
- }
-
- /*
- * 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.
- */
-
- Tcl_Seek(errorChan, 0L, SEEK_SET);
-
- if (interp != (Tcl_Interp *) NULL) {
- while (1) {
-#define BUFFER_SIZE 1000
- char buffer[BUFFER_SIZE+1];
- int count;
-
- count = Tcl_Read(errorChan, buffer, BUFFER_SIZE);
- if (count == 0) {
- break;
- }
- result = TCL_ERROR;
- if (count < 0) {
- Tcl_AppendResult(interp,
- "error reading stderr output file: ",
- Tcl_PosixError(interp), (char *) NULL);
- break; /* out of the "while (1)" loop. */
- }
- buffer[count] = 0;
- Tcl_AppendResult(interp, buffer, (char *) NULL);
- anyErrorInfo = 1;
- }
- }
-
- Tcl_Close(NULL, errorChan);
- }
-
- /*
- * If a child exited abnormally but didn't output any error information
- * at all, generate an error message here.
- */
-
- if (abnormalExit && !anyErrorInfo && (interp != (Tcl_Interp *) NULL)) {
- Tcl_AppendResult(interp, "child process exited abnormally",
- (char *) NULL);
- }
-
- return result;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclCreatePipeline --
- *
- * Given an argc/argv array, instantiate a pipeline of processes
- * as described by the argv.
- *
- * 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.
- *
- * Side effects:
- * Processes and pipes are created.
- *
- *----------------------------------------------------------------------
- */
-
-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. */
- char **argv; /* Array of strings describing commands in
- * pipeline plus I/O redirection with <,
- * <<, >, etc. Argv[argc] must be NULL. */
- int **pidArrayPtr; /* Word at *pidArrayPtr gets filled in with
- * address of array of pids for processes
- * in pipeline (first pid is first process
- * in pipeline). */
- Tcl_File *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. */
- Tcl_File *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. */
- Tcl_File *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. */
-{
-#if defined( MAC_TCL )
- Tcl_AppendResult(interp,
- "command pipelines not supported on Macintosh OS", NULL);
- return -1;
-#else /* !MAC_TCL */
- int *pidPtr = NULL; /* Points to malloc-ed array holding all
- * the pids of child processes. */
- int numPids = 0; /* Actual number of processes that exist
- * at *pidPtr right now. */
- int cmdCount; /* Count of number of distinct commands
- * found in argc/argv. */
- char *input = 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_File inputFile = NULL;
- /* If != NULL, gives file to use as input for
- * first process in pipeline (specified via <
- * or <@). */
- int closeInput = 0; /* If non-zero, then must close inputId
- * when cleaning up (zero means the file needs
- * to stay open for some other reason). */
- Tcl_File outputFile = NULL;
- /* Writable file for output from last command
- * in pipeline (could be file or pipe). NULL
- * means use stdout. */
- int closeOutput = 0; /* Non-zero means must close outputId when
- * cleaning up (similar to closeInput). */
- Tcl_File errorFile = NULL;
- /* Writable file for error output from all
- * commands in pipeline. NULL means use
- * stderr. */
- int closeError = 0; /* Non-zero means must close errorId when
- * cleaning up. */
- int skip; /* Number of arguments to skip (because they
- * specify redirection). */
- int lastBar;
- int i, j;
- char *p;
- int hasPipes = TclHasPipes();
- char finalOut[L_tmpnam];
- char intIn[L_tmpnam];
-
- finalOut[0] = '\0';
- intIn[0] = '\0';
-
- if (inPipePtr != NULL) {
- *inPipePtr = NULL;
- }
- if (outPipePtr != NULL) {
- *outPipePtr = NULL;
- }
- if (errFilePtr != NULL) {
- *errFilePtr = NULL;
- }
-
- /*
- * 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.
- */
-
- cmdCount = 1;
- lastBar = -1;
- for (i = 0; i < argc; i++) {
- if ((argv[i][0] == '|') && (((argv[i][1] == 0))
- || ((argv[i][1] == '&') && (argv[i][2] == 0)))) {
- if ((i == (lastBar+1)) || (i == (argc-1))) {
- interp->result = "illegal use of | or |& in command";
- return -1;
- }
- lastBar = i;
- cmdCount++;
- continue;
- } else if (argv[i][0] == '<') {
- if ((inputFile != NULL) && closeInput) {
- TclCloseFile(inputFile);
- }
- inputFile = NULL;
- skip = 1;
- if (argv[i][1] == '<') {
- input = argv[i]+2;
- if (*input == 0) {
- input = argv[i+1];
- if (input == 0) {
- Tcl_AppendResult(interp, "can't specify \"", argv[i],
- "\" as last word in command", (char *) NULL);
- goto error;
- }
- skip = 2;
- }
- } else {
- input = 0;
- inputFile = FileForRedirect(interp, argv[i]+1, 1, argv[i],
- O_RDONLY, argv[i+1], &skip, &closeInput);
- if (inputFile == NULL) {
- goto error;
- }
-
- /* When Win32s dies out, this code can be removed */
- if (!hasPipes) {
- if (!closeInput) {
- Tcl_AppendResult(interp, "redirection with '@'",
- " notation is not supported on this system",
- (char *) NULL);
- goto error;
- }
- strcpy(intIn, skip == 1 ? argv[i]+1 : argv[i+1]);
- }
- }
- } else if (argv[i][0] == '>') {
- int append, useForStdErr, useForStdOut, mustClose, atOk, flags;
- Tcl_File file;
-
- skip = atOk = 1;
- append = useForStdErr = 0;
- useForStdOut = 1;
- if (argv[i][1] == '>') {
- p = argv[i] + 2;
- append = 1;
- atOk = 0;
- flags = O_WRONLY|O_CREAT;
- } else {
- p = argv[i] + 1;
- flags = O_WRONLY|O_CREAT|O_TRUNC;
- }
- if (*p == '&') {
- useForStdErr = 1;
- p++;
- }
- file = FileForRedirect(interp, p, atOk, argv[i], flags, argv[i+1],
- &skip, &mustClose);
- if (file == NULL) {
- goto error;
- }
-
- /* When Win32s dies out, this code can be removed */
- if (!hasPipes) {
- if (!mustClose) {
- Tcl_AppendResult(interp, "redirection with '@'",
- " notation is not supported on this system",
- (char *) NULL);
- goto error;
- }
- strcpy(finalOut, skip == 1 ? p : argv[i+1]);
- }
-
- if (hasPipes && append) {
- TclSeekFile(file, 0L, 2);
- }
-
- /*
- * Got the file descriptor. Now use it for standard output,
- * standard error, or both, depending on the redirection.
- */
-
- if (useForStdOut) {
- if ((outputFile != NULL) && closeOutput) {
- TclCloseFile(outputFile);
- }
- outputFile = file;
- closeOutput = mustClose;
- }
- if (useForStdErr) {
- if ((errorFile != NULL) && closeError) {
- TclCloseFile(errorFile);
- }
- errorFile = file;
- closeError = (useForStdOut) ? 0 : mustClose;
- }
- } else if ((argv[i][0] == '2') && (argv[i][1] == '>')) {
- int append, atOk, flags;
-
- if ((errorFile != NULL) && closeError) {
- TclCloseFile(errorFile);
- }
- skip = 1;
- p = argv[i] + 2;
- if (*p == '>') {
- p++;
- append = 1;
- atOk = 0;
- flags = O_WRONLY|O_CREAT;
- } else {
- append = 0;
- atOk = 1;
- flags = O_WRONLY|O_CREAT|O_TRUNC;
- }
- errorFile = FileForRedirect(interp, p, atOk, argv[i], flags,
- argv[i+1], &skip, &closeError);
- if (errorFile == NULL) {
- goto error;
- }
- if (hasPipes && append) {
- TclSeekFile(errorFile, 0L, 2);
- }
- } else {
- continue;
- }
- for (j = i+skip; j < argc; j++) {
- argv[j-skip] = argv[j];
- }
- argc -= skip;
- i -= 1; /* Process next arg from same position. */
- }
- if (argc == 0) {
- interp->result = "didn't specify command to execute";
- return -1;
- }
-
- if ((hasPipes && inputFile == NULL) || (!hasPipes && intIn[0] == '\0')) {
- if (input != 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
- * file.
- */
-
- inputFile = TclCreateTempFile(input);
- closeInput = 1;
- if (inputFile == NULL) {
- Tcl_AppendResult(interp,
- "couldn't create input file for command: ",
- Tcl_PosixError(interp), (char *) NULL);
- goto error;
- }
- } else if (inPipePtr != NULL) {
- Tcl_File inPipe, outPipe;
- /*
- * The input for the first process in the pipeline is to
- * come from a pipe that can be written from this end.
- */
-
- if (!hasPipes || TclCreatePipe(&inPipe, &outPipe) == 0) {
- Tcl_AppendResult(interp,
- "couldn't create input pipe for command: ",
- Tcl_PosixError(interp), (char *) NULL);
- goto error;
- }
- inputFile = inPipe;
- closeInput = 1;
- *inPipePtr = outPipe;
- }
- }
-
- /*
- * Set up a pipe to receive output from the pipeline, if no other
- * output sink has been specified.
- */
-
- if ((outputFile == NULL) && (outPipePtr != NULL)) {
- if (!hasPipes) {
- tmpnam(finalOut);
- } else {
- Tcl_File inPipe, outPipe;
- if (TclCreatePipe(&inPipe, &outPipe) == 0) {
- Tcl_AppendResult(interp,
- "couldn't create output pipe for command: ",
- Tcl_PosixError(interp), (char *) NULL);
- goto error;
- }
- outputFile = outPipe;
- closeOutput = 1;
- *outPipePtr = inPipe;
- }
- }
-
- /*
- * Set up the standard error output sink for the pipeline, if
- * 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 complete
- * because stderr was backed up.
- */
-
- if (errFilePtr && !errorFile) {
- *errFilePtr = TclCreateTempFile(NULL);
- if (*errFilePtr == NULL) {
- Tcl_AppendResult(interp,
- "couldn't create error file for command: ",
- Tcl_PosixError(interp), (char *) NULL);
- goto error;
- }
- errorFile = *errFilePtr;
- closeError = 0;
- }
-
- /*
- * Scan through the argc array, forking off a process for each
- * group of arguments between "|" arguments.
- */
-
- pidPtr = (int *) ckalloc((unsigned) (cmdCount * sizeof(int)));
- Tcl_ReapDetachedProcs();
-
- if (TclSpawnPipeline(interp, pidPtr, &numPids, argc, argv,
- inputFile, outputFile, errorFile, intIn, finalOut) == 0) {
- goto error;
- }
- *pidArrayPtr = pidPtr;
-
- /*
- * All done. Cleanup open files lying around and then return.
- */
-
-cleanup:
- if ((inputFile != NULL) && closeInput) {
- TclCloseFile(inputFile);
- }
- if ((outputFile != NULL) && closeOutput) {
- TclCloseFile(outputFile);
- }
- if ((errorFile != NULL) && closeError) {
- TclCloseFile(errorFile);
- }
- 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.
- */
-
-error:
- if ((inPipePtr != NULL) && (*inPipePtr != NULL)) {
- TclCloseFile(*inPipePtr);
- *inPipePtr = NULL;
- }
- if ((outPipePtr != NULL) && (*outPipePtr != NULL)) {
- TclCloseFile(*outPipePtr);
- *outPipePtr = NULL;
- }
- if ((errFilePtr != NULL) && (*errFilePtr != NULL)) {
- TclCloseFile(*errFilePtr);
- *errFilePtr = NULL;
- }
- if (pidPtr != NULL) {
- for (i = 0; i < numPids; i++) {
- if (pidPtr[i] != -1) {
- Tcl_DetachPids(1, &pidPtr[i]);
- }
- }
- ckfree((char *) pidPtr);
- }
- numPids = -1;
- goto cleanup;
-#endif /* !MAC_TCL */
-}
-
-/*
- *----------------------------------------------------------------------
- *
* Tcl_GetErrno --
*
* Gets the current value of the Tcl error code variable. This is
@@ -1179,109 +376,3 @@ Tcl_PosixError(interp)
Tcl_SetErrorCode(interp, "POSIX", id, msg, (char *) NULL);
return msg;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * 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.
- *
- * Results:
- * A new command channel, or NULL on failure with an error
- * message left in interp.
- *
- * Side effects:
- * Creates processes, opens pipes.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Channel
-Tcl_OpenCommandChannel(interp, argc, argv, flags)
- Tcl_Interp *interp; /* Interpreter for error reporting. Can
- * NOT be NULL. */
- int argc; /* How many arguments. */
- char **argv; /* Array of arguments for command pipe. */
- int flags; /* Or'ed combination of TCL_STDIN, TCL_STDOUT,
- * TCL_STDERR, and TCL_ENFORCE_MODE. */
-{
- Tcl_File *inPipePtr, *outPipePtr, *errFilePtr;
- Tcl_File inPipe, outPipe, errFile;
- int numPids, *pidPtr;
- Tcl_Channel channel;
-
- inPipe = outPipe = errFile = NULL;
-
- 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);
-
- if (numPids < 0) {
- goto error;
- }
-
- /*
- * 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", (char *) NULL);
- goto error;
- }
- if ((flags & TCL_STDIN) && (inPipe == NULL)) {
- Tcl_AppendResult(interp, "can't write input to command:",
- " standard input was redirected", (char *) NULL);
- goto error;
- }
- }
-
- channel = TclCreateCommandChannel(outPipe, inPipe, errFile,
- numPids, pidPtr);
-
- if (channel == (Tcl_Channel) NULL) {
- Tcl_AppendResult(interp, "pipe for command could not be created",
- (char *) NULL);
- goto error;
- }
- return channel;
-
-error:
- if (numPids > 0) {
- Tcl_DetachPids(numPids, pidPtr);
- ckfree((char *) pidPtr);
- }
- if (inPipe != NULL) {
- TclClosePipeFile(inPipe);
- }
- if (outPipe != NULL) {
- TclClosePipeFile(outPipe);
- }
- if (errFile != NULL) {
- TclClosePipeFile(errFile);
- }
- return NULL;
-}