Tcl Source Code

Artifact [f70435f2e5]
Login

Artifact f70435f2e533a1e77b9a1dd5cb0277a8990afb91:

Attachment "pipeerr.patch" to ticket [957132ffff] added by hobbs 2004-07-03 06:28:38.
Index: doc/exec.n
===================================================================
RCS file: /cvsroot/tcl/tcl/doc/exec.n,v
retrieving revision 1.9
diff -u -r1.9 exec.n
--- doc/exec.n	22 Apr 2004 12:55:15 -0000	1.9
+++ doc/exec.n	2 Jul 2004 23:25:39 -0000
@@ -8,7 +8,7 @@
 '\" RCS: @(#) $Id: exec.n,v 1.9 2004/04/22 12:55:15 dkf Exp $
 '\" 
 .so man.macros
-.TH exec n 7.6 Tcl "Tcl Built-In Commands"
+.TH exec n 8.5 Tcl "Tcl Built-In Commands"
 .BS
 '\" Note:  do not modify the .SH NAME line immediately below!
 .SH NAME
@@ -111,6 +111,11 @@
 redirected to \fIfileId\fR's file.
 The file must have been opened for writing.
 .TP 15
+2>@1\0
+Standard error from all commands in the pipeline is redirected to the
+command result.  This operator is only valid at the end of the command
+pipeline.
+.TP 15
 >&@\0\fIfileId\fR
 \fIFileId\fR must be the identifier for an open file, such as the return
 value from a previous call to \fBopen\fR.
@@ -120,7 +125,11 @@
 .PP
 If standard output has not been redirected then the \fBexec\fR
 command returns the standard output from the last command
-in the pipeline.
+in the pipeline,
+.VS 8.5
+unless ``2>@1'' was specified, in which case
+standard error is included as well.
+.VE 8.5
 If any of the commands in the pipeline exit abnormally or
 are killed or suspended, then \fBexec\fR will return an error
 and the error message will include the pipeline's output followed by
@@ -258,7 +267,7 @@
 .sp
 .RE
 .TP
-\fBWindows 95\fR
+\fBWindows 9x\fR
 .
 When attempting to execute an application, \fBexec\fR first searches for
 the name as it was specified.  Then, in order, \fB.com\fR, \fB.exe\fR, and
@@ -273,9 +282,9 @@
 .br
 The current directory.
 .br
-The Windows 95 system directory.
+The Windows 9x system directory.
 .br
-The Windows 95 home directory.
+The Windows 9x home directory.
 .br
 The directories listed in the path.
 .RE
Index: generic/tclPipe.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclPipe.c,v
retrieving revision 1.8
diff -u -r1.8 tclPipe.c
--- generic/tclPipe.c	6 Apr 2004 22:25:54 -0000	1.8
+++ generic/tclPipe.c	2 Jul 2004 23:25:39 -0000
@@ -67,13 +67,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. */
@@ -106,9 +106,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;
@@ -507,7 +507,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;
@@ -546,7 +546,8 @@
     lastBar = -1;
     cmdCount = 1;
     for (i = 0; i < argc; i++) {
-        skip = 0;
+	errorToOutput = 0;
+	skip = 0;
 	p = argv[i];
 	switch (*p++) {
 	case '|':
@@ -600,7 +601,6 @@
 	case '>':
 	    atOK = 1;
 	    flags = O_WRONLY | O_CREAT | O_TRUNC;
-	    errorToOutput = 0;
 	    if (*p == '>') {
 		p++;
 		atOK = 0;
@@ -674,10 +674,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;
 	}
@@ -764,7 +780,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.
Index: tests/exec.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/exec.test,v
retrieving revision 1.21
diff -u -r1.21 exec.test
--- tests/exec.test	23 Jun 2004 15:36:55 -0000	1.21
+++ tests/exec.test	2 Jul 2004 23:25:39 -0000
@@ -541,6 +541,10 @@
 	    >& "$path(gorp.file)" 2> "$path(gorp.file2)" | [interpreter] "$path(echo)" biz baz
     list [exec [interpreter] "$path(cat)" "$path(gorp.file)"] [exec [interpreter] "$path(cat)" "$path(gorp.file2)"]
 } {{biz baz} {foo bar}}
+test exec-15.7 {standard error redirection 2>@1} {exec stdio} {
+    # This redirects stderr output into normal result output from exec
+    exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" 2>@1
+} {foo bar}
 
 test exec-16.1 {flush output before exec} {exec} {
     set f [open $path(gorp.file) w]