From 2ab4506f34cae724a01ece9dc1c650e5a9b674e9 Mon Sep 17 00:00:00 2001 From: hobbs Date: Fri, 2 Jul 2004 23:31:27 +0000 Subject: * generic/tclPipe.c (TclCreatePipeline): applied TIP #202 patch * doc/exec.n, tests/exec.test: that adds 2>@1 as a special case redirection of stderr to the result output. --- ChangeLog | 6 ++++++ doc/exec.n | 21 +++++++++++++++------ generic/tclPipe.c | 51 ++++++++++++++++++++++++++++++++++++--------------- tests/exec.test | 6 +++++- 4 files changed, 62 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index cd1d05e..aa25c7f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2004-07-02 Jeff Hobbs + + * generic/tclPipe.c (TclCreatePipeline): applied TIP #202 patch + * doc/exec.n, tests/exec.test: that adds 2>@1 as a + special case redirection of stderr to the result output. + 2004-07-02 Kevin B. Kenny * tests/io.test: Changed several tests to run the event diff --git a/doc/exec.n b/doc/exec.n index db0a35c..d44f28c 100644 --- a/doc/exec.n +++ b/doc/exec.n @@ -5,10 +5,10 @@ '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: exec.n,v 1.9 2004/04/22 12:55:15 dkf Exp $ +'\" RCS: @(#) $Id: exec.n,v 1.10 2004/07/02 23:31:29 hobbs 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 @@ Standard error from all commands in the pipeline is 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 @@ The file must have been opened for writing. .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 @@ the caller must prepend ``\fBcmd.exe /c\0\fR'' to the desired command. .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 @@ The directory from which the Tcl executable was loaded. .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 diff --git a/generic/tclPipe.c b/generic/tclPipe.c index 99a89e1..681d18b 100644 --- a/generic/tclPipe.c +++ b/generic/tclPipe.c @@ -10,7 +10,7 @@ * 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.8 2004/04/06 22:25:54 dgp Exp $ + * RCS: @(#) $Id: tclPipe.c,v 1.9 2004/07/02 23:31:29 hobbs Exp $ */ #include "tclInt.h" @@ -67,13 +67,13 @@ 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 + 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 @@ FileForRedirect(interp, spec, atOK, arg, nextArg, flags, skipPtr, closePtr, } 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 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, * 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 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, 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 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, case '>': atOK = 1; flags = O_WRONLY | O_CREAT | O_TRUNC; - errorToOutput = 0; if (*p == '>') { p++; atOK = 0; @@ -674,10 +674,26 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, 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 @@ TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, } 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. diff --git a/tests/exec.test b/tests/exec.test index dce664f..930a4d3 100644 --- a/tests/exec.test +++ b/tests/exec.test @@ -11,7 +11,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: exec.test,v 1.21 2004/06/23 15:36:55 dkf Exp $ +# RCS: @(#) $Id: exec.test,v 1.22 2004/07/02 23:31:30 hobbs Exp $ package require tcltest 2 namespace import -force ::tcltest::* @@ -541,6 +541,10 @@ test exec-15.6 {standard error redirection} {exec stdio} { >& "$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] -- cgit v0.12