tclUtil.c

Go to the documentation of this file.
00001 /*
00002  * tclUtil.c --
00003  *
00004  *      This file contains utility functions that are used by many Tcl
00005  *      commands.
00006  *
00007  * Copyright (c) 1987-1993 The Regents of the University of California.
00008  * Copyright (c) 1994-1998 Sun Microsystems, Inc.
00009  * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.
00010  *
00011  * See the file "license.terms" for information on usage and redistribution of
00012  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
00013  *
00014  * RCS: @(#) $Id: tclUtil.c,v 1.96 2007/12/13 15:23:20 dgp Exp $
00015  */
00016 
00017 #include "tclInt.h"
00018 #include <float.h>
00019 #include <math.h>
00020 
00021 /*
00022  * The absolute pathname of the executable in which this Tcl library is
00023  * running.
00024  */
00025 
00026 static ProcessGlobalValue executableName = {
00027     0, 0, NULL, NULL, NULL, NULL, NULL
00028 };
00029 
00030 /*
00031  * The following values are used in the flags returned by Tcl_ScanElement and
00032  * used by Tcl_ConvertElement. The values TCL_DONT_USE_BRACES and
00033  * TCL_DONT_QUOTE_HASH are defined in tcl.h; make sure neither value overlaps
00034  * with any of the values below.
00035  *
00036  * TCL_DONT_USE_BRACES -        1 means the string mustn't be enclosed in
00037  *                              braces (e.g. it contains unmatched braces, or
00038  *                              ends in a backslash character, or user just
00039  *                              doesn't want braces); handle all special
00040  *                              characters by adding backslashes.
00041  * USE_BRACES -                 1 means the string contains a special
00042  *                              character that can be handled simply by
00043  *                              enclosing the entire argument in braces.
00044  * BRACES_UNMATCHED -           1 means that braces aren't properly matched in
00045  *                              the argument.
00046  * TCL_DONT_QUOTE_HASH -        1 means the caller insists that a leading hash
00047  *                              character ('#') should *not* be quoted. This
00048  *                              is appropriate when the caller can guarantee
00049  *                              the element is not the first element of a
00050  *                              list, so [eval] cannot mis-parse the element
00051  *                              as a comment.
00052  */
00053 
00054 #define USE_BRACES              2
00055 #define BRACES_UNMATCHED        4
00056 
00057 /*
00058  * The following key is used by Tcl_PrintDouble and TclPrecTraceProc to
00059  * access the precision to be used for double formatting.
00060  */
00061 
00062 static Tcl_ThreadDataKey precisionKey;
00063 
00064 /*
00065  * Prototypes for functions defined later in this file.
00066  */
00067 
00068 static void             ClearHash(Tcl_HashTable *tablePtr);
00069 static void             FreeProcessGlobalValue(ClientData clientData);
00070 static void             FreeThreadHash(ClientData clientData);
00071 static Tcl_HashTable *  GetThreadHash(Tcl_ThreadDataKey *keyPtr);
00072 static int              SetEndOffsetFromAny(Tcl_Interp* interp,
00073                             Tcl_Obj* objPtr);
00074 static void             UpdateStringOfEndOffset(Tcl_Obj* objPtr);
00075 
00076 /*
00077  * The following is the Tcl object type definition for an object that
00078  * represents a list index in the form, "end-offset". It is used as a
00079  * performance optimization in TclGetIntForIndex. The internal rep is an
00080  * integer, so no memory management is required for it.
00081  */
00082 
00083 Tcl_ObjType tclEndOffsetType = {
00084     "end-offset",                       /* name */
00085     NULL,                               /* freeIntRepProc */
00086     NULL,                               /* dupIntRepProc */
00087     UpdateStringOfEndOffset,            /* updateStringProc */
00088     SetEndOffsetFromAny
00089 };
00090 
00091 /*
00092  *----------------------------------------------------------------------
00093  *
00094  * TclFindElement --
00095  *
00096  *      Given a pointer into a Tcl list, locate the first (or next) element in
00097  *      the list.
00098  *
00099  * Results:
00100  *      The return value is normally TCL_OK, which means that the element was
00101  *      successfully located. If TCL_ERROR is returned it means that list
00102  *      didn't have proper list structure; the interp's result contains a more
00103  *      detailed error message.
00104  *
00105  *      If TCL_OK is returned, then *elementPtr will be set to point to the
00106  *      first element of list, and *nextPtr will be set to point to the
00107  *      character just after any white space following the last character
00108  *      that's part of the element. If this is the last argument in the list,
00109  *      then *nextPtr will point just after the last character in the list
00110  *      (i.e., at the character at list+listLength). If sizePtr is non-NULL,
00111  *      *sizePtr is filled in with the number of characters in the element. If
00112  *      the element is in braces, then *elementPtr will point to the character
00113  *      after the opening brace and *sizePtr will not include either of the
00114  *      braces. If there isn't an element in the list, *sizePtr will be zero,
00115  *      and both *elementPtr and *termPtr will point just after the last
00116  *      character in the list. Note: this function does NOT collapse backslash
00117  *      sequences.
00118  *
00119  * Side effects:
00120  *      None.
00121  *
00122  *----------------------------------------------------------------------
00123  */
00124 
00125 int
00126 TclFindElement(
00127     Tcl_Interp *interp,         /* Interpreter to use for error reporting. If
00128                                  * NULL, then no error message is left after
00129                                  * errors. */
00130     CONST char *list,           /* Points to the first byte of a string
00131                                  * containing a Tcl list with zero or more
00132                                  * elements (possibly in braces). */
00133     int listLength,             /* Number of bytes in the list's string. */
00134     CONST char **elementPtr,    /* Where to put address of first significant
00135                                  * character in first element of list. */
00136     CONST char **nextPtr,       /* Fill in with location of character just
00137                                  * after all white space following end of
00138                                  * argument (next arg or end of list). */
00139     int *sizePtr,               /* If non-zero, fill in with size of
00140                                  * element. */
00141     int *bracePtr)              /* If non-zero, fill in with non-zero/zero to
00142                                  * indicate that arg was/wasn't in braces. */
00143 {
00144     CONST char *p = list;
00145     CONST char *elemStart;      /* Points to first byte of first element. */
00146     CONST char *limit;          /* Points just after list's last byte. */
00147     int openBraces = 0;         /* Brace nesting level during parse. */
00148     int inQuotes = 0;
00149     int size = 0;               /* lint. */
00150     int numChars;
00151     CONST char *p2;
00152 
00153     /*
00154      * Skim off leading white space and check for an opening brace or quote.
00155      * We treat embedded NULLs in the list as bytes belonging to a list
00156      * element.
00157      */
00158 
00159     limit = (list + listLength);
00160     while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */
00161         p++;
00162     }
00163     if (p == limit) {           /* no element found */
00164         elemStart = limit;
00165         goto done;
00166     }
00167 
00168     if (*p == '{') {
00169         openBraces = 1;
00170         p++;
00171     } else if (*p == '"') {
00172         inQuotes = 1;
00173         p++;
00174     }
00175     elemStart = p;
00176     if (bracePtr != 0) {
00177         *bracePtr = openBraces;
00178     }
00179 
00180     /*
00181      * Find element's end (a space, close brace, or the end of the string).
00182      */
00183 
00184     while (p < limit) {
00185         switch (*p) {
00186             /*
00187              * Open brace: don't treat specially unless the element is in
00188              * braces. In this case, keep a nesting count.
00189              */
00190 
00191         case '{':
00192             if (openBraces != 0) {
00193                 openBraces++;
00194             }
00195             break;
00196 
00197             /*
00198              * Close brace: if element is in braces, keep nesting count and
00199              * quit when the last close brace is seen.
00200              */
00201 
00202         case '}':
00203             if (openBraces > 1) {
00204                 openBraces--;
00205             } else if (openBraces == 1) {
00206                 size = (p - elemStart);
00207                 p++;
00208                 if ((p >= limit)
00209                         || isspace(UCHAR(*p))) {        /* INTL: ISO space. */
00210                     goto done;
00211                 }
00212 
00213                 /*
00214                  * Garbage after the closing brace; return an error.
00215                  */
00216 
00217                 if (interp != NULL) {
00218                     p2 = p;
00219                     while ((p2 < limit)
00220                             && (!isspace(UCHAR(*p2)))   /* INTL: ISO space. */
00221                             && (p2 < p+20)) {
00222                         p2++;
00223                     }
00224                     Tcl_SetObjResult(interp, Tcl_ObjPrintf(
00225                             "list element in braces followed by \"%.*s\" "
00226                             "instead of space", (int) (p2-p), p));
00227                 }
00228                 return TCL_ERROR;
00229             }
00230             break;
00231 
00232             /*
00233              * Backslash: skip over everything up to the end of the backslash
00234              * sequence.
00235              */
00236 
00237         case '\\':
00238             Tcl_UtfBackslash(p, &numChars, NULL);
00239             p += (numChars - 1);
00240             break;
00241 
00242             /*
00243              * Space: ignore if element is in braces or quotes; otherwise
00244              * terminate element.
00245              */
00246 
00247         case ' ':
00248         case '\f':
00249         case '\n':
00250         case '\r':
00251         case '\t':
00252         case '\v':
00253             if ((openBraces == 0) && !inQuotes) {
00254                 size = (p - elemStart);
00255                 goto done;
00256             }
00257             break;
00258 
00259             /*
00260              * Double-quote: if element is in quotes then terminate it.
00261              */
00262 
00263         case '"':
00264             if (inQuotes) {
00265                 size = (p - elemStart);
00266                 p++;
00267                 if ((p >= limit)
00268                         || isspace(UCHAR(*p))) {        /* INTL: ISO space */
00269                     goto done;
00270                 }
00271 
00272                 /*
00273                  * Garbage after the closing quote; return an error.
00274                  */
00275 
00276                 if (interp != NULL) {
00277                     p2 = p;
00278                     while ((p2 < limit)
00279                             && (!isspace(UCHAR(*p2)))   /* INTL: ISO space */
00280                             && (p2 < p+20)) {
00281                         p2++;
00282                     }
00283                     Tcl_SetObjResult(interp, Tcl_ObjPrintf(
00284                             "list element in quotes followed by \"%.*s\" "
00285                             "instead of space", (int) (p2-p), p));
00286                 }
00287                 return TCL_ERROR;
00288             }
00289             break;
00290         }
00291         p++;
00292     }
00293 
00294     /*
00295      * End of list: terminate element.
00296      */
00297 
00298     if (p == limit) {
00299         if (openBraces != 0) {
00300             if (interp != NULL) {
00301                 Tcl_SetResult(interp, "unmatched open brace in list",
00302                         TCL_STATIC);
00303             }
00304             return TCL_ERROR;
00305         } else if (inQuotes) {
00306             if (interp != NULL) {
00307                 Tcl_SetResult(interp, "unmatched open quote in list",
00308                         TCL_STATIC);
00309             }
00310             return TCL_ERROR;
00311         }
00312         size = (p - elemStart);
00313     }
00314 
00315   done:
00316     while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */
00317         p++;
00318     }
00319     *elementPtr = elemStart;
00320     *nextPtr = p;
00321     if (sizePtr != 0) {
00322         *sizePtr = size;
00323     }
00324     return TCL_OK;
00325 }
00326 
00327 /*
00328  *----------------------------------------------------------------------
00329  *
00330  * TclCopyAndCollapse --
00331  *
00332  *      Copy a string and eliminate any backslashes that aren't in braces.
00333  *
00334  * Results:
00335  *      Count characters get copied from src to dst. Along the way, if
00336  *      backslash sequences are found outside braces, the backslashes are
00337  *      eliminated in the copy. After scanning count chars from source, a null
00338  *      character is placed at the end of dst. Returns the number of
00339  *      characters that got copied.
00340  *
00341  * Side effects:
00342  *      None.
00343  *
00344  *----------------------------------------------------------------------
00345  */
00346 
00347 int
00348 TclCopyAndCollapse(
00349     int count,                  /* Number of characters to copy from src. */
00350     CONST char *src,            /* Copy from here... */
00351     char *dst)                  /* ... to here. */
00352 {
00353     register char c;
00354     int numRead;
00355     int newCount = 0;
00356     int backslashCount;
00357 
00358     for (c = *src;  count > 0;  src++, c = *src, count--) {
00359         if (c == '\\') {
00360             backslashCount = Tcl_UtfBackslash(src, &numRead, dst);
00361             dst += backslashCount;
00362             newCount += backslashCount;
00363             src += numRead-1;
00364             count -= numRead-1;
00365         } else {
00366             *dst = c;
00367             dst++;
00368             newCount++;
00369         }
00370     }
00371     *dst = 0;
00372     return newCount;
00373 }
00374 
00375 /*
00376  *----------------------------------------------------------------------
00377  *
00378  * Tcl_SplitList --
00379  *
00380  *      Splits a list up into its constituent fields.
00381  *
00382  * Results
00383  *      The return value is normally TCL_OK, which means that the list was
00384  *      successfully split up. If TCL_ERROR is returned, it means that "list"
00385  *      didn't have proper list structure; the interp's result will contain a
00386  *      more detailed error message.
00387  *
00388  *      *argvPtr will be filled in with the address of an array whose elements
00389  *      point to the elements of list, in order. *argcPtr will get filled in
00390  *      with the number of valid elements in the array. A single block of
00391  *      memory is dynamically allocated to hold both the argv array and a copy
00392  *      of the list (with backslashes and braces removed in the standard way).
00393  *      The caller must eventually free this memory by calling free() on
00394  *      *argvPtr. Note: *argvPtr and *argcPtr are only modified if the
00395  *      function returns normally.
00396  *
00397  * Side effects:
00398  *      Memory is allocated.
00399  *
00400  *----------------------------------------------------------------------
00401  */
00402 
00403 int
00404 Tcl_SplitList(
00405     Tcl_Interp *interp,         /* Interpreter to use for error reporting. If
00406                                  * NULL, no error message is left. */
00407     CONST char *list,           /* Pointer to string with list structure. */
00408     int *argcPtr,               /* Pointer to location to fill in with the
00409                                  * number of elements in the list. */
00410     CONST char ***argvPtr)      /* Pointer to place to store pointer to array
00411                                  * of pointers to list elements. */
00412 {
00413     CONST char **argv, *l, *element;
00414     char *p;
00415     int length, size, i, result, elSize, brace;
00416 
00417     /*
00418      * Figure out how much space to allocate. There must be enough space for
00419      * both the array of pointers and also for a copy of the list. To estimate
00420      * the number of pointers needed, count the number of space characters in
00421      * the list.
00422      */
00423 
00424     for (size = 2, l = list; *l != 0; l++) {
00425         if (isspace(UCHAR(*l))) {                       /* INTL: ISO space. */
00426             size++;
00427 
00428             /*
00429              * Consecutive space can only count as a single list delimiter.
00430              */
00431 
00432             while (1) {
00433                 char next = *(l + 1);
00434 
00435                 if (next == '\0') {
00436                     break;
00437                 }
00438                 ++l;
00439                 if (isspace(UCHAR(next))) {             /* INTL: ISO space. */
00440                     continue;
00441                 }
00442                 break;
00443             }
00444         }
00445     }
00446     length = l - list;
00447     argv = (CONST char **) ckalloc((unsigned)
00448             ((size * sizeof(char *)) + length + 1));
00449     for (i = 0, p = ((char *) argv) + size*sizeof(char *);
00450             *list != 0;  i++) {
00451         CONST char *prevList = list;
00452 
00453         result = TclFindElement(interp, list, length, &element, &list,
00454                 &elSize, &brace);
00455         length -= (list - prevList);
00456         if (result != TCL_OK) {
00457             ckfree((char *) argv);
00458             return result;
00459         }
00460         if (*element == 0) {
00461             break;
00462         }
00463         if (i >= size) {
00464             ckfree((char *) argv);
00465             if (interp != NULL) {
00466                 Tcl_SetResult(interp, "internal error in Tcl_SplitList",
00467                         TCL_STATIC);
00468             }
00469             return TCL_ERROR;
00470         }
00471         argv[i] = p;
00472         if (brace) {
00473             memcpy(p, element, (size_t) elSize);
00474             p += elSize;
00475             *p = 0;
00476             p++;
00477         } else {
00478             TclCopyAndCollapse(elSize, element, p);
00479             p += elSize+1;
00480         }
00481     }
00482 
00483     argv[i] = NULL;
00484     *argvPtr = argv;
00485     *argcPtr = i;
00486     return TCL_OK;
00487 }
00488 
00489 /*
00490  *----------------------------------------------------------------------
00491  *
00492  * TclMarkList --
00493  *
00494  *      Marks the locations within a string where list elements start and
00495  *      computes where they end.
00496  *
00497  * Results
00498  *      The return value is normally TCL_OK, which means that the list was
00499  *      successfully split up. If TCL_ERROR is returned, it means that "list"
00500  *      didn't have proper list structure; the interp's result will contain a
00501  *      more detailed error message.
00502  *
00503  *      *argvPtr will be filled in with the address of an array whose elements
00504  *      point to the places where the elements of list start, in order.
00505  *      *argcPtr will get filled in with the number of valid elements in the
00506  *      array. *argszPtr will get filled in with the address of an array whose
00507  *      elements are the lengths of the elements of the list, in order.
00508  *      Note: *argvPtr, *argcPtr and *argszPtr are only modified if the
00509  *      function returns normally.
00510  *
00511  * Side effects:
00512  *      Memory is allocated.
00513  *
00514  *----------------------------------------------------------------------
00515  */
00516 
00517 int
00518 TclMarkList(
00519     Tcl_Interp *interp,         /* Interpreter to use for error reporting. If
00520                                  * NULL, no error message is left. */
00521     CONST char *list,           /* Pointer to string with list structure. */
00522     CONST char *end,            /* Pointer to first char after the list. */
00523     int *argcPtr,               /* Pointer to location to fill in with the
00524                                  * number of elements in the list. */
00525     CONST int **argszPtr,       /* Pointer to place to store length of list
00526                                  * elements. */
00527     CONST char ***argvPtr)      /* Pointer to place to store pointer to array
00528                                  * of pointers to list elements. */
00529 {
00530     CONST char **argv, *l, *element;
00531     int *argn, length, size, i, result, elSize, brace;
00532 
00533     /*
00534      * Figure out how much space to allocate. There must be enough space for
00535      * the array of pointers and lengths. To estimate the number of pointers
00536      * needed, count the number of whitespace characters in the list.
00537      */
00538 
00539     for (size=2, l=list ; l!=end ; l++) {
00540         if (isspace(UCHAR(*l))) {                       /* INTL: ISO space. */
00541             size++;
00542 
00543             /*
00544              * Consecutive space can only count as a single list delimiter.
00545              */
00546 
00547             while (1) {
00548                 char next = *(l + 1);
00549 
00550                 if ((l+1) == end) {
00551                     break;
00552                 }
00553                 ++l;
00554                 if (isspace(UCHAR(next))) {             /* INTL: ISO space. */
00555                     continue;
00556                 }
00557                 break;
00558             }
00559         }
00560     }
00561     length = l - list;
00562     argv = (CONST char **) ckalloc((unsigned) size * sizeof(char *));
00563     argn = (int *) ckalloc((unsigned) size * sizeof(int *));
00564 
00565     for (i = 0; list != end;  i++) {
00566         CONST char *prevList = list;
00567 
00568         result = TclFindElement(interp, list, length, &element, &list,
00569                 &elSize, &brace);
00570         length -= (list - prevList);
00571         if (result != TCL_OK) {
00572             ckfree((char *) argv);
00573             ckfree((char *) argn);
00574             return result;
00575         }
00576         if (*element == 0) {
00577             break;
00578         }
00579         if (i >= size) {
00580             ckfree((char *) argv);
00581             ckfree((char *) argn);
00582             if (interp != NULL) {
00583                 Tcl_SetResult(interp, "internal error in TclMarkList",
00584                         TCL_STATIC);
00585             }
00586             return TCL_ERROR;
00587         }
00588         argv[i] = element;
00589         argn[i] = elSize;
00590     }
00591 
00592     argv[i] = NULL;
00593     argn[i] = 0;
00594     *argvPtr = argv;
00595     *argszPtr = argn;
00596     *argcPtr = i;
00597     return TCL_OK;
00598 }
00599 
00600 /*
00601  *----------------------------------------------------------------------
00602  *
00603  * Tcl_ScanElement --
00604  *
00605  *      This function is a companion function to Tcl_ConvertElement. It scans
00606  *      a string to see what needs to be done to it (e.g. add backslashes or
00607  *      enclosing braces) to make the string into a valid Tcl list element.
00608  *
00609  * Results:
00610  *      The return value is an overestimate of the number of characters that
00611  *      will be needed by Tcl_ConvertElement to produce a valid list element
00612  *      from string. The word at *flagPtr is filled in with a value needed by
00613  *      Tcl_ConvertElement when doing the actual conversion.
00614  *
00615  * Side effects:
00616  *      None.
00617  *
00618  *----------------------------------------------------------------------
00619  */
00620 
00621 int
00622 Tcl_ScanElement(
00623     register CONST char *string,/* String to convert to list element. */
00624     register int *flagPtr)      /* Where to store information to guide
00625                                  * Tcl_ConvertCountedElement. */
00626 {
00627     return Tcl_ScanCountedElement(string, -1, flagPtr);
00628 }
00629 
00630 /*
00631  *----------------------------------------------------------------------
00632  *
00633  * Tcl_ScanCountedElement --
00634  *
00635  *      This function is a companion function to Tcl_ConvertCountedElement. It
00636  *      scans a string to see what needs to be done to it (e.g. add
00637  *      backslashes or enclosing braces) to make the string into a valid Tcl
00638  *      list element. If length is -1, then the string is scanned up to the
00639  *      first null byte.
00640  *
00641  * Results:
00642  *      The return value is an overestimate of the number of characters that
00643  *      will be needed by Tcl_ConvertCountedElement to produce a valid list
00644  *      element from string. The word at *flagPtr is filled in with a value
00645  *      needed by Tcl_ConvertCountedElement when doing the actual conversion.
00646  *
00647  * Side effects:
00648  *      None.
00649  *
00650  *----------------------------------------------------------------------
00651  */
00652 
00653 int
00654 Tcl_ScanCountedElement(
00655     CONST char *string,         /* String to convert to Tcl list element. */
00656     int length,                 /* Number of bytes in string, or -1. */
00657     int *flagPtr)               /* Where to store information to guide
00658                                  * Tcl_ConvertElement. */
00659 {
00660     int flags, nestingLevel;
00661     register CONST char *p, *lastChar;
00662 
00663     /*
00664      * This function and Tcl_ConvertElement together do two things:
00665      *
00666      * 1. They produce a proper list, one that will yield back the argument
00667      *    strings when evaluated or when disassembled with Tcl_SplitList. This
00668      *    is the most important thing.
00669      *
00670      * 2. They try to produce legible output, which means minimizing the use
00671      *    of backslashes (using braces instead). However, there are some
00672      *    situations where backslashes must be used (e.g. an element like
00673      *    "{abc": the leading brace will have to be backslashed. For each
00674      *    element, one of three things must be done:
00675      *
00676      *    (a) Use the element as-is (it doesn't contain any special
00677      *        characters). This is the most desirable option.
00678      *
00679      *    (b) Enclose the element in braces, but leave the contents alone.
00680      *        This happens if the element contains embedded space, or if it
00681      *        contains characters with special interpretation ($, [, ;, or \),
00682      *        or if it starts with a brace or double-quote, or if there are no
00683      *        characters in the element.
00684      *
00685      *    (c) Don't enclose the element in braces, but add backslashes to
00686      *        prevent special interpretation of special characters. This is a
00687      *        last resort used when the argument would normally fall under
00688      *        case (b) but contains unmatched braces. It also occurs if the
00689      *        last character of the argument is a backslash or if the element
00690      *        contains a backslash followed by newline.
00691      *
00692      * The function figures out how many bytes will be needed to store the
00693      * result (actually, it overestimates). It also collects information about
00694      * the element in the form of a flags word.
00695      *
00696      * Note: list elements produced by this function and
00697      * Tcl_ConvertCountedElement must have the property that they can be
00698      * enclosing in curly braces to make sub-lists. This means, for example,
00699      * that we must not leave unmatched curly braces in the resulting list
00700      * element. This property is necessary in order for functions like
00701      * Tcl_DStringStartSublist to work.
00702      */
00703 
00704     nestingLevel = 0;
00705     flags = 0;
00706     if (string == NULL) {
00707         string = "";
00708     }
00709     if (length == -1) {
00710         length = strlen(string);
00711     }
00712     lastChar = string + length;
00713     p = string;
00714     if ((p == lastChar) || (*p == '{') || (*p == '"')) {
00715         flags |= USE_BRACES;
00716     }
00717     for (; p < lastChar; p++) {
00718         switch (*p) {
00719         case '{':
00720             nestingLevel++;
00721             break;
00722         case '}':
00723             nestingLevel--;
00724             if (nestingLevel < 0) {
00725                 flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
00726             }
00727             break;
00728         case '[':
00729         case '$':
00730         case ';':
00731         case ' ':
00732         case '\f':
00733         case '\n':
00734         case '\r':
00735         case '\t':
00736         case '\v':
00737             flags |= USE_BRACES;
00738             break;
00739         case '\\':
00740             if ((p+1 == lastChar) || (p[1] == '\n')) {
00741                 flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
00742             } else {
00743                 int size;
00744 
00745                 Tcl_UtfBackslash(p, &size, NULL);
00746                 p += size-1;
00747                 flags |= USE_BRACES;
00748             }
00749             break;
00750         }
00751     }
00752     if (nestingLevel != 0) {
00753         flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
00754     }
00755     *flagPtr = flags;
00756 
00757     /*
00758      * Allow enough space to backslash every character plus leave two spaces
00759      * for braces.
00760      */
00761 
00762     return 2*(p-string) + 2;
00763 }
00764 
00765 /*
00766  *----------------------------------------------------------------------
00767  *
00768  * Tcl_ConvertElement --
00769  *
00770  *      This is a companion function to Tcl_ScanElement. Given the information
00771  *      produced by Tcl_ScanElement, this function converts a string to a list
00772  *      element equal to that string.
00773  *
00774  * Results:
00775  *      Information is copied to *dst in the form of a list element identical
00776  *      to src (i.e. if Tcl_SplitList is applied to dst it will produce a
00777  *      string identical to src). The return value is a count of the number of
00778  *      characters copied (not including the terminating NULL character).
00779  *
00780  * Side effects:
00781  *      None.
00782  *
00783  *----------------------------------------------------------------------
00784  */
00785 
00786 int
00787 Tcl_ConvertElement(
00788     register CONST char *src,   /* Source information for list element. */
00789     register char *dst,         /* Place to put list-ified element. */
00790     register int flags)         /* Flags produced by Tcl_ScanElement. */
00791 {
00792     return Tcl_ConvertCountedElement(src, -1, dst, flags);
00793 }
00794 
00795 /*
00796  *----------------------------------------------------------------------
00797  *
00798  * Tcl_ConvertCountedElement --
00799  *
00800  *      This is a companion function to Tcl_ScanCountedElement. Given the
00801  *      information produced by Tcl_ScanCountedElement, this function converts
00802  *      a string to a list element equal to that string.
00803  *
00804  * Results:
00805  *      Information is copied to *dst in the form of a list element identical
00806  *      to src (i.e. if Tcl_SplitList is applied to dst it will produce a
00807  *      string identical to src). The return value is a count of the number of
00808  *      characters copied (not including the terminating NULL character).
00809  *
00810  * Side effects:
00811  *      None.
00812  *
00813  *----------------------------------------------------------------------
00814  */
00815 
00816 int
00817 Tcl_ConvertCountedElement(
00818     register CONST char *src,   /* Source information for list element. */
00819     int length,                 /* Number of bytes in src, or -1. */
00820     char *dst,                  /* Place to put list-ified element. */
00821     int flags)                  /* Flags produced by Tcl_ScanElement. */
00822 {
00823     register char *p = dst;
00824     register CONST char *lastChar;
00825 
00826     /*
00827      * See the comment block at the beginning of the Tcl_ScanElement code for
00828      * details of how this works.
00829      */
00830 
00831     if (src && length == -1) {
00832         length = strlen(src);
00833     }
00834     if ((src == NULL) || (length == 0)) {
00835         p[0] = '{';
00836         p[1] = '}';
00837         p[2] = 0;
00838         return 2;
00839     }
00840     lastChar = src + length;
00841     if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) {
00842         flags |= USE_BRACES;
00843     }
00844     if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
00845         *p = '{';
00846         p++;
00847         for (; src != lastChar; src++, p++) {
00848             *p = *src;
00849         }
00850         *p = '}';
00851         p++;
00852     } else {
00853         if (*src == '{') {
00854             /*
00855              * Can't have a leading brace unless the whole element is enclosed
00856              * in braces. Add a backslash before the brace. Furthermore, this
00857              * may destroy the balance between open and close braces, so set
00858              * BRACES_UNMATCHED.
00859              */
00860 
00861             p[0] = '\\';
00862             p[1] = '{';
00863             p += 2;
00864             src++;
00865             flags |= BRACES_UNMATCHED;
00866         } else if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) {
00867             /*
00868              * Leading '#' could be seen by [eval] as the start of a comment,
00869              * if on the first element of a list, so quote it.
00870              */
00871 
00872             p[0] = '\\';
00873             p[1] = '#';
00874             p += 2;
00875             src++;
00876         }
00877         for (; src != lastChar; src++) {
00878             switch (*src) {
00879             case ']':
00880             case '[':
00881             case '$':
00882             case ';':
00883             case ' ':
00884             case '\\':
00885             case '"':
00886                 *p = '\\';
00887                 p++;
00888                 break;
00889             case '{':
00890             case '}':
00891                 /*
00892                  * It may not seem necessary to backslash braces, but it is.
00893                  * The reason for this is that the resulting list element may
00894                  * actually be an element of a sub-list enclosed in braces
00895                  * (e.g. if Tcl_DStringStartSublist has been invoked), so
00896                  * there may be a brace mismatch if the braces aren't
00897                  * backslashed.
00898                  */
00899 
00900                 if (flags & BRACES_UNMATCHED) {
00901                     *p = '\\';
00902                     p++;
00903                 }
00904                 break;
00905             case '\f':
00906                 *p = '\\';
00907                 p++;
00908                 *p = 'f';
00909                 p++;
00910                 continue;
00911             case '\n':
00912                 *p = '\\';
00913                 p++;
00914                 *p = 'n';
00915                 p++;
00916                 continue;
00917             case '\r':
00918                 *p = '\\';
00919                 p++;
00920                 *p = 'r';
00921                 p++;
00922                 continue;
00923             case '\t':
00924                 *p = '\\';
00925                 p++;
00926                 *p = 't';
00927                 p++;
00928                 continue;
00929             case '\v':
00930                 *p = '\\';
00931                 p++;
00932                 *p = 'v';
00933                 p++;
00934                 continue;
00935             }
00936             *p = *src;
00937             p++;
00938         }
00939     }
00940     *p = '\0';
00941     return p-dst;
00942 }
00943 
00944 /*
00945  *----------------------------------------------------------------------
00946  *
00947  * Tcl_Merge --
00948  *
00949  *      Given a collection of strings, merge them together into a single
00950  *      string that has proper Tcl list structured (i.e. Tcl_SplitList may be
00951  *      used to retrieve strings equal to the original elements, and Tcl_Eval
00952  *      will parse the string back into its original elements).
00953  *
00954  * Results:
00955  *      The return value is the address of a dynamically-allocated string
00956  *      containing the merged list.
00957  *
00958  * Side effects:
00959  *      None.
00960  *
00961  *----------------------------------------------------------------------
00962  */
00963 
00964 char *
00965 Tcl_Merge(
00966     int argc,                   /* How many strings to merge. */
00967     CONST char * CONST *argv)   /* Array of string values. */
00968 {
00969 #   define LOCAL_SIZE 20
00970     int localFlags[LOCAL_SIZE], *flagPtr;
00971     int numChars;
00972     char *result;
00973     char *dst;
00974     int i;
00975 
00976     /*
00977      * Pass 1: estimate space, gather flags.
00978      */
00979 
00980     if (argc <= LOCAL_SIZE) {
00981         flagPtr = localFlags;
00982     } else {
00983         flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
00984     }
00985     numChars = 1;
00986     for (i = 0; i < argc; i++) {
00987         numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
00988     }
00989 
00990     /*
00991      * Pass two: copy into the result area.
00992      */
00993 
00994     result = (char *) ckalloc((unsigned) numChars);
00995     dst = result;
00996     for (i = 0; i < argc; i++) {
00997         numChars = Tcl_ConvertElement(argv[i], dst,
00998                 flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH));
00999         dst += numChars;
01000         *dst = ' ';
01001         dst++;
01002     }
01003     if (dst == result) {
01004         *dst = 0;
01005     } else {
01006         dst[-1] = 0;
01007     }
01008 
01009     if (flagPtr != localFlags) {
01010         ckfree((char *) flagPtr);
01011     }
01012     return result;
01013 }
01014 
01015 /*
01016  *----------------------------------------------------------------------
01017  *
01018  * Tcl_Backslash --
01019  *
01020  *      Figure out how to handle a backslash sequence.
01021  *
01022  * Results:
01023  *      The return value is the character that should be substituted in place
01024  *      of the backslash sequence that starts at src. If readPtr isn't NULL
01025  *      then it is filled in with a count of the number of characters in the
01026  *      backslash sequence.
01027  *
01028  * Side effects:
01029  *      None.
01030  *
01031  *----------------------------------------------------------------------
01032  */
01033 
01034 char
01035 Tcl_Backslash(
01036     CONST char *src,            /* Points to the backslash character of a
01037                                  * backslash sequence. */
01038     int *readPtr)               /* Fill in with number of characters read from
01039                                  * src, unless NULL. */
01040 {
01041     char buf[TCL_UTF_MAX];
01042     Tcl_UniChar ch;
01043 
01044     Tcl_UtfBackslash(src, readPtr, buf);
01045     TclUtfToUniChar(buf, &ch);
01046     return (char) ch;
01047 }
01048 
01049 /*
01050  *----------------------------------------------------------------------
01051  *
01052  * Tcl_Concat --
01053  *
01054  *      Concatenate a set of strings into a single large string.
01055  *
01056  * Results:
01057  *      The return value is dynamically-allocated string containing a
01058  *      concatenation of all the strings in argv, with spaces between the
01059  *      original argv elements.
01060  *
01061  * Side effects:
01062  *      Memory is allocated for the result; the caller is responsible for
01063  *      freeing the memory.
01064  *
01065  *----------------------------------------------------------------------
01066  */
01067 
01068 char *
01069 Tcl_Concat(
01070     int argc,                   /* Number of strings to concatenate. */
01071     CONST char * CONST *argv)   /* Array of strings to concatenate. */
01072 {
01073     int totalSize, i;
01074     char *p;
01075     char *result;
01076 
01077     for (totalSize = 1, i = 0; i < argc; i++) {
01078         totalSize += strlen(argv[i]) + 1;
01079     }
01080     result = (char *) ckalloc((unsigned) totalSize);
01081     if (argc == 0) {
01082         *result = '\0';
01083         return result;
01084     }
01085     for (p = result, i = 0; i < argc; i++) {
01086         CONST char *element;
01087         int length;
01088 
01089         /*
01090          * Clip white space off the front and back of the string to generate a
01091          * neater result, and ignore any empty elements.
01092          */
01093 
01094         element = argv[i];
01095         while (isspace(UCHAR(*element))) { /* INTL: ISO space. */
01096             element++;
01097         }
01098         for (length = strlen(element);
01099                 (length > 0)
01100                 && (isspace(UCHAR(element[length-1]))) /* INTL: ISO space. */
01101                 && ((length < 2) || (element[length-2] != '\\'));
01102                 length--) {
01103             /* Null loop body. */
01104         }
01105         if (length == 0) {
01106             continue;
01107         }
01108         memcpy(p, element, (size_t) length);
01109         p += length;
01110         *p = ' ';
01111         p++;
01112     }
01113     if (p != result) {
01114         p[-1] = 0;
01115     } else {
01116         *p = 0;
01117     }
01118     return result;
01119 }
01120 
01121 /*
01122  *----------------------------------------------------------------------
01123  *
01124  * Tcl_ConcatObj --
01125  *
01126  *      Concatenate the strings from a set of objects into a single string
01127  *      object with spaces between the original strings.
01128  *
01129  * Results:
01130  *      The return value is a new string object containing a concatenation of
01131  *      the strings in objv. Its ref count is zero.
01132  *
01133  * Side effects:
01134  *      A new object is created.
01135  *
01136  *----------------------------------------------------------------------
01137  */
01138 
01139 Tcl_Obj *
01140 Tcl_ConcatObj(
01141     int objc,                   /* Number of objects to concatenate. */
01142     Tcl_Obj *CONST objv[])      /* Array of objects to concatenate. */
01143 {
01144     int allocSize, finalSize, length, elemLength, i;
01145     char *p;
01146     char *element;
01147     char *concatStr;
01148     Tcl_Obj *objPtr, *resPtr;
01149 
01150     /*
01151      * Check first to see if all the items are of list type or empty. If so,
01152      * we will concat them together as lists, and return a list object. This
01153      * is only valid when the lists have no current string representation,
01154      * since we don't know what the original type was. An original string rep
01155      * may have lost some whitespace info when converted which could be
01156      * important.
01157      */
01158 
01159     for (i = 0;  i < objc;  i++) {
01160         List *listRepPtr;
01161 
01162         objPtr = objv[i];
01163         if (objPtr->typePtr != &tclListType) {
01164             TclGetString(objPtr);
01165             if (objPtr->length) {
01166                 break;
01167             } else {
01168                 continue;
01169             }
01170         }
01171         listRepPtr = (List *) objPtr->internalRep.twoPtrValue.ptr1;
01172         if (objPtr->bytes != NULL && !listRepPtr->canonicalFlag) {
01173             break;
01174         }
01175     }
01176     if (i == objc) {
01177         Tcl_Obj **listv;
01178         int listc;
01179 
01180         resPtr = NULL;
01181         for (i = 0;  i < objc;  i++) {
01182             /*
01183              * Tcl_ListObjAppendList could be used here, but this saves us a
01184              * bit of type checking (since we've already done it). Use of
01185              * INT_MAX tells us to always put the new stuff on the end. It
01186              * will be set right in Tcl_ListObjReplace.
01187              * Note that all objs at this point are either lists or have an
01188              * empty string rep.
01189              */
01190 
01191             objPtr = objv[i];
01192             if (objPtr->bytes && !objPtr->length) {
01193                 continue;
01194             }
01195             TclListObjGetElements(NULL, objPtr, &listc, &listv);
01196             if (listc) {
01197                 if (resPtr) {
01198                     Tcl_ListObjReplace(NULL, resPtr, INT_MAX, 0, listc, listv);
01199                 } else {
01200                     if (Tcl_IsShared(objPtr)) {
01201                         resPtr = TclListObjCopy(NULL, objPtr);
01202                     } else {
01203                         resPtr = objPtr;
01204                     }
01205                 }
01206             }
01207         }
01208         if (!resPtr) {
01209             resPtr = Tcl_NewObj();
01210         }
01211         return resPtr;
01212     }
01213 
01214     /*
01215      * Something cannot be determined to be safe, so build the concatenation
01216      * the slow way, using the string representations.
01217      */
01218 
01219     allocSize = 0;
01220     for (i = 0;  i < objc;  i++) {
01221         objPtr = objv[i];
01222         element = TclGetStringFromObj(objPtr, &length);
01223         if ((element != NULL) && (length > 0)) {
01224             allocSize += (length + 1);
01225         }
01226     }
01227     if (allocSize == 0) {
01228         allocSize = 1;          /* enough for the NULL byte at end */
01229     }
01230 
01231     /*
01232      * Allocate storage for the concatenated result. Note that allocSize is
01233      * one more than the total number of characters, and so includes room for
01234      * the terminating NULL byte.
01235      */
01236 
01237     concatStr = ckalloc((unsigned) allocSize);
01238 
01239     /*
01240      * Now concatenate the elements. Clip white space off the front and back
01241      * to generate a neater result, and ignore any empty elements. Also put a
01242      * null byte at the end.
01243      */
01244 
01245     finalSize = 0;
01246     if (objc == 0) {
01247         *concatStr = '\0';
01248     } else {
01249         p = concatStr;
01250         for (i = 0;  i < objc;  i++) {
01251             objPtr = objv[i];
01252             element = TclGetStringFromObj(objPtr, &elemLength);
01253             while ((elemLength > 0) && (UCHAR(*element) < 127)
01254                     && isspace(UCHAR(*element))) { /* INTL: ISO C space. */
01255                 element++;
01256                 elemLength--;
01257             }
01258 
01259             /*
01260              * Trim trailing white space. But, be careful not to trim a space
01261              * character if it is preceded by a backslash: in this case it
01262              * could be significant.
01263              */
01264 
01265             while ((elemLength > 0) && (UCHAR(element[elemLength-1]) < 127)
01266                     && isspace(UCHAR(element[elemLength-1]))
01267                                                 /* INTL: ISO C space. */
01268                     && ((elemLength < 2) || (element[elemLength-2] != '\\'))) {
01269                 elemLength--;
01270             }
01271             if (elemLength == 0) {
01272                 continue;       /* nothing left of this element */
01273             }
01274             memcpy(p, element, (size_t) elemLength);
01275             p += elemLength;
01276             *p = ' ';
01277             p++;
01278             finalSize += (elemLength + 1);
01279         }
01280         if (p != concatStr) {
01281             p[-1] = 0;
01282             finalSize -= 1;     /* we overwrote the final ' ' */
01283         } else {
01284             *p = 0;
01285         }
01286     }
01287 
01288     TclNewObj(objPtr);
01289     objPtr->bytes = concatStr;
01290     objPtr->length = finalSize;
01291     return objPtr;
01292 }
01293 
01294 /*
01295  *----------------------------------------------------------------------
01296  *
01297  * Tcl_StringMatch --
01298  *
01299  *      See if a particular string matches a particular pattern.
01300  *
01301  * Results:
01302  *      The return value is 1 if string matches pattern, and 0 otherwise. The
01303  *      matching operation permits the following special characters in the
01304  *      pattern: *?\[] (see the manual entry for details on what these mean).
01305  *
01306  * Side effects:
01307  *      None.
01308  *
01309  *----------------------------------------------------------------------
01310  */
01311 
01312 int
01313 Tcl_StringMatch(
01314     CONST char *str,            /* String. */
01315     CONST char *pattern)        /* Pattern, which may contain special
01316                                  * characters. */
01317 {
01318     return Tcl_StringCaseMatch(str, pattern, 0);
01319 }
01320 
01321 /*
01322  *----------------------------------------------------------------------
01323  *
01324  * Tcl_StringCaseMatch --
01325  *
01326  *      See if a particular string matches a particular pattern. Allows case
01327  *      insensitivity.
01328  *
01329  * Results:
01330  *      The return value is 1 if string matches pattern, and 0 otherwise. The
01331  *      matching operation permits the following special characters in the
01332  *      pattern: *?\[] (see the manual entry for details on what these mean).
01333  *
01334  * Side effects:
01335  *      None.
01336  *
01337  *----------------------------------------------------------------------
01338  */
01339 
01340 int
01341 Tcl_StringCaseMatch(
01342     CONST char *str,            /* String. */
01343     CONST char *pattern,        /* Pattern, which may contain special
01344                                  * characters. */
01345     int nocase)                 /* 0 for case sensitive, 1 for insensitive */
01346 {
01347     int p, charLen;
01348     CONST char *pstart = pattern;
01349     Tcl_UniChar ch1, ch2;
01350 
01351     while (1) {
01352         p = *pattern;
01353 
01354         /*
01355          * See if we're at the end of both the pattern and the string. If so,
01356          * we succeeded. If we're at the end of the pattern but not at the end
01357          * of the string, we failed.
01358          */
01359 
01360         if (p == '\0') {
01361             return (*str == '\0');
01362         }
01363         if ((*str == '\0') && (p != '*')) {
01364             return 0;
01365         }
01366 
01367         /*
01368          * Check for a "*" as the next pattern character. It matches any
01369          * substring. We handle this by calling ourselves recursively for each
01370          * postfix of string, until either we match or we reach the end of the
01371          * string.
01372          */
01373 
01374         if (p == '*') {
01375             /*
01376              * Skip all successive *'s in the pattern
01377              */
01378 
01379             while (*(++pattern) == '*') {}
01380             p = *pattern;
01381             if (p == '\0') {
01382                 return 1;
01383             }
01384 
01385             /*
01386              * This is a special case optimization for single-byte utf.
01387              */
01388 
01389             if (UCHAR(*pattern) < 0x80) {
01390                 ch2 = (Tcl_UniChar)
01391                         (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
01392             } else {
01393                 Tcl_UtfToUniChar(pattern, &ch2);
01394                 if (nocase) {
01395                     ch2 = Tcl_UniCharToLower(ch2);
01396                 }
01397             }
01398 
01399             while (1) {
01400                 /*
01401                  * Optimization for matching - cruise through the string
01402                  * quickly if the next char in the pattern isn't a special
01403                  * character
01404                  */
01405 
01406                 if ((p != '[') && (p != '?') && (p != '\\')) {
01407                     if (nocase) {
01408                         while (*str) {
01409                             charLen = TclUtfToUniChar(str, &ch1);
01410                             if (ch2==ch1 || ch2==Tcl_UniCharToLower(ch1)) {
01411                                 break;
01412                             }
01413                             str += charLen;
01414                         }
01415                     } else {
01416                         /*
01417                          * There's no point in trying to make this code
01418                          * shorter, as the number of bytes you want to compare
01419                          * each time is non-constant.
01420                          */
01421 
01422                         while (*str) {
01423                             charLen = TclUtfToUniChar(str, &ch1);
01424                             if (ch2 == ch1) {
01425                                 break;
01426                             }
01427                             str += charLen;
01428                         }
01429                     }
01430                 }
01431                 if (Tcl_StringCaseMatch(str, pattern, nocase)) {
01432                     return 1;
01433                 }
01434                 if (*str == '\0') {
01435                     return 0;
01436                 }
01437                 str += TclUtfToUniChar(str, &ch1);
01438             }
01439         }
01440 
01441         /*
01442          * Check for a "?" as the next pattern character. It matches any
01443          * single character.
01444          */
01445 
01446         if (p == '?') {
01447             pattern++;
01448             str += TclUtfToUniChar(str, &ch1);
01449             continue;
01450         }
01451 
01452         /*
01453          * Check for a "[" as the next pattern character. It is followed by a
01454          * list of characters that are acceptable, or by a range (two
01455          * characters separated by "-").
01456          */
01457 
01458         if (p == '[') {
01459             Tcl_UniChar startChar, endChar;
01460 
01461             pattern++;
01462             if (UCHAR(*str) < 0x80) {
01463                 ch1 = (Tcl_UniChar)
01464                         (nocase ? tolower(UCHAR(*str)) : UCHAR(*str));
01465                 str++;
01466             } else {
01467                 str += Tcl_UtfToUniChar(str, &ch1);
01468                 if (nocase) {
01469                     ch1 = Tcl_UniCharToLower(ch1);
01470                 }
01471             }
01472             while (1) {
01473                 if ((*pattern == ']') || (*pattern == '\0')) {
01474                     return 0;
01475                 }
01476                 if (UCHAR(*pattern) < 0x80) {
01477                     startChar = (Tcl_UniChar) (nocase
01478                             ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
01479                     pattern++;
01480                 } else {
01481                     pattern += Tcl_UtfToUniChar(pattern, &startChar);
01482                     if (nocase) {
01483                         startChar = Tcl_UniCharToLower(startChar);
01484                     }
01485                 }
01486                 if (*pattern == '-') {
01487                     pattern++;
01488                     if (*pattern == '\0') {
01489                         return 0;
01490                     }
01491                     if (UCHAR(*pattern) < 0x80) {
01492                         endChar = (Tcl_UniChar) (nocase
01493                                 ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
01494                         pattern++;
01495                     } else {
01496                         pattern += Tcl_UtfToUniChar(pattern, &endChar);
01497                         if (nocase) {
01498                             endChar = Tcl_UniCharToLower(endChar);
01499                         }
01500                     }
01501                     if (((startChar <= ch1) && (ch1 <= endChar))
01502                             || ((endChar <= ch1) && (ch1 <= startChar))) {
01503                         /*
01504                          * Matches ranges of form [a-z] or [z-a].
01505                          */
01506 
01507                         break;
01508                     }
01509                 } else if (startChar == ch1) {
01510                     break;
01511                 }
01512             }
01513             while (*pattern != ']') {
01514                 if (*pattern == '\0') {
01515                     pattern = Tcl_UtfPrev(pattern, pstart);
01516                     break;
01517                 }
01518                 pattern++;
01519             }
01520             pattern++;
01521             continue;
01522         }
01523 
01524         /*
01525          * If the next pattern character is '\', just strip off the '\' so we
01526          * do exact matching on the character that follows.
01527          */
01528 
01529         if (p == '\\') {
01530             pattern++;
01531             if (*pattern == '\0') {
01532                 return 0;
01533             }
01534         }
01535 
01536         /*
01537          * There's no special character. Just make sure that the next bytes of
01538          * each string match.
01539          */
01540 
01541         str += TclUtfToUniChar(str, &ch1);
01542         pattern += TclUtfToUniChar(pattern, &ch2);
01543         if (nocase) {
01544             if (Tcl_UniCharToLower(ch1) != Tcl_UniCharToLower(ch2)) {
01545                 return 0;
01546             }
01547         } else if (ch1 != ch2) {
01548             return 0;
01549         }
01550     }
01551 }
01552 
01553 /*
01554  *----------------------------------------------------------------------
01555  *
01556  * TclByteArrayMatch --
01557  *
01558  *      See if a particular string matches a particular pattern.  Does not
01559  *      allow for case insensitivity.
01560  *      Parallels tclUtf.c:TclUniCharMatch, adjusted for char* and sans nocase.
01561  *
01562  * Results:
01563  *      The return value is 1 if string matches pattern, and 0 otherwise. The
01564  *      matching operation permits the following special characters in the
01565  *      pattern: *?\[] (see the manual entry for details on what these mean).
01566  *
01567  * Side effects:
01568  *      None.
01569  *
01570  *----------------------------------------------------------------------
01571  */
01572 
01573 int
01574 TclByteArrayMatch(
01575     const unsigned char *string,        /* String. */
01576     int strLen,                         /* Length of String */
01577     const unsigned char *pattern,       /* Pattern, which may contain special
01578                                          * characters. */
01579     int ptnLen,                         /* Length of Pattern */
01580     int flags)
01581 {
01582     const unsigned char *stringEnd, *patternEnd;
01583     unsigned char p;
01584 
01585     stringEnd = string + strLen;
01586     patternEnd = pattern + ptnLen;
01587 
01588     while (1) {
01589         /*
01590          * See if we're at the end of both the pattern and the string. If so,
01591          * we succeeded. If we're at the end of the pattern but not at the end
01592          * of the string, we failed.
01593          */
01594 
01595         if (pattern == patternEnd) {
01596             return (string == stringEnd);
01597         }
01598         p = *pattern;
01599         if ((string == stringEnd) && (p != '*')) {
01600             return 0;
01601         }
01602 
01603         /*
01604          * Check for a "*" as the next pattern character. It matches any
01605          * substring. We handle this by skipping all the characters up to the
01606          * next matching one in the pattern, and then calling ourselves
01607          * recursively for each postfix of string, until either we match or we
01608          * reach the end of the string.
01609          */
01610 
01611         if (p == '*') {
01612             /*
01613              * Skip all successive *'s in the pattern.
01614              */
01615 
01616             while (*(++pattern) == '*') {
01617                 /* empty body */
01618             }
01619             if (pattern == patternEnd) {
01620                 return 1;
01621             }
01622             p = *pattern;
01623             while (1) {
01624                 /*
01625                  * Optimization for matching - cruise through the string
01626                  * quickly if the next char in the pattern isn't a special
01627                  * character.
01628                  */
01629 
01630                 if ((p != '[') && (p != '?') && (p != '\\')) {
01631                     while ((string < stringEnd) && (p != *string)) {
01632                         string++;
01633                     }
01634                 }
01635                 if (TclByteArrayMatch(string, stringEnd - string,
01636                                 pattern, patternEnd - pattern, 0)) {
01637                     return 1;
01638                 }
01639                 if (string == stringEnd) {
01640                     return 0;
01641                 }
01642                 string++;
01643             }
01644         }
01645 
01646         /*
01647          * Check for a "?" as the next pattern character. It matches any
01648          * single character.
01649          */
01650 
01651         if (p == '?') {
01652             pattern++;
01653             string++;
01654             continue;
01655         }
01656 
01657         /*
01658          * Check for a "[" as the next pattern character. It is followed by a
01659          * list of characters that are acceptable, or by a range (two
01660          * characters separated by "-").
01661          */
01662 
01663         if (p == '[') {
01664             unsigned char ch1, startChar, endChar;
01665 
01666             pattern++;
01667             ch1 = *string;
01668             string++;
01669             while (1) {
01670                 if ((*pattern == ']') || (pattern == patternEnd)) {
01671                     return 0;
01672                 }
01673                 startChar = *pattern;
01674                 pattern++;
01675                 if (*pattern == '-') {
01676                     pattern++;
01677                     if (pattern == patternEnd) {
01678                         return 0;
01679                     }
01680                     endChar = *pattern;
01681                     pattern++;
01682                     if (((startChar <= ch1) && (ch1 <= endChar))
01683                             || ((endChar <= ch1) && (ch1 <= startChar))) {
01684                         /*
01685                          * Matches ranges of form [a-z] or [z-a].
01686                          */
01687                         break;
01688                     }
01689                 } else if (startChar == ch1) {
01690                     break;
01691                 }
01692             }
01693             while (*pattern != ']') {
01694                 if (pattern == patternEnd) {
01695                     pattern--;
01696                     break;
01697                 }
01698                 pattern++;
01699             }
01700             pattern++;
01701             continue;
01702         }
01703 
01704         /*
01705          * If the next pattern character is '\', just strip off the '\' so we
01706          * do exact matching on the character that follows.
01707          */
01708 
01709         if (p == '\\') {
01710             if (++pattern == patternEnd) {
01711                 return 0;
01712             }
01713         }
01714 
01715         /*
01716          * There's no special character. Just make sure that the next bytes of
01717          * each string match.
01718          */
01719 
01720         if (*string != *pattern) {
01721             return 0;
01722         }
01723         string++;
01724         pattern++;
01725     }
01726 }
01727 
01728 /*
01729  *----------------------------------------------------------------------
01730  *
01731  * TclStringMatchObj --
01732  *
01733  *      See if a particular string matches a particular pattern.
01734  *      Allows case insensitivity.  This is the generic multi-type handler
01735  *      for the various matching algorithms.
01736  *
01737  * Results:
01738  *      The return value is 1 if string matches pattern, and 0 otherwise. The
01739  *      matching operation permits the following special characters in the
01740  *      pattern: *?\[] (see the manual entry for details on what these mean).
01741  *
01742  * Side effects:
01743  *      None.
01744  *
01745  *----------------------------------------------------------------------
01746  */
01747 
01748 int
01749 TclStringMatchObj(
01750     Tcl_Obj *strObj,    /* string object. */
01751     Tcl_Obj *ptnObj,    /* pattern object. */
01752     int flags)          /* Only TCL_MATCH_NOCASE should be passed or 0. */
01753 {
01754     int match, length, plen;
01755 
01756     /*
01757      * Promote based on the type of incoming object.
01758      * XXX: Currently doesn't take advantage of exact-ness that
01759      * XXX: TclReToGlob tells us about
01760     trivial = nocase ? 0 : TclMatchIsTrivial(TclGetString(ptnObj));
01761      */
01762 
01763     if ((strObj->typePtr == &tclStringType)) {
01764         Tcl_UniChar *udata, *uptn;
01765 
01766         udata = Tcl_GetUnicodeFromObj(strObj, &length);
01767         uptn  = Tcl_GetUnicodeFromObj(ptnObj, &plen);
01768         match = TclUniCharMatch(udata, length, uptn, plen, flags);
01769     } else if ((strObj->typePtr == &tclByteArrayType) && !flags) {
01770         unsigned char *data, *ptn;
01771 
01772         data = Tcl_GetByteArrayFromObj(strObj, &length);
01773         ptn  = Tcl_GetByteArrayFromObj(ptnObj, &plen);
01774         match = TclByteArrayMatch(data, length, ptn, plen, 0);
01775     } else {
01776         match = Tcl_StringCaseMatch(TclGetString(strObj),
01777                 TclGetString(ptnObj), flags);
01778     }
01779     return match;
01780 }
01781 
01782 /*
01783  *----------------------------------------------------------------------
01784  *
01785  * Tcl_DStringInit --
01786  *
01787  *      Initializes a dynamic string, discarding any previous contents of the
01788  *      string (Tcl_DStringFree should have been called already if the dynamic
01789  *      string was previously in use).
01790  *
01791  * Results:
01792  *      None.
01793  *
01794  * Side effects:
01795  *      The dynamic string is initialized to be empty.
01796  *
01797  *----------------------------------------------------------------------
01798  */
01799 
01800 void
01801 Tcl_DStringInit(
01802     Tcl_DString *dsPtr)         /* Pointer to structure for dynamic string. */
01803 {
01804     dsPtr->string = dsPtr->staticSpace;
01805     dsPtr->length = 0;
01806     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
01807     dsPtr->staticSpace[0] = '\0';
01808 }
01809 
01810 /*
01811  *----------------------------------------------------------------------
01812  *
01813  * Tcl_DStringAppend --
01814  *
01815  *      Append more bytes to the current value of a dynamic string.
01816  *
01817  * Results:
01818  *      The return value is a pointer to the dynamic string's new value.
01819  *
01820  * Side effects:
01821  *      Length bytes from "bytes" (or all of "bytes" if length is less than
01822  *      zero) are added to the current value of the string. Memory gets
01823  *      reallocated if needed to accomodate the string's new size.
01824  *
01825  *----------------------------------------------------------------------
01826  */
01827 
01828 char *
01829 Tcl_DStringAppend(
01830     Tcl_DString *dsPtr,         /* Structure describing dynamic string. */
01831     CONST char *bytes,          /* String to append. If length is -1 then this
01832                                  * must be null-terminated. */
01833     int length)                 /* Number of bytes from "bytes" to append. If
01834                                  * < 0, then append all of bytes, up to null
01835                                  * at end. */
01836 {
01837     int newSize;
01838     char *dst;
01839     CONST char *end;
01840 
01841     if (length < 0) {
01842         length = strlen(bytes);
01843     }
01844     newSize = length + dsPtr->length;
01845 
01846     /*
01847      * Allocate a larger buffer for the string if the current one isn't large
01848      * enough. Allocate extra space in the new buffer so that there will be
01849      * room to grow before we have to allocate again.
01850      */
01851 
01852     if (newSize >= dsPtr->spaceAvl) {
01853         dsPtr->spaceAvl = newSize * 2;
01854         if (dsPtr->string == dsPtr->staticSpace) {
01855             char *newString = ckalloc((unsigned) dsPtr->spaceAvl);
01856 
01857             memcpy(newString, dsPtr->string, (size_t) dsPtr->length);
01858             dsPtr->string = newString;
01859         } else {
01860             dsPtr->string = ckrealloc((void *) dsPtr->string,
01861                     (size_t) dsPtr->spaceAvl);
01862         }
01863     }
01864 
01865     /*
01866      * Copy the new string into the buffer at the end of the old one.
01867      */
01868 
01869     for (dst = dsPtr->string + dsPtr->length, end = bytes+length;
01870             bytes < end; bytes++, dst++) {
01871         *dst = *bytes;
01872     }
01873     *dst = '\0';
01874     dsPtr->length += length;
01875     return dsPtr->string;
01876 }
01877 
01878 /*
01879  *----------------------------------------------------------------------
01880  *
01881  * Tcl_DStringAppendElement --
01882  *
01883  *      Append a list element to the current value of a dynamic string.
01884  *
01885  * Results:
01886  *      The return value is a pointer to the dynamic string's new value.
01887  *
01888  * Side effects:
01889  *      String is reformatted as a list element and added to the current value
01890  *      of the string. Memory gets reallocated if needed to accomodate the
01891  *      string's new size.
01892  *
01893  *----------------------------------------------------------------------
01894  */
01895 
01896 char *
01897 Tcl_DStringAppendElement(
01898     Tcl_DString *dsPtr,         /* Structure describing dynamic string. */
01899     CONST char *element)        /* String to append. Must be
01900                                  * null-terminated. */
01901 {
01902     int newSize, flags, strSize;
01903     char *dst;
01904 
01905     strSize = ((element== NULL) ? 0 : strlen(element));
01906     newSize = Tcl_ScanCountedElement(element, strSize, &flags)
01907         + dsPtr->length + 1;
01908 
01909     /*
01910      * Allocate a larger buffer for the string if the current one isn't large
01911      * enough. Allocate extra space in the new buffer so that there will be
01912      * room to grow before we have to allocate again. SPECIAL NOTE: must use
01913      * memcpy, not strcpy, to copy the string to a larger buffer, since there
01914      * may be embedded NULLs in the string in some cases.
01915      */
01916 
01917     if (newSize >= dsPtr->spaceAvl) {
01918         dsPtr->spaceAvl = newSize * 2;
01919         if (dsPtr->string == dsPtr->staticSpace) {
01920             char *newString = ckalloc((unsigned) dsPtr->spaceAvl);
01921 
01922             memcpy(newString, dsPtr->string, (size_t) dsPtr->length);
01923             dsPtr->string = newString;
01924         } else {
01925             dsPtr->string = (char *) ckrealloc((void *) dsPtr->string,
01926                     (size_t) dsPtr->spaceAvl);
01927         }
01928     }
01929 
01930     /*
01931      * Convert the new string to a list element and copy it into the buffer at
01932      * the end, with a space, if needed.
01933      */
01934 
01935     dst = dsPtr->string + dsPtr->length;
01936     if (TclNeedSpace(dsPtr->string, dst)) {
01937         *dst = ' ';
01938         dst++;
01939         dsPtr->length++;
01940 
01941         /*
01942          * If we need a space to separate this element from preceding stuff,
01943          * then this element will not lead a list, and need not have it's
01944          * leading '#' quoted.
01945          */
01946 
01947         flags |= TCL_DONT_QUOTE_HASH;
01948     }
01949     dsPtr->length += Tcl_ConvertCountedElement(element, strSize, dst, flags);
01950     return dsPtr->string;
01951 }
01952 
01953 /*
01954  *----------------------------------------------------------------------
01955  *
01956  * Tcl_DStringSetLength --
01957  *
01958  *      Change the length of a dynamic string. This can cause the string to
01959  *      either grow or shrink, depending on the value of length.
01960  *
01961  * Results:
01962  *      None.
01963  *
01964  * Side effects:
01965  *      The length of dsPtr is changed to length and a null byte is stored at
01966  *      that position in the string. If length is larger than the space
01967  *      allocated for dsPtr, then a panic occurs.
01968  *
01969  *----------------------------------------------------------------------
01970  */
01971 
01972 void
01973 Tcl_DStringSetLength(
01974     Tcl_DString *dsPtr,         /* Structure describing dynamic string. */
01975     int length)                 /* New length for dynamic string. */
01976 {
01977     int newsize;
01978 
01979     if (length < 0) {
01980         length = 0;
01981     }
01982     if (length >= dsPtr->spaceAvl) {
01983         /*
01984          * There are two interesting cases here. In the first case, the user
01985          * may be trying to allocate a large buffer of a specific size. It
01986          * would be wasteful to overallocate that buffer, so we just allocate
01987          * enough for the requested size plus the trailing null byte. In the
01988          * second case, we are growing the buffer incrementally, so we need
01989          * behavior similar to Tcl_DStringAppend. The requested length will
01990          * usually be a small delta above the current spaceAvl, so we'll end
01991          * up doubling the old size. This won't grow the buffer quite as
01992          * quickly, but it should be close enough.
01993          */
01994 
01995         newsize = dsPtr->spaceAvl * 2;
01996         if (length < newsize) {
01997             dsPtr->spaceAvl = newsize;
01998         } else {
01999             dsPtr->spaceAvl = length + 1;
02000         }
02001         if (dsPtr->string == dsPtr->staticSpace) {
02002             char *newString = ckalloc((unsigned) dsPtr->spaceAvl);
02003 
02004             memcpy(newString, dsPtr->string, (size_t) dsPtr->length);
02005             dsPtr->string = newString;
02006         } else {
02007             dsPtr->string = (char *) ckrealloc((void *) dsPtr->string,
02008                     (size_t) dsPtr->spaceAvl);
02009         }
02010     }
02011     dsPtr->length = length;
02012     dsPtr->string[length] = 0;
02013 }
02014 
02015 /*
02016  *----------------------------------------------------------------------
02017  *
02018  * Tcl_DStringFree --
02019  *
02020  *      Frees up any memory allocated for the dynamic string and reinitializes
02021  *      the string to an empty state.
02022  *
02023  * Results:
02024  *      None.
02025  *
02026  * Side effects:
02027  *      The previous contents of the dynamic string are lost, and the new
02028  *      value is an empty string.
02029  *
02030  *----------------------------------------------------------------------
02031  */
02032 
02033 void
02034 Tcl_DStringFree(
02035     Tcl_DString *dsPtr)         /* Structure describing dynamic string. */
02036 {
02037     if (dsPtr->string != dsPtr->staticSpace) {
02038         ckfree(dsPtr->string);
02039     }
02040     dsPtr->string = dsPtr->staticSpace;
02041     dsPtr->length = 0;
02042     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
02043     dsPtr->staticSpace[0] = '\0';
02044 }
02045 
02046 /*
02047  *----------------------------------------------------------------------
02048  *
02049  * Tcl_DStringResult --
02050  *
02051  *      This function moves the value of a dynamic string into an interpreter
02052  *      as its string result. Afterwards, the dynamic string is reset to an
02053  *      empty string.
02054  *
02055  * Results:
02056  *      None.
02057  *
02058  * Side effects:
02059  *      The string is "moved" to interp's result, and any existing string
02060  *      result for interp is freed. dsPtr is reinitialized to an empty string.
02061  *
02062  *----------------------------------------------------------------------
02063  */
02064 
02065 void
02066 Tcl_DStringResult(
02067     Tcl_Interp *interp,         /* Interpreter whose result is to be reset. */
02068     Tcl_DString *dsPtr)         /* Dynamic string that is to become the
02069                                  * result of interp. */
02070 {
02071     Tcl_ResetResult(interp);
02072 
02073     if (dsPtr->string != dsPtr->staticSpace) {
02074         interp->result = dsPtr->string;
02075         interp->freeProc = TCL_DYNAMIC;
02076     } else if (dsPtr->length < TCL_RESULT_SIZE) {
02077         interp->result = ((Interp *) interp)->resultSpace;
02078         strcpy(interp->result, dsPtr->string);
02079     } else {
02080         Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE);
02081     }
02082 
02083     dsPtr->string = dsPtr->staticSpace;
02084     dsPtr->length = 0;
02085     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
02086     dsPtr->staticSpace[0] = '\0';
02087 }
02088 
02089 /*
02090  *----------------------------------------------------------------------
02091  *
02092  * Tcl_DStringGetResult --
02093  *
02094  *      This function moves an interpreter's result into a dynamic string.
02095  *
02096  * Results:
02097  *      None.
02098  *
02099  * Side effects:
02100  *      The interpreter's string result is cleared, and the previous contents
02101  *      of dsPtr are freed.
02102  *
02103  *      If the string result is empty, the object result is moved to the
02104  *      string result, then the object result is reset.
02105  *
02106  *----------------------------------------------------------------------
02107  */
02108 
02109 void
02110 Tcl_DStringGetResult(
02111     Tcl_Interp *interp,         /* Interpreter whose result is to be reset. */
02112     Tcl_DString *dsPtr)         /* Dynamic string that is to become the result
02113                                  * of interp. */
02114 {
02115     Interp *iPtr = (Interp *) interp;
02116 
02117     if (dsPtr->string != dsPtr->staticSpace) {
02118         ckfree(dsPtr->string);
02119     }
02120 
02121     /*
02122      * If the string result is empty, move the object result to the string
02123      * result, then reset the object result.
02124      */
02125 
02126     (void) Tcl_GetStringResult(interp);
02127 
02128     dsPtr->length = strlen(iPtr->result);
02129     if (iPtr->freeProc != NULL) {
02130         if (iPtr->freeProc == TCL_DYNAMIC) {
02131             dsPtr->string = iPtr->result;
02132             dsPtr->spaceAvl = dsPtr->length+1;
02133         } else {
02134             dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length+1));
02135             memcpy(dsPtr->string, iPtr->result, (unsigned) dsPtr->length+1);
02136             (*iPtr->freeProc)(iPtr->result);
02137         }
02138         dsPtr->spaceAvl = dsPtr->length+1;
02139         iPtr->freeProc = NULL;
02140     } else {
02141         if (dsPtr->length < TCL_DSTRING_STATIC_SIZE) {
02142             dsPtr->string = dsPtr->staticSpace;
02143             dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
02144         } else {
02145             dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length + 1));
02146             dsPtr->spaceAvl = dsPtr->length + 1;
02147         }
02148         memcpy(dsPtr->string, iPtr->result, (unsigned) dsPtr->length+1);
02149     }
02150 
02151     iPtr->result = iPtr->resultSpace;
02152     iPtr->resultSpace[0] = 0;
02153 }
02154 
02155 /*
02156  *----------------------------------------------------------------------
02157  *
02158  * Tcl_DStringStartSublist --
02159  *
02160  *      This function adds the necessary information to a dynamic string
02161  *      (e.g. " {") to start a sublist. Future element appends will be in the
02162  *      sublist rather than the main list.
02163  *
02164  * Results:
02165  *      None.
02166  *
02167  * Side effects:
02168  *      Characters get added to the dynamic string.
02169  *
02170  *----------------------------------------------------------------------
02171  */
02172 
02173 void
02174 Tcl_DStringStartSublist(
02175     Tcl_DString *dsPtr)         /* Dynamic string. */
02176 {
02177     if (TclNeedSpace(dsPtr->string, dsPtr->string + dsPtr->length)) {
02178         Tcl_DStringAppend(dsPtr, " {", -1);
02179     } else {
02180         Tcl_DStringAppend(dsPtr, "{", -1);
02181     }
02182 }
02183 
02184 /*
02185  *----------------------------------------------------------------------
02186  *
02187  * Tcl_DStringEndSublist --
02188  *
02189  *      This function adds the necessary characters to a dynamic string to end
02190  *      a sublist (e.g. "}"). Future element appends will be in the enclosing
02191  *      (sub)list rather than the current sublist.
02192  *
02193  * Results:
02194  *      None.
02195  *
02196  * Side effects:
02197  *      None.
02198  *
02199  *----------------------------------------------------------------------
02200  */
02201 
02202 void
02203 Tcl_DStringEndSublist(
02204     Tcl_DString *dsPtr)         /* Dynamic string. */
02205 {
02206     Tcl_DStringAppend(dsPtr, "}", -1);
02207 }
02208 
02209 /*
02210  *----------------------------------------------------------------------
02211  *
02212  * Tcl_PrintDouble --
02213  *
02214  *      Given a floating-point value, this function converts it to an ASCII
02215  *      string using.
02216  *
02217  * Results:
02218  *      The ASCII equivalent of "value" is written at "dst". It is written
02219  *      using the current precision, and it is guaranteed to contain a decimal
02220  *      point or exponent, so that it looks like a floating-point value and
02221  *      not an integer.
02222  *
02223  * Side effects:
02224  *      None.
02225  *
02226  *----------------------------------------------------------------------
02227  */
02228 
02229 void
02230 Tcl_PrintDouble(
02231     Tcl_Interp *interp,         /* Interpreter whose tcl_precision variable
02232                                  * used to be used to control printing. It's
02233                                  * ignored now. */
02234     double value,               /* Value to print as string. */
02235     char *dst)                  /* Where to store converted value; must have
02236                                  * at least TCL_DOUBLE_SPACE characters. */
02237 {
02238     char *p, c;
02239     int exp;
02240     int signum;
02241     char buffer[TCL_DOUBLE_SPACE];
02242     Tcl_UniChar ch;
02243 
02244     int *precisionPtr = Tcl_GetThreadData(&precisionKey, (int)sizeof(int));
02245 
02246     /*
02247      * If *precisionPtr == 0, then use TclDoubleDigits to develop a decimal
02248      * significand and exponent, then format it in E or F format as
02249      * appropriate. If *precisionPtr != 0, use the native sprintf and then add
02250      * a trailing ".0" if there is no decimal point in the rep.
02251      */
02252 
02253     if (*precisionPtr == 0) {
02254         /*
02255          * Handle NaN.
02256          */
02257 
02258         if (TclIsNaN(value)) {
02259             TclFormatNaN(value, dst);
02260             return;
02261         }
02262 
02263         /*
02264          * Handle infinities.
02265          */
02266 
02267         if (TclIsInfinite(value)) {
02268             if (value < 0) {
02269                 strcpy(dst, "-Inf");
02270             } else {
02271                 strcpy(dst, "Inf");
02272             }
02273             return;
02274         }
02275 
02276         /*
02277          * Ordinary (normal and denormal) values.
02278          */
02279 
02280         exp = TclDoubleDigits(buffer, value, &signum);
02281         if (signum) {
02282             *dst++ = '-';
02283         }
02284         p = buffer;
02285         if (exp < -3 || exp > 17) {
02286             /*
02287              * E format for numbers < 1e-3 or >= 1e17.
02288              */
02289 
02290             *dst++ = *p++;
02291             c = *p;
02292             if (c != '\0') {
02293                 *dst++ = '.';
02294                 while (c != '\0') {
02295                     *dst++ = c;
02296                     c = *++p;
02297                 }
02298             }
02299             sprintf(dst, "e%+d", exp-1);
02300         } else {
02301             /*
02302              * F format for others.
02303              */
02304 
02305             if (exp <= 0) {
02306                 *dst++ = '0';
02307             }
02308             c = *p;
02309             while (exp-- > 0) {
02310                 if (c != '\0') {
02311                     *dst++ = c;
02312                     c = *++p;
02313                 } else {
02314                     *dst++ = '0';
02315                 }
02316             }
02317             *dst++ = '.';
02318             if (c == '\0') {
02319                 *dst++ = '0';
02320             } else {
02321                 while (++exp < 0) {
02322                     *dst++ = '0';
02323                 }
02324                 while (c != '\0') {
02325                     *dst++ = c;
02326                     c = *++p;
02327                 }
02328             }
02329             *dst++ = '\0';
02330         }
02331     } else {
02332         /*
02333          * tcl_precision is supplied, pass it to the native sprintf.
02334          */
02335 
02336         sprintf(dst, "%.*g", *precisionPtr, value);
02337 
02338         /*
02339          * If the ASCII result looks like an integer, add ".0" so that it
02340          * doesn't look like an integer anymore. This prevents floating-point
02341          * values from being converted to integers unintentionally. Check for
02342          * ASCII specifically to speed up the function.
02343          */
02344 
02345         for (p = dst; *p != 0;) {
02346             if (UCHAR(*p) < 0x80) {
02347                 c = *p++;
02348             } else {
02349                 p += Tcl_UtfToUniChar(p, &ch);
02350                 c = UCHAR(ch);
02351             }
02352             if ((c == '.') || isalpha(UCHAR(c))) {      /* INTL: ISO only. */
02353                 return;
02354             }
02355         }
02356         p[0] = '.';
02357         p[1] = '0';
02358         p[2] = 0;
02359     }
02360 }
02361 
02362 /*
02363  *----------------------------------------------------------------------
02364  *
02365  * TclPrecTraceProc --
02366  *
02367  *      This function is invoked whenever the variable "tcl_precision" is
02368  *      written.
02369  *
02370  * Results:
02371  *      Returns NULL if all went well, or an error message if the new value
02372  *      for the variable doesn't make sense.
02373  *
02374  * Side effects:
02375  *      If the new value doesn't make sense then this function undoes the
02376  *      effect of the variable modification. Otherwise it modifies the format
02377  *      string that's used by Tcl_PrintDouble.
02378  *
02379  *----------------------------------------------------------------------
02380  */
02381 
02382         /* ARGSUSED */
02383 char *
02384 TclPrecTraceProc(
02385     ClientData clientData,      /* Not used. */
02386     Tcl_Interp *interp,         /* Interpreter containing variable. */
02387     CONST char *name1,          /* Name of variable. */
02388     CONST char *name2,          /* Second part of variable name. */
02389     int flags)                  /* Information about what happened. */
02390 {
02391     Tcl_Obj* value;
02392     int prec;
02393     int *precisionPtr = Tcl_GetThreadData(&precisionKey, (int) sizeof(int));
02394 
02395     /*
02396      * If the variable is unset, then recreate the trace.
02397      */
02398 
02399     if (flags & TCL_TRACE_UNSETS) {
02400         if ((flags & TCL_TRACE_DESTROYED) && !Tcl_InterpDeleted(interp)) {
02401             Tcl_TraceVar2(interp, name1, name2,
02402                     TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES
02403                     |TCL_TRACE_UNSETS, TclPrecTraceProc, clientData);
02404         }
02405         return NULL;
02406     }
02407 
02408     /*
02409      * When the variable is read, reset its value from our shared value. This
02410      * is needed in case the variable was modified in some other interpreter
02411      * so that this interpreter's value is out of date.
02412      */
02413 
02414 
02415     if (flags & TCL_TRACE_READS) {
02416         Tcl_SetVar2Ex(interp, name1, name2, Tcl_NewIntObj(*precisionPtr),
02417                 flags & TCL_GLOBAL_ONLY);
02418         return NULL;
02419     }
02420 
02421     /*
02422      * The variable is being written. Check the new value and disallow it if
02423      * it isn't reasonable or if this is a safe interpreter (we don't want
02424      * safe interpreters messing up the precision of other interpreters).
02425      */
02426 
02427     if (Tcl_IsSafe(interp)) {
02428         return "can't modify precision from a safe interpreter";
02429     }
02430     value = Tcl_GetVar2Ex(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
02431     if (value == NULL
02432             || Tcl_GetIntFromObj((Tcl_Interp*) NULL, value, &prec) != TCL_OK
02433             || prec < 0 || prec > TCL_MAX_PREC) {
02434         return "improper value for precision";
02435     }
02436     *precisionPtr = prec;
02437     return NULL;
02438 }
02439 
02440 /*
02441  *----------------------------------------------------------------------
02442  *
02443  * TclNeedSpace --
02444  *
02445  *      This function checks to see whether it is appropriate to add a space
02446  *      before appending a new list element to an existing string.
02447  *
02448  * Results:
02449  *      The return value is 1 if a space is appropriate, 0 otherwise.
02450  *
02451  * Side effects:
02452  *      None.
02453  *
02454  *----------------------------------------------------------------------
02455  */
02456 
02457 int
02458 TclNeedSpace(
02459     CONST char *start,          /* First character in string. */
02460     CONST char *end)            /* End of string (place where space will be
02461                                  * added, if appropriate). */
02462 {
02463     /*
02464      * A space is needed unless either:
02465      * (a) we're at the start of the string, or
02466      */
02467 
02468     if (end == start) {
02469         return 0;
02470     }
02471 
02472     /*
02473      * (b) we're at the start of a nested list-element, quoted with an open
02474      *     curly brace; we can be nested arbitrarily deep, so long as the
02475      *     first curly brace starts an element, so backtrack over open curly
02476      *     braces that are trailing characters of the string; and
02477      */
02478 
02479     end = Tcl_UtfPrev(end, start);
02480     while (*end == '{') {
02481         if (end == start) {
02482             return 0;
02483         }
02484         end = Tcl_UtfPrev(end, start);
02485     }
02486 
02487     /*
02488      * (c) the trailing character of the string is already a list-element
02489      *     separator (according to TclFindElement); that is, one of these
02490      *     characters:
02491      *          \u0009  \t      TAB
02492      *          \u000A  \n      NEWLINE
02493      *          \u000B  \v      VERTICAL TAB
02494      *          \u000C  \f      FORM FEED
02495      *          \u000D  \r      CARRIAGE RETURN
02496      *          \u0020          SPACE
02497      *     with the condition that the penultimate character is not a
02498      *     backslash.
02499      */
02500 
02501     if (*end > 0x20) {
02502         /*
02503          * Performance tweak. All ASCII spaces are <= 0x20. So get a quick
02504          * answer for most characters before comparing against all spaces in
02505          * the switch below.
02506          *
02507          * NOTE: Remove this if other Unicode spaces ever get accepted as
02508          * list-element separators.
02509          */
02510         return 1;
02511     }
02512     switch (*end) {
02513     case ' ':
02514     case '\t':
02515     case '\n':
02516     case '\r':
02517     case '\v':
02518     case '\f':
02519         if ((end == start) || (end[-1] != '\\')) {
02520             return 0;
02521         }
02522     }
02523     return 1;
02524 }
02525 
02526 /*
02527  *----------------------------------------------------------------------
02528  *
02529  * TclGetIntForIndex --
02530  *
02531  *      This function returns an integer corresponding to the list index held
02532  *      in a Tcl object. The Tcl object's value is expected to be in the
02533  *      format integer([+-]integer)? or the format end([+-]integer)?.
02534  *
02535  * Results:
02536  *      The return value is normally TCL_OK, which means that the index was
02537  *      successfully stored into the location referenced by "indexPtr". If the
02538  *      Tcl object referenced by "objPtr" has the value "end", the value
02539  *      stored is "endValue". If "objPtr"s values is not of one of the
02540  *      expected formats, TCL_ERROR is returned and, if "interp" is non-NULL,
02541  *      an error message is left in the interpreter's result object.
02542  *
02543  * Side effects:
02544  *      The object referenced by "objPtr" might be converted to an integer,
02545  *      wide integer, or end-based-index object.
02546  *
02547  *----------------------------------------------------------------------
02548  */
02549 
02550 int
02551 TclGetIntForIndex(
02552     Tcl_Interp *interp,         /* Interpreter to use for error reporting. If
02553                                  * NULL, then no error message is left after
02554                                  * errors. */
02555     Tcl_Obj *objPtr,            /* Points to an object containing either "end"
02556                                  * or an integer. */
02557     int endValue,               /* The value to be stored at "indexPtr" if
02558                                  * "objPtr" holds "end". */
02559     int *indexPtr)              /* Location filled in with an integer
02560                                  * representing an index. */
02561 {
02562     int length;
02563     char *opPtr, *bytes;
02564 
02565     if (TclGetIntFromObj(NULL, objPtr, indexPtr) == TCL_OK) {
02566         return TCL_OK;
02567     }
02568 
02569     if (SetEndOffsetFromAny(NULL, objPtr) == TCL_OK) {
02570         /*
02571          * If the object is already an offset from the end of the list, or can
02572          * be converted to one, use it.
02573          */
02574 
02575         *indexPtr = endValue + objPtr->internalRep.longValue;
02576         return TCL_OK;
02577     }
02578 
02579     bytes = TclGetStringFromObj(objPtr, &length);
02580 
02581     /*
02582      * Leading whitespace is acceptable in an index.
02583      */
02584 
02585     while (length && isspace(UCHAR(*bytes))) {          /* INTL: ISO space. */
02586         bytes++;
02587         length--;
02588     }
02589 
02590     if (TclParseNumber(NULL, NULL, NULL, bytes, length, (const char **)&opPtr,
02591             TCL_PARSE_INTEGER_ONLY | TCL_PARSE_NO_WHITESPACE) == TCL_OK) {
02592         int code, first, second;
02593         char savedOp = *opPtr;
02594 
02595         if ((savedOp != '+') && (savedOp != '-')) {
02596             goto parseError;
02597         }
02598         if (isspace(UCHAR(opPtr[1]))) {
02599             goto parseError;
02600         }
02601         *opPtr = '\0';
02602         code = Tcl_GetInt(interp, bytes, &first);
02603         *opPtr = savedOp;
02604         if (code == TCL_ERROR) {
02605             goto parseError;
02606         }
02607         if (TCL_ERROR == Tcl_GetInt(interp, opPtr+1, &second)) {
02608             goto parseError;
02609         }
02610         if (savedOp == '+') {
02611             *indexPtr = first + second;
02612         } else {
02613             *indexPtr = first - second;
02614         }
02615         return TCL_OK;
02616     }
02617 
02618     /*
02619      * Report a parse error.
02620      */
02621 
02622   parseError:
02623     if (interp != NULL) {
02624         char *bytes = Tcl_GetString(objPtr);
02625 
02626         /*
02627          * The result might not be empty; this resets it which should be both
02628          * a cheap operation, and of little problem because this is an
02629          * error-generation path anyway.
02630          */
02631 
02632         Tcl_ResetResult(interp);
02633         Tcl_AppendResult(interp, "bad index \"", bytes,
02634                 "\": must be integer?[+-]integer? or end?[+-]integer?", NULL);
02635         if (!strncmp(bytes, "end-", 4)) {
02636             bytes += 4;
02637         }
02638         TclCheckBadOctal(interp, bytes);
02639     }
02640 
02641     return TCL_ERROR;
02642 }
02643 
02644 /*
02645  *----------------------------------------------------------------------
02646  *
02647  * UpdateStringOfEndOffset --
02648  *
02649  *      Update the string rep of a Tcl object holding an "end-offset"
02650  *      expression.
02651  *
02652  * Results:
02653  *      None.
02654  *
02655  * Side effects:
02656  *      Stores a valid string in the object's string rep.
02657  *
02658  * This function does NOT free any earlier string rep. If it is called on an
02659  * object that already has a valid string rep, it will leak memory.
02660  *
02661  *----------------------------------------------------------------------
02662  */
02663 
02664 static void
02665 UpdateStringOfEndOffset(
02666     register Tcl_Obj* objPtr)
02667 {
02668     char buffer[TCL_INTEGER_SPACE + sizeof("end") + 1];
02669     register int len;
02670 
02671     strcpy(buffer, "end");
02672     len = sizeof("end") - 1;
02673     if (objPtr->internalRep.longValue != 0) {
02674         buffer[len++] = '-';
02675         len += TclFormatInt(buffer+len, -(objPtr->internalRep.longValue));
02676     }
02677     objPtr->bytes = ckalloc((unsigned) len+1);
02678     memcpy(objPtr->bytes, buffer, (unsigned) len+1);
02679     objPtr->length = len;
02680 }
02681 
02682 /*
02683  *----------------------------------------------------------------------
02684  *
02685  * SetEndOffsetFromAny --
02686  *
02687  *      Look for a string of the form "end[+-]offset" and convert it to an
02688  *      internal representation holding the offset.
02689  *
02690  * Results:
02691  *      Returns TCL_OK if ok, TCL_ERROR if the string was badly formed.
02692  *
02693  * Side effects:
02694  *      If interp is not NULL, stores an error message in the interpreter
02695  *      result.
02696  *
02697  *----------------------------------------------------------------------
02698  */
02699 
02700 static int
02701 SetEndOffsetFromAny(
02702     Tcl_Interp *interp,         /* Tcl interpreter or NULL */
02703     Tcl_Obj *objPtr)            /* Pointer to the object to parse */
02704 {
02705     int offset;                 /* Offset in the "end-offset" expression */
02706     register char* bytes;       /* String rep of the object */
02707     int length;                 /* Length of the object's string rep */
02708 
02709     /*
02710      * If it's already the right type, we're fine.
02711      */
02712 
02713     if (objPtr->typePtr == &tclEndOffsetType) {
02714         return TCL_OK;
02715     }
02716 
02717     /*
02718      * Check for a string rep of the right form.
02719      */
02720 
02721     bytes = TclGetStringFromObj(objPtr, &length);
02722     if ((*bytes != 'e') || (strncmp(bytes, "end",
02723             (size_t)((length > 3) ? 3 : length)) != 0)) {
02724         if (interp != NULL) {
02725             Tcl_ResetResult(interp);
02726             Tcl_AppendResult(interp, "bad index \"", bytes,
02727                     "\": must be end?[+-]integer?", NULL);
02728         }
02729         return TCL_ERROR;
02730     }
02731 
02732     /*
02733      * Convert the string rep.
02734      */
02735 
02736     if (length <= 3) {
02737         offset = 0;
02738     } else if ((length > 4) && ((bytes[3] == '-') || (bytes[3] == '+'))) {
02739         /*
02740          * This is our limited string expression evaluator. Pass everything
02741          * after "end-" to Tcl_GetInt, then reverse for offset.
02742          */
02743 
02744         if (isspace(UCHAR(bytes[4]))) {
02745             return TCL_ERROR;
02746         }
02747         if (Tcl_GetInt(interp, bytes+4, &offset) != TCL_OK) {
02748             return TCL_ERROR;
02749         }
02750         if (bytes[3] == '-') {
02751             offset = -offset;
02752         }
02753     } else {
02754         /*
02755          * Conversion failed. Report the error.
02756          */
02757 
02758         if (interp != NULL) {
02759             Tcl_ResetResult(interp);
02760             Tcl_AppendResult(interp, "bad index \"", bytes,
02761                     "\": must be end?[+-]integer?", NULL);
02762         }
02763         return TCL_ERROR;
02764     }
02765 
02766     /*
02767      * The conversion succeeded. Free the old internal rep and set the new
02768      * one.
02769      */
02770 
02771     TclFreeIntRep(objPtr);
02772     objPtr->internalRep.longValue = offset;
02773     objPtr->typePtr = &tclEndOffsetType;
02774 
02775     return TCL_OK;
02776 }
02777 
02778 /*
02779  *----------------------------------------------------------------------
02780  *
02781  * TclCheckBadOctal --
02782  *
02783  *      This function checks for a bad octal value and appends a meaningful
02784  *      error to the interp's result.
02785  *
02786  * Results:
02787  *      1 if the argument was a bad octal, else 0.
02788  *
02789  * Side effects:
02790  *      The interpreter's result is modified.
02791  *
02792  *----------------------------------------------------------------------
02793  */
02794 
02795 int
02796 TclCheckBadOctal(
02797     Tcl_Interp *interp,         /* Interpreter to use for error reporting. If
02798                                  * NULL, then no error message is left after
02799                                  * errors. */
02800     CONST char *value)          /* String to check. */
02801 {
02802     register CONST char *p = value;
02803 
02804     /*
02805      * A frequent mistake is invalid octal values due to an unwanted leading
02806      * zero. Try to generate a meaningful error message.
02807      */
02808 
02809     while (isspace(UCHAR(*p))) {        /* INTL: ISO space. */
02810         p++;
02811     }
02812     if (*p == '+' || *p == '-') {
02813         p++;
02814     }
02815     if (*p == '0') {
02816         if ((p[1] == 'o') || p[1] == 'O') {
02817             p+=2;
02818         }
02819         while (isdigit(UCHAR(*p))) {    /* INTL: digit. */
02820             p++;
02821         }
02822         while (isspace(UCHAR(*p))) {    /* INTL: ISO space. */
02823             p++;
02824         }
02825         if (*p == '\0') {
02826             /*
02827              * Reached end of string.
02828              */
02829 
02830             if (interp != NULL) {
02831                 /*
02832                  * Don't reset the result here because we want this result to
02833                  * be added to an existing error message as extra info.
02834                  */
02835 
02836                 Tcl_AppendResult(interp, " (looks like invalid octal number)",
02837                         NULL);
02838             }
02839             return 1;
02840         }
02841     }
02842     return 0;
02843 }
02844 
02845 /*
02846  *----------------------------------------------------------------------
02847  *
02848  * ClearHash --
02849  *
02850  *      Remove all the entries in the hash table *tablePtr.
02851  *
02852  *----------------------------------------------------------------------
02853  */
02854 
02855 static void
02856 ClearHash(
02857     Tcl_HashTable *tablePtr)
02858 {
02859     Tcl_HashSearch search;
02860     Tcl_HashEntry *hPtr;
02861 
02862     for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL;
02863             hPtr = Tcl_NextHashEntry(&search)) {
02864         Tcl_Obj *objPtr = (Tcl_Obj *) Tcl_GetHashValue(hPtr);
02865         Tcl_DecrRefCount(objPtr);
02866         Tcl_DeleteHashEntry(hPtr);
02867     }
02868 }
02869 
02870 /*
02871  *----------------------------------------------------------------------
02872  *
02873  * GetThreadHash --
02874  *
02875  *      Get a thread-specific (Tcl_HashTable *) associated with a thread data
02876  *      key.
02877  *
02878  * Results:
02879  *      The Tcl_HashTable * corresponding to *keyPtr.
02880  *
02881  * Side effects:
02882  *      The first call on a keyPtr in each thread creates a new Tcl_HashTable,
02883  *      and registers a thread exit handler to dispose of it.
02884  *
02885  *----------------------------------------------------------------------
02886  */
02887 
02888 static Tcl_HashTable *
02889 GetThreadHash(
02890     Tcl_ThreadDataKey *keyPtr)
02891 {
02892     Tcl_HashTable **tablePtrPtr = (Tcl_HashTable **)
02893             Tcl_GetThreadData(keyPtr, (int) sizeof(Tcl_HashTable *));
02894 
02895     if (NULL == *tablePtrPtr) {
02896         *tablePtrPtr = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
02897         Tcl_CreateThreadExitHandler(FreeThreadHash, (ClientData)*tablePtrPtr);
02898         Tcl_InitHashTable(*tablePtrPtr, TCL_ONE_WORD_KEYS);
02899     }
02900     return *tablePtrPtr;
02901 }
02902 
02903 /*
02904  *----------------------------------------------------------------------
02905  *
02906  * FreeThreadHash --
02907  *
02908  *      Thread exit handler used by GetThreadHash to dispose of a thread hash
02909  *      table.
02910  *
02911  * Side effects:
02912  *      Frees a Tcl_HashTable.
02913  *
02914  *----------------------------------------------------------------------
02915  */
02916 
02917 static void
02918 FreeThreadHash(
02919     ClientData clientData)
02920 {
02921     Tcl_HashTable *tablePtr = (Tcl_HashTable *) clientData;
02922 
02923     ClearHash(tablePtr);
02924     Tcl_DeleteHashTable(tablePtr);
02925     ckfree((char *) tablePtr);
02926 }
02927 
02928 /*
02929  *----------------------------------------------------------------------
02930  *
02931  * FreeProcessGlobalValue --
02932  *
02933  *      Exit handler used by Tcl(Set|Get)ProcessGlobalValue to cleanup a
02934  *      ProcessGlobalValue at exit.
02935  *
02936  *----------------------------------------------------------------------
02937  */
02938 
02939 static void
02940 FreeProcessGlobalValue(
02941     ClientData clientData)
02942 {
02943     ProcessGlobalValue *pgvPtr = (ProcessGlobalValue *) clientData;
02944 
02945     pgvPtr->epoch++;
02946     pgvPtr->numBytes = 0;
02947     ckfree(pgvPtr->value);
02948     pgvPtr->value = NULL;
02949     if (pgvPtr->encoding) {
02950         Tcl_FreeEncoding(pgvPtr->encoding);
02951         pgvPtr->encoding = NULL;
02952     }
02953     Tcl_MutexFinalize(&pgvPtr->mutex);
02954 }
02955 
02956 /*
02957  *----------------------------------------------------------------------
02958  *
02959  * TclSetProcessGlobalValue --
02960  *
02961  *      Utility routine to set a global value shared by all threads in the
02962  *      process while keeping a thread-local copy as well.
02963  *
02964  *----------------------------------------------------------------------
02965  */
02966 
02967 void
02968 TclSetProcessGlobalValue(
02969     ProcessGlobalValue *pgvPtr,
02970     Tcl_Obj *newValue,
02971     Tcl_Encoding encoding)
02972 {
02973     CONST char *bytes;
02974     Tcl_HashTable *cacheMap;
02975     Tcl_HashEntry *hPtr;
02976     int dummy;
02977 
02978     Tcl_MutexLock(&pgvPtr->mutex);
02979 
02980     /*
02981      * Fill the global string value.
02982      */
02983 
02984     pgvPtr->epoch++;
02985     if (NULL != pgvPtr->value) {
02986         ckfree(pgvPtr->value);
02987     } else {
02988         Tcl_CreateExitHandler(FreeProcessGlobalValue, (ClientData) pgvPtr);
02989     }
02990     bytes = Tcl_GetStringFromObj(newValue, &pgvPtr->numBytes);
02991     pgvPtr->value = ckalloc((unsigned) pgvPtr->numBytes + 1);
02992     memcpy(pgvPtr->value, bytes, (unsigned) pgvPtr->numBytes + 1);
02993     if (pgvPtr->encoding) {
02994         Tcl_FreeEncoding(pgvPtr->encoding);
02995     }
02996     pgvPtr->encoding = encoding;
02997 
02998     /*
02999      * Fill the local thread copy directly with the Tcl_Obj value to avoid
03000      * loss of the intrep. Increment newValue refCount early to handle case
03001      * where we set a PGV to itself.
03002      */
03003 
03004     Tcl_IncrRefCount(newValue);
03005     cacheMap = GetThreadHash(&pgvPtr->key);
03006     ClearHash(cacheMap);
03007     hPtr = Tcl_CreateHashEntry(cacheMap,
03008             (char *) INT2PTR(pgvPtr->epoch), &dummy);
03009     Tcl_SetHashValue(hPtr, (ClientData) newValue);
03010     Tcl_MutexUnlock(&pgvPtr->mutex);
03011 }
03012 
03013 /*
03014  *----------------------------------------------------------------------
03015  *
03016  * TclGetProcessGlobalValue --
03017  *
03018  *      Retrieve a global value shared among all threads of the process,
03019  *      preferring a thread-local copy as long as it remains valid.
03020  *
03021  * Results:
03022  *      Returns a (Tcl_Obj *) that holds a copy of the global value.
03023  *
03024  *----------------------------------------------------------------------
03025  */
03026 
03027 Tcl_Obj *
03028 TclGetProcessGlobalValue(
03029     ProcessGlobalValue *pgvPtr)
03030 {
03031     Tcl_Obj *value = NULL;
03032     Tcl_HashTable *cacheMap;
03033     Tcl_HashEntry *hPtr;
03034     int epoch = pgvPtr->epoch;
03035 
03036     if (pgvPtr->encoding) {
03037         Tcl_Encoding current = Tcl_GetEncoding(NULL, NULL);
03038 
03039         if (pgvPtr->encoding != current) {
03040             /*
03041              * The system encoding has changed since the master string value
03042              * was saved. Convert the master value to be based on the new
03043              * system encoding.
03044              */
03045 
03046             Tcl_DString native, newValue;
03047 
03048             Tcl_MutexLock(&pgvPtr->mutex);
03049             pgvPtr->epoch++;
03050             epoch = pgvPtr->epoch;
03051             Tcl_UtfToExternalDString(pgvPtr->encoding, pgvPtr->value,
03052                     pgvPtr->numBytes, &native);
03053             Tcl_ExternalToUtfDString(current, Tcl_DStringValue(&native),
03054             Tcl_DStringLength(&native), &newValue);
03055             Tcl_DStringFree(&native);
03056             ckfree(pgvPtr->value);
03057             pgvPtr->value = ckalloc((unsigned int)
03058                     Tcl_DStringLength(&newValue) + 1);
03059             memcpy(pgvPtr->value, Tcl_DStringValue(&newValue),
03060                     (size_t) Tcl_DStringLength(&newValue) + 1);
03061             Tcl_DStringFree(&newValue);
03062             Tcl_FreeEncoding(pgvPtr->encoding);
03063             pgvPtr->encoding = current;
03064             Tcl_MutexUnlock(&pgvPtr->mutex);
03065         } else {
03066             Tcl_FreeEncoding(current);
03067         }
03068     }
03069     cacheMap = GetThreadHash(&pgvPtr->key);
03070     hPtr = Tcl_FindHashEntry(cacheMap, (char *) INT2PTR(epoch));
03071     if (NULL == hPtr) {
03072         int dummy;
03073 
03074         /*
03075          * No cache for the current epoch - must be a new one.
03076          *
03077          * First, clear the cacheMap, as anything in it must refer to some
03078          * expired epoch.
03079          */
03080 
03081         ClearHash(cacheMap);
03082 
03083         /*
03084          * If no thread has set the shared value, call the initializer.
03085          */
03086 
03087         Tcl_MutexLock(&pgvPtr->mutex);
03088         if ((NULL == pgvPtr->value) && (pgvPtr->proc)) {
03089             pgvPtr->epoch++;
03090             (*(pgvPtr->proc))(&pgvPtr->value, &pgvPtr->numBytes,
03091                     &pgvPtr->encoding);
03092             if (pgvPtr->value == NULL) {
03093                 Tcl_Panic("PGV Initializer did not initialize");
03094             }
03095             Tcl_CreateExitHandler(FreeProcessGlobalValue, (ClientData)pgvPtr);
03096         }
03097 
03098         /*
03099          * Store a copy of the shared value in our epoch-indexed cache.
03100          */
03101 
03102         value = Tcl_NewStringObj(pgvPtr->value, pgvPtr->numBytes);
03103         hPtr = Tcl_CreateHashEntry(cacheMap,
03104                 (char *) INT2PTR(pgvPtr->epoch), &dummy);
03105         Tcl_MutexUnlock(&pgvPtr->mutex);
03106         Tcl_SetHashValue(hPtr, (ClientData) value);
03107         Tcl_IncrRefCount(value);
03108     }
03109     return (Tcl_Obj *) Tcl_GetHashValue(hPtr);
03110 }
03111 
03112 /*
03113  *----------------------------------------------------------------------
03114  *
03115  * TclSetObjNameOfExecutable --
03116  *
03117  *      This function stores the absolute pathname of the executable file
03118  *      (normally as computed by TclpFindExecutable).
03119  *
03120  * Results:
03121  *      None.
03122  *
03123  * Side effects:
03124  *      Stores the executable name.
03125  *
03126  *----------------------------------------------------------------------
03127  */
03128 
03129 void
03130 TclSetObjNameOfExecutable(
03131     Tcl_Obj *name,
03132     Tcl_Encoding encoding)
03133 {
03134     TclSetProcessGlobalValue(&executableName, name, encoding);
03135 }
03136 
03137 /*
03138  *----------------------------------------------------------------------
03139  *
03140  * TclGetObjNameOfExecutable --
03141  *
03142  *      This function retrieves the absolute pathname of the application in
03143  *      which the Tcl library is running, usually as previously stored by
03144  *      TclpFindExecutable(). This function call is the C API equivalent to
03145  *      the "info nameofexecutable" command.
03146  *
03147  * Results:
03148  *      A pointer to an "fsPath" Tcl_Obj, or to an empty Tcl_Obj if the
03149  *      pathname of the application is unknown.
03150  *
03151  * Side effects:
03152  *      None.
03153  *
03154  *----------------------------------------------------------------------
03155  */
03156 
03157 Tcl_Obj *
03158 TclGetObjNameOfExecutable(void)
03159 {
03160     return TclGetProcessGlobalValue(&executableName);
03161 }
03162 
03163 /*
03164  *----------------------------------------------------------------------
03165  *
03166  * Tcl_GetNameOfExecutable --
03167  *
03168  *      This function retrieves the absolute pathname of the application in
03169  *      which the Tcl library is running, and returns it in string form.
03170  *
03171  *      The returned string belongs to Tcl and should be copied if the caller
03172  *      plans to keep it, to guard against it becoming invalid.
03173  *
03174  * Results:
03175  *      A pointer to the internal string or NULL if the internal full path
03176  *      name has not been computed or unknown.
03177  *
03178  * Side effects:
03179  *      None.
03180  *
03181  *----------------------------------------------------------------------
03182  */
03183 
03184 CONST char *
03185 Tcl_GetNameOfExecutable(void)
03186 {
03187     int numBytes;
03188     const char *bytes =
03189             Tcl_GetStringFromObj(TclGetObjNameOfExecutable(), &numBytes);
03190 
03191     if (numBytes == 0) {
03192         return NULL;
03193     }
03194     return bytes;
03195 }
03196 
03197 /*
03198  *----------------------------------------------------------------------
03199  *
03200  * TclpGetTime --
03201  *
03202  *      Deprecated synonym for Tcl_GetTime. This function is provided for the
03203  *      benefit of extensions written before Tcl_GetTime was exported from the
03204  *      library.
03205  *
03206  * Results:
03207  *      None.
03208  *
03209  * Side effects:
03210  *      Stores current time in the buffer designated by "timePtr"
03211  *
03212  *----------------------------------------------------------------------
03213  */
03214 
03215 void
03216 TclpGetTime(
03217     Tcl_Time *timePtr)
03218 {
03219     Tcl_GetTime(timePtr);
03220 }
03221 
03222 /*
03223  *----------------------------------------------------------------------
03224  *
03225  * TclGetPlatform --
03226  *
03227  *      This is a kludge that allows the test library to get access the
03228  *      internal tclPlatform variable.
03229  *
03230  * Results:
03231  *      Returns a pointer to the tclPlatform variable.
03232  *
03233  * Side effects:
03234  *      None.
03235  *
03236  *----------------------------------------------------------------------
03237  */
03238 
03239 TclPlatformType *
03240 TclGetPlatform(void)
03241 {
03242     return &tclPlatform;
03243 }
03244 
03245 /*
03246  *----------------------------------------------------------------------
03247  *
03248  * TclReToGlob --
03249  *
03250  *      Attempt to convert a regular expression to an equivalent glob pattern.
03251  *
03252  * Results:
03253  *      Returns TCL_OK on success, TCL_ERROR on failure. If interp is not
03254  *      NULL, an error message is placed in the result. On success, the
03255  *      DString will contain an exact equivalent glob pattern. The caller is
03256  *      responsible for calling Tcl_DStringFree on success. If exactPtr is not
03257  *      NULL, it will be 1 if an exact match qualifies.
03258  *
03259  * Side effects:
03260  *      None.
03261  *
03262  *----------------------------------------------------------------------
03263  */
03264 
03265 int
03266 TclReToGlob(
03267     Tcl_Interp *interp,
03268     const char *reStr,
03269     int reStrLen,
03270     Tcl_DString *dsPtr,
03271     int *exactPtr)
03272 {
03273     int anchorLeft, anchorRight;
03274     char *dsStr, *dsStrStart, *msg;
03275     const char *p, *strEnd;
03276 
03277     strEnd = reStr + reStrLen;
03278     Tcl_DStringInit(dsPtr);
03279 
03280     /*
03281      * "***=xxx" == "*xxx*"
03282      */
03283 
03284     if ((reStrLen >= 4) && (memcmp("***=", reStr, 4) == 0)) {
03285         if (exactPtr) {
03286             *exactPtr = 1;
03287         }
03288         Tcl_DStringAppend(dsPtr, reStr + 4, reStrLen - 4);
03289         return TCL_OK;
03290     }
03291 
03292     /*
03293      * Write to the ds directly without the function overhead.
03294      * An equivalent glob pattern can be no more than reStrLen+2 in size.
03295      */
03296 
03297     Tcl_DStringSetLength(dsPtr, reStrLen + 2);
03298     dsStrStart = Tcl_DStringValue(dsPtr);
03299 
03300     /*
03301      * Check for anchored REs (ie ^foo$), so we can use string equal if
03302      * possible. Do not alter the start of str so we can free it correctly.
03303      */
03304 
03305     msg = NULL;
03306     p = reStr;
03307     anchorRight = 0;
03308     dsStr = dsStrStart;
03309     if (*p == '^') {
03310         anchorLeft = 1;
03311         p++;
03312     } else {
03313         anchorLeft = 0;
03314         *dsStr++ = '*';
03315     }
03316 
03317     for ( ; p < strEnd; p++) {
03318         switch (*p) {
03319         case '\\':
03320             p++;
03321             switch (*p) {
03322             case 'a':
03323                 *dsStr++ = '\a';
03324                 break;
03325             case 'b':
03326                 *dsStr++ = '\b';
03327                 break;
03328             case 'f':
03329                 *dsStr++ = '\f';
03330                 break;
03331             case 'n':
03332                 *dsStr++ = '\n';
03333                 break;
03334             case 'r':
03335                 *dsStr++ = '\r';
03336                 break;
03337             case 't':
03338                 *dsStr++ = '\t';
03339                 break;
03340             case 'v':
03341                 *dsStr++ = '\v';
03342                 break;
03343             case 'B': case '\\':
03344                 *dsStr++ = '\\';
03345                 *dsStr++ = '\\';
03346                 anchorLeft = 0; /* prevent exact match */
03347                 break;
03348             case '*': case '[': case ']': case '?':
03349                 /* Only add \ where necessary for glob */
03350                 *dsStr++ = '\\';
03351                 anchorLeft = 0; /* prevent exact match */
03352                 /* fall through */
03353             case '{': case '}': case '(': case ')': case '+':
03354             case '.': case '|': case '^': case '$':
03355                 *dsStr++ = *p;
03356                 break;
03357             default:
03358                 msg = "invalid escape sequence";
03359                 goto invalidGlob;
03360             }
03361             break;
03362         case '.':
03363             anchorLeft = 0; /* prevent exact match */
03364             if (p+1 < strEnd) {
03365                 if (p[1] == '*') {
03366                     p++;
03367                     if ((dsStr == dsStrStart) || (dsStr[-1] != '*')) {
03368                         *dsStr++ = '*';
03369                     }
03370                     continue;
03371                 } else if (p[1] == '+') {
03372                     p++;
03373                     *dsStr++ = '?';
03374                     *dsStr++ = '*';
03375                     continue;
03376                 }
03377             }
03378             *dsStr++ = '?';
03379             break;
03380         case '$':
03381             if (p+1 != strEnd) {
03382                 msg = "$ not anchor";
03383                 goto invalidGlob;
03384             }
03385             anchorRight = 1;
03386             break;
03387         case '*': case '+': case '?': case '|': case '^':
03388         case '{': case '}': case '(': case ')': case '[': case ']':
03389             msg = "unhandled RE special char";
03390             goto invalidGlob;
03391             break;
03392         default:
03393             *dsStr++ = *p;
03394             break;
03395         }
03396     }
03397     if (!anchorRight && ((dsStr == dsStrStart) || (dsStr[-1] != '*'))) {
03398         *dsStr++ = '*';
03399     }
03400     Tcl_DStringSetLength(dsPtr, dsStr - dsStrStart);
03401 
03402     if (exactPtr) {
03403         *exactPtr = (anchorLeft && anchorRight);
03404     }
03405 
03406 #if 0
03407     fprintf(stderr, "INPUT RE '%.*s' OUTPUT GLOB '%s' anchor %d:%d \n",
03408             reStrLen, reStr,
03409             Tcl_DStringValue(dsPtr), anchorLeft, anchorRight);
03410     fflush(stderr);
03411 #endif
03412     return TCL_OK;
03413 
03414   invalidGlob:
03415 #if 0
03416     fprintf(stderr, "INPUT RE '%.*s' NO OUTPUT GLOB %s (%c)\n",
03417             reStrLen, reStr, msg, *p);
03418     fflush(stderr);
03419 #endif
03420     if (interp != NULL) {
03421         Tcl_AppendResult(interp, msg, NULL);
03422     }
03423     Tcl_DStringFree(dsPtr);
03424     return TCL_ERROR;
03425 }
03426 
03427 /*
03428  * Local Variables:
03429  * mode: c
03430  * c-basic-offset: 4
03431  * fill-column: 78
03432  * End:
03433  */



Generated on Wed Mar 12 12:18:23 2008 by  doxygen 1.5.1