Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Revised TclFindElement() interface. The final argument had been bracePtr, the address of a boolean var, where the caller can be told whether or not the parsed list element was enclosed in braces. In practice, no callers really care about that. What the callers really want to know is whether the list element value exists as a literal substring of the string being parsed, or whether a call to TclCopyAndCollpase() is needed to produce the list element value. Now the final argument is changed to do what callers actually need. This is a better fit for the calls in tclParse.c, where now a good deal of post-processing checking for "naked backslashes" is no longer necessary. ***POTENTIAL INCOMPATIBILITY*** For any callers calling in via the internal stubs table who really do use the final argument explicitly to check for the enclosing brace scenario. Simply looking for the braces where they must be is the revision available to those callers, and it will backport cleanly. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | core-8-5-branch | potential incompatibility |
Files: | files | file ages | folders |
SHA1: |
04d0ff20b9d7b9263bb7fd09e367b175 |
User & Date: | dgp 2011-05-02 17:36:27 |
Context
2011-05-02
| ||
20:10 | Tests for expanded literals quoting detection. check-in: 52e2ce6ae1 user: dgp tags: core-8-5-branch | |
17:47 | Revised TclFindElement() interface. The final argument had been bracePtr, the address of a boolean v... check-in: c2ee6476c2 user: dgp tags: dgp-switch-compile | |
17:36 | Revised TclFindElement() interface. The final argument had been bracePtr, the address of a boolean v... check-in: 04d0ff20b9 user: dgp tags: core-8-5-branch, potential incompatibility | |
15:38 | Replace TclCountSpaceRuns() with TclMaxListLength() which is the function we actually want. check-in: 63ec2ace6e user: dgp tags: core-8-5-branch | |
Changes
Changes to ChangeLog.
1 2 3 4 5 6 7 8 9 | 2011-05-02 Don Porter <[email protected]> * generic/tclInt.h: Replace TclCountSpaceRuns() with * generic/tclListObj.c: TclMaxListLength() which is the function we * generic/tclUtil.c: actually want. 2011-04-28 Don Porter <[email protected]> * generic/tclInt.h: New utility routines: | > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 2011-05-02 Don Porter <[email protected]> * generic/tclCmdMZ.c: Revised TclFindElement() interface. The * generic/tclDictObj.c: final argument had been bracePtr, the address * generic/tclListObj.c: of a boolean var, where the caller can be told * generic/tclParse.c: whether or not the parsed list element was * generic/tclUtil.c: enclosed in braces. In practice, no callers really care about that. What the callers really want to know is whether the list element value exists as a literal substring of the string being parsed, or whether a call to TclCopyAndCollpase() is needed to produce the list element value. Now the final argument is changed to do what callers actually need. This is a better fit for the calls in tclParse.c, where now a good deal of post-processing checking for "naked backslashes" is no longer necessary. ***POTENTIAL INCOMPATIBILITY*** For any callers calling in via the internal stubs table who really do use the final argument explicitly to check for the enclosing brace scenario. Simply looking for the braces where they must be is the revision available to those callers, and it will backport cleanly. * generic/tclInt.h: Replace TclCountSpaceRuns() with * generic/tclListObj.c: TclMaxListLength() which is the function we * generic/tclUtil.c: actually want. 2011-04-28 Don Porter <[email protected]> * generic/tclInt.h: New utility routines: |
︙ | ︙ |
Changes to generic/tclCmdMZ.c.
︙ | ︙ | |||
1617 1618 1619 1620 1621 1622 1623 | /* * Need to figure out where the list parsing failed, which is * fairly expensive. This is adapted from the core of * SetListFromAny(). */ const char *elemStart, *nextElem; | | | | 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 | /* * Need to figure out where the list parsing failed, which is * fairly expensive. This is adapted from the core of * SetListFromAny(). */ const char *elemStart, *nextElem; int lenRemain, elemSize; register const char *p; string1 = TclGetStringFromObj(objPtr, &length1); end = string1 + length1; failat = -1; for (p=string1, lenRemain=length1; lenRemain > 0; p=nextElem, lenRemain=end-nextElem) { if (TCL_ERROR == TclFindElement(NULL, p, lenRemain, &elemStart, &nextElem, &elemSize, NULL)) { Tcl_Obj *tmpStr; /* * This is the simplest way of getting the number of * characters parsed. Note that this is not the same as * the number of bytes when parsing strings with non-ASCII * characters in them. |
︙ | ︙ |
Changes to generic/tclDictObj.c.
︙ | ︙ | |||
554 555 556 557 558 559 560 | static int SetDictFromAny( Tcl_Interp *interp, Tcl_Obj *objPtr) { char *string, *s; const char *elemStart, *nextElem; | | | 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 | static int SetDictFromAny( Tcl_Interp *interp, Tcl_Obj *objPtr) { char *string, *s; const char *elemStart, *nextElem; int lenRemain, length, elemSize, result, isNew; char *limit; /* Points just after string's last byte. */ register const char *p; register Tcl_Obj *keyPtr, *valuePtr; Dict *dict; Tcl_HashEntry *hPtr; /* |
︙ | ︙ | |||
635 636 637 638 639 640 641 642 | */ dict = (Dict *) ckalloc(sizeof(Dict)); InitChainTable(dict); for (p = string, lenRemain = length; lenRemain > 0; p = nextElem, lenRemain = (limit - nextElem)) { result = TclFindElement(interp, p, lenRemain, | > > | | | | | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 | */ dict = (Dict *) ckalloc(sizeof(Dict)); InitChainTable(dict); for (p = string, lenRemain = length; lenRemain > 0; p = nextElem, lenRemain = (limit - nextElem)) { int literal; result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem, &elemSize, &literal); if (result != TCL_OK) { goto errorExit; } if (elemStart >= limit) { break; } /* * Allocate a Tcl object for the element and initialize it from the * "elemSize" bytes starting at "elemStart". */ s = ckalloc((unsigned) elemSize + 1); if (literal) { memcpy(s, elemStart, (size_t) elemSize); s[elemSize] = 0; } else { elemSize = TclCopyAndCollapse(elemSize, elemStart, s); } TclNewObj(keyPtr); keyPtr->bytes = s; keyPtr->length = elemSize; p = nextElem; lenRemain = (limit - nextElem); if (lenRemain <= 0) { goto missingKey; } result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem, &elemSize, &literal); if (result != TCL_OK) { TclDecrRefCount(keyPtr); goto errorExit; } if (elemStart >= limit) { goto missingKey; } /* * Allocate a Tcl object for the element and initialize it from the * "elemSize" bytes starting at "elemStart". */ s = ckalloc((unsigned) elemSize + 1); if (literal) { memcpy((void *) s, (void *) elemStart, (size_t) elemSize); s[elemSize] = 0; } else { elemSize = TclCopyAndCollapse(elemSize, elemStart, s); } TclNewObj(valuePtr); |
︙ | ︙ |
Changes to generic/tclListObj.c.
︙ | ︙ | |||
1689 1690 1691 1692 1693 1694 1695 | static int SetListFromAny( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr) /* The object to convert. */ { char *string, *s; const char *elemStart, *nextElem; | | | 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 | static int SetListFromAny( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr) /* The object to convert. */ { char *string, *s; const char *elemStart, *nextElem; int lenRemain, length, estCount, elemSize, i, j, result; const char *limit; /* Points just after string's last byte. */ register const char *p; register Tcl_Obj **elemPtrs; register Tcl_Obj *elemPtr; List *listRepPtr; /* |
︙ | ︙ | |||
1773 1774 1775 1776 1777 1778 1779 1780 | } elemPtrs = &listRepPtr->elements; /* Each iteration, parse and store a list element */ for (p=string, lenRemain=length, i=0; lenRemain > 0; p=nextElem, lenRemain=limit-nextElem, i++) { result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem, | > > | | 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 | } elemPtrs = &listRepPtr->elements; /* Each iteration, parse and store a list element */ for (p=string, lenRemain=length, i=0; lenRemain > 0; p=nextElem, lenRemain=limit-nextElem, i++) { int literal; result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem, &elemSize, &literal); if (result != TCL_OK) { for (j = 0; j < i; j++) { elemPtr = elemPtrs[j]; Tcl_DecrRefCount(elemPtr); } ckfree((char *) listRepPtr); return result; |
︙ | ︙ | |||
1796 1797 1798 1799 1800 1801 1802 | /* * Allocate a Tcl object for the element and initialize it from the * "elemSize" bytes starting at "elemStart". */ s = ckalloc((unsigned) elemSize + 1); | | | 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 | /* * Allocate a Tcl object for the element and initialize it from the * "elemSize" bytes starting at "elemStart". */ s = ckalloc((unsigned) elemSize + 1); if (literal) { memcpy(s, elemStart, (size_t) elemSize); s[elemSize] = 0; } else { elemSize = TclCopyAndCollapse(elemSize, elemStart, s); } TclNewObj(elemPtr); |
︙ | ︙ |
Changes to generic/tclParse.c.
︙ | ︙ | |||
429 430 431 432 433 434 435 | if (tokenPtr[i].type != TCL_TOKEN_TEXT) { isLiteral = 0; break; } } if (isLiteral) { | | | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | if (tokenPtr[i].type != TCL_TOKEN_TEXT) { isLiteral = 0; break; } } if (isLiteral) { int elemCount = 0, code = TCL_OK, literal = 1; const char *nextElem, *listEnd, *elemStart; /* * The word to be expanded is a literal, so determine the * boundaries of the literal string to be treated as a list * and expanded. That literal string starts at * tokenPtr[1].start, and includes all bytes up to, but not |
︙ | ︙ | |||
451 452 453 454 455 456 457 | /* * Step through the literal string, parsing and counting list * elements. */ while (nextElem < listEnd) { | | | | < < < < < < < < < < | | | > | | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 | /* * Step through the literal string, parsing and counting list * elements. */ while (nextElem < listEnd) { int size; code = TclFindElement(NULL, nextElem, listEnd - nextElem, &elemStart, &nextElem, &size, &literal); if ((code != TCL_OK) || !literal) { break; } if (elemStart < listEnd) { elemCount++; } } if ((code != TCL_OK) || !literal) { /* * Some list element could not be parsed, or is not * present as a literal substring of the script. The * compiler cannot handle list elements that get generated * by a call to TclCopyAndCollapse(). Defer the * handling of this to compile/eval time, where code is * already in place to report the "attempt to expand a * non-list" error or expand lists that require * substitution. */ tokenPtr->type = TCL_TOKEN_EXPAND_WORD; |
︙ | ︙ | |||
521 522 523 524 525 526 527 | * token so they point to the right literal characters in * the original script to represent the right expanded * word value. */ nextElem = tokenPtr[1].start; while (nextElem < listEnd) { | | | > | | 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | * token so they point to the right literal characters in * the original script to represent the right expanded * word value. */ nextElem = tokenPtr[1].start; while (nextElem < listEnd) { int quoted; tokenPtr->type = TCL_TOKEN_SIMPLE_WORD; tokenPtr->numComponents = 1; tokenPtr++; tokenPtr->type = TCL_TOKEN_TEXT; tokenPtr->numComponents = 0; TclFindElement(NULL, nextElem, listEnd - nextElem, &(tokenPtr->start), &nextElem, &(tokenPtr->size), NULL); quoted = tokenPtr->start[-1] == '{' || tokenPtr->start[-1] == '"'; tokenPtr[-1].start = tokenPtr->start - quoted; tokenPtr[-1].size = tokenPtr->start + tokenPtr->size - tokenPtr[-1].start + quoted; tokenPtr++; } } |
︙ | ︙ |
Changes to generic/tclUtil.c.
︙ | ︙ | |||
177 178 179 180 181 182 183 | * then *nextPtr will point just after the last character in the list * (i.e., at the character at list+listLength). If sizePtr is non-NULL, * *sizePtr is filled in with the number of characters in the element. If * the element is in braces, then *elementPtr will point to the character * after the opening brace and *sizePtr will not include either of the * braces. If there isn't an element in the list, *sizePtr will be zero, * and both *elementPtr and *termPtr will point just after the last | | > > > > | > | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | * then *nextPtr will point just after the last character in the list * (i.e., at the character at list+listLength). If sizePtr is non-NULL, * *sizePtr is filled in with the number of characters in the element. If * the element is in braces, then *elementPtr will point to the character * after the opening brace and *sizePtr will not include either of the * braces. If there isn't an element in the list, *sizePtr will be zero, * and both *elementPtr and *termPtr will point just after the last * character in the list. If literalPtr is non-NULL, *literalPtr is set * to a boolean value indicating whether the substring returned as * the values of **elementPtr and *sizePtr is the literal value of * a list element. If not, a call to TclCopyAndCollapse() is needed * to produce the actual value of the list element. Note: this function * does NOT collapse backslash sequences, but uses *literalPtr to tell * callers when it is required for them to do so. * * Side effects: * None. * *---------------------------------------------------------------------- */ |
︙ | ︙ | |||
202 203 204 205 206 207 208 | CONST char **elementPtr, /* Where to put address of first significant * character in first element of list. */ CONST char **nextPtr, /* Fill in with location of character just * after all white space following end of * argument (next arg or end of list). */ int *sizePtr, /* If non-zero, fill in with size of * element. */ | | | > > > > > | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | CONST char **elementPtr, /* Where to put address of first significant * character in first element of list. */ CONST char **nextPtr, /* Fill in with location of character just * after all white space following end of * argument (next arg or end of list). */ int *sizePtr, /* If non-zero, fill in with size of * element. */ int *literalPtr) /* If non-zero, fill in with non-zero/zero to * indicate that the substring of *sizePtr * bytes starting at **elementPtr is/is not * the literal list element and therefore * does not/does require a call to * TclCopyAndCollapse() by the caller. */ { CONST char *p = list; CONST char *elemStart; /* Points to first byte of first element. */ CONST char *limit; /* Points just after list's last byte. */ int openBraces = 0; /* Brace nesting level during parse. */ int inQuotes = 0; int size = 0; /* lint. */ int numChars; int literal = 1; CONST char *p2; /* * Skim off leading white space and check for an opening brace or quote. * We treat embedded NULLs in the list as bytes belonging to a list * element. */ |
︙ | ︙ | |||
237 238 239 240 241 242 243 | openBraces = 1; p++; } else if (*p == '"') { inQuotes = 1; p++; } elemStart = p; | < < < | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | openBraces = 1; p++; } else if (*p == '"') { inQuotes = 1; p++; } elemStart = p; /* * Find element's end (a space, close brace, or the end of the string). */ while (p < limit) { switch (*p) { |
︙ | ︙ | |||
297 298 299 300 301 302 303 304 305 306 307 308 309 310 | /* * Backslash: skip over everything up to the end of the backslash * sequence. */ case '\\': TclParseBackslash(p, limit - p, &numChars, NULL); p += (numChars - 1); break; /* * Space: ignore if element is in braces or quotes; otherwise * terminate element. | > > > > > > > > > | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | /* * Backslash: skip over everything up to the end of the backslash * sequence. */ case '\\': if (openBraces == 0) { /* * A backslash sequence not within a brace quoted element * means the value of the element is different from the * substring we are parsing. A call to TclCopyAndCollapse() * is needed to produce the element value. Inform the caller. */ literal = 0; } TclParseBackslash(p, limit - p, &numChars, NULL); p += (numChars - 1); break; /* * Space: ignore if element is in braces or quotes; otherwise * terminate element. |
︙ | ︙ | |||
380 381 382 383 384 385 386 387 388 389 390 391 392 393 | while ((p < limit) && (TclIsSpaceProc(*p))) { p++; } *elementPtr = elemStart; *nextPtr = p; if (sizePtr != 0) { *sizePtr = size; } return TCL_OK; } /* *---------------------------------------------------------------------- * | > > > | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | while ((p < limit) && (TclIsSpaceProc(*p))) { p++; } *elementPtr = elemStart; *nextPtr = p; if (sizePtr != 0) { *sizePtr = size; } if (literalPtr != 0) { *literalPtr = literal; } return TCL_OK; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
473 474 475 476 477 478 479 | int *argcPtr, /* Pointer to location to fill in with the * number of elements in the list. */ CONST char ***argvPtr) /* Pointer to place to store pointer to array * of pointers to list elements. */ { CONST char **argv, *end, *element; char *p; | | > | | | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 | int *argcPtr, /* Pointer to location to fill in with the * number of elements in the list. */ CONST char ***argvPtr) /* Pointer to place to store pointer to array * of pointers to list elements. */ { CONST char **argv, *end, *element; char *p; int length, size, i, result, elSize; /* * Allocate enough space to work in. A (CONST char *) for each * (possible) list element plus one more for terminating NULL, * plus as many bytes as in the original string value, plus one * more for a terminating '\0'. Space used to hold element separating * white space in the original string gets re-purposed to hold '\0' * characters in the argv array. */ size = TclMaxListLength(list, -1, &end) + 1; length = end - list; argv = (CONST char **) ckalloc((unsigned) ((size * sizeof(char *)) + length + 1)); for (i = 0, p = ((char *) argv) + size*sizeof(char *); *list != 0; i++) { CONST char *prevList = list; int literal; result = TclFindElement(interp, list, length, &element, &list, &elSize, &literal); length -= (list - prevList); if (result != TCL_OK) { ckfree((char *) argv); return result; } if (*element == 0) { break; } if (i >= size) { ckfree((char *) argv); if (interp != NULL) { Tcl_SetResult(interp, "internal error in Tcl_SplitList", TCL_STATIC); } return TCL_ERROR; } argv[i] = p; if (literal) { memcpy(p, element, (size_t) elSize); p += elSize; *p = 0; p++; } else { TclCopyAndCollapse(elSize, element, p); p += elSize+1; |
︙ | ︙ |