Tcl Source Code

Changes On Branch tip-improve-exec
Login
Bounty program for improvements to Tcl and certain Tcl packages.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch tip-improve-exec Excluding Merge-Ins

This is equivalent to a diff from e72d624507 to ca7271f40f

2013-07-08
06:51
Build stub objects with -DSTATIC_BUILD on all platforms. Only important on win32 (already done) and ... check-in: 15c829bcbe user: jan.nijtmans tags: trunk
2013-07-07
15:43
First part of upcoming TIP - Improving [exec]'s syntax : the syntax extension (not the new redirects... Leaf check-in: ca7271f40f user: ferrieux tags: tip-improve-exec
11:57
merge trunk check-in: da2f2cfb27 user: dkf tags: dkf-improved-disassembler
09:15
merge-mark check-in: e72d624507 user: jan.nijtmans tags: trunk
02:19
OpenBSD/m88k is now elf. Remove unneeded elf check. check-in: 62f5521264 user: stwo tags: core-8-5-branch
02:11
OpenBSD/m88k is now elf. Remove unneeded elf check. check-in: 6340b1084c user: stwo tags: trunk

Changes to generic/tclPipe.c.

498
499
500
501
502
503
504



505
506
507
508
509
510
511
...
533
534
535
536
537
538
539




540
541
542
543
544





545
546
547
548
549
550
551
...
703
704
705
706
707
708
709











710
711
712
713
714

715
716
717
718
719
720
721
...
854
855
856
857
858
859
860


861
862
863
864
865
866












867
868
869
870
871
872

873
874
875
876
877
878
879
...
909
910
911
912
913
914
915







916
917
918
919
920
921
922
923
924
925

926
927
928
929
930
931
932
....
1005
1006
1007
1008
1009
1010
1011




1012
1013
1014
1015
1016
1017
1018
    const char *p;
    const char *nextArg;
    int skip, lastBar, lastArg, i, j, atOK, flags, needCmd, errorToOutput = 0;
    Tcl_DString execBuffer;
    TclFile pipeIn;
    TclFile curInFile, curOutFile, curErrFile;
    Tcl_Channel channel;




    if (inPipePtr != NULL) {
	*inPipePtr = NULL;
    }
    if (outPipePtr != NULL) {
	*outPipePtr = NULL;
    }
................................................................................
     * list.
     */

    lastBar = -1;
    cmdCount = 1;
    needCmd = 1;
    for (i = 0; i < argc; i++) {




	errorToOutput = 0;
	skip = 0;
	p = argv[i];
	switch (*p++) {
	case '|':





	    if (*p == '&') {
		p++;
	    }
	    if (*p == '\0') {
		if ((i == (lastBar + 1)) || (i == (argc - 1))) {
		    Tcl_SetObjResult(interp, Tcl_NewStringObj(
			    "illegal use of | or |& in command", -1));
................................................................................
		if (errorFile == NULL) {
		    goto error;
		}
	    }
	    break;

	default:











	    /*
	     * Got a command word, not a redirection.
	     */

	    needCmd = 0;

	    break;
	}

	if (skip != 0) {
	    for (j = i + skip; j < argc; j++) {
		argv[j - skip] = argv[j];
	    }
................................................................................
     * arguments between the "|" characters.
     */

    Tcl_ReapDetachedProcs();
    pidPtr = ckalloc(cmdCount * sizeof(Tcl_Pid));

    curInFile = inputFile;



    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;

	}

	/*
	 * Find the end of the current segment of the pipeline.
	 */

	joinThisError = 0;
................................................................................

	if (joinThisError != 0) {
	    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 (result != TCL_OK) {
	    goto error;
	}
	Tcl_DStringFree(&execBuffer);

	pidPtr[numPids] = pid;
	numPids++;
................................................................................
    if (pidPtr != NULL) {
	for (i = 0; i < numPids; i++) {
	    if (pidPtr[i] != (Tcl_Pid) -1) {
		Tcl_DetachPids(1, &pidPtr[i]);
	    }
	}
	ckfree(pidPtr);




    }
    numPids = -1;
    goto cleanup;
}
 
/*
 *----------------------------------------------------------------------






>
>
>







 







>
>
>
>





>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
>







 







>
>






>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
>







 







>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
>







 







>
>
>
>







498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
...
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
...
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
...
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
...
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
....
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
    const char *p;
    const char *nextArg;
    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) {
	*outPipePtr = NULL;
    }
................................................................................
     * list.
     */

    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))) {
		    Tcl_SetObjResult(interp, Tcl_NewStringObj(
			    "illegal use of | or |& in command", -1));
................................................................................
		if (errorFile == NULL) {
		    goto error;
		}
	    }
	    break;

	default:

	    if (newSyntax) {
		Tcl_SetObjResult(interp,
				 Tcl_ObjPrintf(
					       "Unsupported redirection \"%s\"",
					       argv[i]));
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC",
				 "PIPESYNTAX", NULL);
		goto error;
	    } else {

		/*
		 * Got a command word, not a redirection.
		 */
		
		needCmd = 0;
	    }
	    break;
	}

	if (skip != 0) {
	    for (j = i + skip; j < argc; j++) {
		argv[j - skip] = argv[j];
	    }
................................................................................
     * arguments between the "|" characters.
     */

    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;

	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.
	 */

	joinThisError = 0;
................................................................................

	if (joinThisError != 0) {
	    curErrFile = curOutFile;
	} else {
	    curErrFile = errorFile;
	}

	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);

	pidPtr[numPids] = pid;
	numPids++;
................................................................................
    if (pidPtr != NULL) {
	for (i = 0; i < numPids; i++) {
	    if (pidPtr[i] != (Tcl_Pid) -1) {
		Tcl_DetachPids(1, &pidPtr[i]);
	    }
	}
	ckfree(pidPtr);
    }
    if (subArgv != NULL) {
	ckfree(subArgv);
	subArgv = NULL;
    }
    numPids = -1;
    goto cleanup;
}
 
/*
 *----------------------------------------------------------------------

Changes to tests/exec.test.

368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
...
678
679
680
681
682
683
684






685
686
687
688
689
690
691
# Errors in executing the Tcl command, as opposed to errors in the processes
# that are invoked.

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
} -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 {
    exec cat | | cat
} -returnCodes error -result {illegal use of | or |& in command}
................................................................................
    # Check that no bytes have got lost through mixups with overlapping
    # appends, which is only guaranteed to work when we set O_APPEND on the
    # file descriptor in the [exec >>...]
    file size $tmpfile
} -cleanup {
    removeFile $tmpfile
} -result 14






 
# ----------------------------------------------------------------------
# cleanup

foreach file {gorp.file gorp.file2 echo echo2 cat wc sh sh2 sleep exit err} {
    removeFile $file
}






|







 







>
>
>
>
>
>







368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
...
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
# Errors in executing the Tcl command, as opposed to errors in the processes
# that are invoked.

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
} -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 {
    exec cat | | cat
} -returnCodes error -result {illegal use of | or |& in command}
................................................................................
    # Check that no bytes have got lost through mixups with overlapping
    # appends, which is only guaranteed to work when we set O_APPEND on the
    # 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} {
    removeFile $file
}