summaryrefslogtreecommitdiffstats
path: root/generic/tclPipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclPipe.c')
-rw-r--r--generic/tclPipe.c714
1 files changed, 351 insertions, 363 deletions
diff --git a/generic/tclPipe.c b/generic/tclPipe.c
index d0b136d..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;
@@ -94,37 +99,30 @@ FileForRedirect(
}
*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_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_SetErrorCode(interp, "TCL", "OPERATION", "EXEC",
- "BADCHAN", NULL);
- }
- return NULL;
- }
+ if (file == 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);
+ Tcl_Flush(chan);
}
} else {
- const char *name;
+ CONST char *name;
Tcl_DString nameString;
if (*spec == '\0') {
@@ -143,17 +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;
+ *closePtr = 1;
}
return file;
- badLastArg:
+ badLastArg:
Tcl_AppendResult(interp, "can't specify \"", arg,
- "\" as last word in command", NULL);
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "SYNTAX", NULL);
+ "\" as last word in command", (char *) NULL);
return NULL;
}
@@ -162,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.
@@ -176,17 +174,17 @@ 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;
Tcl_MutexLock(&pipeMutex);
for (i = 0; i < numPids; i++) {
- detPtr = ckalloc(sizeof(Detached));
+ detPtr = (Detached *) ckalloc(sizeof(Detached));
detPtr->pid = pidPtr[i];
detPtr->nextPtr = detList;
detList = detPtr;
@@ -200,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;
@@ -236,7 +235,7 @@ Tcl_ReapDetachedProcs(void)
} else {
prevPtr->nextPtr = detPtr->nextPtr;
}
- ckfree(detPtr);
+ ckfree((char *) detPtr);
detPtr = nextPtr;
}
Tcl_MutexUnlock(&pipeMutex);
@@ -247,126 +246,137 @@ 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;
int i, abnormalExit, anyErrorInfo;
Tcl_Pid pid;
- int waitStatus;
- const char *msg;
+ WAIT_STATUS_TYPE 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
- * 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], &waitStatus, 0);
+ pid = Tcl_WaitPid(pidPtr[i], (int *) &waitStatus, 0);
if (pid == (Tcl_Pid) -1) {
result = TCL_ERROR;
- if (interp != NULL) {
- msg = Tcl_PosixError(interp);
- if (errno == ECHILD) {
+ 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, 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_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).
+ * 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 != NULL) {
- sprintf(msg2, "%u", WEXITSTATUS(waitStatus));
- Tcl_SetErrorCode(interp, "CHILDSTATUS", msg1, msg2, NULL);
- }
+ if (interp != (Tcl_Interp *) 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)) {
- p = Tcl_SignalMsg(WTERMSIG(waitStatus));
- Tcl_SetErrorCode(interp, "CHILDKILLED", msg1,
- Tcl_SignalId(WTERMSIG(waitStatus)), p, NULL);
- Tcl_AppendResult(interp, "child killed: ", p, "\n", NULL);
- } else if (WIFSTOPPED(waitStatus)) {
- p = Tcl_SignalMsg(WSTOPSIG(waitStatus));
- Tcl_SetErrorCode(interp, "CHILDSUSP", msg1,
- Tcl_SignalId(WSTOPSIG(waitStatus)), p, NULL);
- Tcl_AppendResult(interp, "child suspended: ", p, "\n",
- NULL);
- } else {
- Tcl_AppendResult(interp,
- "child wait status didn't make sense\n", NULL);
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC",
- "ODDWAITRESULT", msg1, NULL);
- }
+ } 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);
+ }
}
}
}
/*
- * 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.
*/
- 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);
@@ -388,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;
}
@@ -403,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.
@@ -428,70 +441,71 @@ 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
- * closed when cleaning up. */
+ 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
- * closed when cleaning up. */
+ 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
- * closed when cleaning up. */
+ int errorClose = 0; /* If non-zero, then errorFile should be
+ * closed when cleaning up. */
int errorRelease = 0;
- const char *p;
- const char *nextArg;
+ CONST char *p;
+ CONST char *nextArg;
int skip, lastBar, lastArg, i, j, atOK, flags, needCmd, errorToOutput = 0;
Tcl_DString execBuffer;
TclFile pipeIn;
@@ -509,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;
@@ -542,10 +556,9 @@ 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);
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC",
- "PIPESYNTAX", NULL);
goto error;
}
}
@@ -571,9 +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);
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC",
- "PIPESYNTAX", NULL);
+ "\" as last word in command", (char *) NULL);
goto error;
}
skip = 2;
@@ -581,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;
}
@@ -613,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) {
@@ -634,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;
}
@@ -675,15 +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);
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC",
- "PIPESYNTAX", NULL);
+ "\" as last word in command", (char *) NULL);
goto error;
}
errorFile = outputFile;
@@ -691,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;
@@ -700,12 +708,9 @@ TclCreatePipeline(
break;
default:
- /*
- * Got a command word, not a redirection.
- */
-
- needCmd = 0;
- break;
+ /* Got a command word, not a redirection */
+ needCmd = 0;
+ break;
}
if (skip != 0) {
@@ -718,14 +723,11 @@ 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",
- TCL_STATIC);
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "PIPESYNTAX",
- NULL);
+ Tcl_SetResult(interp,
+ "illegal use of | or |& in command",
+ TCL_STATIC);
goto error;
}
@@ -733,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;
@@ -776,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;
@@ -805,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.
*/
@@ -823,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;
@@ -841,24 +841,24 @@ 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();
- pidPtr = ckalloc(cmdCount * sizeof(Tcl_Pid));
+ pidPtr = (Tcl_Pid *) ckalloc((unsigned) (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) {
@@ -871,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.
*/
@@ -895,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;
}
}
@@ -910,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,
@@ -925,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)) {
@@ -944,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) {
@@ -968,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);
}
@@ -1001,7 +1000,7 @@ TclCreatePipeline(
Tcl_DetachPids(1, &pidPtr[i]);
}
}
- ckfree(pidPtr);
+ ckfree((char *) pidPtr);
}
numPids = -1;
goto cleanup;
@@ -1012,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.
@@ -1040,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;
@@ -1059,51 +1060,46 @@ 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);
+ outPipePtr, errFilePtr);
if (numPids < 0) {
goto error;
}
/*
- * 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_SetErrorCode(interp, "TCL", "OPERATION", "EXEC",
- "BADREDIRECT", 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_SetErrorCode(interp, "TCL", "OPERATION", "EXEC",
- "BADREDIRECT", 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 == NULL) {
- Tcl_AppendResult(interp, "pipe for command could not be created",
- NULL);
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "NOPIPE", NULL);
+ if (channel == (Tcl_Channel) NULL) {
+ Tcl_AppendResult(interp, "pipe for command could not be created",
+ (char *) NULL);
goto error;
}
return channel;
- error:
+error:
if (numPids > 0) {
Tcl_DetachPids(numPids, pidPtr);
- ckfree(pidPtr);
+ ckfree((char *) pidPtr);
}
if (inPipe != NULL) {
TclpCloseFile(inPipe);
@@ -1116,11 +1112,3 @@ Tcl_OpenCommandChannel(
}
return NULL;
}
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */