home *** CD-ROM | disk | FTP | other *** search
/ Stone Design / Stone Design.iso / Stone_Friends / Wave / WavesWorld / Source / Libraries / tcl7.4b3 / tclUtil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-15  |  55.7 KB  |  2,175 lines

  1. /* 
  2.  * tclUtil.c --
  3.  *
  4.  *    This file contains utility procedures that are used by many Tcl
  5.  *    commands.
  6.  *
  7.  * Copyright (c) 1987-1993 The Regents of the University of California.
  8.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  */
  13.  
  14. #ifndef lint
  15. static char sccsid[] = "@(#) tclUtil.c 1.103 95/02/15 12:45:10";
  16. #endif
  17.  
  18. #include "tclInt.h"
  19. #include "tclPort.h"
  20.  
  21. /*
  22.  * The following values are used in the flags returned by Tcl_ScanElement
  23.  * and used by Tcl_ConvertElement.  The value TCL_DONT_USE_BRACES is also
  24.  * defined in tcl.h;  make sure its value doesn't overlap with any of the
  25.  * values below.
  26.  *
  27.  * TCL_DONT_USE_BRACES -    1 means the string mustn't be enclosed in
  28.  *                braces (e.g. it contains unmatched braces,
  29.  *                or ends in a backslash character, or user
  30.  *                just doesn't want braces);  handle all
  31.  *                special characters by adding backslashes.
  32.  * USE_BRACES -            1 means the string contains a special
  33.  *                character that can be handled simply by
  34.  *                enclosing the entire argument in braces.
  35.  * BRACES_UNMATCHED -        1 means that braces aren't properly matched
  36.  *                in the argument.
  37.  */
  38.  
  39. #define USE_BRACES        2
  40. #define BRACES_UNMATCHED    4
  41.  
  42. /*
  43.  * Function prototypes for local procedures in this file:
  44.  */
  45.  
  46. static void        SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr,
  47.                 int newSpace));
  48.  
  49. /*
  50.  *----------------------------------------------------------------------
  51.  *
  52.  * TclFindElement --
  53.  *
  54.  *    Given a pointer into a Tcl list, locate the first (or next)
  55.  *    element in the list.
  56.  *
  57.  * Results:
  58.  *    The return value is normally TCL_OK, which means that the
  59.  *    element was successfully located.  If TCL_ERROR is returned
  60.  *    it means that list didn't have proper list structure;
  61.  *    interp->result contains a more detailed error message.
  62.  *
  63.  *    If TCL_OK is returned, then *elementPtr will be set to point
  64.  *    to the first element of list, and *nextPtr will be set to point
  65.  *    to the character just after any white space following the last
  66.  *    character that's part of the element.  If this is the last argument
  67.  *    in the list, then *nextPtr will point to the NULL character at the
  68.  *    end of list.  If sizePtr is non-NULL, *sizePtr is filled in with
  69.  *    the number of characters in the element.  If the element is in
  70.  *    braces, then *elementPtr will point to the character after the
  71.  *    opening brace and *sizePtr will not include either of the braces.
  72.  *    If there isn't an element in the list, *sizePtr will be zero, and
  73.  *    both *elementPtr and *termPtr will refer to the null character at
  74.  *    the end of list.  Note:  this procedure does NOT collapse backslash
  75.  *    sequences.
  76.  *
  77.  * Side effects:
  78.  *    None.
  79.  *
  80.  *----------------------------------------------------------------------
  81.  */
  82.  
  83. int
  84. TclFindElement(interp, list, elementPtr, nextPtr, sizePtr, bracePtr)
  85.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  86.     register char *list;    /* String containing Tcl list with zero
  87.                  * or more elements (possibly in braces). */
  88.     char **elementPtr;        /* Fill in with location of first significant
  89.                  * character in first element of list. */
  90.     char **nextPtr;        /* Fill in with location of character just
  91.                  * after all white space following end of
  92.                  * argument (i.e. next argument or end of
  93.                  * list). */
  94.     int *sizePtr;        /* If non-zero, fill in with size of
  95.                  * element. */
  96.     int *bracePtr;        /* If non-zero fill in with non-zero/zero
  97.                  * to indicate that arg was/wasn't
  98.                  * in braces. */
  99. {
  100.     register char *p;
  101.     int openBraces = 0;
  102.     int inQuotes = 0;
  103.     int size;
  104.  
  105.     /*
  106.      * Skim off leading white space and check for an opening brace or
  107.      * quote.   Note:  use of "isascii" below and elsewhere in this
  108.      * procedure is a temporary hack (7/27/90) because Mx uses characters
  109.      * with the high-order bit set for some things.  This should probably
  110.      * be changed back eventually, or all of Tcl should call isascii.
  111.      */
  112.  
  113.     while (isspace(UCHAR(*list))) {
  114.     list++;
  115.     }
  116.     if (*list == '{') {
  117.     openBraces = 1;
  118.     list++;
  119.     } else if (*list == '"') {
  120.     inQuotes = 1;
  121.     list++;
  122.     }
  123.     if (bracePtr != 0) {
  124.     *bracePtr = openBraces;
  125.     }
  126.     p = list;
  127.  
  128.     /*
  129.      * Find the end of the element (either a space or a close brace or
  130.      * the end of the string).
  131.      */
  132.  
  133.     while (1) {
  134.     switch (*p) {
  135.  
  136.         /*
  137.          * Open brace: don't treat specially unless the element is
  138.          * in braces.  In this case, keep a nesting count.
  139.          */
  140.  
  141.         case '{':
  142.         if (openBraces != 0) {
  143.             openBraces++;
  144.         }
  145.         break;
  146.  
  147.         /*
  148.          * Close brace: if element is in braces, keep nesting
  149.          * count and quit when the last close brace is seen.
  150.          */
  151.  
  152.         case '}':
  153.         if (openBraces == 1) {
  154.             char *p2;
  155.  
  156.             size = p - list;
  157.             p++;
  158.             if (isspace(UCHAR(*p)) || (*p == 0)) {
  159.             goto done;
  160.             }
  161.             for (p2 = p; (*p2 != 0) && (!isspace(UCHAR(*p2)))
  162.                 && (p2 < p+20); p2++) {
  163.             /* null body */
  164.             }
  165.             Tcl_ResetResult(interp);
  166.             sprintf(interp->result,
  167.                 "list element in braces followed by \"%.*s\" instead of space",
  168.                 (int) (p2-p), p);
  169.             return TCL_ERROR;
  170.         } else if (openBraces != 0) {
  171.             openBraces--;
  172.         }
  173.         break;
  174.  
  175.         /*
  176.          * Backslash:  skip over everything up to the end of the
  177.          * backslash sequence.
  178.          */
  179.  
  180.         case '\\': {
  181.         int size;
  182.  
  183.         (void) Tcl_Backslash(p, &size);
  184.         p += size - 1;
  185.         break;
  186.         }
  187.  
  188.         /*
  189.          * Space: ignore if element is in braces or quotes;  otherwise
  190.          * terminate element.
  191.          */
  192.  
  193.         case ' ':
  194.         case '\f':
  195.         case '\n':
  196.         case '\r':
  197.         case '\t':
  198.         case '\v':
  199.         if ((openBraces == 0) && !inQuotes) {
  200.             size = p - list;
  201.             goto done;
  202.         }
  203.         break;
  204.  
  205.         /*
  206.          * Double-quote:  if element is in quotes then terminate it.
  207.          */
  208.  
  209.         case '"':
  210.         if (inQuotes) {
  211.             char *p2;
  212.  
  213.             size = p-list;
  214.             p++;
  215.             if (isspace(UCHAR(*p)) || (*p == 0)) {
  216.             goto done;
  217.             }
  218.             for (p2 = p; (*p2 != 0) && (!isspace(UCHAR(*p2)))
  219.                 && (p2 < p+20); p2++) {
  220.             /* null body */
  221.             }
  222.             Tcl_ResetResult(interp);
  223.             sprintf(interp->result,
  224.                 "list element in quotes followed by \"%.*s\" %s",
  225.                 (int) (p2-p), p, "instead of space");
  226.             return TCL_ERROR;
  227.         }
  228.         break;
  229.  
  230.         /*
  231.          * End of list:  terminate element.
  232.          */
  233.  
  234.         case 0:
  235.         if (openBraces != 0) {
  236.             Tcl_SetResult(interp, "unmatched open brace in list",
  237.                 TCL_STATIC);
  238.             return TCL_ERROR;
  239.         } else if (inQuotes) {
  240.             Tcl_SetResult(interp, "unmatched open quote in list",
  241.                 TCL_STATIC);
  242.             return TCL_ERROR;
  243.         }
  244.         size = p - list;
  245.         goto done;
  246.  
  247.     }
  248.     p++;
  249.     }
  250.  
  251.     done:
  252.     while (isspace(UCHAR(*p))) {
  253.     p++;
  254.     }
  255.     *elementPtr = list;
  256.     *nextPtr = p;
  257.     if (sizePtr != 0) {
  258.     *sizePtr = size;
  259.     }
  260.     return TCL_OK;
  261. }
  262.  
  263. /*
  264.  *----------------------------------------------------------------------
  265.  *
  266.  * TclCopyAndCollapse --
  267.  *
  268.  *    Copy a string and eliminate any backslashes that aren't in braces.
  269.  *
  270.  * Results:
  271.  *    There is no return value.  Count chars. get copied from src
  272.  *    to dst.  Along the way, if backslash sequences are found outside
  273.  *    braces, the backslashes are eliminated in the copy.
  274.  *    After scanning count chars. from source, a null character is
  275.  *    placed at the end of dst.
  276.  *
  277.  * Side effects:
  278.  *    None.
  279.  *
  280.  *----------------------------------------------------------------------
  281.  */
  282.  
  283. void
  284. TclCopyAndCollapse(count, src, dst)
  285.     int count;            /* Total number of characters to copy
  286.                  * from src. */
  287.     register char *src;        /* Copy from here... */
  288.     register char *dst;        /* ... to here. */
  289. {
  290.     register char c;
  291.     int numRead;
  292.  
  293.     for (c = *src; count > 0; src++, c = *src, count--) {
  294.     if (c == '\\') {
  295.         *dst = Tcl_Backslash(src, &numRead);
  296.         dst++;
  297.         src += numRead-1;
  298.         count -= numRead-1;
  299.     } else {
  300.         *dst = c;
  301.         dst++;
  302.     }
  303.     }
  304.     *dst = 0;
  305. }
  306.  
  307. /*
  308.  *----------------------------------------------------------------------
  309.  *
  310.  * Tcl_SplitList --
  311.  *
  312.  *    Splits a list up into its constituent fields.
  313.  *
  314.  * Results
  315.  *    The return value is normally TCL_OK, which means that
  316.  *    the list was successfully split up.  If TCL_ERROR is
  317.  *    returned, it means that "list" didn't have proper list
  318.  *    structure;  interp->result will contain a more detailed
  319.  *    error message.
  320.  *
  321.  *    *argvPtr will be filled in with the address of an array
  322.  *    whose elements point to the elements of list, in order.
  323.  *    *argcPtr will get filled in with the number of valid elements
  324.  *    in the array.  A single block of memory is dynamically allocated
  325.  *    to hold both the argv array and a copy of the list (with
  326.  *    backslashes and braces removed in the standard way).
  327.  *    The caller must eventually free this memory by calling free()
  328.  *    on *argvPtr.  Note:  *argvPtr and *argcPtr are only modified
  329.  *    if the procedure returns normally.
  330.  *
  331.  * Side effects:
  332.  *    Memory is allocated.
  333.  *
  334.  *----------------------------------------------------------------------
  335.  */
  336.  
  337. int
  338. Tcl_SplitList(interp, list, argcPtr, argvPtr)
  339.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  340.     char *list;            /* Pointer to string with list structure. */
  341.     int *argcPtr;        /* Pointer to location to fill in with
  342.                  * the number of elements in the list. */
  343.     char ***argvPtr;        /* Pointer to place to store pointer to array
  344.                  * of pointers to list elements. */
  345. {
  346.     char **argv;
  347.     register char *p;
  348.     int size, i, result, elSize, brace;
  349.     char *element;
  350.  
  351.     /*
  352.      * Figure out how much space to allocate.  There must be enough
  353.      * space for both the array of pointers and also for a copy of
  354.      * the list.  To estimate the number of pointers needed, count
  355.      * the number of space characters in the list.
  356.      */
  357.  
  358.     for (size = 1, p = list; *p != 0; p++) {
  359.     if (isspace(UCHAR(*p))) {
  360.         size++;
  361.     }
  362.     }
  363.     size++;            /* Leave space for final NULL pointer. */
  364.     argv = (char **) ckalloc((unsigned)
  365.         ((size * sizeof(char *)) + (p - list) + 1));
  366.     for (i = 0, p = ((char *) argv) + size*sizeof(char *);
  367.         *list != 0; i++) {
  368.     result = TclFindElement(interp, list, &element, &list, &elSize, &brace);
  369.     if (result != TCL_OK) {
  370.         ckfree((char *) argv);
  371.         return result;
  372.     }
  373.     if (*element == 0) {
  374.         break;
  375.     }
  376.     if (i >= size) {
  377.         ckfree((char *) argv);
  378.         Tcl_SetResult(interp, "internal error in Tcl_SplitList",
  379.             TCL_STATIC);
  380.         return TCL_ERROR;
  381.     }
  382.     argv[i] = p;
  383.     if (brace) {
  384.         strncpy(p, element, (size_t) elSize);
  385.         p += elSize;
  386.         *p = 0;
  387.         p++;
  388.     } else {
  389.         TclCopyAndCollapse(elSize, element, p);
  390.         p += elSize+1;
  391.     }
  392.     }
  393.  
  394.     argv[i] = NULL;
  395.     *argvPtr = argv;
  396.     *argcPtr = i;
  397.     return TCL_OK;
  398. }
  399.  
  400. /*
  401.  *----------------------------------------------------------------------
  402.  *
  403.  * Tcl_ScanElement --
  404.  *
  405.  *    This procedure is a companion procedure to Tcl_ConvertElement.
  406.  *    It scans a string to see what needs to be done to it (e.g.
  407.  *    add backslashes or enclosing braces) to make the string into
  408.  *    a valid Tcl list element.
  409.  *
  410.  * Results:
  411.  *    The return value is an overestimate of the number of characters
  412.  *    that will be needed by Tcl_ConvertElement to produce a valid
  413.  *    list element from string.  The word at *flagPtr is filled in
  414.  *    with a value needed by Tcl_ConvertElement when doing the actual
  415.  *    conversion.
  416.  *
  417.  * Side effects:
  418.  *    None.
  419.  *
  420.  *----------------------------------------------------------------------
  421.  */
  422.  
  423. int
  424. Tcl_ScanElement(string, flagPtr)
  425.     char *string;        /* String to convert to Tcl list element. */
  426.     int *flagPtr;        /* Where to store information to guide
  427.                  * Tcl_ConvertElement. */
  428. {
  429.     int flags, nestingLevel;
  430.     register char *p;
  431.  
  432.     /*
  433.      * This procedure and Tcl_ConvertElement together do two things:
  434.      *
  435.      * 1. They produce a proper list, one that will yield back the
  436.      * argument strings when evaluated or when disassembled with
  437.      * Tcl_SplitList.  This is the most important thing.
  438.      * 
  439.      * 2. They try to produce legible output, which means minimizing the
  440.      * use of backslashes (using braces instead).  However, there are
  441.      * some situations where backslashes must be used (e.g. an element
  442.      * like "{abc": the leading brace will have to be backslashed.  For
  443.      * each element, one of three things must be done:
  444.      *
  445.      * (a) Use the element as-is (it doesn't contain anything special
  446.      * characters).  This is the most desirable option.
  447.      *
  448.      * (b) Enclose the element in braces, but leave the contents alone.
  449.      * This happens if the element contains embedded space, or if it
  450.      * contains characters with special interpretation ($, [, ;, or \),
  451.      * or if it starts with a brace or double-quote, or if there are
  452.      * no characters in the element.
  453.      *
  454.      * (c) Don't enclose the element in braces, but add backslashes to
  455.      * prevent special interpretation of special characters.  This is a
  456.      * last resort used when the argument would normally fall under case
  457.      * (b) but contains unmatched braces.  It also occurs if the last
  458.      * character of the argument is a backslash or if the element contains
  459.      * a backslash followed by newline.
  460.      *
  461.      * The procedure figures out how many bytes will be needed to store
  462.      * the result (actually, it overestimates).  It also collects information
  463.      * about the element in the form of a flags word.
  464.      */
  465.  
  466.     nestingLevel = 0;
  467.     flags = 0;
  468.     if (string == NULL) {
  469.     string = "";
  470.     }
  471.     p = string;
  472.     if ((*p == '{') || (*p == '"') || (*p == 0)) {
  473.     flags |= USE_BRACES;
  474.     }
  475.     for ( ; *p != 0; p++) {
  476.     switch (*p) {
  477.         case '{':
  478.         nestingLevel++;
  479.         break;
  480.         case '}':
  481.         nestingLevel--;
  482.         if (nestingLevel < 0) {
  483.             flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
  484.         }
  485.         break;
  486.         case '[':
  487.         case '$':
  488.         case ';':
  489.         case ' ':
  490.         case '\f':
  491.         case '\n':
  492.         case '\r':
  493.         case '\t':
  494.         case '\v':
  495.         flags |= USE_BRACES;
  496.         break;
  497.         case '\\':
  498.         if ((p[1] == 0) || (p[1] == '\n')) {
  499.             flags = TCL_DONT_USE_BRACES;
  500.         } else {
  501.             int size;
  502.  
  503.             (void) Tcl_Backslash(p, &size);
  504.             p += size-1;
  505.             flags |= USE_BRACES;
  506.         }
  507.         break;
  508.     }
  509.     }
  510.     if (nestingLevel != 0) {
  511.     flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
  512.     }
  513.     *flagPtr = flags;
  514.  
  515.     /*
  516.      * Allow enough space to backslash every character plus leave
  517.      * two spaces for braces.
  518.      */
  519.  
  520.     return 2*(p-string) + 2;
  521. }
  522.  
  523. /*
  524.  *----------------------------------------------------------------------
  525.  *
  526.  * Tcl_ConvertElement --
  527.  *
  528.  *    This is a companion procedure to Tcl_ScanElement.  Given the
  529.  *    information produced by Tcl_ScanElement, this procedure converts
  530.  *    a string to a list element equal to that string.
  531.  *
  532.  * Results:
  533.  *    Information is copied to *dst in the form of a list element
  534.  *    identical to src (i.e. if Tcl_SplitList is applied to dst it
  535.  *    will produce a string identical to src).  The return value is
  536.  *    a count of the number of characters copied (not including the
  537.  *    terminating NULL character).
  538.  *
  539.  * Side effects:
  540.  *    None.
  541.  *
  542.  *----------------------------------------------------------------------
  543.  */
  544.  
  545. int
  546. Tcl_ConvertElement(src, dst, flags)
  547.     register char *src;        /* Source information for list element. */
  548.     char *dst;            /* Place to put list-ified element. */
  549.     int flags;            /* Flags produced by Tcl_ScanElement. */
  550. {
  551.     register char *p = dst;
  552.  
  553.     /*
  554.      * See the comment block at the beginning of the Tcl_ScanElement
  555.      * code for details of how this works.
  556.      */
  557.  
  558.     if ((src == NULL) || (*src == 0)) {
  559.     p[0] = '{';
  560.     p[1] = '}';
  561.     p[2] = 0;
  562.     return 2;
  563.     }
  564.     if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
  565.     *p = '{';
  566.     p++;
  567.     for ( ; *src != 0; src++, p++) {
  568.         *p = *src;
  569.     }
  570.     *p = '}';
  571.     p++;
  572.     } else {
  573.     if (*src == '{') {
  574.         /*
  575.          * Can't have a leading brace unless the whole element is
  576.          * enclosed in braces.  Add a backslash before the brace.
  577.          * Furthermore, this may destroy the balance between open
  578.          * and close braces, so set BRACES_UNMATCHED.
  579.          */
  580.  
  581.         p[0] = '\\';
  582.         p[1] = '{';
  583.         p += 2;
  584.         src++;
  585.         flags |= BRACES_UNMATCHED;
  586.     }
  587.     for (; *src != 0 ; src++) {
  588.         switch (*src) {
  589.         case ']':
  590.         case '[':
  591.         case '$':
  592.         case ';':
  593.         case ' ':
  594.         case '\\':
  595.         case '"':
  596.             *p = '\\';
  597.             p++;
  598.             break;
  599.         case '{':
  600.         case '}':
  601.             /*
  602.              * It may not seem necessary to backslash braces, but
  603.              * it is.  The reason for this is that the resulting
  604.              * list element may actually be an element of a sub-list
  605.              * enclosed in braces (e.g. if Tcl_DStringStartSublist
  606.              * has been invoked), so there may be a brace mismatch
  607.              * if the braces aren't backslashed.
  608.              */
  609.  
  610.             if (flags & BRACES_UNMATCHED) {
  611.             *p = '\\';
  612.             p++;
  613.             }
  614.             break;
  615.         case '\f':
  616.             *p = '\\';
  617.             p++;
  618.             *p = 'f';
  619.             p++;
  620.             continue;
  621.         case '\n':
  622.             *p = '\\';
  623.             p++;
  624.             *p = 'n';
  625.             p++;
  626.             continue;
  627.         case '\r':
  628.             *p = '\\';
  629.             p++;
  630.             *p = 'r';
  631.             p++;
  632.             continue;
  633.         case '\t':
  634.             *p = '\\';
  635.             p++;
  636.             *p = 't';
  637.             p++;
  638.             continue;
  639.         case '\v':
  640.             *p = '\\';
  641.             p++;
  642.             *p = 'v';
  643.             p++;
  644.             continue;
  645.         }
  646.         *p = *src;
  647.         p++;
  648.     }
  649.     }
  650.     *p = '\0';
  651.     return p-dst;
  652. }
  653.  
  654. /*
  655.  *----------------------------------------------------------------------
  656.  *
  657.  * Tcl_Merge --
  658.  *
  659.  *    Given a collection of strings, merge them together into a
  660.  *    single string that has proper Tcl list structured (i.e.
  661.  *    Tcl_SplitList may be used to retrieve strings equal to the
  662.  *    original elements, and Tcl_Eval will parse the string back
  663.  *    into its original elements).
  664.  *
  665.  * Results:
  666.  *    The return value is the address of a dynamically-allocated
  667.  *    string containing the merged list.
  668.  *
  669.  * Side effects:
  670.  *    None.
  671.  *
  672.  *----------------------------------------------------------------------
  673.  */
  674.  
  675. char *
  676. Tcl_Merge(argc, argv)
  677.     int argc;            /* How many strings to merge. */
  678.     char **argv;        /* Array of string values. */
  679. {
  680. #   define LOCAL_SIZE 20
  681.     int localFlags[LOCAL_SIZE], *flagPtr;
  682.     int numChars;
  683.     char *result;
  684.     register char *dst;
  685.     int i;
  686.  
  687.     /*
  688.      * Pass 1: estimate space, gather flags.
  689.      */
  690.  
  691.     if (argc <= LOCAL_SIZE) {
  692.     flagPtr = localFlags;
  693.     } else {
  694.     flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
  695.     }
  696.     numChars = 1;
  697.     for (i = 0; i < argc; i++) {
  698.     numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
  699.     }
  700.  
  701.     /*
  702.      * Pass two: copy into the result area.
  703.      */
  704.  
  705.     result = (char *) ckalloc((unsigned) numChars);
  706.     dst = result;
  707.     for (i = 0; i < argc; i++) {
  708.     numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]);
  709.     dst += numChars;
  710.     *dst = ' ';
  711.     dst++;
  712.     }
  713.     if (dst == result) {
  714.     *dst = 0;
  715.     } else {
  716.     dst[-1] = 0;
  717.     }
  718.  
  719.     if (flagPtr != localFlags) {
  720.     ckfree((char *) flagPtr);
  721.     }
  722.     return result;
  723. }
  724.  
  725. /*
  726.  *----------------------------------------------------------------------
  727.  *
  728.  * Tcl_Concat --
  729.  *
  730.  *    Concatenate a set of strings into a single large string.
  731.  *
  732.  * Results:
  733.  *    The return value is dynamically-allocated string containing
  734.  *    a concatenation of all the strings in argv, with spaces between
  735.  *    the original argv elements.
  736.  *
  737.  * Side effects:
  738.  *    Memory is allocated for the result;  the caller is responsible
  739.  *    for freeing the memory.
  740.  *
  741.  *----------------------------------------------------------------------
  742.  */
  743.  
  744. char *
  745. Tcl_Concat(argc, argv)
  746.     int argc;            /* Number of strings to concatenate. */
  747.     char **argv;        /* Array of strings to concatenate. */
  748. {
  749.     int totalSize, i;
  750.     register char *p;
  751.     char *result;
  752.  
  753.     for (totalSize = 1, i = 0; i < argc; i++) {
  754.     totalSize += strlen(argv[i]) + 1;
  755.     }
  756.     result = (char *) ckalloc((unsigned) totalSize);
  757.     if (argc == 0) {
  758.     *result = '\0';
  759.     return result;
  760.     }
  761.     for (p = result, i = 0; i < argc; i++) {
  762.     char *element;
  763.     int length;
  764.  
  765.     /*
  766.      * Clip white space off the front and back of the string
  767.      * to generate a neater result, and ignore any empty
  768.      * elements.
  769.      */
  770.  
  771.     element = argv[i];
  772.     while (isspace(UCHAR(*element))) {
  773.         element++;
  774.     }
  775.     for (length = strlen(element);
  776.         (length > 0) && (isspace(UCHAR(element[length-1])));
  777.         length--) {
  778.         /* Null loop body. */
  779.     }
  780.     if (length == 0) {
  781.         continue;
  782.     }
  783.     (void) strncpy(p, element, (size_t) length);
  784.     p += length;
  785.     *p = ' ';
  786.     p++;
  787.     }
  788.     if (p != result) {
  789.     p[-1] = 0;
  790.     } else {
  791.     *p = 0;
  792.     }
  793.     return result;
  794. }
  795.  
  796. /*
  797.  *----------------------------------------------------------------------
  798.  *
  799.  * Tcl_StringMatch --
  800.  *
  801.  *    See if a particular string matches a particular pattern.
  802.  *
  803.  * Results:
  804.  *    The return value is 1 if string matches pattern, and
  805.  *    0 otherwise.  The matching operation permits the following
  806.  *    special characters in the pattern: *?\[] (see the manual
  807.  *    entry for details on what these mean).
  808.  *
  809.  * Side effects:
  810.  *    None.
  811.  *
  812.  *----------------------------------------------------------------------
  813.  */
  814.  
  815. int
  816. Tcl_StringMatch(string, pattern)
  817.     register char *string;    /* String. */
  818.     register char *pattern;    /* Pattern, which may contain
  819.                  * special characters. */
  820. {
  821.     char c2;
  822.  
  823.     while (1) {
  824.     /* See if we're at the end of both the pattern and the string.
  825.      * If so, we succeeded.  If we're at the end of the pattern
  826.      * but not at the end of the string, we failed.
  827.      */
  828.     
  829.     if (*pattern == 0) {
  830.         if (*string == 0) {
  831.         return 1;
  832.         } else {
  833.         return 0;
  834.         }
  835.     }
  836.     if ((*string == 0) && (*pattern != '*')) {
  837.         return 0;
  838.     }
  839.  
  840.     /* Check for a "*" as the next pattern character.  It matches
  841.      * any substring.  We handle this by calling ourselves
  842.      * recursively for each postfix of string, until either we
  843.      * match or we reach the end of the string.
  844.      */
  845.     
  846.     if (*pattern == '*') {
  847.         pattern += 1;
  848.         if (*pattern == 0) {
  849.         return 1;
  850.         }
  851.         while (1) {
  852.         if (Tcl_StringMatch(string, pattern)) {
  853.             return 1;
  854.         }
  855.         if (*string == 0) {
  856.             return 0;
  857.         }
  858.         string += 1;
  859.         }
  860.     }
  861.     
  862.     /* Check for a "?" as the next pattern character.  It matches
  863.      * any single character.
  864.      */
  865.  
  866.     if (*pattern == '?') {
  867.         goto thisCharOK;
  868.     }
  869.  
  870.     /* Check for a "[" as the next pattern character.  It is followed
  871.      * by a list of characters that are acceptable, or by a range
  872.      * (two characters separated by "-").
  873.      */
  874.     
  875.     if (*pattern == '[') {
  876.         pattern += 1;
  877.         while (1) {
  878.         if ((*pattern == ']') || (*pattern == 0)) {
  879.             return 0;
  880.         }
  881.         if (*pattern == *string) {
  882.             break;
  883.         }
  884.         if (pattern[1] == '-') {
  885.             c2 = pattern[2];
  886.             if (c2 == 0) {
  887.             return 0;
  888.             }
  889.             if ((*pattern <= *string) && (c2 >= *string)) {
  890.             break;
  891.             }
  892.             if ((*pattern >= *string) && (c2 <= *string)) {
  893.             break;
  894.             }
  895.             pattern += 2;
  896.         }
  897.         pattern += 1;
  898.         }
  899.         while (*pattern != ']') {
  900.         if (*pattern == 0) {
  901.             pattern--;
  902.             break;
  903.         }
  904.         pattern += 1;
  905.         }
  906.         goto thisCharOK;
  907.     }
  908.     
  909.     /* If the next pattern character is '/', just strip off the '/'
  910.      * so we do exact matching on the character that follows.
  911.      */
  912.     
  913.     if (*pattern == '\\') {
  914.         pattern += 1;
  915.         if (*pattern == 0) {
  916.         return 0;
  917.         }
  918.     }
  919.  
  920.     /* There's no special character.  Just make sure that the next
  921.      * characters of each string match.
  922.      */
  923.     
  924.     if (*pattern != *string) {
  925.         return 0;
  926.     }
  927.  
  928.     thisCharOK: pattern += 1;
  929.     string += 1;
  930.     }
  931. }
  932.  
  933. /*
  934.  *----------------------------------------------------------------------
  935.  *
  936.  * Tcl_SetResult --
  937.  *
  938.  *    Arrange for "string" to be the Tcl return value.
  939.  *
  940.  * Results:
  941.  *    None.
  942.  *
  943.  * Side effects:
  944.  *    interp->result is left pointing either to "string" (if "copy" is 0)
  945.  *    or to a copy of string.
  946.  *
  947.  *----------------------------------------------------------------------
  948.  */
  949.  
  950. void
  951. Tcl_SetResult(interp, string, freeProc)
  952.     Tcl_Interp *interp;        /* Interpreter with which to associate the
  953.                  * return value. */
  954.     char *string;        /* Value to be returned.  If NULL,
  955.                  * the result is set to an empty string. */
  956.     Tcl_FreeProc *freeProc;    /* Gives information about the string:
  957.                  * TCL_STATIC, TCL_VOLATILE, or the address
  958.                  * of a Tcl_FreeProc such as free. */
  959. {
  960.     register Interp *iPtr = (Interp *) interp;
  961.     int length;
  962.     Tcl_FreeProc *oldFreeProc = iPtr->freeProc;
  963.     char *oldResult = iPtr->result;
  964.  
  965.     if (string == NULL) {
  966.     iPtr->resultSpace[0] = 0;
  967.     iPtr->result = iPtr->resultSpace;
  968.     iPtr->freeProc = 0;
  969.     } else if (freeProc == TCL_DYNAMIC) {
  970.     iPtr->result = string;
  971.     iPtr->freeProc = (Tcl_FreeProc *) free;
  972.     } else if (freeProc == TCL_VOLATILE) {
  973.     length = strlen(string);
  974.     if (length > TCL_RESULT_SIZE) {
  975.         iPtr->result = (char *) ckalloc((unsigned) length+1);
  976.         iPtr->freeProc = (Tcl_FreeProc *) free;
  977.     } else {
  978.         iPtr->result = iPtr->resultSpace;
  979.         iPtr->freeProc = 0;
  980.     }
  981.     strcpy(iPtr->result, string);
  982.     } else {
  983.     iPtr->result = string;
  984.     iPtr->freeProc = freeProc;
  985.     }
  986.  
  987.     /*
  988.      * If the old result was dynamically-allocated, free it up.  Do it
  989.      * here, rather than at the beginning, in case the new result value
  990.      * was part of the old result value.
  991.      */
  992.  
  993.     if (oldFreeProc != 0) {
  994.     if (oldFreeProc == (Tcl_FreeProc *) free) {
  995.         ckfree(oldResult);
  996.     } else {
  997.         (*oldFreeProc)(oldResult);
  998.     }
  999.     }
  1000. }
  1001.  
  1002. /*
  1003.  *----------------------------------------------------------------------
  1004.  *
  1005.  * Tcl_Volatile, Tcl_Dynamic --
  1006.  *
  1007.  *    These are dummy procedures, which should never actually be
  1008.  *    invoked.  They are simply a placeholders, to provide addresses
  1009.  *    for TCL_VOLATILE and TCL_DYNAMIC to refer to, which won't be
  1010.  *    used by any other procedure.
  1011.  *
  1012.  * Results:
  1013.  *    None.
  1014.  *
  1015.  * Side effects:
  1016.  *    None.
  1017.  *
  1018.  *----------------------------------------------------------------------
  1019.  */
  1020.  
  1021. void
  1022. Tcl_Volatile(buffer)
  1023.     char *buffer;            /* Not used. */
  1024. {
  1025. }
  1026. void
  1027. Tcl_Dynamic(buffer)
  1028.     char *buffer;            /* Not used. */
  1029. {
  1030. }
  1031.  
  1032. /*
  1033.  *----------------------------------------------------------------------
  1034.  *
  1035.  * Tcl_AppendResult --
  1036.  *
  1037.  *    Append a variable number of strings onto the result already
  1038.  *    present for an interpreter.
  1039.  *
  1040.  * Results:
  1041.  *    None.
  1042.  *
  1043.  * Side effects:
  1044.  *    The result in the interpreter given by the first argument
  1045.  *    is extended by the strings given by the second and following
  1046.  *    arguments (up to a terminating NULL argument).
  1047.  *
  1048.  *----------------------------------------------------------------------
  1049.  */
  1050.  
  1051.     /* VARARGS2 */
  1052. #ifndef lint
  1053. void
  1054. Tcl_AppendResult(va_alist)
  1055. #else
  1056. void
  1057.     /* VARARGS2 */ /* ARGSUSED */
  1058. Tcl_AppendResult(interp, p, va_alist)
  1059.     Tcl_Interp *interp;        /* Interpreter whose result is to be
  1060.                  * extended. */
  1061.     char *p;            /* One or more strings to add to the
  1062.                  * result, terminated with NULL. */
  1063. #endif
  1064.     va_dcl
  1065. {
  1066.     va_list argList;
  1067.     register Interp *iPtr;
  1068.     char *string;
  1069.     int newSpace;
  1070.  
  1071.     /*
  1072.      * First, scan through all the arguments to see how much space is
  1073.      * needed.
  1074.      */
  1075.  
  1076.     va_start(argList);
  1077.     iPtr = va_arg(argList, Interp *);
  1078.     newSpace = 0;
  1079.     while (1) {
  1080.     string = va_arg(argList, char *);
  1081.     if (string == NULL) {
  1082.         break;
  1083.     }
  1084.     newSpace += strlen(string);
  1085.     }
  1086.     va_end(argList);
  1087.  
  1088.     /*
  1089.      * If the append buffer isn't already setup and large enough
  1090.      * to hold the new data, set it up.
  1091.      */
  1092.  
  1093.     if ((iPtr->result != iPtr->appendResult)
  1094.         || (iPtr->appendResult[iPtr->appendUsed] != 0)
  1095.         || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) {
  1096.        SetupAppendBuffer(iPtr, newSpace);
  1097.     }
  1098.  
  1099.     /*
  1100.      * Final step:  go through all the argument strings again, copying
  1101.      * them into the buffer.
  1102.      */
  1103.  
  1104.     va_start(argList);
  1105.     (void) va_arg(argList, Tcl_Interp *);
  1106.     while (1) {
  1107.     string = va_arg(argList, char *);
  1108.     if (string == NULL) {
  1109.         break;
  1110.     }
  1111.     strcpy(iPtr->appendResult + iPtr->appendUsed, string);
  1112.     iPtr->appendUsed += strlen(string);
  1113.     }
  1114.     va_end(argList);
  1115. }
  1116.  
  1117. /*
  1118.  *----------------------------------------------------------------------
  1119.  *
  1120.  * Tcl_AppendElement --
  1121.  *
  1122.  *    Convert a string to a valid Tcl list element and append it
  1123.  *    to the current result (which is ostensibly a list).
  1124.  *
  1125.  * Results:
  1126.  *    None.
  1127.  *
  1128.  * Side effects:
  1129.  *    The result in the interpreter given by the first argument
  1130.  *    is extended with a list element converted from string.  A
  1131.  *    separator space is added before the converted list element
  1132.  *    unless the current result is empty, contains the single
  1133.  *    character "{", or ends in " {".
  1134.  *
  1135.  *----------------------------------------------------------------------
  1136.  */
  1137.  
  1138. void
  1139. Tcl_AppendElement(interp, string)
  1140.     Tcl_Interp *interp;        /* Interpreter whose result is to be
  1141.                  * extended. */
  1142.     char *string;        /* String to convert to list element and
  1143.                  * add to result. */
  1144. {
  1145.     register Interp *iPtr = (Interp *) interp;
  1146.     int size, flags;
  1147.     char *dst;
  1148.  
  1149.     /*
  1150.      * See how much space is needed, and grow the append buffer if
  1151.      * needed to accommodate the list element.
  1152.      */
  1153.  
  1154.     size = Tcl_ScanElement(string, &flags) + 1;
  1155.     if ((iPtr->result != iPtr->appendResult)
  1156.         || (iPtr->appendResult[iPtr->appendUsed] != 0)
  1157.         || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) {
  1158.        SetupAppendBuffer(iPtr, size+iPtr->appendUsed);
  1159.     }
  1160.  
  1161.     /*
  1162.      * Convert the string into a list element and copy it to the
  1163.      * buffer that's forming, with a space separator if needed.
  1164.      */
  1165.  
  1166.     dst = iPtr->appendResult + iPtr->appendUsed;
  1167.     if (TclNeedSpace(iPtr->appendResult, dst)) {
  1168.     iPtr->appendUsed++;
  1169.     *dst = ' ';
  1170.     dst++;
  1171.     }
  1172.     iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);
  1173. }
  1174.  
  1175. /*
  1176.  *----------------------------------------------------------------------
  1177.  *
  1178.  * SetupAppendBuffer --
  1179.  *
  1180.  *    This procedure makes sure that there is an append buffer
  1181.  *    properly initialized for interp, and that it has at least
  1182.  *    enough room to accommodate newSpace new bytes of information.
  1183.  *
  1184.  * Results:
  1185.  *    None.
  1186.  *
  1187.  * Side effects:
  1188.  *    None.
  1189.  *
  1190.  *----------------------------------------------------------------------
  1191.  */
  1192.  
  1193. static void
  1194. SetupAppendBuffer(iPtr, newSpace)
  1195.     register Interp *iPtr;    /* Interpreter whose result is being set up. */
  1196.     int newSpace;        /* Make sure that at least this many bytes
  1197.                  * of new information may be added. */
  1198. {
  1199.     int totalSpace;
  1200.  
  1201.     /*
  1202.      * Make the append buffer larger, if that's necessary, then
  1203.      * copy the current result into the append buffer and make the
  1204.      * append buffer the official Tcl result.
  1205.      */
  1206.  
  1207.     if (iPtr->result != iPtr->appendResult) {
  1208.     /*
  1209.      * If an oversized buffer was used recently, then free it up
  1210.      * so we go back to a smaller buffer.  This avoids tying up
  1211.      * memory forever after a large operation.
  1212.      */
  1213.  
  1214.     if (iPtr->appendAvl > 500) {
  1215.         ckfree(iPtr->appendResult);
  1216.         iPtr->appendResult = NULL;
  1217.         iPtr->appendAvl = 0;
  1218.     }
  1219.     iPtr->appendUsed = strlen(iPtr->result);
  1220.     } else if (iPtr->result[iPtr->appendUsed] != 0) {
  1221.     /*
  1222.      * Most likely someone has modified a result created by
  1223.      * Tcl_AppendResult et al. so that it has a different size.
  1224.      * Just recompute the size.
  1225.      */
  1226.  
  1227.     iPtr->appendUsed = strlen(iPtr->result);
  1228.     }
  1229.     totalSpace = newSpace + iPtr->appendUsed;
  1230.     if (totalSpace >= iPtr->appendAvl) {
  1231.     char *new;
  1232.  
  1233.     if (totalSpace < 100) {
  1234.         totalSpace = 200;
  1235.     } else {
  1236.         totalSpace *= 2;
  1237.     }
  1238.     new = (char *) ckalloc((unsigned) totalSpace);
  1239.     strcpy(new, iPtr->result);
  1240.     if (iPtr->appendResult != NULL) {
  1241.         ckfree(iPtr->appendResult);
  1242.     }
  1243.     iPtr->appendResult = new;
  1244.     iPtr->appendAvl = totalSpace;
  1245.     } else if (iPtr->result != iPtr->appendResult) {
  1246.     strcpy(iPtr->appendResult, iPtr->result);
  1247.     }
  1248.     Tcl_FreeResult(iPtr);
  1249.     iPtr->result = iPtr->appendResult;
  1250. }
  1251.  
  1252. /*
  1253.  *----------------------------------------------------------------------
  1254.  *
  1255.  * Tcl_ResetResult --
  1256.  *
  1257.  *    This procedure restores the result area for an interpreter
  1258.  *    to its default initialized state, freeing up any memory that
  1259.  *    may have been allocated for the result and clearing any
  1260.  *    error information for the interpreter.
  1261.  *
  1262.  * Results:
  1263.  *    None.
  1264.  *
  1265.  * Side effects:
  1266.  *    None.
  1267.  *
  1268.  *----------------------------------------------------------------------
  1269.  */
  1270.  
  1271. void
  1272. Tcl_ResetResult(interp)
  1273.     Tcl_Interp *interp;        /* Interpreter for which to clear result. */
  1274. {
  1275.     register Interp *iPtr = (Interp *) interp;
  1276.  
  1277.     Tcl_FreeResult(iPtr);
  1278.     iPtr->result = iPtr->resultSpace;
  1279.     iPtr->resultSpace[0] = 0;
  1280.     iPtr->flags &=
  1281.         ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);
  1282. }
  1283.  
  1284. /*
  1285.  *----------------------------------------------------------------------
  1286.  *
  1287.  * Tcl_SetErrorCode --
  1288.  *
  1289.  *    This procedure is called to record machine-readable information
  1290.  *    about an error that is about to be returned.
  1291.  *
  1292.  * Results:
  1293.  *    None.
  1294.  *
  1295.  * Side effects:
  1296.  *    The errorCode global variable is modified to hold all of the
  1297.  *    arguments to this procedure, in a list form with each argument
  1298.  *    becoming one element of the list.  A flag is set internally
  1299.  *    to remember that errorCode has been set, so the variable doesn't
  1300.  *    get set automatically when the error is returned.
  1301.  *
  1302.  *----------------------------------------------------------------------
  1303.  */
  1304.     /* VARARGS2 */
  1305. #ifndef lint
  1306. void
  1307. Tcl_SetErrorCode(va_alist)
  1308. #else
  1309. void
  1310.     /* VARARGS2 */ /* ARGSUSED */
  1311. Tcl_SetErrorCode(interp, p, va_alist)
  1312.     Tcl_Interp *interp;        /* Interpreter whose errorCode variable is
  1313.                  * to be set. */
  1314.     char *p;            /* One or more elements to add to errorCode,
  1315.                  * terminated with NULL. */
  1316. #endif
  1317.     va_dcl
  1318. {
  1319.     va_list argList;
  1320.     char *string;
  1321.     int flags;
  1322.     Interp *iPtr;
  1323.  
  1324.     /*
  1325.      * Scan through the arguments one at a time, appending them to
  1326.      * $errorCode as list elements.
  1327.      */
  1328.  
  1329.     va_start(argList);
  1330.     iPtr = va_arg(argList, Interp *);
  1331.     flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT;
  1332.     while (1) {
  1333.     string = va_arg(argList, char *);
  1334.     if (string == NULL) {
  1335.         break;
  1336.     }
  1337.     (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode",
  1338.         (char *) NULL, string, flags);
  1339.     flags |= TCL_APPEND_VALUE;
  1340.     }
  1341.     va_end(argList);
  1342.     iPtr->flags |= ERROR_CODE_SET;
  1343. }
  1344.  
  1345. /*
  1346.  *----------------------------------------------------------------------
  1347.  *
  1348.  * TclGetListIndex --
  1349.  *
  1350.  *    Parse a list index, which may be either an integer or the
  1351.  *    value "end".
  1352.  *
  1353.  * Results:
  1354.  *    The return value is either TCL_OK or TCL_ERROR.  If it is
  1355.  *    TCL_OK, then the index corresponding to string is left in
  1356.  *    *indexPtr.  If the return value is TCL_ERROR, then string
  1357.  *    was bogus;  an error message is returned in interp->result.
  1358.  *    If a negative index is specified, it is rounded up to 0.
  1359.  *    The index value may be larger than the size of the list
  1360.  *    (this happens when "end" is specified).
  1361.  *
  1362.  * Side effects:
  1363.  *    None.
  1364.  *
  1365.  *----------------------------------------------------------------------
  1366.  */
  1367.  
  1368. int
  1369. TclGetListIndex(interp, string, indexPtr)
  1370.     Tcl_Interp *interp;            /* Interpreter for error reporting. */
  1371.     char *string;            /* String containing list index. */
  1372.     int *indexPtr;            /* Where to store index. */
  1373. {
  1374.     if (isdigit(UCHAR(*string)) || (*string == '-')) {
  1375.     if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
  1376.         return TCL_ERROR;
  1377.     }
  1378.     if (*indexPtr < 0) {
  1379.         *indexPtr = 0;
  1380.     }
  1381.     } else if (strncmp(string, "end", strlen(string)) == 0) {
  1382.     *indexPtr = INT_MAX;
  1383.     } else {
  1384.     Tcl_AppendResult(interp, "bad index \"", string,
  1385.         "\": must be integer or \"end\"", (char *) NULL);
  1386.     return TCL_ERROR;
  1387.     }
  1388.     return TCL_OK;
  1389. }
  1390.  
  1391. /*
  1392.  *----------------------------------------------------------------------
  1393.  *
  1394.  * Tcl_RegExpCompile --
  1395.  *
  1396.  *    Compile a regular expression into a form suitable for fast
  1397.  *    matching.  This procedure retains a small cache of pre-compiled
  1398.  *    regular expressions in the interpreter, in order to avoid
  1399.  *    compilation costs as much as possible.
  1400.  *
  1401.  * Results:
  1402.  *    The return value is a pointer to the compiled form of string,
  1403.  *    suitable for passing to Tcl_RegExpExec.  This compiled form
  1404.  *    is only valid up until the next call to this procedure, so
  1405.  *    don't keep these around for a long time!  If an error occurred
  1406.  *    while compiling the pattern, then NULL is returned and an error
  1407.  *    message is left in interp->result.
  1408.  *
  1409.  * Side effects:
  1410.  *    The cache of compiled regexp's in interp will be modified to
  1411.  *    hold information for string, if such information isn't already
  1412.  *    present in the cache.
  1413.  *
  1414.  *----------------------------------------------------------------------
  1415.  */
  1416.  
  1417. Tcl_RegExp
  1418. Tcl_RegExpCompile(interp, string)
  1419.     Tcl_Interp *interp;            /* For use in error reporting. */
  1420.     char *string;            /* String for which to produce
  1421.                      * compiled regular expression. */
  1422. {
  1423.     register Interp *iPtr = (Interp *) interp;
  1424.     int i, length;
  1425.     regexp *result;
  1426.  
  1427.     length = strlen(string);
  1428.     for (i = 0; i < NUM_REGEXPS; i++) {
  1429.     if ((length == iPtr->patLengths[i])
  1430.         && (strcmp(string, iPtr->patterns[i]) == 0)) {
  1431.         /*
  1432.          * Move the matched pattern to the first slot in the
  1433.          * cache and shift the other patterns down one position.
  1434.          */
  1435.  
  1436.         if (i != 0) {
  1437.         int j;
  1438.         char *cachedString;
  1439.  
  1440.         cachedString = iPtr->patterns[i];
  1441.         result = iPtr->regexps[i];
  1442.         for (j = i-1; j >= 0; j--) {
  1443.             iPtr->patterns[j+1] = iPtr->patterns[j];
  1444.             iPtr->patLengths[j+1] = iPtr->patLengths[j];
  1445.             iPtr->regexps[j+1] = iPtr->regexps[j];
  1446.         }
  1447.         iPtr->patterns[0] = cachedString;
  1448.         iPtr->patLengths[0] = length;
  1449.         iPtr->regexps[0] = result;
  1450.         }
  1451.         return (Tcl_RegExp) iPtr->regexps[0];
  1452.     }
  1453.     }
  1454.  
  1455.     /*
  1456.      * No match in the cache.  Compile the string and add it to the
  1457.      * cache.
  1458.      */
  1459.  
  1460.     tclRegexpError = NULL;
  1461.     result = TclRegComp(string);
  1462.     if (tclRegexpError != NULL) {
  1463.     Tcl_AppendResult(interp,
  1464.         "couldn't compile regular expression pattern: ",
  1465.         tclRegexpError, (char *) NULL);
  1466.     return NULL;
  1467.     }
  1468.     if (iPtr->patterns[NUM_REGEXPS-1] != NULL) {
  1469.     ckfree(iPtr->patterns[NUM_REGEXPS-1]);
  1470.     ckfree((char *) iPtr->regexps[NUM_REGEXPS-1]);
  1471.     }
  1472.     for (i = NUM_REGEXPS - 2; i >= 0; i--) {
  1473.     iPtr->patterns[i+1] = iPtr->patterns[i];
  1474.     iPtr->patLengths[i+1] = iPtr->patLengths[i];
  1475.     iPtr->regexps[i+1] = iPtr->regexps[i];
  1476.     }
  1477.     iPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1));
  1478.     strcpy(iPtr->patterns[0], string);
  1479.     iPtr->patLengths[0] = length;
  1480.     iPtr->regexps[0] = result;
  1481.     return (Tcl_RegExp) result;
  1482. }
  1483.  
  1484. /*
  1485.  *----------------------------------------------------------------------
  1486.  *
  1487.  * Tcl_RegExpExec --
  1488.  *
  1489.  *    Execute the regular expression matcher using a compiled form
  1490.  *    of a regular expression and save information about any match
  1491.  *    that is found.
  1492.  *
  1493.  * Results:
  1494.  *    If an error occurs during the matching operation then -1
  1495.  *    is returned and interp->result contains an error message.
  1496.  *    Otherwise the return value is 1 if 
  1497.  *
  1498.  * Side effects:
  1499.  *    None.
  1500.  *
  1501.  *----------------------------------------------------------------------
  1502.  */
  1503.  
  1504. int
  1505. Tcl_RegExpExec(interp, re, string, start)
  1506.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  1507.     Tcl_RegExp re;        /* Compiled regular expression;  must have
  1508.                  * been returned by previous call to
  1509.                  * Tcl_RegExpCompile. */
  1510.     char *string;        /* String against which to match re. */
  1511.     char *start;        /* If string is part of a larger string,
  1512.                  * this identifies beginning of larger
  1513.                  * string, so that "^" won't match. */
  1514. {
  1515.     int match;
  1516.  
  1517.     regexp *regexpPtr = (regexp *) re;
  1518.     tclRegexpError = NULL;
  1519.     match = TclRegExec(regexpPtr, string, start);
  1520.     if (tclRegexpError != NULL) {
  1521.     Tcl_ResetResult(interp);
  1522.     Tcl_AppendResult(interp, "error while matching regular expression: ",
  1523.         tclRegexpError, (char *) NULL);
  1524.     return -1;
  1525.     }
  1526.     return match;
  1527. }
  1528.  
  1529. /*
  1530.  *----------------------------------------------------------------------
  1531.  *
  1532.  * Tcl_RegExpRange --
  1533.  *
  1534.  *    Returns pointers describing the range of a regular expression match,
  1535.  *    or one of the subranges within the match.
  1536.  *
  1537.  * Results:
  1538.  *    The variables at *startPtr and *endPtr are modified to hold the
  1539.  *    addresses of the endpoints of the range given by index.  If the
  1540.  *    specified range doesn't exist then NULLs are returned.
  1541.  *
  1542.  * Side effects:
  1543.  *    None.
  1544.  *
  1545.  *----------------------------------------------------------------------
  1546.  */
  1547.  
  1548. void
  1549. Tcl_RegExpRange(re, index, startPtr, endPtr)
  1550.     Tcl_RegExp re;        /* Compiled regular expression that has
  1551.                  * been passed to Tcl_RegExpExec. */
  1552.     int index;            /* 0 means give the range of the entire
  1553.                  * match, > 0 means give the range of
  1554.                  * a matching subrange.  Must be no greater
  1555.                  * than NSUBEXP. */
  1556.     char **startPtr;        /* Store address of first character in
  1557.                  * (sub-) range here. */
  1558.     char **endPtr;        /* Store address of character just after last
  1559.                  * in (sub-) range here. */
  1560. {
  1561.     regexp *regexpPtr = (regexp *) re;
  1562.  
  1563.     if (index >= NSUBEXP) {
  1564.     *startPtr = *endPtr = NULL;
  1565.     } else {
  1566.     *startPtr = regexpPtr->startp[index];
  1567.     *endPtr = regexpPtr->endp[index];
  1568.     }
  1569. }
  1570.  
  1571. /*
  1572.  *----------------------------------------------------------------------
  1573.  *
  1574.  * Tcl_RegExpMatch --
  1575.  *
  1576.  *    See if a string matches a regular expression.
  1577.  *
  1578.  * Results:
  1579.  *    If an error occurs during the matching operation then -1
  1580.  *    is returned and interp->result contains an error message.
  1581.  *    Otherwise the return value is 1 if "string" matches "pattern"
  1582.  *    and 0 otherwise.
  1583.  *
  1584.  * Side effects:
  1585.  *    None.
  1586.  *
  1587.  *----------------------------------------------------------------------
  1588.  */
  1589.  
  1590. int
  1591. Tcl_RegExpMatch(interp, string, pattern)
  1592.     Tcl_Interp *interp;        /* Used for error reporting. */
  1593.     char *string;        /* String. */
  1594.     char *pattern;        /* Regular expression to match against
  1595.                  * string. */
  1596. {
  1597.     Tcl_RegExp re;
  1598.  
  1599.     re = Tcl_RegExpCompile(interp, pattern);
  1600.     if (re == NULL) {
  1601.     return -1;
  1602.     }
  1603.     return Tcl_RegExpExec(interp, re, string, string);
  1604. }
  1605.  
  1606. /*
  1607.  *----------------------------------------------------------------------
  1608.  *
  1609.  * Tcl_DStringInit --
  1610.  *
  1611.  *    Initializes a dynamic string, discarding any previous contents
  1612.  *    of the string (Tcl_DStringFree should have been called already
  1613.  *    if the dynamic string was previously in use).
  1614.  *
  1615.  * Results:
  1616.  *    None.
  1617.  *
  1618.  * Side effects:
  1619.  *    The dynamic string is initialized to be empty.
  1620.  *
  1621.  *----------------------------------------------------------------------
  1622.  */
  1623.  
  1624. void
  1625. Tcl_DStringInit(dsPtr)
  1626.     register Tcl_DString *dsPtr;    /* Pointer to structure for
  1627.                      * dynamic string. */
  1628. {
  1629.     dsPtr->string = dsPtr->staticSpace;
  1630.     dsPtr->length = 0;
  1631.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1632.     dsPtr->staticSpace[0] = 0;
  1633. }
  1634.  
  1635. /*
  1636.  *----------------------------------------------------------------------
  1637.  *
  1638.  * Tcl_DStringAppend --
  1639.  *
  1640.  *    Append more characters to the current value of a dynamic string.
  1641.  *
  1642.  * Results:
  1643.  *    The return value is a pointer to the dynamic string's new value.
  1644.  *
  1645.  * Side effects:
  1646.  *    Length bytes from string (or all of string if length is less
  1647.  *    than zero) are added to the current value of the string.  Memory
  1648.  *    gets reallocated if needed to accomodate the string's new size.
  1649.  *
  1650.  *----------------------------------------------------------------------
  1651.  */
  1652.  
  1653. char *
  1654. Tcl_DStringAppend(dsPtr, string, length)
  1655.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1656.                      * string. */
  1657.     char *string;            /* String to append.  If length is
  1658.                      * -1 then this must be
  1659.                      * null-terminated. */
  1660.     int length;                /* Number of characters from string
  1661.                      * to append.  If < 0, then append all
  1662.                      * of string, up to null at end. */
  1663. {
  1664.     int newSize;
  1665.     char *newString, *dst, *end;
  1666.  
  1667.     if (length < 0) {
  1668.     length = strlen(string);
  1669.     }
  1670.     newSize = length + dsPtr->length;
  1671.  
  1672.     /*
  1673.      * Allocate a larger buffer for the string if the current one isn't
  1674.      * large enough.  Allocate extra space in the new buffer so that there
  1675.      * will be room to grow before we have to allocate again.
  1676.      */
  1677.  
  1678.     if (newSize >= dsPtr->spaceAvl) {
  1679.     dsPtr->spaceAvl = newSize*2;
  1680.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1681.     memcpy((VOID *)newString, (VOID *) dsPtr->string,
  1682.         (size_t) dsPtr->length);
  1683.     if (dsPtr->string != dsPtr->staticSpace) {
  1684.         ckfree(dsPtr->string);
  1685.     }
  1686.     dsPtr->string = newString;
  1687.     }
  1688.  
  1689.     /*
  1690.      * Copy the new string into the buffer at the end of the old
  1691.      * one.
  1692.      */
  1693.  
  1694.     for (dst = dsPtr->string + dsPtr->length, end = string+length;
  1695.         string < end; string++, dst++) {
  1696.     *dst = *string;
  1697.     }
  1698.     *dst = 0;
  1699.     dsPtr->length += length;
  1700.     return dsPtr->string;
  1701. }
  1702.  
  1703. /*
  1704.  *----------------------------------------------------------------------
  1705.  *
  1706.  * Tcl_DStringAppendElement --
  1707.  *
  1708.  *    Append a list element to the current value of a dynamic string.
  1709.  *
  1710.  * Results:
  1711.  *    The return value is a pointer to the dynamic string's new value.
  1712.  *
  1713.  * Side effects:
  1714.  *    String is reformatted as a list element and added to the current
  1715.  *    value of the string.  Memory gets reallocated if needed to
  1716.  *    accomodate the string's new size.
  1717.  *
  1718.  *----------------------------------------------------------------------
  1719.  */
  1720.  
  1721. char *
  1722. Tcl_DStringAppendElement(dsPtr, string)
  1723.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1724.                      * string. */
  1725.     char *string;            /* String to append.  Must be
  1726.                      * null-terminated. */
  1727. {
  1728.     int newSize, flags;
  1729.     char *dst, *newString;
  1730.  
  1731.     newSize = Tcl_ScanElement(string, &flags) + dsPtr->length + 1;
  1732.  
  1733.     /*
  1734.      * Allocate a larger buffer for the string if the current one isn't
  1735.      * large enough.  Allocate extra space in the new buffer so that there
  1736.      * will be room to grow before we have to allocate again.
  1737.      * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
  1738.      * to a larger buffer, since there may be embedded NULLs in the
  1739.      * string in some cases.
  1740.      */
  1741.  
  1742.     if (newSize >= dsPtr->spaceAvl) {
  1743.     dsPtr->spaceAvl = newSize*2;
  1744.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1745.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  1746.         (size_t) dsPtr->length);
  1747.     if (dsPtr->string != dsPtr->staticSpace) {
  1748.         ckfree(dsPtr->string);
  1749.     }
  1750.     dsPtr->string = newString;
  1751.     }
  1752.  
  1753.     /*
  1754.      * Convert the new string to a list element and copy it into the
  1755.      * buffer at the end, with a space, if needed.
  1756.      */
  1757.  
  1758.     dst = dsPtr->string + dsPtr->length;
  1759.     if (TclNeedSpace(dsPtr->string, dst)) {
  1760.     *dst = ' ';
  1761.     dst++;
  1762.     dsPtr->length++;
  1763.     }
  1764.     dsPtr->length += Tcl_ConvertElement(string, dst, flags);
  1765.     return dsPtr->string;
  1766. }
  1767.  
  1768. /*
  1769.  *----------------------------------------------------------------------
  1770.  *
  1771.  * Tcl_DStringSetLength --
  1772.  *
  1773.  *    Change the length of a dynamic string.  This can cause the
  1774.  *    string to either grow or shrink, depending on the value of
  1775.  *    length.
  1776.  *
  1777.  * Results:
  1778.  *    None.
  1779.  *
  1780.  * Side effects:
  1781.  *    The length of dsPtr is changed to length and a null byte is
  1782.  *    stored at that position in the string.  If length is larger
  1783.  *    than the space allocated for dsPtr, then a panic occurs.
  1784.  *
  1785.  *----------------------------------------------------------------------
  1786.  */
  1787.  
  1788. void
  1789. Tcl_DStringSetLength(dsPtr, length)
  1790.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1791.                      * string. */
  1792.     int length;                /* New length for dynamic string. */
  1793. {
  1794.     if (length < 0) {
  1795.     length = 0;
  1796.     }
  1797.     if (length >= dsPtr->spaceAvl) {
  1798.     char *newString;
  1799.  
  1800.     dsPtr->spaceAvl = length+1;
  1801.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1802.  
  1803.     /*
  1804.      * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
  1805.      * to a larger buffer, since there may be embedded NULLs in the
  1806.      * string in some cases.
  1807.      */
  1808.  
  1809.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  1810.         (size_t) dsPtr->length);
  1811.     if (dsPtr->string != dsPtr->staticSpace) {
  1812.         ckfree(dsPtr->string);
  1813.     }
  1814.     dsPtr->string = newString;
  1815.     }
  1816.     dsPtr->length = length;
  1817.     dsPtr->string[length] = 0;
  1818. }
  1819.  
  1820. /*
  1821.  *----------------------------------------------------------------------
  1822.  *
  1823.  * Tcl_DStringFree --
  1824.  *
  1825.  *    Frees up any memory allocated for the dynamic string and
  1826.  *    reinitializes the string to an empty state.
  1827.  *
  1828.  * Results:
  1829.  *    None.
  1830.  *
  1831.  * Side effects:
  1832.  *    The previous contents of the dynamic string are lost, and
  1833.  *    the new value is an empty string.
  1834.  *
  1835.  *----------------------------------------------------------------------
  1836.  */
  1837.  
  1838. void
  1839. Tcl_DStringFree(dsPtr)
  1840.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1841.                      * string. */
  1842. {
  1843.     if (dsPtr->string != dsPtr->staticSpace) {
  1844.     ckfree(dsPtr->string);
  1845.     }
  1846.     dsPtr->string = dsPtr->staticSpace;
  1847.     dsPtr->length = 0;
  1848.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1849.     dsPtr->staticSpace[0] = 0;
  1850. }
  1851.  
  1852. /*
  1853.  *----------------------------------------------------------------------
  1854.  *
  1855.  * Tcl_DStringResult --
  1856.  *
  1857.  *    This procedure moves the value of a dynamic string into an
  1858.  *    interpreter as its result.  The string itself is reinitialized
  1859.  *    to an empty string.
  1860.  *
  1861.  * Results:
  1862.  *    None.
  1863.  *
  1864.  * Side effects:
  1865.  *    The string is "moved" to interp's result, and any existing
  1866.  *    result for interp is freed up.  DsPtr is reinitialized to
  1867.  *    an empty string.
  1868.  *
  1869.  *----------------------------------------------------------------------
  1870.  */
  1871.  
  1872. void
  1873. Tcl_DStringResult(interp, dsPtr)
  1874.     Tcl_Interp *interp;            /* Interpreter whose result is to be
  1875.                      * reset. */
  1876.     Tcl_DString *dsPtr;            /* Dynamic string that is to become
  1877.                      * the result of interp. */
  1878. {
  1879.     Tcl_ResetResult(interp);
  1880.     if (dsPtr->string != dsPtr->staticSpace) {
  1881.     interp->result = dsPtr->string;
  1882.     interp->freeProc = (Tcl_FreeProc *) free;
  1883.     } else if (dsPtr->length < TCL_RESULT_SIZE) {
  1884.     interp->result = ((Interp *) interp)->resultSpace;
  1885.     strcpy(interp->result, dsPtr->string);
  1886.     } else {
  1887.     Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE);
  1888.     }
  1889.     dsPtr->string = dsPtr->staticSpace;
  1890.     dsPtr->length = 0;
  1891.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1892.     dsPtr->staticSpace[0] = 0;
  1893. }
  1894.  
  1895. /*
  1896.  *----------------------------------------------------------------------
  1897.  *
  1898.  * Tcl_DStringGetResult --
  1899.  *
  1900.  *    This procedure moves the result of an interpreter into a
  1901.  *    dynamic string.
  1902.  *
  1903.  * Results:
  1904.  *    None.
  1905.  *
  1906.  * Side effects:
  1907.  *    The interpreter's result is cleared, and the previous contents
  1908.  *    of dsPtr are freed.
  1909.  *
  1910.  *----------------------------------------------------------------------
  1911.  */
  1912.  
  1913. void
  1914. Tcl_DStringGetResult(interp, dsPtr)
  1915.     Tcl_Interp *interp;            /* Interpreter whose result is to be
  1916.                      * reset. */
  1917.     Tcl_DString *dsPtr;            /* Dynamic string that is to become
  1918.                      * the result of interp. */
  1919. {
  1920.     Interp *iPtr = (Interp *) interp;
  1921.     if (dsPtr->string != dsPtr->staticSpace) {
  1922.     ckfree(dsPtr->string);
  1923.     }
  1924.     dsPtr->length = strlen(iPtr->result);
  1925.     if (iPtr->freeProc != NULL) {
  1926.     if (iPtr->freeProc == (Tcl_FreeProc *) free) {
  1927.         dsPtr->string = iPtr->result;
  1928.         dsPtr->spaceAvl = dsPtr->length+1;
  1929.     } else {
  1930.         dsPtr->string = ckalloc((unsigned) (dsPtr->length+1));
  1931.         strcpy(dsPtr->string, iPtr->result);
  1932.         (*iPtr->freeProc)(iPtr->result);
  1933.     }
  1934.     dsPtr->spaceAvl = dsPtr->length+1;
  1935.     iPtr->freeProc = NULL;
  1936.     } else {
  1937.     if (dsPtr->length < TCL_DSTRING_STATIC_SIZE) {
  1938.         dsPtr->string = dsPtr->staticSpace;
  1939.         dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1940.     } else {
  1941.         dsPtr->string = ckalloc((unsigned) (dsPtr->length + 1));
  1942.         dsPtr->spaceAvl = dsPtr->length + 1;
  1943.     }
  1944.     strcpy(dsPtr->string, iPtr->result);
  1945.     }
  1946.     iPtr->result = iPtr->resultSpace;
  1947.     iPtr->resultSpace[0] = 0;
  1948. }
  1949.  
  1950. /*
  1951.  *----------------------------------------------------------------------
  1952.  *
  1953.  * Tcl_DStringStartSublist --
  1954.  *
  1955.  *    This procedure adds the necessary information to a dynamic
  1956.  *    string (e.g. " {" to start a sublist.  Future element
  1957.  *    appends will be in the sublist rather than the main list.
  1958.  *
  1959.  * Results:
  1960.  *    None.
  1961.  *
  1962.  * Side effects:
  1963.  *    Characters get added to the dynamic string.
  1964.  *
  1965.  *----------------------------------------------------------------------
  1966.  */
  1967.  
  1968. void
  1969. Tcl_DStringStartSublist(dsPtr)
  1970.     Tcl_DString *dsPtr;            /* Dynamic string. */
  1971. {
  1972.     if (TclNeedSpace(dsPtr->string, dsPtr->string + dsPtr->length)) {
  1973.     Tcl_DStringAppend(dsPtr, " {", -1);
  1974.     } else {
  1975.     Tcl_DStringAppend(dsPtr, "{", -1);
  1976.     }
  1977. }
  1978.  
  1979. /*
  1980.  *----------------------------------------------------------------------
  1981.  *
  1982.  * Tcl_DStringEndSublist --
  1983.  *
  1984.  *    This procedure adds the necessary characters to a dynamic
  1985.  *    string to end a sublist (e.g. "}").  Future element appends
  1986.  *    will be in the enclosing (sub)list rather than the current
  1987.  *    sublist.
  1988.  *
  1989.  * Results:
  1990.  *    None.
  1991.  *
  1992.  * Side effects:
  1993.  *    None.
  1994.  *
  1995.  *----------------------------------------------------------------------
  1996.  */
  1997.  
  1998. void
  1999. Tcl_DStringEndSublist(dsPtr)
  2000.     Tcl_DString *dsPtr;            /* Dynamic string. */
  2001. {
  2002.     Tcl_DStringAppend(dsPtr, "}", -1);
  2003. }
  2004.  
  2005. /*
  2006.  *----------------------------------------------------------------------
  2007.  *
  2008.  * Tcl_PrintDouble --
  2009.  *
  2010.  *    Given a floating-point value, this procedure converts it to
  2011.  *    an ASCII string using.
  2012.  *
  2013.  * Results:
  2014.  *    The ASCII equivalent of "value" is written at "dst".  It is
  2015.  *    written using the current precision, and it is guaranteed to
  2016.  *    contain a decimal point or exponent, so that it looks like
  2017.  *    a floating-point value and not an integer.
  2018.  *
  2019.  * Side effects:
  2020.  *    None.
  2021.  *
  2022.  *----------------------------------------------------------------------
  2023.  */
  2024.  
  2025. void
  2026. Tcl_PrintDouble(interp, value, dst)
  2027.     Tcl_Interp *interp;            /* Interpreter whose tcl_precision
  2028.                      * variable controls printing. */
  2029.     double value;            /* Value to print as string. */
  2030.     char *dst;                /* Where to store converted value;
  2031.                      * must have at least TCL_DOUBLE_SPACE
  2032.                      * characters. */
  2033. {
  2034.     register char *p;
  2035.     sprintf(dst, ((Interp *) interp)->pdFormat, value);
  2036.  
  2037.     /*
  2038.      * If the ASCII result looks like an integer, add ".0" so that it
  2039.      * doesn't look like an integer anymore.  This prevents floating-point
  2040.      * values from being converted to integers unintentionally.
  2041.      */
  2042.  
  2043.     for (p = dst; *p != 0; p++) {
  2044.     if ((*p == '.') || (isalpha(UCHAR(*p)))) {
  2045.         return;
  2046.     }
  2047.     }
  2048.     p[0] = '.';
  2049.     p[1] = '0';
  2050.     p[2] = 0;
  2051. }
  2052.  
  2053. /*
  2054.  *----------------------------------------------------------------------
  2055.  *
  2056.  * TclPrecTraceProc --
  2057.  *
  2058.  *    This procedure is invoked whenever the variable "tcl_precision"
  2059.  *    is written.
  2060.  *
  2061.  * Results:
  2062.  *    Returns NULL if all went well, or an error message if the
  2063.  *    new value for the variable doesn't make sense.
  2064.  *
  2065.  * Side effects:
  2066.  *    If the new value doesn't make sense then this procedure
  2067.  *    undoes the effect of the variable modification.  Otherwise
  2068.  *    it modifies the format string that's used by Tcl_PrintDouble.
  2069.  *
  2070.  *----------------------------------------------------------------------
  2071.  */
  2072.  
  2073.     /* ARGSUSED */
  2074. char *
  2075. TclPrecTraceProc(clientData, interp, name1, name2, flags)
  2076.     ClientData clientData;    /* Not used. */
  2077.     Tcl_Interp *interp;        /* Interpreter containing variable. */
  2078.     char *name1;        /* Name of variable. */
  2079.     char *name2;        /* Second part of variable name. */
  2080.     int flags;            /* Information about what happened. */
  2081. {
  2082.     register Interp *iPtr = (Interp *) interp;
  2083.     char *value, *end;
  2084.     int prec;
  2085.  
  2086.     /*
  2087.      * If the variable is unset, then recreate the trace and restore
  2088.      * the default value of the format string.
  2089.      */
  2090.  
  2091.     if (flags & TCL_TRACE_UNSETS) {
  2092.     if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
  2093.         Tcl_TraceVar2(interp, name1, name2,
  2094.             TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
  2095.             TclPrecTraceProc, clientData);
  2096.     }
  2097.     strcpy(iPtr->pdFormat, DEFAULT_PD_FORMAT);
  2098.     iPtr->pdPrec = DEFAULT_PD_PREC;
  2099.     return (char *) NULL;
  2100.     }
  2101.  
  2102.     value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
  2103.     if (value == NULL) {
  2104.     value = "";
  2105.     }
  2106.     prec = strtoul(value, &end, 10);
  2107.     if ((prec <= 0) || (prec > TCL_MAX_PREC) || (prec > 100) ||
  2108.         (end == value) || (*end != 0)) {
  2109.     char oldValue[10];
  2110.  
  2111.     sprintf(oldValue, "%d", iPtr->pdPrec);
  2112.     Tcl_SetVar2(interp, name1, name2, oldValue, flags & TCL_GLOBAL_ONLY);
  2113.     return "improper value for precision";
  2114.     }
  2115.     sprintf(iPtr->pdFormat, "%%.%dg", prec);
  2116.     iPtr->pdPrec = prec;
  2117.     return (char *) NULL;
  2118. }
  2119.  
  2120. /*
  2121.  *----------------------------------------------------------------------
  2122.  *
  2123.  * TclNeedSpace --
  2124.  *
  2125.  *    This procedure checks to see whether it is appropriate to
  2126.  *    add a space before appending a new list element to an
  2127.  *    existing string.
  2128.  *
  2129.  * Results:
  2130.  *    The return value is 1 if a space is appropriate, 0 otherwise.
  2131.  *
  2132.  * Side effects:
  2133.  *    None.
  2134.  *
  2135.  *----------------------------------------------------------------------
  2136.  */
  2137.  
  2138. int
  2139. TclNeedSpace(start, end)
  2140.     char *start;        /* First character in string. */
  2141.     char *end;            /* End of string (place where space will
  2142.                  * be added, if appropriate). */
  2143. {
  2144.     /*
  2145.      * A space is needed unless either
  2146.      * (a) we're at the start of the string, or
  2147.      * (b) the trailing characters of the string consist of one or more
  2148.      *     open curly braces preceded by a space or extending back to
  2149.      *     the beginning of the string.
  2150.      * (c) the trailing characters of the string consist of a space
  2151.      *       preceded by a character other than backslash.
  2152.      */
  2153.  
  2154.     if (end == start) {
  2155.     return 0;
  2156.     }
  2157.     end--;
  2158.     if (*end != '{') {
  2159.     if (isspace(UCHAR(*end)) && ((end == start) || (end[-1] != '\\'))) {
  2160.         return 0;
  2161.     }
  2162.     return 1;
  2163.     }
  2164.     do {
  2165.     if (end == start) {
  2166.         return 0;
  2167.     }
  2168.     end--;
  2169.     } while (*end == '{');
  2170.     if (isspace(UCHAR(*end))) {
  2171.     return 0;
  2172.     }
  2173.     return 1;
  2174. }
  2175.