tclUtf.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:46k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tclUtf.c --
  3.  *
  4.  * Routines for manipulating UTF-8 strings.
  5.  *
  6.  * Copyright (c) 1997-1998 Sun Microsystems, Inc.
  7.  *
  8.  * See the file "license.terms" for information on usage and redistribution
  9.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10.  *
  11.  * RCS: @(#) $Id: tclUtf.c,v 1.30.2.3 2005/09/07 14:35:56 dgp Exp $
  12.  */
  13. #include "tclInt.h"
  14. /*
  15.  * Include the static character classification tables and macros.
  16.  */
  17. #include "tclUniData.c"
  18. /*
  19.  * The following macros are used for fast character category tests.  The
  20.  * x_BITS values are shifted right by the category value to determine whether
  21.  * the given category is included in the set.
  22.  */ 
  23. #define ALPHA_BITS ((1 << UPPERCASE_LETTER) | (1 << LOWERCASE_LETTER) 
  24.     | (1 << TITLECASE_LETTER) | (1 << MODIFIER_LETTER) | (1 << OTHER_LETTER))
  25. #define DIGIT_BITS (1 << DECIMAL_DIGIT_NUMBER)
  26. #define SPACE_BITS ((1 << SPACE_SEPARATOR) | (1 << LINE_SEPARATOR) 
  27.     | (1 << PARAGRAPH_SEPARATOR))
  28. #define CONNECTOR_BITS (1 << CONNECTOR_PUNCTUATION)
  29. #define PRINT_BITS (ALPHA_BITS | DIGIT_BITS | SPACE_BITS | 
  30.     (1 << NON_SPACING_MARK) | (1 << ENCLOSING_MARK) | 
  31.     (1 << COMBINING_SPACING_MARK) | (1 << LETTER_NUMBER) | 
  32.     (1 << OTHER_NUMBER) | (1 << CONNECTOR_PUNCTUATION) | 
  33.     (1 << DASH_PUNCTUATION) | (1 << OPEN_PUNCTUATION) | 
  34.     (1 << CLOSE_PUNCTUATION) | (1 << INITIAL_QUOTE_PUNCTUATION) | 
  35.     (1 << FINAL_QUOTE_PUNCTUATION) | (1 << OTHER_PUNCTUATION) | 
  36.     (1 << MATH_SYMBOL) | (1 << CURRENCY_SYMBOL) | 
  37.     (1 << MODIFIER_SYMBOL) | (1 << OTHER_SYMBOL))
  38. #define PUNCT_BITS ((1 << CONNECTOR_PUNCTUATION) | 
  39.     (1 << DASH_PUNCTUATION) | (1 << OPEN_PUNCTUATION) | 
  40.     (1 << CLOSE_PUNCTUATION) | (1 << INITIAL_QUOTE_PUNCTUATION) | 
  41.     (1 << FINAL_QUOTE_PUNCTUATION) | (1 << OTHER_PUNCTUATION))
  42. /*
  43.  * Unicode characters less than this value are represented by themselves 
  44.  * in UTF-8 strings. 
  45.  */
  46. #define UNICODE_SELF 0x80
  47. /*
  48.  * The following structures are used when mapping between Unicode (UCS-2)
  49.  * and UTF-8.
  50.  */
  51. static CONST unsigned char totalBytes[256] = {
  52.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  53.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  54.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  55.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  56.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  57.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  58.     2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  59.     3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
  60. #if TCL_UTF_MAX > 3
  61.     4,4,4,4,4,4,4,4,
  62. #else
  63.     1,1,1,1,1,1,1,1,
  64. #endif
  65. #if TCL_UTF_MAX > 4
  66.     5,5,5,5,
  67. #else
  68.     1,1,1,1,
  69. #endif
  70. #if TCL_UTF_MAX > 5
  71.     6,6,6,6
  72. #else
  73.     1,1,1,1
  74. #endif
  75. };
  76. /*
  77.  * Procedures used only in this module.
  78.  */
  79. static int UtfCount _ANSI_ARGS_((int ch));
  80. /*
  81.  *---------------------------------------------------------------------------
  82.  *
  83.  * UtfCount --
  84.  *
  85.  * Find the number of bytes in the Utf character "ch".
  86.  *
  87.  * Results:
  88.  * The return values is the number of bytes in the Utf character "ch".
  89.  *
  90.  * Side effects:
  91.  * None.
  92.  *
  93.  *---------------------------------------------------------------------------
  94.  */
  95.  
  96. INLINE static int
  97. UtfCount(ch)
  98.     int ch; /* The Tcl_UniChar whose size is returned. */
  99. {
  100.     if ((ch > 0) && (ch < UNICODE_SELF)) {
  101. return 1;
  102.     }
  103.     if (ch <= 0x7FF) {
  104. return 2;
  105.     }
  106.     if (ch <= 0xFFFF) {
  107. return 3;
  108.     }
  109. #if TCL_UTF_MAX > 3
  110.     if (ch <= 0x1FFFFF) {
  111. return 4;
  112.     }
  113.     if (ch <= 0x3FFFFFF) {
  114. return 5;
  115.     }
  116.     if (ch <= 0x7FFFFFFF) {
  117. return 6;
  118.     }
  119. #endif
  120.     return 3;
  121. }
  122. /*
  123.  *---------------------------------------------------------------------------
  124.  *
  125.  * Tcl_UniCharToUtf --
  126.  *
  127.  * Store the given Tcl_UniChar as a sequence of UTF-8 bytes in the
  128.  * provided buffer.  Equivalent to Plan 9 runetochar().
  129.  *
  130.  * Results:
  131.  * The return values is the number of bytes in the buffer that
  132.  * were consumed.  
  133.  *
  134.  * Side effects:
  135.  * None.
  136.  *
  137.  *---------------------------------------------------------------------------
  138.  */
  139.  
  140. INLINE int
  141. Tcl_UniCharToUtf(ch, str)
  142.     int ch; /* The Tcl_UniChar to be stored in the
  143.  * buffer. */
  144.     char *str; /* Buffer in which the UTF-8 representation
  145.  * of the Tcl_UniChar is stored.  Buffer must
  146.  * be large enough to hold the UTF-8 character
  147.  * (at most TCL_UTF_MAX bytes). */
  148. {
  149.     if ((ch > 0) && (ch < UNICODE_SELF)) {
  150. str[0] = (char) ch;
  151. return 1;
  152.     }
  153.     if (ch >= 0) {
  154. if (ch <= 0x7FF) {
  155.     str[1] = (char) ((ch | 0x80) & 0xBF);
  156.     str[0] = (char) ((ch >> 6) | 0xC0);
  157.     return 2;
  158. }
  159. if (ch <= 0xFFFF) {
  160. three:
  161.     str[2] = (char) ((ch | 0x80) & 0xBF);
  162.     str[1] = (char) (((ch >> 6) | 0x80) & 0xBF);
  163.     str[0] = (char) ((ch >> 12) | 0xE0);
  164.     return 3;
  165. }
  166. #if TCL_UTF_MAX > 3
  167. if (ch <= 0x1FFFFF) {
  168.     str[3] = (char) ((ch | 0x80) & 0xBF);
  169.     str[2] = (char) (((ch >> 6) | 0x80) & 0xBF);
  170.     str[1] = (char) (((ch >> 12) | 0x80) & 0xBF);
  171.     str[0] = (char) ((ch >> 18) | 0xF0);
  172.     return 4;
  173. }
  174. if (ch <= 0x3FFFFFF) {
  175.     str[4] = (char) ((ch | 0x80) & 0xBF);
  176.     str[3] = (char) (((ch >> 6) | 0x80) & 0xBF);
  177.     str[2] = (char) (((ch >> 12) | 0x80) & 0xBF);
  178.     str[1] = (char) (((ch >> 18) | 0x80) & 0xBF);
  179.     str[0] = (char) ((ch >> 24) | 0xF8);
  180.     return 5;
  181. }
  182. if (ch <= 0x7FFFFFFF) {
  183.     str[5] = (char) ((ch | 0x80) & 0xBF);
  184.     str[4] = (char) (((ch >> 6) | 0x80) & 0xBF);
  185.     str[3] = (char) (((ch >> 12) | 0x80) & 0xBF);
  186.     str[2] = (char) (((ch >> 18) | 0x80) & 0xBF);
  187.     str[1] = (char) (((ch >> 24) | 0x80) & 0xBF);
  188.     str[0] = (char) ((ch >> 30) | 0xFC);
  189.     return 6;
  190. }
  191. #endif
  192.     }
  193.     ch = 0xFFFD;
  194.     goto three;
  195. }
  196. /*
  197.  *---------------------------------------------------------------------------
  198.  *
  199.  * Tcl_UniCharToUtfDString --
  200.  *
  201.  * Convert the given Unicode string to UTF-8.
  202.  *
  203.  * Results:
  204.  * The return value is a pointer to the UTF-8 representation of the
  205.  * Unicode string.  Storage for the return value is appended to the
  206.  * end of dsPtr.
  207.  *
  208.  * Side effects:
  209.  * None.
  210.  *
  211.  *---------------------------------------------------------------------------
  212.  */
  213.  
  214. char *
  215. Tcl_UniCharToUtfDString(wString, numChars, dsPtr)
  216.     CONST Tcl_UniChar *wString; /* Unicode string to convert to UTF-8. */
  217.     int numChars; /* Length of Unicode string in Tcl_UniChars
  218.  * (must be >= 0). */
  219.     Tcl_DString *dsPtr; /* UTF-8 representation of string is
  220.  * appended to this previously initialized
  221.  * DString. */
  222. {
  223.     CONST Tcl_UniChar *w, *wEnd;
  224.     char *p, *string;
  225.     int oldLength;
  226.     /*
  227.      * UTF-8 string length in bytes will be <= Unicode string length *
  228.      * TCL_UTF_MAX.
  229.      */
  230.     oldLength = Tcl_DStringLength(dsPtr);
  231.     Tcl_DStringSetLength(dsPtr, (oldLength + numChars + 1) * TCL_UTF_MAX);
  232.     string = Tcl_DStringValue(dsPtr) + oldLength;
  233.     p = string;
  234.     wEnd = wString + numChars;
  235.     for (w = wString; w < wEnd; ) {
  236. p += Tcl_UniCharToUtf(*w, p);
  237. w++;
  238.     }
  239.     Tcl_DStringSetLength(dsPtr, oldLength + (p - string));
  240.     return string;
  241. }
  242. /*
  243.  *---------------------------------------------------------------------------
  244.  *
  245.  * Tcl_UtfToUniChar --
  246.  *
  247.  * Extract the Tcl_UniChar represented by the UTF-8 string.  Bad
  248.  * UTF-8 sequences are converted to valid Tcl_UniChars and processing
  249.  * continues.  Equivalent to Plan 9 chartorune().
  250.  *
  251.  * The caller must ensure that the source buffer is long enough that
  252.  * this routine does not run off the end and dereference non-existent
  253.  * memory looking for trail bytes.  If the source buffer is known to
  254.  * be '' terminated, this cannot happen.  Otherwise, the caller
  255.  * should call Tcl_UtfCharComplete() before calling this routine to
  256.  * ensure that enough bytes remain in the string.
  257.  *
  258.  * Results:
  259.  * *chPtr is filled with the Tcl_UniChar, and the return value is the
  260.  * number of bytes from the UTF-8 string that were consumed.
  261.  *
  262.  * Side effects:
  263.  * None.
  264.  *
  265.  *---------------------------------------------------------------------------
  266.  */
  267.  
  268. int
  269. Tcl_UtfToUniChar(str, chPtr)
  270.     register CONST char *str;  /* The UTF-8 string. */
  271.     register Tcl_UniChar *chPtr; /* Filled with the Tcl_UniChar represented
  272.   * by the UTF-8 string. */
  273. {
  274.     register int byte;
  275.     
  276.     /*
  277.      * Unroll 1 to 3 byte UTF-8 sequences, use loop to handle longer ones.
  278.      */
  279.     byte = *((unsigned char *) str);
  280.     if (byte < 0xC0) {
  281. /*
  282.  * Handles properly formed UTF-8 characters between 0x01 and 0x7F.
  283.  * Also treats  and naked trail bytes 0x80 to 0xBF as valid
  284.  * characters representing themselves.
  285.  */
  286. *chPtr = (Tcl_UniChar) byte;
  287. return 1;
  288.     } else if (byte < 0xE0) {
  289. if ((str[1] & 0xC0) == 0x80) {
  290.     /*
  291.      * Two-byte-character lead-byte followed by a trail-byte.
  292.      */
  293.     *chPtr = (Tcl_UniChar) (((byte & 0x1F) << 6) | (str[1] & 0x3F));
  294.     return 2;
  295. }
  296. /*
  297.  * A two-byte-character lead-byte not followed by trail-byte
  298.  * represents itself.
  299.  */
  300. *chPtr = (Tcl_UniChar) byte;
  301. return 1;
  302.     } else if (byte < 0xF0) {
  303. if (((str[1] & 0xC0) == 0x80) && ((str[2] & 0xC0) == 0x80)) {
  304.     /*
  305.      * Three-byte-character lead byte followed by two trail bytes.
  306.      */
  307.     *chPtr = (Tcl_UniChar) (((byte & 0x0F) << 12) 
  308.     | ((str[1] & 0x3F) << 6) | (str[2] & 0x3F));
  309.     return 3;
  310. }
  311. /*
  312.  * A three-byte-character lead-byte not followed by two trail-bytes
  313.  * represents itself.
  314.  */
  315. *chPtr = (Tcl_UniChar) byte;
  316. return 1;
  317.     }
  318. #if TCL_UTF_MAX > 3
  319.     else {
  320. int ch, total, trail;
  321. total = totalBytes[byte];
  322. trail = total - 1;
  323. if (trail > 0) {
  324.     ch = byte & (0x3F >> trail);
  325.     do {
  326. str++;
  327. if ((*str & 0xC0) != 0x80) {
  328.     *chPtr = byte;
  329.     return 1;
  330. }
  331. ch <<= 6;
  332. ch |= (*str & 0x3F);
  333. trail--;
  334.     } while (trail > 0);
  335.     *chPtr = ch;
  336.     return total;
  337. }
  338.     }
  339. #endif
  340.     *chPtr = (Tcl_UniChar) byte;
  341.     return 1;
  342. }
  343. /*
  344.  *---------------------------------------------------------------------------
  345.  *
  346.  * Tcl_UtfToUniCharDString --
  347.  *
  348.  * Convert the UTF-8 string to Unicode.
  349.  *
  350.  * Results:
  351.  * The return value is a pointer to the Unicode representation of the
  352.  * UTF-8 string.  Storage for the return value is appended to the
  353.  * end of dsPtr.  The Unicode string is terminated with a Unicode
  354.  * NULL character.
  355.  *
  356.  * Side effects:
  357.  * None.
  358.  *
  359.  *---------------------------------------------------------------------------
  360.  */
  361. Tcl_UniChar *
  362. Tcl_UtfToUniCharDString(string, length, dsPtr)
  363.     CONST char *string; /* UTF-8 string to convert to Unicode. */
  364.     int length; /* Length of UTF-8 string in bytes, or -1
  365.  * for strlen(). */
  366.     Tcl_DString *dsPtr; /* Unicode representation of string is
  367.  * appended to this previously initialized
  368.  * DString. */
  369. {
  370.     Tcl_UniChar *w, *wString;
  371.     CONST char *p, *end;
  372.     int oldLength;
  373.     if (length < 0) {
  374. length = strlen(string);
  375.     }
  376.     /*
  377.      * Unicode string length in Tcl_UniChars will be <= UTF-8 string length
  378.      * in bytes.
  379.      */
  380.     oldLength = Tcl_DStringLength(dsPtr);
  381.     Tcl_DStringSetLength(dsPtr,
  382.     (int) ((oldLength + length + 1) * sizeof(Tcl_UniChar)));
  383.     wString = (Tcl_UniChar *) (Tcl_DStringValue(dsPtr) + oldLength);
  384.     w = wString;
  385.     end = string + length;
  386.     for (p = string; p < end; ) {
  387. p += TclUtfToUniChar(p, w);
  388. w++;
  389.     }
  390.     *w = '';
  391.     Tcl_DStringSetLength(dsPtr,
  392.     (oldLength + ((char *) w - (char *) wString)));
  393.     return wString;
  394. }
  395. /*
  396.  *---------------------------------------------------------------------------
  397.  *
  398.  * Tcl_UtfCharComplete --
  399.  *
  400.  * Determine if the UTF-8 string of the given length is long enough
  401.  * to be decoded by Tcl_UtfToUniChar().  This does not ensure that the
  402.  * UTF-8 string is properly formed.  Equivalent to Plan 9 fullrune().
  403.  *
  404.  * Results:
  405.  * The return value is 0 if the string is not long enough, non-zero
  406.  * otherwise.
  407.  *
  408.  * Side effects:
  409.  * None.
  410.  *
  411.  *---------------------------------------------------------------------------
  412.  */
  413. int
  414. Tcl_UtfCharComplete(str, len)
  415.     CONST char *str; /* String to check if first few bytes
  416.  * contain a complete UTF-8 character. */
  417.     int len; /* Length of above string in bytes. */
  418. {
  419.     int ch;
  420.     ch = *((unsigned char *) str);
  421.     return len >= totalBytes[ch];
  422. }
  423. /*
  424.  *---------------------------------------------------------------------------
  425.  *
  426.  * Tcl_NumUtfChars --
  427.  *
  428.  * Returns the number of characters (not bytes) in the UTF-8 string,
  429.  * not including the terminating NULL byte.  This is equivalent to
  430.  * Plan 9 utflen() and utfnlen().
  431.  *
  432.  * Results:
  433.  * As above.  
  434.  *
  435.  * Side effects:
  436.  * None.
  437.  *
  438.  *---------------------------------------------------------------------------
  439.  */
  440.  
  441. int 
  442. Tcl_NumUtfChars(str, len)
  443.     register CONST char *str; /* The UTF-8 string to measure. */
  444.     int len; /* The length of the string in bytes, or -1
  445.  * for strlen(string). */
  446. {
  447.     Tcl_UniChar ch;
  448.     register Tcl_UniChar *chPtr = &ch;
  449.     register int i;
  450.     /*
  451.      * The separate implementations are faster.
  452.      *
  453.      * Since this is a time-sensitive function, we also do the check for
  454.      * the single-byte char case specially.
  455.      */
  456.     i = 0;
  457.     if (len < 0) {
  458. while (*str != '') {
  459.     str += TclUtfToUniChar(str, chPtr);
  460.     i++;
  461. }
  462.     } else {
  463. register int n;
  464. while (len > 0) {
  465.     if (UCHAR(*str) < 0xC0) {
  466. len--;
  467. str++;
  468.     } else {
  469. n = Tcl_UtfToUniChar(str, chPtr);
  470. len -= n;
  471. str += n;
  472.     }
  473.     i++;
  474. }
  475.     }
  476.     return i;
  477. }
  478. /*
  479.  *---------------------------------------------------------------------------
  480.  *
  481.  * Tcl_UtfFindFirst --
  482.  *
  483.  * Returns a pointer to the first occurance of the given Tcl_UniChar
  484.  * in the NULL-terminated UTF-8 string.  The NULL terminator is
  485.  * considered part of the UTF-8 string.  Equivalent to Plan 9
  486.  * utfrune().
  487.  *
  488.  * Results:
  489.  * As above.  If the Tcl_UniChar does not exist in the given string,
  490.  * the return value is NULL.
  491.  *
  492.  * Side effects:
  493.  * None.
  494.  *
  495.  *---------------------------------------------------------------------------
  496.  */
  497. CONST char *
  498. Tcl_UtfFindFirst(string, ch)
  499.     CONST char *string; /* The UTF-8 string to be searched. */
  500.     int ch; /* The Tcl_UniChar to search for. */
  501. {
  502.     int len;
  503.     Tcl_UniChar find;
  504.     
  505.     while (1) {
  506. len = TclUtfToUniChar(string, &find);
  507. if (find == ch) {
  508.     return string;
  509. }
  510. if (*string == '') {
  511.     return NULL;
  512. }
  513. string += len;
  514.     }
  515. }
  516. /*
  517.  *---------------------------------------------------------------------------
  518.  *
  519.  * Tcl_UtfFindLast --
  520.  *
  521.  * Returns a pointer to the last occurance of the given Tcl_UniChar
  522.  * in the NULL-terminated UTF-8 string.  The NULL terminator is
  523.  * considered part of the UTF-8 string.  Equivalent to Plan 9
  524.  * utfrrune().
  525.  *
  526.  * Results:
  527.  * As above.  If the Tcl_UniChar does not exist in the given string,
  528.  * the return value is NULL.
  529.  *
  530.  * Side effects:
  531.  * None.
  532.  *
  533.  *---------------------------------------------------------------------------
  534.  */
  535. CONST char *
  536. Tcl_UtfFindLast(string, ch)
  537.     CONST char *string; /* The UTF-8 string to be searched. */
  538.     int ch; /* The Tcl_UniChar to search for. */
  539. {
  540.     int len;
  541.     Tcl_UniChar find;
  542.     CONST char *last;
  543.     last = NULL;
  544.     while (1) {
  545. len = TclUtfToUniChar(string, &find);
  546. if (find == ch) {
  547.     last = string;
  548. }
  549. if (*string == '') {
  550.     break;
  551. }
  552. string += len;
  553.     }
  554.     return last;
  555. }
  556. /*
  557.  *---------------------------------------------------------------------------
  558.  *
  559.  * Tcl_UtfNext --
  560.  *
  561.  * Given a pointer to some current location in a UTF-8 string,
  562.  * move forward one character.  The caller must ensure that they
  563.  * are not asking for the next character after the last character
  564.  * in the string.
  565.  *
  566.  * Results:
  567.  * The return value is the pointer to the next character in
  568.  * the UTF-8 string.
  569.  *
  570.  * Side effects:
  571.  * None.
  572.  *
  573.  *---------------------------------------------------------------------------
  574.  */
  575.  
  576. CONST char *
  577. Tcl_UtfNext(str) 
  578.     CONST char *str;     /* The current location in the string. */
  579. {
  580.     Tcl_UniChar ch;
  581.     return str + TclUtfToUniChar(str, &ch);
  582. }
  583. /*
  584.  *---------------------------------------------------------------------------
  585.  *
  586.  * Tcl_UtfPrev --
  587.  *
  588.  * Given a pointer to some current location in a UTF-8 string,
  589.  * move backwards one character.  This works correctly when the
  590.  * pointer is in the middle of a UTF-8 character.
  591.  *
  592.  * Results:
  593.  * The return value is a pointer to the previous character in the
  594.  * UTF-8 string.  If the current location was already at the
  595.  * beginning of the string, the return value will also be a
  596.  * pointer to the beginning of the string.
  597.  *
  598.  * Side effects:
  599.  * None.
  600.  *
  601.  *---------------------------------------------------------------------------
  602.  */
  603. CONST char *
  604. Tcl_UtfPrev(str, start)
  605.     CONST char *str;     /* The current location in the string. */
  606.     CONST char *start;     /* Pointer to the beginning of the
  607.      * string, to avoid going backwards too
  608.      * far. */
  609. {
  610.     CONST char *look;
  611.     int i, byte;
  612.     
  613.     str--;
  614.     look = str;
  615.     for (i = 0; i < TCL_UTF_MAX; i++) {
  616. if (look < start) {
  617.     if (str < start) {
  618. str = start;
  619.     }
  620.     break;
  621. }
  622. byte = *((unsigned char *) look);
  623. if (byte < 0x80) {
  624.     break;
  625. }
  626. if (byte >= 0xC0) {
  627.     return look;
  628. }
  629. look--;
  630.     }
  631.     return str;
  632. }
  633. /*
  634.  *---------------------------------------------------------------------------
  635.  *
  636.  * Tcl_UniCharAtIndex --
  637.  *
  638.  * Returns the Unicode character represented at the specified
  639.  * character (not byte) position in the UTF-8 string.
  640.  *
  641.  * Results:
  642.  * As above.
  643.  *
  644.  * Side effects:
  645.  * None.
  646.  *
  647.  *---------------------------------------------------------------------------
  648.  */
  649.  
  650. Tcl_UniChar
  651. Tcl_UniCharAtIndex(src, index)
  652.     register CONST char *src; /* The UTF-8 string to dereference. */
  653.     register int index; /* The position of the desired character. */
  654. {
  655.     Tcl_UniChar ch;
  656.     while (index >= 0) {
  657. index--;
  658. src += TclUtfToUniChar(src, &ch);
  659.     }
  660.     return ch;
  661. }
  662. /*
  663.  *---------------------------------------------------------------------------
  664.  *
  665.  * Tcl_UtfAtIndex --
  666.  *
  667.  * Returns a pointer to the specified character (not byte) position
  668.  * in the UTF-8 string.
  669.  *
  670.  * Results:
  671.  * As above.
  672.  *
  673.  * Side effects:
  674.  * None.
  675.  *
  676.  *---------------------------------------------------------------------------
  677.  */
  678. CONST char *
  679. Tcl_UtfAtIndex(src, index)
  680.     register CONST char *src; /* The UTF-8 string. */
  681.     register int index; /* The position of the desired character. */
  682. {
  683.     Tcl_UniChar ch;
  684.     
  685.     while (index > 0) {
  686. index--;
  687. src += TclUtfToUniChar(src, &ch);
  688.     }
  689.     return src;
  690. }
  691. /*
  692.  *---------------------------------------------------------------------------
  693.  *
  694.  * Tcl_UtfBackslash --
  695.  *
  696.  * Figure out how to handle a backslash sequence.
  697.  *
  698.  * Results:
  699.  * Stores the bytes represented by the backslash sequence in dst and
  700.  * returns the number of bytes written to dst.  At most TCL_UTF_MAX
  701.  * bytes are written to dst; dst must have been large enough to accept
  702.  * those bytes.  If readPtr isn't NULL then it is filled in with a
  703.  * count of the number of bytes in the backslash sequence.  
  704.  *
  705.  * Side effects:
  706.  * The maximum number of bytes it takes to represent a Unicode
  707.  * character in UTF-8 is guaranteed to be less than the number of
  708.  * bytes used to express the backslash sequence that represents
  709.  * that Unicode character.  If the target buffer into which the
  710.  * caller is going to store the bytes that represent the Unicode
  711.  * character is at least as large as the source buffer from which
  712.  * the backslashed sequence was extracted, no buffer overruns should
  713.  * occur.
  714.  *
  715.  *---------------------------------------------------------------------------
  716.  */
  717. int
  718. Tcl_UtfBackslash(src, readPtr, dst)
  719.     CONST char *src; /* Points to the backslash character of
  720.  * a backslash sequence. */
  721.     int *readPtr; /* Fill in with number of characters read
  722.  * from src, unless NULL. */
  723.     char *dst; /* Filled with the bytes represented by the
  724.  * backslash sequence. */
  725. {
  726. #define LINE_LENGTH 128
  727.     int numRead;
  728.     int result;
  729.     result = TclParseBackslash(src, LINE_LENGTH, &numRead, dst);
  730.     if (numRead == LINE_LENGTH) {
  731. /* We ate a whole line.  Pay the price of a strlen() */
  732. result = TclParseBackslash(src, (int)strlen(src), &numRead, dst);
  733.     }
  734.     if (readPtr != NULL) {
  735. *readPtr = numRead;
  736.     }
  737.     return result;
  738. }
  739. /*
  740.  *----------------------------------------------------------------------
  741.  *
  742.  * Tcl_UtfToUpper --
  743.  *
  744.  * Convert lowercase characters to uppercase characters in a UTF
  745.  * string in place.  The conversion may shrink the UTF string.
  746.  *
  747.  * Results:
  748.  * Returns the number of bytes in the resulting string
  749.  * excluding the trailing null.
  750.  *
  751.  * Side effects:
  752.  * Writes a terminating null after the last converted character.
  753.  *
  754.  *----------------------------------------------------------------------
  755.  */
  756. int
  757. Tcl_UtfToUpper(str)
  758.     char *str; /* String to convert in place. */
  759. {
  760.     Tcl_UniChar ch, upChar;
  761.     char *src, *dst;
  762.     int bytes;
  763.     /*
  764.      * Iterate over the string until we hit the terminating null.
  765.      */
  766.     src = dst = str;
  767.     while (*src) {
  768.         bytes = TclUtfToUniChar(src, &ch);
  769. upChar = Tcl_UniCharToUpper(ch);
  770. /*
  771.  * To keep badly formed Utf strings from getting inflated by
  772.  * the conversion (thereby causing a segfault), only copy the
  773.  * upper case char to dst if its size is <= the original char.
  774.  */
  775. if (bytes < UtfCount(upChar)) {
  776.     memcpy(dst, src, (size_t) bytes);
  777.     dst += bytes;
  778. } else {
  779.     dst += Tcl_UniCharToUtf(upChar, dst);
  780. }
  781. src += bytes;
  782.     }
  783.     *dst = '';
  784.     return (dst - str);
  785. }
  786. /*
  787.  *----------------------------------------------------------------------
  788.  *
  789.  * Tcl_UtfToLower --
  790.  *
  791.  * Convert uppercase characters to lowercase characters in a UTF
  792.  * string in place.  The conversion may shrink the UTF string.
  793.  *
  794.  * Results:
  795.  * Returns the number of bytes in the resulting string
  796.  * excluding the trailing null.
  797.  *
  798.  * Side effects:
  799.  * Writes a terminating null after the last converted character.
  800.  *
  801.  *----------------------------------------------------------------------
  802.  */
  803. int
  804. Tcl_UtfToLower(str)
  805.     char *str; /* String to convert in place. */
  806. {
  807.     Tcl_UniChar ch, lowChar;
  808.     char *src, *dst;
  809.     int bytes;
  810.     
  811.     /*
  812.      * Iterate over the string until we hit the terminating null.
  813.      */
  814.     src = dst = str;
  815.     while (*src) {
  816. bytes = TclUtfToUniChar(src, &ch);
  817. lowChar = Tcl_UniCharToLower(ch);
  818. /*
  819.  * To keep badly formed Utf strings from getting inflated by
  820.  * the conversion (thereby causing a segfault), only copy the
  821.  * lower case char to dst if its size is <= the original char.
  822.  */
  823. if (bytes < UtfCount(lowChar)) {
  824.     memcpy(dst, src, (size_t) bytes);
  825.     dst += bytes;
  826. } else {
  827.     dst += Tcl_UniCharToUtf(lowChar, dst);
  828. }
  829. src += bytes;
  830.     }
  831.     *dst = '';
  832.     return (dst - str);
  833. }
  834. /*
  835.  *----------------------------------------------------------------------
  836.  *
  837.  * Tcl_UtfToTitle --
  838.  *
  839.  * Changes the first character of a UTF string to title case or
  840.  * uppercase and the rest of the string to lowercase.  The
  841.  * conversion happens in place and may shrink the UTF string.
  842.  *
  843.  * Results:
  844.  * Returns the number of bytes in the resulting string
  845.  * excluding the trailing null.
  846.  *
  847.  * Side effects:
  848.  * Writes a terminating null after the last converted character.
  849.  *
  850.  *----------------------------------------------------------------------
  851.  */
  852. int
  853. Tcl_UtfToTitle(str)
  854.     char *str; /* String to convert in place. */
  855. {
  856.     Tcl_UniChar ch, titleChar, lowChar;
  857.     char *src, *dst;
  858.     int bytes;
  859.     
  860.     /*
  861.      * Capitalize the first character and then lowercase the rest of the
  862.      * characters until we get to a null.
  863.      */
  864.     src = dst = str;
  865.     if (*src) {
  866. bytes = TclUtfToUniChar(src, &ch);
  867. titleChar = Tcl_UniCharToTitle(ch);
  868. if (bytes < UtfCount(titleChar)) {
  869.     memcpy(dst, src, (size_t) bytes);
  870.     dst += bytes;
  871. } else {
  872.     dst += Tcl_UniCharToUtf(titleChar, dst);
  873. }
  874. src += bytes;
  875.     }
  876.     while (*src) {
  877. bytes = TclUtfToUniChar(src, &ch);
  878. lowChar = Tcl_UniCharToLower(ch);
  879. if (bytes < UtfCount(lowChar)) {
  880.     memcpy(dst, src, (size_t) bytes);
  881.     dst += bytes;
  882. } else {
  883.     dst += Tcl_UniCharToUtf(lowChar, dst);
  884. }
  885. src += bytes;
  886.     }
  887.     *dst = '';
  888.     return (dst - str);
  889. }
  890. /*
  891.  *----------------------------------------------------------------------
  892.  *
  893.  * TclpUtfNcmp2 --
  894.  *
  895.  * Compare at most n bytes of utf-8 strings cs and ct.  Both cs
  896.  * and ct are assumed to be at least n bytes long.
  897.  *
  898.  * Results:
  899.  * Return <0 if cs < ct, 0 if cs == ct, or >0 if cs > ct.
  900.  *
  901.  * Side effects:
  902.  * None.
  903.  *
  904.  *----------------------------------------------------------------------
  905.  */
  906. int
  907. TclpUtfNcmp2(cs, ct, n)
  908.     CONST char *cs; /* UTF string to compare to ct. */
  909.     CONST char *ct; /* UTF string cs is compared to. */
  910.     unsigned long n; /* Number of *bytes* to compare. */
  911. {
  912.     /*
  913.      * We can't simply call 'memcmp(cs, ct, n);' because we need to check
  914.      * for Tcl's xC0x80 non-utf-8 null encoding.
  915.      * Otherwise utf-8 lexes fine in the strcmp manner.
  916.      */
  917.     register int result = 0;
  918.     for ( ; n != 0; n--, cs++, ct++) {
  919. if (*cs != *ct) {
  920.     result = UCHAR(*cs) - UCHAR(*ct);
  921.     break;
  922. }
  923.     }
  924.     if (n && ((UCHAR(*cs) == 0xC0) || (UCHAR(*ct) == 0xC0))) {
  925. unsigned char c1, c2;
  926. c1 = ((UCHAR(*cs) == 0xC0) && (UCHAR(cs[1]) == 0x80)) ? 0 : UCHAR(*cs);
  927. c2 = ((UCHAR(*ct) == 0xC0) && (UCHAR(ct[1]) == 0x80)) ? 0 : UCHAR(*ct);
  928. result = (c1 - c2);
  929.     }
  930.     return result;
  931. }
  932. /*
  933.  *----------------------------------------------------------------------
  934.  *
  935.  * Tcl_UtfNcmp --
  936.  *
  937.  * Compare at most n UTF chars of string cs to string ct.  Both cs
  938.  * and ct are assumed to be at least n UTF chars long.
  939.  *
  940.  * Results:
  941.  * Return <0 if cs < ct, 0 if cs == ct, or >0 if cs > ct.
  942.  *
  943.  * Side effects:
  944.  * None.
  945.  *
  946.  *----------------------------------------------------------------------
  947.  */
  948. int
  949. Tcl_UtfNcmp(cs, ct, n)
  950.     CONST char *cs; /* UTF string to compare to ct. */
  951.     CONST char *ct; /* UTF string cs is compared to. */
  952.     unsigned long n; /* Number of UTF chars to compare. */
  953. {
  954.     Tcl_UniChar ch1, ch2;
  955.     /*
  956.      * Cannot use 'memcmp(cs, ct, n);' as byte representation of
  957.      * u0000 (the pair of bytes 0xc0,0x80) is larger than byte
  958.      * representation of u0001 (the byte 0x01.)
  959.      */
  960.     while (n-- > 0) {
  961. /*
  962.  * n must be interpreted as chars, not bytes.
  963.  * This should be called only when both strings are of
  964.  * at least n chars long (no need for  check)
  965.  */
  966. cs += TclUtfToUniChar(cs, &ch1);
  967. ct += TclUtfToUniChar(ct, &ch2);
  968. if (ch1 != ch2) {
  969.     return (ch1 - ch2);
  970. }
  971.     }
  972.     return 0;
  973. }
  974. /*
  975.  *----------------------------------------------------------------------
  976.  *
  977.  * Tcl_UtfNcasecmp --
  978.  *
  979.  * Compare at most n UTF chars of string cs to string ct case
  980.  * insensitive.  Both cs and ct are assumed to be at least n
  981.  * UTF chars long.
  982.  *
  983.  * Results:
  984.  * Return <0 if cs < ct, 0 if cs == ct, or >0 if cs > ct.
  985.  *
  986.  * Side effects:
  987.  * None.
  988.  *
  989.  *----------------------------------------------------------------------
  990.  */
  991. int
  992. Tcl_UtfNcasecmp(cs, ct, n)
  993.     CONST char *cs; /* UTF string to compare to ct. */
  994.     CONST char *ct; /* UTF string cs is compared to. */
  995.     unsigned long n; /* Number of UTF chars to compare. */
  996. {
  997.     Tcl_UniChar ch1, ch2;
  998.     while (n-- > 0) {
  999. /*
  1000.  * n must be interpreted as chars, not bytes.
  1001.  * This should be called only when both strings are of
  1002.  * at least n chars long (no need for  check)
  1003.  */
  1004. cs += TclUtfToUniChar(cs, &ch1);
  1005. ct += TclUtfToUniChar(ct, &ch2);
  1006. if (ch1 != ch2) {
  1007.     ch1 = Tcl_UniCharToLower(ch1);
  1008.     ch2 = Tcl_UniCharToLower(ch2);
  1009.     if (ch1 != ch2) {
  1010. return (ch1 - ch2);
  1011.     }
  1012. }
  1013.     }
  1014.     return 0;
  1015. }
  1016. /*
  1017.  *----------------------------------------------------------------------
  1018.  *
  1019.  * Tcl_UniCharToUpper --
  1020.  *
  1021.  * Compute the uppercase equivalent of the given Unicode character.
  1022.  *
  1023.  * Results:
  1024.  * Returns the uppercase Unicode character.
  1025.  *
  1026.  * Side effects:
  1027.  * None.
  1028.  *
  1029.  *----------------------------------------------------------------------
  1030.  */
  1031. Tcl_UniChar
  1032. Tcl_UniCharToUpper(ch)
  1033.     int ch; /* Unicode character to convert. */
  1034. {
  1035.     int info = GetUniCharInfo(ch);
  1036.     if (GetCaseType(info) & 0x04) {
  1037. return (Tcl_UniChar) (ch - GetDelta(info));
  1038.     } else {
  1039. return ch;
  1040.     }
  1041. }
  1042. /*
  1043.  *----------------------------------------------------------------------
  1044.  *
  1045.  * Tcl_UniCharToLower --
  1046.  *
  1047.  * Compute the lowercase equivalent of the given Unicode character.
  1048.  *
  1049.  * Results:
  1050.  * Returns the lowercase Unicode character.
  1051.  *
  1052.  * Side effects:
  1053.  * None.
  1054.  *
  1055.  *----------------------------------------------------------------------
  1056.  */
  1057. Tcl_UniChar
  1058. Tcl_UniCharToLower(ch)
  1059.     int ch; /* Unicode character to convert. */
  1060. {
  1061.     int info = GetUniCharInfo(ch);
  1062.     if (GetCaseType(info) & 0x02) {
  1063. return (Tcl_UniChar) (ch + GetDelta(info));
  1064.     } else {
  1065. return ch;
  1066.     }
  1067. }
  1068. /*
  1069.  *----------------------------------------------------------------------
  1070.  *
  1071.  * Tcl_UniCharToTitle --
  1072.  *
  1073.  * Compute the titlecase equivalent of the given Unicode character.
  1074.  *
  1075.  * Results:
  1076.  * Returns the titlecase Unicode character.
  1077.  *
  1078.  * Side effects:
  1079.  * None.
  1080.  *
  1081.  *----------------------------------------------------------------------
  1082.  */
  1083. Tcl_UniChar
  1084. Tcl_UniCharToTitle(ch)
  1085.     int ch; /* Unicode character to convert. */
  1086. {
  1087.     int info = GetUniCharInfo(ch);
  1088.     int mode = GetCaseType(info);
  1089.     if (mode & 0x1) {
  1090. /*
  1091.  * Subtract or add one depending on the original case.
  1092.  */
  1093. return (Tcl_UniChar) (ch + ((mode & 0x4) ? -1 : 1));
  1094.     } else if (mode == 0x4) {
  1095. return (Tcl_UniChar) (ch - GetDelta(info));
  1096.     } else {
  1097. return ch;
  1098.     }
  1099. }
  1100. /*
  1101.  *----------------------------------------------------------------------
  1102.  *
  1103.  * Tcl_UniCharLen --
  1104.  *
  1105.  * Find the length of a UniChar string.  The str input must be null
  1106.  * terminated.
  1107.  *
  1108.  * Results:
  1109.  * Returns the length of str in UniChars (not bytes).
  1110.  *
  1111.  * Side effects:
  1112.  * None.
  1113.  *
  1114.  *----------------------------------------------------------------------
  1115.  */
  1116. int
  1117. Tcl_UniCharLen(str)
  1118.     CONST Tcl_UniChar *str; /* Unicode string to find length of. */
  1119. {
  1120.     int len = 0;
  1121.     
  1122.     while (*str != '') {
  1123. len++;
  1124. str++;
  1125.     }
  1126.     return len;
  1127. }
  1128. /*
  1129.  *----------------------------------------------------------------------
  1130.  *
  1131.  * Tcl_UniCharNcmp --
  1132.  *
  1133.  * Compare at most n unichars of string cs to string ct.  Both cs
  1134.  * and ct are assumed to be at least n unichars long.
  1135.  *
  1136.  * Results:
  1137.  * Return <0 if cs < ct, 0 if cs == ct, or >0 if cs > ct.
  1138.  *
  1139.  * Side effects:
  1140.  * None.
  1141.  *
  1142.  *----------------------------------------------------------------------
  1143.  */
  1144. int
  1145. Tcl_UniCharNcmp(cs, ct, n)
  1146.     CONST Tcl_UniChar *cs; /* Unicode string to compare to ct. */
  1147.     CONST Tcl_UniChar *ct; /* Unicode string cs is compared to. */
  1148.     unsigned long n; /* Number of unichars to compare. */
  1149. {
  1150. #ifdef WORDS_BIGENDIAN
  1151.     /*
  1152.      * We are definitely on a big-endian machine; memcmp() is safe
  1153.      */
  1154.     return memcmp(cs, ct, n*sizeof(Tcl_UniChar));
  1155. #else /* !WORDS_BIGENDIAN */
  1156.     /*
  1157.      * We can't simply call memcmp() because that is not lexically correct.
  1158.      */
  1159.     for ( ; n != 0; cs++, ct++, n--) {
  1160. if (*cs != *ct) {
  1161.     return (*cs - *ct);
  1162. }
  1163.     }
  1164.     return 0;
  1165. #endif /* WORDS_BIGENDIAN */
  1166. }
  1167. /*
  1168.  *----------------------------------------------------------------------
  1169.  *
  1170.  * Tcl_UniCharNcasecmp --
  1171.  *
  1172.  * Compare at most n unichars of string cs to string ct case
  1173.  * insensitive.  Both cs and ct are assumed to be at least n
  1174.  * unichars long.
  1175.  *
  1176.  * Results:
  1177.  * Return <0 if cs < ct, 0 if cs == ct, or >0 if cs > ct.
  1178.  *
  1179.  * Side effects:
  1180.  * None.
  1181.  *
  1182.  *----------------------------------------------------------------------
  1183.  */
  1184. int
  1185. Tcl_UniCharNcasecmp(cs, ct, n)
  1186.     CONST Tcl_UniChar *cs; /* Unicode string to compare to ct. */
  1187.     CONST Tcl_UniChar *ct; /* Unicode string cs is compared to. */
  1188.     unsigned long n; /* Number of unichars to compare. */
  1189. {
  1190.     for ( ; n != 0; n--, cs++, ct++) {
  1191. if (*cs != *ct) {
  1192.     Tcl_UniChar lcs = Tcl_UniCharToLower(*cs);
  1193.     Tcl_UniChar lct = Tcl_UniCharToLower(*ct);
  1194.     if (lcs != lct) {
  1195. return (lcs - lct);
  1196.     }
  1197. }
  1198.     }
  1199.     return 0;
  1200. }
  1201. /*
  1202.  *----------------------------------------------------------------------
  1203.  *
  1204.  * Tcl_UniCharIsAlnum --
  1205.  *
  1206.  * Test if a character is an alphanumeric Unicode character.
  1207.  *
  1208.  * Results:
  1209.  * Returns 1 if character is alphanumeric.
  1210.  *
  1211.  * Side effects:
  1212.  * None.
  1213.  *
  1214.  *----------------------------------------------------------------------
  1215.  */
  1216. int
  1217. Tcl_UniCharIsAlnum(ch)
  1218.     int ch; /* Unicode character to test. */
  1219. {
  1220.     register int category = (GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK);
  1221.     return (((ALPHA_BITS | DIGIT_BITS) >> category) & 1);
  1222. }
  1223. /*
  1224.  *----------------------------------------------------------------------
  1225.  *
  1226.  * Tcl_UniCharIsAlpha --
  1227.  *
  1228.  * Test if a character is an alphabetic Unicode character.
  1229.  *
  1230.  * Results:
  1231.  * Returns 1 if character is alphabetic.
  1232.  *
  1233.  * Side effects:
  1234.  * None.
  1235.  *
  1236.  *----------------------------------------------------------------------
  1237.  */
  1238. int
  1239. Tcl_UniCharIsAlpha(ch)
  1240.     int ch; /* Unicode character to test. */
  1241. {
  1242.     register int category = (GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK);
  1243.     return ((ALPHA_BITS >> category) & 1);
  1244. }
  1245. /*
  1246.  *----------------------------------------------------------------------
  1247.  *
  1248.  * Tcl_UniCharIsControl --
  1249.  *
  1250.  * Test if a character is a Unicode control character.
  1251.  *
  1252.  * Results:
  1253.  * Returns non-zero if character is a control.
  1254.  *
  1255.  * Side effects:
  1256.  * None.
  1257.  *
  1258.  *----------------------------------------------------------------------
  1259.  */
  1260. int
  1261. Tcl_UniCharIsControl(ch)
  1262.     int ch; /* Unicode character to test. */
  1263. {
  1264.     return ((GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK) == CONTROL);
  1265. }
  1266. /*
  1267.  *----------------------------------------------------------------------
  1268.  *
  1269.  * Tcl_UniCharIsDigit --
  1270.  *
  1271.  * Test if a character is a numeric Unicode character.
  1272.  *
  1273.  * Results:
  1274.  * Returns non-zero if character is a digit.
  1275.  *
  1276.  * Side effects:
  1277.  * None.
  1278.  *
  1279.  *----------------------------------------------------------------------
  1280.  */
  1281. int
  1282. Tcl_UniCharIsDigit(ch)
  1283.     int ch; /* Unicode character to test. */
  1284. {
  1285.     return ((GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK)
  1286.     == DECIMAL_DIGIT_NUMBER);
  1287. }
  1288. /*
  1289.  *----------------------------------------------------------------------
  1290.  *
  1291.  * Tcl_UniCharIsGraph --
  1292.  *
  1293.  * Test if a character is any Unicode print character except space.
  1294.  *
  1295.  * Results:
  1296.  * Returns non-zero if character is printable, but not space.
  1297.  *
  1298.  * Side effects:
  1299.  * None.
  1300.  *
  1301.  *----------------------------------------------------------------------
  1302.  */
  1303. int
  1304. Tcl_UniCharIsGraph(ch)
  1305.     int ch; /* Unicode character to test. */
  1306. {
  1307.     register int category = (GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK);
  1308.     return (((PRINT_BITS >> category) & 1) && ((unsigned char) ch != ' '));
  1309. }
  1310. /*
  1311.  *----------------------------------------------------------------------
  1312.  *
  1313.  * Tcl_UniCharIsLower --
  1314.  *
  1315.  * Test if a character is a lowercase Unicode character.
  1316.  *
  1317.  * Results:
  1318.  * Returns non-zero if character is lowercase.
  1319.  *
  1320.  * Side effects:
  1321.  * None.
  1322.  *
  1323.  *----------------------------------------------------------------------
  1324.  */
  1325. int
  1326. Tcl_UniCharIsLower(ch)
  1327.     int ch; /* Unicode character to test. */
  1328. {
  1329.     return ((GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK) == LOWERCASE_LETTER);
  1330. }
  1331. /*
  1332.  *----------------------------------------------------------------------
  1333.  *
  1334.  * Tcl_UniCharIsPrint --
  1335.  *
  1336.  * Test if a character is a Unicode print character.
  1337.  *
  1338.  * Results:
  1339.  * Returns non-zero if character is printable.
  1340.  *
  1341.  * Side effects:
  1342.  * None.
  1343.  *
  1344.  *----------------------------------------------------------------------
  1345.  */
  1346. int
  1347. Tcl_UniCharIsPrint(ch)
  1348.     int ch; /* Unicode character to test. */
  1349. {
  1350.     register int category = (GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK);
  1351.     return ((PRINT_BITS >> category) & 1);
  1352. }
  1353. /*
  1354.  *----------------------------------------------------------------------
  1355.  *
  1356.  * Tcl_UniCharIsPunct --
  1357.  *
  1358.  * Test if a character is a Unicode punctuation character.
  1359.  *
  1360.  * Results:
  1361.  * Returns non-zero if character is punct.
  1362.  *
  1363.  * Side effects:
  1364.  * None.
  1365.  *
  1366.  *----------------------------------------------------------------------
  1367.  */
  1368. int
  1369. Tcl_UniCharIsPunct(ch)
  1370.     int ch; /* Unicode character to test. */
  1371. {
  1372.     register int category = (GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK);
  1373.     return ((PUNCT_BITS >> category) & 1);
  1374. }
  1375. /*
  1376.  *----------------------------------------------------------------------
  1377.  *
  1378.  * Tcl_UniCharIsSpace --
  1379.  *
  1380.  * Test if a character is a whitespace Unicode character.
  1381.  *
  1382.  * Results:
  1383.  * Returns non-zero if character is a space.
  1384.  *
  1385.  * Side effects:
  1386.  * None.
  1387.  *
  1388.  *----------------------------------------------------------------------
  1389.  */
  1390. int
  1391. Tcl_UniCharIsSpace(ch)
  1392.     int ch; /* Unicode character to test. */
  1393. {
  1394.     register int category;
  1395.     /*
  1396.      * If the character is within the first 127 characters, just use the
  1397.      * standard C function, otherwise consult the Unicode table.
  1398.      */
  1399.     if (ch < 0x80) {
  1400. return isspace(UCHAR(ch)); /* INTL: ISO space */
  1401.     } else {
  1402. category = (GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK);
  1403. return ((SPACE_BITS >> category) & 1);
  1404.     }
  1405. }
  1406. /*
  1407.  *----------------------------------------------------------------------
  1408.  *
  1409.  * Tcl_UniCharIsUpper --
  1410.  *
  1411.  * Test if a character is a uppercase Unicode character.
  1412.  *
  1413.  * Results:
  1414.  * Returns non-zero if character is uppercase.
  1415.  *
  1416.  * Side effects:
  1417.  * None.
  1418.  *
  1419.  *----------------------------------------------------------------------
  1420.  */
  1421. int
  1422. Tcl_UniCharIsUpper(ch)
  1423.     int ch; /* Unicode character to test. */
  1424. {
  1425.     return ((GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK) == UPPERCASE_LETTER);
  1426. }
  1427. /*
  1428.  *----------------------------------------------------------------------
  1429.  *
  1430.  * Tcl_UniCharIsWordChar --
  1431.  *
  1432.  * Test if a character is alphanumeric or a connector punctuation
  1433.  * mark.
  1434.  *
  1435.  * Results:
  1436.  * Returns 1 if character is a word character.
  1437.  *
  1438.  * Side effects:
  1439.  * None.
  1440.  *
  1441.  *----------------------------------------------------------------------
  1442.  */
  1443. int
  1444. Tcl_UniCharIsWordChar(ch)
  1445.     int ch; /* Unicode character to test. */
  1446. {
  1447.     register int category = (GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK);
  1448.     return (((ALPHA_BITS | DIGIT_BITS | CONNECTOR_BITS) >> category) & 1);
  1449. }
  1450. /*
  1451.  *----------------------------------------------------------------------
  1452.  *
  1453.  * Tcl_UniCharCaseMatch --
  1454.  *
  1455.  * See if a particular Unicode string matches a particular pattern.
  1456.  * Allows case insensitivity.  This is the Unicode equivalent of
  1457.  * the char* Tcl_StringCaseMatch.  The UniChar strings must be
  1458.  * NULL-terminated.  This has no provision for counted UniChar
  1459.  * strings, thus should not be used where NULLs are expected in the
  1460.  * UniChar string.  Use TclUniCharMatch where possible.
  1461.  *
  1462.  * Results:
  1463.  * The return value is 1 if string matches pattern, and
  1464.  * 0 otherwise.  The matching operation permits the following
  1465.  * special characters in the pattern: *?[] (see the manual
  1466.  * entry for details on what these mean).
  1467.  *
  1468.  * Side effects:
  1469.  * None.
  1470.  *
  1471.  *----------------------------------------------------------------------
  1472.  */
  1473. int
  1474. Tcl_UniCharCaseMatch(string, pattern, nocase)
  1475.     CONST Tcl_UniChar *string; /* Unicode String. */
  1476.     CONST Tcl_UniChar *pattern; /* Pattern, which may contain special
  1477.  * characters. */
  1478.     int nocase; /* 0 for case sensitive, 1 for insensitive */
  1479. {
  1480.     Tcl_UniChar ch1, p;
  1481.     
  1482.     while (1) {
  1483. p = *pattern;
  1484. /*
  1485.  * See if we're at the end of both the pattern and the string.  If
  1486.  * so, we succeeded.  If we're at the end of the pattern but not at
  1487.  * the end of the string, we failed.
  1488.  */
  1489. if (p == 0) {
  1490.     return (*string == 0);
  1491. }
  1492. if ((*string == 0) && (p != '*')) {
  1493.     return 0;
  1494. }
  1495. /*
  1496.  * Check for a "*" as the next pattern character.  It matches any
  1497.  * substring.  We handle this by skipping all the characters up to the
  1498.  * next matching one in the pattern, and then calling ourselves
  1499.  * recursively for each postfix of string, until either we match or we
  1500.  * reach the end of the string.
  1501.  */
  1502. if (p == '*') {
  1503.     /*
  1504.      * Skip all successive *'s in the pattern
  1505.      */
  1506.     while (*(++pattern) == '*') {}
  1507.     p = *pattern;
  1508.     if (p == 0) {
  1509. return 1;
  1510.     }
  1511.     if (nocase) {
  1512. p = Tcl_UniCharToLower(p);
  1513.     }
  1514.     while (1) {
  1515. /*
  1516.  * Optimization for matching - cruise through the string
  1517.  * quickly if the next char in the pattern isn't a special
  1518.  * character
  1519.  */
  1520. if ((p != '[') && (p != '?') && (p != '\')) {
  1521.     if (nocase) {
  1522. while (*string && (p != *string)
  1523. && (p != Tcl_UniCharToLower(*string))) {
  1524.     string++;
  1525. }
  1526.     } else {
  1527. while (*string && (p != *string)) { string++; }
  1528.     }
  1529. }
  1530. if (Tcl_UniCharCaseMatch(string, pattern, nocase)) {
  1531.     return 1;
  1532. }
  1533. if (*string == 0) {
  1534.     return 0;
  1535. }
  1536. string++;
  1537.     }
  1538. }
  1539. /*
  1540.  * Check for a "?" as the next pattern character.  It matches
  1541.  * any single character.
  1542.  */
  1543. if (p == '?') {
  1544.     pattern++;
  1545.     string++;
  1546.     continue;
  1547. }
  1548. /*
  1549.  * Check for a "[" as the next pattern character.  It is followed
  1550.  * by a list of characters that are acceptable, or by a range
  1551.  * (two characters separated by "-").
  1552.  */
  1553. if (p == '[') {
  1554.     Tcl_UniChar startChar, endChar;
  1555.     pattern++;
  1556.     ch1 = (nocase ? Tcl_UniCharToLower(*string) : *string);
  1557.     string++;
  1558.     while (1) {
  1559. if ((*pattern == ']') || (*pattern == 0)) {
  1560.     return 0;
  1561. }
  1562. startChar = (nocase ? Tcl_UniCharToLower(*pattern) : *pattern);
  1563. pattern++;
  1564. if (*pattern == '-') {
  1565.     pattern++;
  1566.     if (*pattern == 0) {
  1567. return 0;
  1568.     }
  1569.     endChar = (nocase ? Tcl_UniCharToLower(*pattern)
  1570.     : *pattern);
  1571.     pattern++;
  1572.     if (((startChar <= ch1) && (ch1 <= endChar))
  1573.     || ((endChar <= ch1) && (ch1 <= startChar))) {
  1574. /*
  1575.  * Matches ranges of form [a-z] or [z-a].
  1576.  */
  1577. break;
  1578.     }
  1579. } else if (startChar == ch1) {
  1580.     break;
  1581. }
  1582.     }
  1583.     while (*pattern != ']') {
  1584. if (*pattern == 0) {
  1585.     pattern--;
  1586.     break;
  1587. }
  1588. pattern++;
  1589.     }
  1590.     pattern++;
  1591.     continue;
  1592. }
  1593. /*
  1594.  * If the next pattern character is '', just strip off the ''
  1595.  * so we do exact matching on the character that follows.
  1596.  */
  1597. if (p == '\') {
  1598.     if (*(++pattern) == '') {
  1599. return 0;
  1600.     }
  1601. }
  1602. /*
  1603.  * There's no special character.  Just make sure that the next
  1604.  * bytes of each string match.
  1605.  */
  1606. if (nocase) {
  1607.     if (Tcl_UniCharToLower(*string) != Tcl_UniCharToLower(*pattern)) {
  1608. return 0;
  1609.     }
  1610. } else if (*string != *pattern) {
  1611.     return 0;
  1612. }
  1613. string++;
  1614. pattern++;
  1615.     }
  1616. }
  1617. /*
  1618.  *----------------------------------------------------------------------
  1619.  *
  1620.  * TclUniCharMatch --
  1621.  *
  1622.  * See if a particular Unicode string matches a particular pattern.
  1623.  * Allows case insensitivity.  This is the Unicode equivalent of the
  1624.  * char* Tcl_StringCaseMatch.  This variant of Tcl_UniCharCaseMatch
  1625.  * uses counted Strings, so embedded NULLs are allowed.
  1626.  *
  1627.  * Results:
  1628.  * The return value is 1 if string matches pattern, and
  1629.  * 0 otherwise.  The matching operation permits the following
  1630.  * special characters in the pattern: *?[] (see the manual
  1631.  * entry for details on what these mean).
  1632.  *
  1633.  * Side effects:
  1634.  * None.
  1635.  *
  1636.  *----------------------------------------------------------------------
  1637.  */
  1638. int
  1639. TclUniCharMatch(string, strLen, pattern, ptnLen, nocase)
  1640.     CONST Tcl_UniChar *string; /* Unicode String. */
  1641.     int strLen; /* length of String */
  1642.     CONST Tcl_UniChar *pattern; /* Pattern, which may contain special
  1643.  * characters. */
  1644.     int ptnLen; /* length of Pattern */
  1645.     int nocase; /* 0 for case sensitive, 1 for insensitive */
  1646. {
  1647.     CONST Tcl_UniChar *stringEnd, *patternEnd;
  1648.     Tcl_UniChar p;
  1649.     stringEnd  = string + strLen;
  1650.     patternEnd = pattern + ptnLen;
  1651.     while (1) {
  1652. /*
  1653.  * See if we're at the end of both the pattern and the string.  If
  1654.  * so, we succeeded.  If we're at the end of the pattern but not at
  1655.  * the end of the string, we failed.
  1656.  */
  1657. if (pattern == patternEnd) {
  1658.     return (string == stringEnd);
  1659. }
  1660. p = *pattern;
  1661. if ((string == stringEnd) && (p != '*')) {
  1662.     return 0;
  1663. }
  1664. /*
  1665.  * Check for a "*" as the next pattern character.  It matches any
  1666.  * substring.  We handle this by skipping all the characters up to the
  1667.  * next matching one in the pattern, and then calling ourselves
  1668.  * recursively for each postfix of string, until either we match or we
  1669.  * reach the end of the string.
  1670.  */
  1671. if (p == '*') {
  1672.     /*
  1673.      * Skip all successive *'s in the pattern
  1674.      */
  1675.     while (*(++pattern) == '*') {}
  1676.     if (pattern == patternEnd) {
  1677. return 1;
  1678.     }
  1679.     p = *pattern;
  1680.     if (nocase) {
  1681. p = Tcl_UniCharToLower(p);
  1682.     }
  1683.     while (1) {
  1684. /*
  1685.  * Optimization for matching - cruise through the string
  1686.  * quickly if the next char in the pattern isn't a special
  1687.  * character
  1688.  */
  1689. if ((p != '[') && (p != '?') && (p != '\')) {
  1690.     if (nocase) {
  1691. while ((string < stringEnd) && (p != *string)
  1692. && (p != Tcl_UniCharToLower(*string))) {
  1693.     string++;
  1694. }
  1695.     } else {
  1696. while ((string < stringEnd) && (p != *string)) {
  1697.     string++;
  1698. }
  1699.     }
  1700. }
  1701. if (TclUniCharMatch(string, stringEnd - string,
  1702. pattern, patternEnd - pattern, nocase)) {
  1703.     return 1;
  1704. }
  1705. if (string == stringEnd) {
  1706.     return 0;
  1707. }
  1708. string++;
  1709.     }
  1710. }
  1711. /*
  1712.  * Check for a "?" as the next pattern character.  It matches
  1713.  * any single character.
  1714.  */
  1715. if (p == '?') {
  1716.     pattern++;
  1717.     string++;
  1718.     continue;
  1719. }
  1720. /*
  1721.  * Check for a "[" as the next pattern character.  It is followed
  1722.  * by a list of characters that are acceptable, or by a range
  1723.  * (two characters separated by "-").
  1724.  */
  1725. if (p == '[') {
  1726.     Tcl_UniChar ch1, startChar, endChar;
  1727.     pattern++;
  1728.     ch1 = (nocase ? Tcl_UniCharToLower(*string) : *string);
  1729.     string++;
  1730.     while (1) {
  1731. if ((*pattern == ']') || (pattern == patternEnd)) {
  1732.     return 0;
  1733. }
  1734. startChar = (nocase ? Tcl_UniCharToLower(*pattern) : *pattern);
  1735. pattern++;
  1736. if (*pattern == '-') {
  1737.     pattern++;
  1738.     if (pattern == patternEnd) {
  1739. return 0;
  1740.     }
  1741.     endChar = (nocase ? Tcl_UniCharToLower(*pattern)
  1742.     : *pattern);
  1743.     pattern++;
  1744.     if (((startChar <= ch1) && (ch1 <= endChar))
  1745.     || ((endChar <= ch1) && (ch1 <= startChar))) {
  1746. /*
  1747.  * Matches ranges of form [a-z] or [z-a].
  1748.  */
  1749. break;
  1750.     }
  1751. } else if (startChar == ch1) {
  1752.     break;
  1753. }
  1754.     }
  1755.     while (*pattern != ']') {
  1756. if (pattern == patternEnd) {
  1757.     pattern--;
  1758.     break;
  1759. }
  1760. pattern++;
  1761.     }
  1762.     pattern++;
  1763.     continue;
  1764. }
  1765. /*
  1766.  * If the next pattern character is '', just strip off the ''
  1767.  * so we do exact matching on the character that follows.
  1768.  */
  1769. if (p == '\') {
  1770.     if (++pattern == patternEnd) {
  1771. return 0;
  1772.     }
  1773. }
  1774. /*
  1775.  * There's no special character.  Just make sure that the next
  1776.  * bytes of each string match.
  1777.  */
  1778. if (nocase) {
  1779.     if (Tcl_UniCharToLower(*string) != Tcl_UniCharToLower(*pattern)) {
  1780. return 0;
  1781.     }
  1782. } else if (*string != *pattern) {
  1783.     return 0;
  1784. }
  1785. string++;
  1786. pattern++;
  1787.     }
  1788. }