Tcl Source Code

Check-in [897a17c523]
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.

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

Overview
Comment:code review, restored backwards compatibility of the simplest escape of quote-chars (so reverted several tests winpipe-7.x)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | 0-day-21b0629c81
Files: files | file ages | folders
SHA3-256: 897a17c523a1e34560ad8c00a5179a1ccbf0690b5d89e3e2e29b502619ac7a9c
User & Date: sebres 2018-08-23 08:00:32
Context
2018-08-23
10:26
code review, skip slow test winpipe-8.2 executed args from injectList particularly (normally winpipe... Closed-Leaf check-in: 7f273d6639 user: sebres tags: 0-day-21b0629c81
08:00
code review, restored backwards compatibility of the simplest escape of quote-chars (so reverted sev... check-in: 897a17c523 user: sebres tags: 0-day-21b0629c81
2018-08-21
18:52
fixes escape for special cases (+ more test-cases): - `%` char to be escaped (quoted) in any case (r... check-in: ae46c72447 user: sebres tags: 0-day-21b0629c81
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to tests/winPipe.test.

358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
    exec $env(COMSPEC) /c echo foo "" bar
} {foo "" bar}
test winpipe-7.2 {BuildCommandLine: null arguments} {win exec} {
    exec $env(COMSPEC) /c echo foo {} bar
} {foo "" bar}
test winpipe-7.3 {BuildCommandLine: dbl quote quoting #1} {win exec} {
    exec $env(COMSPEC) /c echo foo "\"" bar
} {foo "\"" bar}
test winpipe-7.4 {BuildCommandLine: dbl quote quoting #2} {win exec} {
    exec $env(COMSPEC) /c echo foo {""} bar
} {foo "\"\"" bar}
test winpipe-7.5 {BuildCommandLine: dbl quote quoting #3} {win exec} {
    exec $env(COMSPEC) /c echo foo "\" " bar
} {foo "\" " bar}
test winpipe-7.6 {BuildCommandLine: dbl quote quoting #4} {win exec} {
    exec $env(COMSPEC) /c echo foo {a="b"} bar
} {foo "a=\"b\"" bar}
test winpipe-7.7 {BuildCommandLine: dbl quote quoting #5} {win exec} {
    exec $env(COMSPEC) /c echo foo {a = "b"} bar
} {foo "a = \"b\"" bar}
test winpipe-7.8 {BuildCommandLine: dbl quote quoting #6} {win exec} {
    exec $env(COMSPEC) /c echo {"hello"} {""hello""} {"""hello"""} {"\"hello\""} {he llo} "he \" llo"
} {"\"hello\"" "\"\"hello\"\"" "\"\"\"hello\"\"\"" "\"\\\"hello\\\"\"" "he llo" "he \" llo"}
test winpipe-7.9 {BuildCommandLine: N backslashes followed a quote rule #1} {win exec} {
    exec $env(COMSPEC) /c echo foo \\ bar
} {foo \ bar}
test winpipe-7.10 {BuildCommandLine: N backslashes followed a quote rule #2} {win exec} {
    exec $env(COMSPEC) /c echo foo \\\\ bar
} {foo \\ bar}
test winpipe-7.11 {BuildCommandLine: N backslashes followed a quote rule #3} {win exec} {






|


|





|





|







358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
    exec $env(COMSPEC) /c echo foo "" bar
} {foo "" bar}
test winpipe-7.2 {BuildCommandLine: null arguments} {win exec} {
    exec $env(COMSPEC) /c echo foo {} bar
} {foo "" bar}
test winpipe-7.3 {BuildCommandLine: dbl quote quoting #1} {win exec} {
    exec $env(COMSPEC) /c echo foo "\"" bar
} {foo \" bar}
test winpipe-7.4 {BuildCommandLine: dbl quote quoting #2} {win exec} {
    exec $env(COMSPEC) /c echo foo {""} bar
} {foo \"\" bar}
test winpipe-7.5 {BuildCommandLine: dbl quote quoting #3} {win exec} {
    exec $env(COMSPEC) /c echo foo "\" " bar
} {foo "\" " bar}
test winpipe-7.6 {BuildCommandLine: dbl quote quoting #4} {win exec} {
    exec $env(COMSPEC) /c echo foo {a="b"} bar
} {foo a=\"b\" bar}
test winpipe-7.7 {BuildCommandLine: dbl quote quoting #5} {win exec} {
    exec $env(COMSPEC) /c echo foo {a = "b"} bar
} {foo "a = \"b\"" bar}
test winpipe-7.8 {BuildCommandLine: dbl quote quoting #6} {win exec} {
    exec $env(COMSPEC) /c echo {"hello"} {""hello""} {"""hello"""} {"\"hello\""} {he llo} "he \" llo"
} {\"hello\" \"\"hello\"\" \"\"\"hello\"\"\" \"\\\"hello\\\"\" "he llo" "he \" llo"}
test winpipe-7.9 {BuildCommandLine: N backslashes followed a quote rule #1} {win exec} {
    exec $env(COMSPEC) /c echo foo \\ bar
} {foo \ bar}
test winpipe-7.10 {BuildCommandLine: N backslashes followed a quote rule #2} {win exec} {
    exec $env(COMSPEC) /c echo foo \\\\ bar
} {foo \\ bar}
test winpipe-7.11 {BuildCommandLine: N backslashes followed a quote rule #3} {win exec} {

Changes to win/tclWinPipe.c.

1643
1644
1645
1646
1647
1648
1649

1650
1651
1652
1653
1654
1655
1656
1657
1658
1659

1660
1661
1662
1663
1664




1665
1666
1667
1668
1669
1670
1671
1672

1673

1674
1675
1676
1677
1678
1679
1680
....
1704
1705
1706
1707
1708
1709
1710

1711
1712
1713
1714




1715
1716
1717
1718
1719
1720
1721
	    arg = argv[i];
	    Tcl_DStringAppend(&ds, " ", 1);
	}

	/* Quote flags:
	 *   1 - escape argument;
	 *   2 - previous arguments chain contains unpaired quote-char;

	 */
	quote &= ~1; /* reset escape flag */
	bspos = NULL;
	if (arg[0] == '\0') {
	    quote = 1;
	} else {
	    int count;
	    Tcl_UniChar ch;
	    for (start = arg; *start != '\0'; start += count) {
		count = Tcl_UtfToUniChar(start, &ch);

		if (Tcl_UniCharIsSpace(ch) ||
		   (count == 1 && (*start=='"' || strchr(specMetaChars, *start)))
		) {
		    quote |= 1; /* set escape flag - must be quoted */
		    break;




		}
	    }
	}
	if (!(quote & 1)) {
	    /* nothing to escape */
	    Tcl_DStringAppend(&ds, arg, -1);
	} else {
	    /* start of argument (main opening quote-char) */

	    Tcl_DStringAppend(&ds, "\"", 1);

	    start = arg;
	    for (special = arg; *special != '\0'; ) {
		/* position of `\` is important before quote or at end (equal `\"` because quoted) */
		if (*special == '\\') {
		    /* bypass backslashes (and mark first backslash possition)*/
		    special = BuildCmdLineBypassBS(special, &bspos);
		    if (*special == '\0') break;
................................................................................
		    start = !bspos ? special : bspos;
		    continue;
		}
		/* other not special (and not meta) character */
		bspos = NULL; /* reset last backslash possition (not interesting) */
		special++;
	    }

	    /* rest of argument (and escape backslashes before closing main quote) */
	    QuoteCmdLineBackslash(&ds, start, special, bspos);
	    /* end of argument (main closing quote-char) */
	    Tcl_DStringAppend(&ds, "\"", 1);




	}
    }
    Tcl_DStringFree(linePtr);
    Tcl_WinUtfToTChar(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), linePtr);
    Tcl_DStringFree(&ds);
}
 






>

|


|





>
|
|
|
|
|
>
>
>
>








>
|
>







 







>
|
|
|
|
>
>
>
>







1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
....
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
	    arg = argv[i];
	    Tcl_DStringAppend(&ds, " ", 1);
	}

	/* Quote flags:
	 *   1 - escape argument;
	 *   2 - previous arguments chain contains unpaired quote-char;
	 *   4 - enclose in quotes;
	 */
	quote &= ~5; /* reset escape flags */
	bspos = NULL;
	if (arg[0] == '\0') {
	    quote = 5;
	} else {
	    int count;
	    Tcl_UniChar ch;
	    for (start = arg; *start != '\0'; start += count) {
		count = Tcl_UtfToUniChar(start, &ch);
		if (count == 1) {
		    if (Tcl_UniCharIsSpace(ch) ||
			strchr(specMetaChars, *start)
		    ) {
			quote |= 5; /* set escape flag & must be quoted */
			break;
		    }
		    if (*start == '"') {
			quote |= 1; /* set escape flag */
		    }
		}
	    }
	}
	if (!(quote & 1)) {
	    /* nothing to escape */
	    Tcl_DStringAppend(&ds, arg, -1);
	} else {
	    /* start of argument (main opening quote-char) */
	    if (quote & 4) {
		Tcl_DStringAppend(&ds, "\"", 1);
	    }
	    start = arg;
	    for (special = arg; *special != '\0'; ) {
		/* position of `\` is important before quote or at end (equal `\"` because quoted) */
		if (*special == '\\') {
		    /* bypass backslashes (and mark first backslash possition)*/
		    special = BuildCmdLineBypassBS(special, &bspos);
		    if (*special == '\0') break;
................................................................................
		    start = !bspos ? special : bspos;
		    continue;
		}
		/* other not special (and not meta) character */
		bspos = NULL; /* reset last backslash possition (not interesting) */
		special++;
	    }
	    if (quote & 4) {
		/* rest of argument (and escape backslashes before closing main quote) */
		QuoteCmdLineBackslash(&ds, start, special, bspos);
		/* end of argument (main closing quote-char) */
		Tcl_DStringAppend(&ds, "\"", 1);
	    } else {
		/* rest of argument */
		QuoteCmdLineBackslash(&ds, start, special, NULL);
	    }
	}
    }
    Tcl_DStringFree(linePtr);
    Tcl_WinUtfToTChar(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), linePtr);
    Tcl_DStringFree(&ds);
}