Index: generic/tclPipe.c ================================================================== --- generic/tclPipe.c +++ generic/tclPipe.c @@ -500,10 +500,13 @@ int skip, lastBar, lastArg, i, j, atOK, flags, needCmd, errorToOutput = 0; Tcl_DString execBuffer; TclFile pipeIn; TclFile curInFile, curOutFile, curErrFile; Tcl_Channel channel; + int newSyntax = 0; + int subArgc; + const char **subArgv = NULL; if (inPipePtr != NULL) { *inPipePtr = NULL; } if (outPipePtr != NULL) { @@ -535,15 +538,24 @@ lastBar = -1; cmdCount = 1; needCmd = 1; for (i = 0; i < argc; i++) { + if (newSyntax && needCmd) { + needCmd = 0; + continue; + } errorToOutput = 0; skip = 0; p = argv[i]; switch (*p++) { case '|': + if ((i == 0) && (*p == '\0')) { + newSyntax = 1; + lastBar = 0; + continue; + } if (*p == '&') { p++; } if (*p == '\0') { if ((i == (lastBar + 1)) || (i == (argc - 1))) { @@ -705,15 +717,27 @@ } } break; default: - /* - * Got a command word, not a redirection. - */ + + if (newSyntax) { + Tcl_SetObjResult(interp, + Tcl_ObjPrintf( + "Unsupported redirection \"%s\"", + argv[i])); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", + "PIPESYNTAX", NULL); + goto error; + } else { - needCmd = 0; + /* + * Got a command word, not a redirection. + */ + + needCmd = 0; + } break; } if (skip != 0) { for (j = i + skip; j < argc; j++) { @@ -856,22 +880,37 @@ Tcl_ReapDetachedProcs(); pidPtr = ckalloc(cmdCount * sizeof(Tcl_Pid)); curInFile = inputFile; + + lastArg = argc; /* compiler warning */ for (i = 0; i < argc; i = lastArg + 1) { int result, joinThisError; Tcl_Pid pid; const char *oldName; - /* - * Convert the program name into native form. - */ - - if (Tcl_TranslateFileName(interp, argv[i], &execBuffer) == NULL) { - goto error; + if (newSyntax) { + if (i == 0) { + lastArg = i; + continue; + } + if (Tcl_SplitList(interp, argv[i], &subArgc, &subArgv) != TCL_OK) { + goto error; + } + if (Tcl_TranslateFileName(interp, subArgv[0], &execBuffer) == NULL) { + goto error; + } + } else { + /* + * Convert the program name into native form. + */ + + if (Tcl_TranslateFileName(interp, argv[i], &execBuffer) == NULL) { + goto error; + } } /* * Find the end of the current segment of the pipeline. */ @@ -911,20 +950,28 @@ curErrFile = curOutFile; } else { curErrFile = errorFile; } - /* - * 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, - curInFile, curOutFile, curErrFile, &pid); - argv[i] = oldName; + if (newSyntax) { + subArgv[0] = Tcl_DStringValue(&execBuffer); + result = TclpCreateProcess(interp, subArgc, subArgv, + curInFile, curOutFile, curErrFile, &pid); + ckfree(subArgv); + subArgv = NULL; + } else { + /* + * 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, + curInFile, curOutFile, curErrFile, &pid); + argv[i] = oldName; + } if (result != TCL_OK) { goto error; } Tcl_DStringFree(&execBuffer); @@ -1007,10 +1054,14 @@ if (pidPtr[i] != (Tcl_Pid) -1) { Tcl_DetachPids(1, &pidPtr[i]); } } ckfree(pidPtr); + } + if (subArgv != NULL) { + ckfree(subArgv); + subArgv = NULL; } numPids = -1; goto cleanup; } Index: tests/exec.test ================================================================== --- tests/exec.test +++ tests/exec.test @@ -370,11 +370,11 @@ test exec-10.1 {errors in exec invocation} -constraints {exec} -body { exec } -returnCodes error -result {wrong # args: should be "exec ?-switch ...? arg ?arg ...?"} test exec-10.2 {errors in exec invocation} -constraints {exec} -body { - exec | cat + exec |& cat } -returnCodes error -result {illegal use of | or |& in command} test exec-10.3 {errors in exec invocation} -constraints {exec} -body { exec cat | } -returnCodes error -result {illegal use of | or |& in command} test exec-10.4 {errors in exec invocation} -constraints {exec} -body { @@ -680,10 +680,16 @@ # file descriptor in the [exec >>...] file size $tmpfile } -cleanup { removeFile $tmpfile } -result 14 + +# New Syntax +test exec-20.1 {New exec syntax with sublists} {exec} { + exec | {echo >} +} > + # ---------------------------------------------------------------------- # cleanup foreach file {gorp.file gorp.file2 echo echo2 cat wc sh sh2 sleep exit err} {