home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 0 / 0991 / tclUtil.c < prev   
C/C++ Source or Header  |  1990-12-28  |  22KB  |  901 lines

  1. /* 
  2.  * tclUtil.c --
  3.  *
  4.  *    This file contains utility procedures that are used by many Tcl
  5.  *    commands.
  6.  *
  7.  * Copyright 1987, 1989 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /sprite/src/lib/tcl/RCS/tclUtil.c,v 1.27 90/01/07 12:05:20 ouster Exp $ SPRITE (Berkeley)";
  19. #endif /* not lint */
  20.  
  21. #include <ctype.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include "tcl.h"
  26. #include "tclInt.h"
  27.  
  28. /*
  29.  *----------------------------------------------------------------------
  30.  *
  31.  * TclFindElement --
  32.  *
  33.  *    Given a pointer into a Tcl list, locate the first (or next)
  34.  *    element in the list.
  35.  *
  36.  * Results:
  37.  *    The return value is normally TCL_OK, which means that the
  38.  *    element was successfully located.  If TCL_ERROR is returned
  39.  *    it means that list didn't have proper list structure;
  40.  *    interp->result contains a more detailed error message.
  41.  *
  42.  *    If TCL_OK is returned, then *elementPtr will be set to point
  43.  *    to the first element of list, and *nextPtr will be set to point
  44.  *    to the character just after any white space following the last
  45.  *    character that's part of the element.  If this is the last argument
  46.  *    in the list, then *nextPtr will point to the NULL character at the
  47.  *    end of list.  If sizePtr is non-NULL, *sizePtr is filled in with
  48.  *    the number of characters in the element.  If the element is in
  49.  *    braces, then *elementPtr will point to the character after the
  50.  *    opening brace and *sizePtr will not include either of the braces.
  51.  *    If there isn't an element in the list, *sizePtr will be zero, and
  52.  *    both *elementPtr and *termPtr will refer to the null character at
  53.  *    the end of list.  Note:  this procedure does NOT collapse backslash
  54.  *    sequences.
  55.  *
  56.  * Side effects:
  57.  *    None.
  58.  *
  59.  *----------------------------------------------------------------------
  60.  */
  61.  
  62. int
  63. TclFindElement(interp, list, elementPtr, nextPtr, sizePtr, bracePtr)
  64.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  65.     register char *list;    /* String containing Tcl list with zero
  66.                  * or more elements (possibly in braces). */
  67.     char **elementPtr;        /* Fill in with location of first significant
  68.                  * character in first element of list. */
  69.     char **nextPtr;        /* Fill in with location of character just
  70.                  * after all white space following end of
  71.                  * argument (i.e. next argument or end of
  72.                  * list). */
  73.     int *sizePtr;        /* If non-zero, fill in with size of
  74.                  * element. */
  75.     int *bracePtr;        /* If non-zero fill in with non-zero/zero
  76.                  * to indicate that arg was/wasn't
  77.                  * in braces. */
  78. {
  79.     register char *p;
  80.     int openBraces = 0;
  81.     int size;
  82.  
  83.     /*
  84.      * Skim off leading white space and check for an opening brace.
  85.      */
  86.  
  87.     while (isspace(*list)) {
  88.     list++;
  89.     }
  90.     if (*list == '{') {
  91.     openBraces = 1;
  92.     list++;
  93.     }
  94.     if (bracePtr != 0) {
  95.     *bracePtr = openBraces;
  96.     }
  97.     p = list;
  98.  
  99.     /*
  100.      * Find the end of the element (either a space or a close brace or
  101.      * the end of the string).
  102.      */
  103.  
  104.     while (1) {
  105.     switch (*p) {
  106.  
  107.         /*
  108.          * Open brace: don't treat specially unless the element is
  109.          * in braces.  In this case, keep a nesting count.
  110.          */
  111.  
  112.         case '{':
  113.         if (openBraces != 0) {
  114.             openBraces++;
  115.         }
  116.         break;
  117.  
  118.         /*
  119.          * Close brace: if element is in braces, keep nesting
  120.          * count and quit when the last close brace is seen.
  121.          */
  122.  
  123.         case '}':
  124.         if (openBraces == 1) {
  125.             char *p2;
  126.  
  127.             size = p - list;
  128.             p++;
  129.             if (isspace(*p) || (*p == 0)) {
  130.             goto done;
  131.             }
  132.             for (p2 = p; (*p2 != 0) && (!isspace(*p2)) && (p2 < p+20);
  133.                 p2++) {
  134.             /* null body */
  135.             }
  136.             Tcl_Return(interp, (char *) NULL, TCL_STATIC);
  137.             sprintf(interp->result,
  138.                 "list element in braces followed by \"%.*s\" instead of space",
  139.                 p2-p, p);
  140.             return TCL_ERROR;
  141.         } else if (openBraces != 0) {
  142.             openBraces--;
  143.         }
  144.         break;
  145.  
  146.         /*
  147.          * Backslash:  skip over everything up to the end of the
  148.          * backslash sequence.
  149.          */
  150.  
  151.         case '\\': {
  152.         int size;
  153.  
  154.         (void) Tcl_Backslash(p, &size);
  155.         p += size - 1;
  156.         break;
  157.         }
  158.  
  159.         /*
  160.          * Space: ignore if element is in braces;  otherwise
  161.          * terminate element.
  162.          */
  163.  
  164.         case ' ':
  165.         case '\t':
  166.         case '\n':
  167.         if (openBraces == 0) {
  168.             size = p - list;
  169.             goto done;
  170.         }
  171.         break;
  172.  
  173.         /*
  174.          * End of list:  terminate element.
  175.          */
  176.  
  177.         case 0:
  178.         if (openBraces != 0) {
  179.             Tcl_Return(interp, "unmatched open brace in list",
  180.                 TCL_STATIC);
  181.             return TCL_ERROR;
  182.         }
  183.         size = p - list;
  184.         goto done;
  185.  
  186.     }
  187.     p++;
  188.     }
  189.  
  190.     done:
  191.     while (isspace(*p)) {
  192.     p++;
  193.     }
  194.     *elementPtr = list;
  195.     *nextPtr = p;
  196.     if (sizePtr != 0) {
  197.     *sizePtr = size;
  198.     }
  199.     return TCL_OK;
  200. }
  201.  
  202. /*
  203.  *----------------------------------------------------------------------
  204.  *
  205.  * TclCopyAndCollapse --
  206.  *
  207.  *    Copy a string and eliminate any backslashes that aren't in braces.
  208.  *
  209.  * Results:
  210.  *    There is no return value.  Count chars. get copied from src
  211.  *    to dst.  Along the way, if backslash sequences are found outside
  212.  *    braces, the backslashes are eliminated in the copy.
  213.  *    After scanning count chars. from source, a null character is
  214.  *    placed at the end of dst.
  215.  *
  216.  * Side effects:
  217.  *    None.
  218.  *
  219.  *----------------------------------------------------------------------
  220.  */
  221.  
  222. void
  223. TclCopyAndCollapse(count, src, dst)
  224.     register char *src;        /* Copy from here... */
  225.     register char *dst;        /* ... to here. */
  226. {
  227.     register char c;
  228.     int numRead;
  229.  
  230.     for (c = *src; count > 0; dst++, src++, c = *src, count--) {
  231.     if (c == '\\') {
  232.         *dst = Tcl_Backslash(src, &numRead);
  233.         src += numRead-1;
  234.         count -= numRead-1;
  235.     } else {
  236.         *dst = c;
  237.     }
  238.     }
  239.     *dst = 0;
  240. }
  241.  
  242. /*
  243.  *----------------------------------------------------------------------
  244.  *
  245.  * Tcl_Merge --
  246.  *
  247.  *    Given a collection of strings, merge them together into a
  248.  *    single string that has proper Tcl list structured (i.e.
  249.  *    TclFindElement and TclCopyAndCollapse may be used to retrieve
  250.  *    strings equal to the original elements, and Tcl_Eval will
  251.  *    parse the string back into its original elements).
  252.  *
  253.  * Results:
  254.  *    The return value is the address of a dynamically-allocated
  255.  *    string containing the merged list.
  256.  *
  257.  * Side effects:
  258.  *    None.
  259.  *
  260.  *----------------------------------------------------------------------
  261.  */
  262.  
  263. char *
  264. Tcl_Merge(argc, argv)
  265.     int argc;            /* How many strings to merge. */
  266.     char **argv;        /* Array of string values. */
  267. {
  268.     /*
  269.      * This procedure operates in two passes.  In the first pass it figures
  270.      * out how many bytes will be needed to store the result (actually,
  271.      * it overestimates slightly).  The first pass also collects information
  272.      * about each element in the form of a flags word.  If there are only
  273.      * a few elements, local storage gets used for the flags;  if there are
  274.      * a lot of elements, a new array is dynamically allocated.
  275.      *
  276.      * In the second pass this procedure copies the arguments into the
  277.      * result string.  The special cases to worry about are:
  278.      *
  279.      * 1. Argument contains embedded spaces, or starts with a brace:  must
  280.      * add another level of braces when copying to the result.
  281.      *
  282.      * 2. Argument contains unbalanced braces:  backslash all of the
  283.      * braces when copying to the result.  In this case, don't add another
  284.      * level of braces (they would prevent the backslash from
  285.      * being removed when the argument is extracted from the list later).
  286.      *
  287.      * 3. Argument contains backslashed brace/bracket:  if possible,
  288.      * group the argument in braces:  then no special action needs to be taken
  289.      * with the backslashes.  If the argument can't be put in braces, then
  290.      * add another backslash in front of the sequence, so that upon
  291.      * extraction the original sequence will be restored.
  292.      *
  293.      * These potential problems are the reasons why particular information
  294.      * is gathered during pass 1.
  295.      */
  296. #   define WANT_PARENS            1
  297. #   define PARENS_UNBALANCED        2
  298. #   define PARENTHESIZED        4
  299. #   define CANT_PARENTHESIZE        8
  300.  
  301. #   define LOCAL_SIZE 20
  302.     int localFlags[LOCAL_SIZE];
  303.     int *flagPtr;
  304.     int numChars;
  305.     char *result;
  306.     register char *src, *dst;
  307.     register int curFlags;
  308.     int i;
  309.  
  310.     /*
  311.      * Pass 1: estimate space, gather information.
  312.      */
  313.  
  314.     if (argc <= LOCAL_SIZE) {
  315.     flagPtr = localFlags;
  316.     } else {
  317.     flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
  318.     }
  319.     numChars = 0;
  320.     for (i = 0; i < argc; i++) {
  321.     int braceCount, nestingLevel, nestedBS, whiteSpace, brackets, dollars;
  322.  
  323.     curFlags = braceCount = nestingLevel = nestedBS = whiteSpace = 0;
  324.     brackets = dollars = 0;
  325.     src = argv[i];
  326.     if (*src == '{') {
  327.         curFlags |= PARENTHESIZED|WANT_PARENS;
  328.     }
  329.     if (*src == 0) {
  330.         curFlags |= WANT_PARENS;
  331.     } else {
  332.         for (; ; src++) {
  333.         switch (*src) {
  334.             case '{':
  335.             braceCount++;
  336.             nestingLevel++;
  337.             break;
  338.             case '}':
  339.             braceCount++;
  340.             nestingLevel--;
  341.             break;
  342.             case ']':
  343.             case '[':
  344.             curFlags |= WANT_PARENS;
  345.             brackets++;
  346.             break;
  347.             case '$':
  348.             curFlags |= WANT_PARENS;
  349.             dollars++;
  350.             break;
  351.             case ' ':
  352.             case '\n':
  353.             case '\t':
  354.             curFlags |= WANT_PARENS;
  355.             whiteSpace++;
  356.             break;
  357.             case '\\':
  358.             src++;
  359.             if (*src == 0) {
  360.                 goto elementDone;
  361.             } else if ((*src == '{') || (*src == '}')
  362.                 || (*src == '[') || (*src == ']')) {
  363.                 curFlags |= WANT_PARENS;
  364.                 nestedBS++;
  365.             }
  366.             break;
  367.             case 0:
  368.             goto elementDone;
  369.         }
  370.         }
  371.     }
  372.     elementDone:
  373.     numChars += src - argv[i];
  374.     if (nestingLevel != 0) {
  375.         numChars += braceCount + nestedBS + whiteSpace
  376.             + brackets + dollars;
  377.         curFlags = CANT_PARENTHESIZE;
  378.     }
  379.     if (curFlags & WANT_PARENS) {
  380.         numChars += 2;
  381.     }
  382.     numChars++;        /* Space to separate arguments. */
  383.     flagPtr[i] = curFlags;
  384.     }
  385.  
  386.     /*
  387.      * Pass two: copy into the result area.
  388.      */
  389.  
  390.     result = (char *) ckalloc((unsigned) numChars + 1);
  391.     dst = result;
  392.     for (i = 0; i < argc; i++) {
  393.     curFlags = flagPtr[i];
  394.     if (curFlags & WANT_PARENS) {
  395.         *dst = '{';
  396.         dst++;
  397.     }
  398.     for (src = argv[i]; *src != 0 ; src++) {
  399.         if (curFlags & CANT_PARENTHESIZE) {
  400.         switch (*src) {
  401.             case '{':
  402.             case '}':
  403.             case ']':
  404.             case '[':
  405.             case '$':
  406.             case ' ':
  407.             *dst = '\\';
  408.             dst++;
  409.             break;
  410.             case '\n':
  411.             *dst = '\\';
  412.             dst++;
  413.             *dst = 'n';
  414.             goto loopBottom;
  415.             case '\t':
  416.             *dst = '\\';
  417.             dst++;
  418.             *dst = 't';
  419.             goto loopBottom;
  420.             case '\\':
  421.             *dst = '\\';
  422.             dst++;
  423.             src++;
  424.             if ((*src == '{') || (*src == '}') || (*src == '[')
  425.                 || (*src == ']')) {
  426.                 *dst = '\\';
  427.                 dst++;
  428.             } else if (*src == 0) {
  429.                 goto pass2ElementDone;
  430.             }
  431.             break;
  432.         }
  433.         }
  434.         *dst = *src;
  435.         loopBottom:
  436.         dst++;
  437.     }
  438.     pass2ElementDone:
  439.     if (curFlags & WANT_PARENS) {
  440.         *dst = '}';
  441.         dst++;
  442.     }
  443.     *dst = ' ';
  444.     dst++;
  445.     }
  446.     if (dst == result) {
  447.     *dst = 0;
  448.     } else {
  449.     dst[-1] = 0;
  450.     }
  451.  
  452.     if (flagPtr != localFlags) {
  453.     ckfree((char *) flagPtr);
  454.     }
  455.     return result;
  456. }
  457.  
  458. /*
  459.  *----------------------------------------------------------------------
  460.  *
  461.  * Tcl_Concat --
  462.  *
  463.  *    Concatenate a set of strings into a single large string.
  464.  *
  465.  * Results:
  466.  *    The return value is dynamically-allocated string containing
  467.  *    a concatenation of all the strings in argv, with spaces between
  468.  *    the original argv elements.
  469.  *
  470.  * Side effects:
  471.  *    Memory is allocated for the result;  the caller is responsible
  472.  *    for freeing the memory.
  473.  *
  474.  *----------------------------------------------------------------------
  475.  */
  476.  
  477. char *
  478. Tcl_Concat(argc, argv)
  479.     int argc;            /* Number of strings to concatenate. */
  480.     char **argv;        /* Array of strings to concatenate. */
  481. {
  482.     int totalSize, i;
  483.     register char *p;
  484.     char *result;
  485.  
  486.     for (totalSize = 1, i = 0; i < argc; i++) {
  487.     totalSize += strlen(argv[i]) + 1;
  488.     }
  489.     result = (char *)ckalloc((unsigned) totalSize);
  490.     for (p = result, i = 0; i < argc; i++) {
  491.     (void) strcpy(p, argv[i]);
  492.     p += strlen(argv[i]);
  493.     *p = ' ';
  494.     p++;
  495.     }
  496.     p[-1] = 0;
  497.     return result;
  498. }
  499.  
  500. /*
  501.  *----------------------------------------------------------------------
  502.  *
  503.  * Tcl_Return --
  504.  *
  505.  *    Arrange for "string" to be the Tcl return value.
  506.  *
  507.  * Results:
  508.  *    None.
  509.  *
  510.  * Side effects:
  511.  *    interp->result is left pointing either to "string" (if "copy" is 0)
  512.  *    or to a copy of string.
  513.  *
  514.  *----------------------------------------------------------------------
  515.  */
  516.  
  517. void
  518. Tcl_Return(interp, string, status)
  519.     Tcl_Interp *interp;        /* Interpreter with which to associate the
  520.                  * return value. */
  521.     char *string;        /* Value to be returned.  If NULL,
  522.                  * the result is set to an empty string. */
  523.     int status;            /* Gives information about the string:
  524.                  * TCL_STATIC, TCL_DYNAMIC, TCL_VOLATILE.
  525.                  * Ignored if string is NULL. */
  526. {
  527.     register Interp *iPtr = (Interp *) interp;
  528.     int length;
  529.     int wasDynamic = iPtr->dynamic;
  530.     char *oldResult = iPtr->result;
  531.  
  532.     if (string == NULL) {
  533.     iPtr->resultSpace[0] = 0;
  534.     iPtr->result = iPtr->resultSpace;
  535.     iPtr->dynamic = 0;
  536.     } else if (status == TCL_STATIC) {
  537.     iPtr->result = string;
  538.     iPtr->dynamic = 0;
  539.     } else if (status == TCL_DYNAMIC) {
  540.     iPtr->result = string;
  541.     iPtr->dynamic = 1;
  542.     } else {
  543.     length = strlen(string);
  544.     if (length > TCL_RESULT_SIZE) {
  545.         iPtr->result = (char *) ckalloc((unsigned) length+1);
  546.         iPtr->dynamic = 1;
  547.     } else {
  548.         iPtr->dynamic = 0;
  549.     }
  550.     strcpy(iPtr->result, string);
  551.     }
  552.  
  553.     /*
  554.      * If the old result was dynamically-allocated, ckfree it up.  Do it
  555.      * here, rather than at the beginning, in case the new result value
  556.      * was part of the old result value.
  557.      */
  558.  
  559.     if (wasDynamic) {
  560.     ckfree(oldResult);
  561.     }
  562. }
  563.  
  564. /*
  565.  *----------------------------------------------------------------------
  566.  *
  567.  * Tcl_Backslash --
  568.  *
  569.  *    Figure out how to handle a backslash sequence.
  570.  *
  571.  * Results:
  572.  *    The return value is the character that should be substituted
  573.  *    in place of the backslash sequence that starts at src.  If
  574.  *    readPtr isn't NULL then it is filled in with a count of the
  575.  *    number of characters in the backslash sequence.  Note:  if
  576.  *    the backslash isn't followed by characters that are understood
  577.  *    here, then the backslash sequence is only considered to be
  578.  *    one character long, and it is replaced by a backslash char.
  579.  *
  580.  * Side effects:
  581.  *    None.
  582.  *
  583.  *----------------------------------------------------------------------
  584.  */
  585.  
  586. char
  587. Tcl_Backslash(src, readPtr)
  588.     char *src;            /* Points to the backslash character of
  589.                  * a backslash sequence. */
  590.     int *readPtr;        /* Fill in with number of characters read
  591.                  * from src, unless NULL. */
  592. {
  593.     register char *p = src+1;
  594.     char result;
  595.     int count;
  596.  
  597.     count = 2;
  598.  
  599.     switch (*p) {
  600.     case 'b':
  601.         result = '\b';
  602.         break;
  603.     case 'e':
  604.         result = 033;
  605.         break;
  606.     case 'n':
  607.         result = '\n';
  608.         break;
  609.     case 't':
  610.         result = '\t';
  611.         break;
  612.     case 'C':
  613.         p++;
  614.         if (isspace(*p) || (*p == 0)) {
  615.         result = 'C';
  616.         count = 1;
  617.         break;
  618.         }
  619.         count = 3;
  620.         if (*p == 'M') {
  621.         p++;
  622.         if (isspace(*p) || (*p == 0)) {
  623.             result = 'M' & 037;
  624.             break;
  625.         }
  626.         count = 4;
  627.         result = (*p & 037) | 0200;
  628.         break;
  629.         }
  630.         count = 3;
  631.         result = *p & 037;
  632.         break;
  633.     case 'M':
  634.         p++;
  635.         if (isspace(*p) || (*p == 0)) {
  636.         result = 'M';
  637.         count = 1;
  638.         break;
  639.         }
  640.         count = 3;
  641.         result = *p + 0200;
  642.         break;
  643.     case '}':
  644.     case '{':
  645.     case ']':
  646.     case '[':
  647.     case '$':
  648.     case ' ':
  649.     case ';':
  650.     case '"':
  651.     case '\\':
  652.         result = *p;
  653.         break;
  654.     default:
  655.         if (isdigit(*p)) {
  656.         result = *p - '0';
  657.         p++;
  658.         if (!isdigit(*p)) {
  659.             break;
  660.         }
  661.         count = 3;
  662.         result = (result << 3) + (*p - '0');
  663.         p++;
  664.         if (!isdigit(*p)) {
  665.             break;
  666.         }
  667.         count = 4;
  668.         result = (result << 3) + (*p - '0');
  669.         break;
  670.         }
  671.         result = '\\';
  672.         count = 1;
  673.         break;
  674.     }
  675.  
  676.     if (readPtr != NULL) {
  677.     *readPtr = count;
  678.     }
  679.     return result;
  680. }
  681.  
  682. /*
  683.  *----------------------------------------------------------------------
  684.  *
  685.  * Tcl_SplitList --
  686.  *
  687.  *    Splits a list up into its constituent fields.
  688.  *
  689.  * Results
  690.  *    The return value is normally TCL_OK, which means that
  691.  *    the list was successfully split up.  If TCL_ERROR is
  692.  *    returned, it means that "list" didn't have proper list
  693.  *    structure;  interp->result will contain a more detailed
  694.  *    error message.
  695.  *
  696.  *    *argvPtr will be filled in with the address of an array
  697.  *    whose elements point to the elements of list, in order.
  698.  *    *argcPtr will get filled in with the number of valid elements
  699.  *    in the array.  A single block of memory is dynamically allocated
  700.  *    to hold both the argv array and a copy of the list (with
  701.  *    backslashes and braces removed in the standard way).
  702.  *    The caller must eventually ckfree this memory by calling ckfree()
  703.  *    on *argvPtr.  Note:  *argvPtr and *argcPtr are only modified
  704.  *    if the procedure returns normally.
  705.  *
  706.  * Side effects:
  707.  *    Memory is allocated.
  708.  *
  709.  *----------------------------------------------------------------------
  710.  */
  711.  
  712. int
  713. Tcl_SplitList(interp, list, argcPtr, argvPtr)
  714.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  715.     char *list;            /* Pointer to string with list structure. */
  716.     int *argcPtr;        /* Pointer to location to fill in with
  717.                  * the number of elements in the list. */
  718.     char ***argvPtr;        /* Pointer to place to store pointer to array
  719.                  * of pointers to list elements. */
  720. {
  721.     char **argv;
  722.     register char *p;
  723.     int size, i, result, elSize, brace;
  724.     char *element;
  725.  
  726.     /*
  727.      * Figure out how much space to allocate.  There must be enough
  728.      * space for both the array of pointers and also for a copy of
  729.      * the list.  To estimate the number of pointers needed, count
  730.      * the number of space characters in the list.
  731.      */
  732.  
  733.     for (size = 1, p = list; *p != 0; p++) {
  734.     if (isspace(*p)) {
  735.         size++;
  736.     }
  737.     }
  738.     argv = (char **) ckalloc((unsigned)
  739.         ((size * sizeof(char *)) + (p - list) + 1));
  740.     for (i = 0, p = ((char *) argv) + size*sizeof(char *);
  741.         *list != 0; i++) {
  742.     result = TclFindElement(interp, list, &element, &list, &elSize, &brace);
  743.     if (result != TCL_OK) {
  744.         ckfree((char *) argv);
  745.         return result;
  746.     }
  747.     if (*element == 0) {
  748.         break;
  749.     }
  750.     if (i >= size) {
  751.         Tcl_Return(interp, "internal error in Tcl_SplitList", TCL_STATIC);
  752.         return TCL_ERROR;
  753.     }
  754.     argv[i] = p;
  755.     if (brace) {
  756.         strncpy(p, element, elSize);
  757.         p += elSize;
  758.         *p = 0;
  759.         p++;
  760.     } else {
  761.         TclCopyAndCollapse(elSize, element, p);
  762.         p += elSize+1;
  763.     }
  764.     }
  765.  
  766.     *argvPtr = argv;
  767.     *argcPtr = i;
  768.     return TCL_OK;
  769. }
  770.  
  771. /*
  772.  *----------------------------------------------------------------------
  773.  *
  774.  * Tcl_StringMatch --
  775.  *
  776.  *    See if a particular string matches a particular pattern.
  777.  *
  778.  * Results:
  779.  *    The return value is 1 if string matches pattern, and
  780.  *    0 otherwise.  The matching operation permits the following
  781.  *    special characters in the pattern: *?\[] (see the manual
  782.  *    entry for details on what these mean).
  783.  *
  784.  * Side effects:
  785.  *    None.
  786.  *
  787.  *----------------------------------------------------------------------
  788.  */
  789.  
  790. int
  791. Tcl_StringMatch(string, pattern)
  792.     register char *string;    /* String. */
  793.     register char *pattern;    /* Pattern, which may contain
  794.                  * special characters. */
  795. {
  796.     char c2;
  797.  
  798.     while (1) {
  799.     /* See if we're at the end of both the pattern and the string.
  800.      * If so, we succeeded.  If we're at the end of the pattern
  801.      * but not at the end of the string, we failed.
  802.      */
  803.     
  804.     if (*pattern == 0) {
  805.         if (*string == 0) {
  806.         return 1;
  807.         } else {
  808.         return 0;
  809.         }
  810.     }
  811.     if ((*string == 0) && (*pattern != '*')) {
  812.         return 0;
  813.     }
  814.  
  815.     /* Check for a "*" as the next pattern character.  It matches
  816.      * any substring.  We handle this by calling ourselves
  817.      * recursively for each postfix of string, until either we
  818.      * match or we reach the end of the string.
  819.      */
  820.     
  821.     if (*pattern == '*') {
  822.         pattern += 1;
  823.         if (*pattern == 0) {
  824.         return 1;
  825.         }
  826.         while (*string != 0) {
  827.         if (Tcl_StringMatch(string, pattern)) {
  828.             return 1;
  829.         }
  830.         string += 1;
  831.         }
  832.         return 0;
  833.     }
  834.     
  835.     /* Check for a "?" as the next pattern character.  It matches
  836.      * any single character.
  837.      */
  838.  
  839.     if (*pattern == '?') {
  840.         goto thisCharOK;
  841.     }
  842.  
  843.     /* Check for a "[" as the next pattern character.  It is followed
  844.      * by a list of characters that are acceptable, or by a range
  845.      * (two characters separated by "-").
  846.      */
  847.     
  848.     if (*pattern == '[') {
  849.         pattern += 1;
  850.         while (1) {
  851.         if ((*pattern == ']') || (*pattern == 0)) {
  852.             return 0;
  853.         }
  854.         if (*pattern == *string) {
  855.             break;
  856.         }
  857.         if (pattern[1] == '-') {
  858.             c2 = pattern[2];
  859.             if (c2 == 0) {
  860.             return 0;
  861.             }
  862.             if ((*pattern <= *string) && (c2 >= *string)) {
  863.             break;
  864.             }
  865.             if ((*pattern >= *string) && (c2 <= *string)) {
  866.             break;
  867.             }
  868.             pattern += 2;
  869.         }
  870.         pattern += 1;
  871.         }
  872.         while ((*pattern != ']') && (*pattern != 0)) {
  873.         pattern += 1;
  874.         }
  875.         goto thisCharOK;
  876.     }
  877.     
  878.     /* If the next pattern character is '/', just strip off the '/'
  879.      * so we do exact matching on the character that follows.
  880.      */
  881.     
  882.     if (*pattern == '\\') {
  883.         pattern += 1;
  884.         if (*pattern == 0) {
  885.         return 0;
  886.         }
  887.     }
  888.  
  889.     /* There's no special character.  Just make sure that the next
  890.      * characters of each string match.
  891.      */
  892.     
  893.     if (*pattern != *string) {
  894.         return 0;
  895.     }
  896.  
  897.     thisCharOK: pattern += 1;
  898.     string += 1;
  899.     }
  900. }
  901.