Tcl Source Code

Artifact Content
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Artifact 1286d1beab2af1a08cea7a0718234eedadb7b926:

Attachment "open-pipeerr3.patch" to ticket [957132ffff] added by hobbs 2004-05-28 03:32:24.
Index: generic/tclPipe.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclPipe.c,v
retrieving revision 1.7
diff -u -r1.7 tclPipe.c
--- generic/tclPipe.c	17 Dec 2002 02:47:39 -0000	1.7
+++ generic/tclPipe.c	27 May 2004 20:31:22 -0000
@@ -68,13 +68,13 @@
 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
+    CONST char *spec;		/* Points to character just after
 				 * redirection character. */
-    CONST char *arg;		/* Pointer to entire argument containing 
-				 * spec:  used for error reporting. */
     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 
 				 * NULL. */
@@ -107,9 +107,9 @@
         }
 	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);
+	    Tcl_AppendResult(interp, "channel \"", Tcl_GetChannelName(chan),
+		    "\" wasn't opened for ",
+		    ((writing) ? "writing" : "reading"), (char *) NULL);
             return NULL;
         }
 	*releasePtr = 1;
@@ -508,7 +508,7 @@
     				 * closed when cleaning up. */
     int errorRelease = 0;
     CONST char *p;
-    int skip, lastBar, lastArg, i, j, atOK, flags, errorToOutput;
+    int skip, lastBar, lastArg, i, j, atOK, flags, errorToOutput = 0;
     Tcl_DString execBuffer;
     TclFile pipeIn;
     TclFile curInFile, curOutFile, curErrFile;
@@ -547,7 +547,8 @@
     lastBar = -1;
     cmdCount = 1;
     for (i = 0; i < argc; i++) {
-        skip = 0;
+	errorToOutput = 0;
+	skip = 0;
 	p = argv[i];
 	switch (*p++) {
 	case '|':
@@ -601,7 +602,6 @@
 	case '>':
 	    atOK = 1;
 	    flags = O_WRONLY | O_CREAT | O_TRUNC;
-	    errorToOutput = 0;
 	    if (*p == '>') {
 		p++;
 		atOK = 0;
@@ -675,10 +675,26 @@
 		errorRelease = 0;
 		TclpReleaseFile(errorFile);
 	    }
-	    errorFile = FileForRedirect(interp, p, atOK, argv[i], 
-		    argv[i + 1], flags, &skip, &errorClose, &errorRelease);
-	    if (errorFile == NULL) {
-		goto error;
+	    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.
+		 */
+		if (i != argc - 1) {
+		    Tcl_AppendResult(interp, "must specify \"", argv[i],
+			    "\" as last word in command", (char *) NULL);
+		    goto error;
+		}
+		errorFile = outputFile;
+		errorToOutput = 2;
+		skip = 1;
+	    } else {
+		errorFile = FileForRedirect(interp, p, atOK, argv[i], 
+			argv[i + 1], flags, &skip, &errorClose, &errorRelease);
+		if (errorFile == NULL) {
+		    goto error;
+		}
 	    }
 	    break;
 	}
@@ -765,7 +781,12 @@
     }
 
     if (errorFile == NULL) {
-	if (errFilePtr != NULL) {
+	if (errorToOutput == 2) {
+	    /*
+	     * 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.