Tcl Source Code

Check-in [3ba4c8e05a]
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:merge 8.7
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 3ba4c8e05ad6b08a295aaeed52c5a660de525f3c5a4f0bd37a5293223c13eaed
User & Date: dgp 2018-03-14 05:51:18
Context
2018-03-14
16:17
merge 8.7 check-in: 961ccb69d2 user: dgp tags: trunk
05:51
merge 8.7 check-in: 3ba4c8e05a user: dgp tags: trunk
05:41
merge mark check-in: 97dd207476 user: dgp tags: core-8-branch
2018-03-13
17:30
merge 8.7 check-in: ff0766467e user: dgp tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to generic/tclCmdMZ.c.

  3223   3223   	length2 = strlen(tclDefaultTrimSet);
  3224   3224       } else {
  3225   3225   	Tcl_WrongNumArgs(interp, 1, objv, "string ?chars?");
  3226   3226   	return TCL_ERROR;
  3227   3227       }
  3228   3228       string1 = TclGetStringFromObj(objv[1], &length1);
  3229   3229   
  3230         -    triml = TclTrimLeft(string1, length1, string2, length2);
  3231         -    trimr = TclTrimRight(string1 + triml, length1 - triml, string2, length2);
         3230  +    triml = TclTrim(string1, length1, string2, length2, &trimr);
  3232   3231   
  3233   3232       Tcl_SetObjResult(interp,
  3234   3233   	    Tcl_NewStringObj(string1 + triml, length1 - triml - trimr));
  3235   3234       return TCL_OK;
  3236   3235   }
  3237   3236   
  3238   3237   /*

Changes to generic/tclInt.h.

  3130   3130   			    Tcl_Obj *const opts[], int *flagPtr);
  3131   3131   MODULE_SCOPE void	TclSubstParse(Tcl_Interp *interp, const char *bytes,
  3132   3132   			    int numBytes, int flags, Tcl_Parse *parsePtr,
  3133   3133   			    Tcl_InterpState *statePtr);
  3134   3134   MODULE_SCOPE int	TclSubstTokens(Tcl_Interp *interp, Tcl_Token *tokenPtr,
  3135   3135   			    int count, int *tokensLeftPtr, int line,
  3136   3136   			    int *clNextOuter, const char *outerScript);
         3137  +MODULE_SCOPE int	TclTrim(const char *bytes, int numBytes,
         3138  +			    const char *trim, int numTrim, int *trimRight);
  3137   3139   MODULE_SCOPE int	TclTrimLeft(const char *bytes, int numBytes,
  3138   3140   			    const char *trim, int numTrim);
  3139   3141   MODULE_SCOPE int	TclTrimRight(const char *bytes, int numBytes,
  3140   3142   			    const char *trim, int numTrim);
  3141   3143   MODULE_SCOPE int	TclUtfCmp(const char *cs, const char *ct);
  3142   3144   MODULE_SCOPE int	TclUtfCasecmp(const char *cs, const char *ct);
  3143   3145   MODULE_SCOPE int	TclUtfCount(int ch);

Changes to generic/tclProcess.c.

   206    206       Tcl_Obj **errorObjPtr)	/* If non-NULL, will receive error code. */
   207    207   {
   208    208       int waitStatus;
   209    209       Tcl_Obj *errorStrings[5];
   210    210       const char *msg;
   211    211   
   212    212       pid = Tcl_WaitPid(pid, &waitStatus, options);
   213         -    if ((pid == 0)) {
          213  +    if (pid == 0) {
   214    214   	/*
   215    215   	 * No change.
   216    216   	 */
   217    217   	
   218    218   	return TCL_PROCESS_UNCHANGED;
   219    219       }
   220    220   

Changes to generic/tclUtil.c.

  1600   1600       }
  1601   1601       return result;
  1602   1602   }
  1603   1603   
  1604   1604   /*
  1605   1605    *----------------------------------------------------------------------
  1606   1606    *
         1607  + * UtfWellFormedEnd --
         1608  + *	Checks the end of utf string is malformed, if yes - wraps bytes
         1609  + *	to the given buffer (as well-formed NTS string).  The buffer
         1610  + *	argument should be initialized by the caller and ready to use.
         1611  + *
         1612  + * Results:
         1613  + *	The bytes with well-formed end of the string.
         1614  + *
         1615  + * Side effects:
         1616  + *	Buffer (DString) may be allocated, so must be released.
         1617  + *
         1618  + *----------------------------------------------------------------------
         1619  + */
         1620  +
         1621  +static inline const char*
         1622  +UtfWellFormedEnd(
         1623  +    Tcl_DString *buffer,	/* Buffer used to hold well-formed string. */
         1624  +    const char *bytes,		/* Pointer to the beginning of the string. */
         1625  +    int length)			/* Length of the string. */
         1626  +{
         1627  +    const char *l = bytes + length;
         1628  +    const char *p = Tcl_UtfPrev(l, bytes);
         1629  +
         1630  +    if (Tcl_UtfCharComplete(p, l - p)) {
         1631  +	return bytes;
         1632  +    }
         1633  +    /* 
         1634  +     * Malformed utf-8 end, be sure we've NTS to safe compare of end-character,
         1635  +     * avoid segfault by access violation out of range.
         1636  +     */
         1637  +    Tcl_DStringAppend(buffer, bytes, length);
         1638  +    return Tcl_DStringValue(buffer);
         1639  +}
         1640  +/*
         1641  + *----------------------------------------------------------------------
         1642  + *
  1607   1643    * TclTrimRight --
  1608         - *
  1609         - *	Takes two counted strings in the Tcl encoding which must both be null
  1610         - *	terminated. Conceptually trims from the right side of the first string
  1611         - *	all characters found in the second string.
         1644  + *	Takes two counted strings in the Tcl encoding.  Conceptually
         1645  + *	finds the sub string (offset) to trim from the right side of the
         1646  + *	first string all characters found in the second string.
  1612   1647    *
  1613   1648    * Results:
  1614   1649    *	The number of bytes to be removed from the end of the string.
  1615   1650    *
  1616   1651    * Side effects:
  1617   1652    *	None.
  1618   1653    *
  1619   1654    *----------------------------------------------------------------------
  1620   1655    */
  1621   1656   
  1622         -int
  1623         -TclTrimRight(
         1657  +static inline int
         1658  +TrimRight(
  1624   1659       const char *bytes,		/* String to be trimmed... */
  1625   1660       int numBytes,		/* ...and its length in bytes */
  1626   1661       const char *trim,		/* String of trim characters... */
  1627   1662       int numTrim)		/* ...and its length in bytes */
  1628   1663   {
  1629   1664       const char *p = bytes + numBytes;
  1630   1665       int pInc;
  1631   1666       Tcl_UniChar ch1 = 0, ch2 = 0;
  1632   1667   
  1633         -    if ((bytes[numBytes] != '\0') || (trim[numTrim] != '\0')) {
  1634         -	Tcl_Panic("TclTrimRight works only on null-terminated strings");
  1635         -    }
  1636         -
  1637         -    /*
  1638         -     * Empty strings -> nothing to do.
  1639         -     */
  1640         -
  1641         -    if ((numBytes == 0) || (numTrim == 0)) {
  1642         -	return 0;
  1643         -    }
  1644         -
  1645   1668       /*
  1646   1669        * Outer loop: iterate over string to be trimmed.
  1647   1670        */
  1648   1671   
  1649   1672       do {
  1650   1673   	const char *q = trim;
  1651   1674   	int bytesLeft = numTrim;
................................................................................
  1676   1699   	    p += pInc;
  1677   1700   	    break;
  1678   1701   	}
  1679   1702       } while (p > bytes);
  1680   1703   
  1681   1704       return numBytes - (p - bytes);
  1682   1705   }
         1706  +
         1707  +int
         1708  +TclTrimRight(
         1709  +    const char *bytes,	/* String to be trimmed... */
         1710  +    int numBytes,	/* ...and its length in bytes */
         1711  +    const char *trim,	/* String of trim characters... */
         1712  +    int numTrim)	/* ...and its length in bytes */
         1713  +{
         1714  +    int res;
         1715  +    Tcl_DString bytesBuf, trimBuf;
         1716  +
         1717  +    /* Empty strings -> nothing to do */
         1718  +    if ((numBytes == 0) || (numTrim == 0)) {
         1719  +	return 0;
         1720  +    }
         1721  +
         1722  +    Tcl_DStringInit(&bytesBuf);
         1723  +    Tcl_DStringInit(&trimBuf);
         1724  +    bytes = UtfWellFormedEnd(&bytesBuf, bytes, numBytes);
         1725  +    trim = UtfWellFormedEnd(&trimBuf, trim, numTrim);
         1726  +
         1727  +    res = TrimRight(bytes, numBytes, trim, numTrim);
         1728  +    if (res > numBytes) {
         1729  +	res = numBytes;
         1730  +    }
         1731  +
         1732  +    Tcl_DStringFree(&bytesBuf);
         1733  +    Tcl_DStringFree(&trimBuf);
         1734  +
         1735  +    return res;
         1736  +}
  1683   1737   
  1684   1738   /*
  1685   1739    *----------------------------------------------------------------------
  1686   1740    *
  1687   1741    * TclTrimLeft --
  1688   1742    *
  1689         - *	Takes two counted strings in the Tcl encoding which must both be null
  1690         - *	terminated. Conceptually trims from the left side of the first string
  1691         - *	all characters found in the second string.
         1743  + *	Takes two counted strings in the Tcl encoding.  Conceptually
         1744  + *	finds the sub string (offset) to trim from the left side of the
         1745  + *	first string all characters found in the second string.
  1692   1746    *
  1693   1747    * Results:
  1694   1748    *	The number of bytes to be removed from the start of the string.
  1695   1749    *
  1696   1750    * Side effects:
  1697   1751    *	None.
  1698   1752    *
  1699   1753    *----------------------------------------------------------------------
  1700   1754    */
  1701   1755   
  1702         -int
  1703         -TclTrimLeft(
         1756  +static inline int
         1757  +TrimLeft(
  1704   1758       const char *bytes,		/* String to be trimmed... */
  1705   1759       int numBytes,		/* ...and its length in bytes */
  1706   1760       const char *trim,		/* String of trim characters... */
  1707   1761       int numTrim)		/* ...and its length in bytes */
  1708   1762   {
  1709   1763       const char *p = bytes;
  1710   1764   	Tcl_UniChar ch1 = 0, ch2 = 0;
  1711   1765   
  1712         -    if ((bytes[numBytes] != '\0') || (trim[numTrim] != '\0')) {
  1713         -	Tcl_Panic("TclTrimLeft works only on null-terminated strings");
  1714         -    }
  1715         -
  1716         -    /*
  1717         -     * Empty strings -> nothing to do.
  1718         -     */
  1719         -
  1720         -    if ((numBytes == 0) || (numTrim == 0)) {
  1721         -	return 0;
  1722         -    }
  1723         -
  1724   1766       /*
  1725   1767        * Outer loop: iterate over string to be trimmed.
  1726   1768        */
  1727   1769   
  1728   1770       do {
  1729   1771   	int pInc = TclUtfToUniChar(p, &ch1);
  1730   1772   	const char *q = trim;
................................................................................
  1751   1793   	     */
  1752   1794   
  1753   1795   	    break;
  1754   1796   	}
  1755   1797   
  1756   1798   	p += pInc;
  1757   1799   	numBytes -= pInc;
  1758         -    } while (numBytes);
         1800  +    } while (numBytes > 0);
  1759   1801   
  1760   1802       return p - bytes;
  1761   1803   }
         1804  +
         1805  +int
         1806  +TclTrimLeft(
         1807  +    const char *bytes,	/* String to be trimmed... */
         1808  +    int numBytes,	/* ...and its length in bytes */
         1809  +    const char *trim,	/* String of trim characters... */
         1810  +    int numTrim)	/* ...and its length in bytes */
         1811  +{
         1812  +    int res;
         1813  +    Tcl_DString bytesBuf, trimBuf;
         1814  +
         1815  +    /* Empty strings -> nothing to do */
         1816  +    if ((numBytes == 0) || (numTrim == 0)) {
         1817  +	return 0;
         1818  +    }
         1819  +
         1820  +    Tcl_DStringInit(&bytesBuf);
         1821  +    Tcl_DStringInit(&trimBuf);
         1822  +    bytes = UtfWellFormedEnd(&bytesBuf, bytes, numBytes);
         1823  +    trim = UtfWellFormedEnd(&trimBuf, trim, numTrim);
         1824  +
         1825  +    res = TrimLeft(bytes, numBytes, trim, numTrim);
         1826  +    if (res > numBytes) {
         1827  +	res = numBytes;
         1828  +    }
         1829  +
         1830  +    Tcl_DStringFree(&bytesBuf);
         1831  +    Tcl_DStringFree(&trimBuf);
         1832  +
         1833  +    return res;
         1834  +}
         1835  +
         1836  +/*
         1837  + *----------------------------------------------------------------------
         1838  + *
         1839  + * TclTrim --
         1840  + *	Finds the sub string (offset) to trim from both sides of the
         1841  + *	first string all characters found in the second string.
         1842  + *
         1843  + * Results:
         1844  + *	The number of bytes to be removed from the start of the string
         1845  + *
         1846  + * Side effects:
         1847  + *	None.
         1848  + *
         1849  + *----------------------------------------------------------------------
         1850  + */
         1851  +
         1852  +int
         1853  +TclTrim(
         1854  +    const char *bytes,	/* String to be trimmed... */
         1855  +    int numBytes,	/* ...and its length in bytes */
         1856  +    const char *trim,	/* String of trim characters... */
         1857  +    int numTrim,	/* ...and its length in bytes */
         1858  +    int *trimRight)		/* Offset from the end of the string. */
         1859  +{
         1860  +    int trimLeft;
         1861  +    Tcl_DString bytesBuf, trimBuf;
         1862  +
         1863  +    /* Empty strings -> nothing to do */
         1864  +    if ((numBytes == 0) || (numTrim == 0)) {
         1865  +	*trimRight = 0;
         1866  +	return 0;
         1867  +    }
         1868  +
         1869  +    Tcl_DStringInit(&bytesBuf);
         1870  +    Tcl_DStringInit(&trimBuf);
         1871  +    bytes = UtfWellFormedEnd(&bytesBuf, bytes, numBytes);
         1872  +    trim = UtfWellFormedEnd(&trimBuf, trim, numTrim);
         1873  +
         1874  +    trimLeft = TrimLeft(bytes, numBytes, trim, numTrim);
         1875  +    if (trimLeft > numBytes) {
         1876  +	trimLeft = numBytes;
         1877  +    }
         1878  +    numBytes -= trimLeft;
         1879  +    *trimRight = 0;
         1880  +    if (numBytes) {
         1881  +	bytes += trimLeft;
         1882  +	*trimRight = TrimRight(bytes, numBytes, trim, numTrim);
         1883  +	if (*trimRight > numBytes) {
         1884  +	    *trimRight = numBytes;
         1885  +	}
         1886  +    }
         1887  +
         1888  +    Tcl_DStringFree(&bytesBuf);
         1889  +    Tcl_DStringFree(&trimBuf);
         1890  +
         1891  +    return trimLeft;
         1892  +}
  1762   1893   
  1763   1894   /*
  1764   1895    *----------------------------------------------------------------------
  1765   1896    *
  1766   1897    * Tcl_Concat --
  1767   1898    *
  1768   1899    *	Concatenate a set of strings into a single large string.
................................................................................
  1822   1953       /*
  1823   1954        * All element bytes + (argc - 1) spaces + 1 terminating NULL.
  1824   1955        */
  1825   1956   
  1826   1957       result = ckalloc((unsigned) (bytesNeeded + argc));
  1827   1958   
  1828   1959       for (p = result, i = 0;  i < argc;  i++) {
  1829         -	int trim, elemLength;
         1960  +	int triml, trimr, elemLength;
  1830   1961   	const char *element;
  1831   1962   
  1832   1963   	element = argv[i];
  1833   1964   	elemLength = strlen(argv[i]);
  1834   1965   
  1835         -	/*
  1836         -	 * Trim away the leading whitespace.
  1837         -	 */
         1966  +	/* Trim away the leading/trailing whitespace. */
         1967  +	triml = TclTrim(element, elemLength, CONCAT_TRIM_SET,
         1968  +		CONCAT_WS_SIZE, &trimr);
         1969  +	element += triml;
         1970  +	elemLength -= triml + trimr;
  1838   1971   
  1839         -	trim = TclTrimLeft(element, elemLength, CONCAT_TRIM_SET,
  1840         -		CONCAT_WS_SIZE);
  1841         -	element += trim;
  1842         -	elemLength -= trim;
  1843         -
  1844         -	/*
  1845         -	 * Trim away the trailing whitespace. Do not permit trimming to expose
  1846         -	 * a final backslash character.
  1847         -	 */
  1848         -
  1849         -	trim = TclTrimRight(element, elemLength, CONCAT_TRIM_SET,
  1850         -		CONCAT_WS_SIZE);
  1851         -	trim -= trim && (element[elemLength - trim - 1] == '\\');
  1852         -	elemLength -= trim;
         1972  +	/* Do not permit trimming to expose a final backslash character. */
         1973  +	elemLength += trimr && (element[elemLength - 1] == '\\');
  1853   1974   
  1854   1975   	/*
  1855   1976   	 * If we're left with empty element after trimming, do nothing.
  1856   1977   	 */
  1857   1978   
  1858   1979   	if (elemLength == 0) {
  1859   1980   	    continue;
................................................................................
  1965   2086        */
  1966   2087   
  1967   2088       TclNewObj(resPtr);
  1968   2089       (void) Tcl_AttemptSetObjLength(resPtr, bytesNeeded + objc - 1);
  1969   2090       Tcl_SetObjLength(resPtr, 0);
  1970   2091   
  1971   2092       for (i = 0;  i < objc;  i++) {
  1972         -	int trim;
         2093  +	int triml, trimr;
  1973   2094   
  1974   2095   	element = TclGetStringFromObj(objv[i], &elemLength);
  1975   2096   
  1976         -	/*
  1977         -	 * Trim away the leading whitespace.
  1978         -	 */
         2097  +	/* Trim away the leading/trailing whitespace. */
         2098  +	triml = TclTrim(element, elemLength, CONCAT_TRIM_SET,
         2099  +		CONCAT_WS_SIZE, &trimr);
         2100  +	element += triml;
         2101  +	elemLength -= triml + trimr;
  1979   2102   
  1980         -	trim = TclTrimLeft(element, elemLength, CONCAT_TRIM_SET,
  1981         -		CONCAT_WS_SIZE);
  1982         -	element += trim;
  1983         -	elemLength -= trim;
  1984         -
  1985         -	/*
  1986         -	 * Trim away the trailing whitespace. Do not permit trimming to expose
  1987         -	 * a final backslash character.
  1988         -	 */
  1989         -
  1990         -	trim = TclTrimRight(element, elemLength, CONCAT_TRIM_SET,
  1991         -		CONCAT_WS_SIZE);
  1992         -	trim -= trim && (element[elemLength - trim - 1] == '\\');
  1993         -	elemLength -= trim;
         2103  +	/* Do not permit trimming to expose a final backslash character. */
         2104  +	elemLength += trimr && (element[elemLength - 1] == '\\');
  1994   2105   
  1995   2106   	/*
  1996   2107   	 * If we're left with empty element after trimming, do nothing.
  1997   2108   	 */
  1998   2109   
  1999   2110   	if (elemLength == 0) {
  2000   2111   	    continue;