Annotation of micropolis/src/tcl/tclutil.c, revision 1.1.1.1

1.1       root        1: /* 
                      2:  * tclUtil.c --
                      3:  *
                      4:  *     This file contains utility procedures that are used by many Tcl
                      5:  *     commands.
                      6:  *
                      7:  * Copyright 1987-1991 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: /user6/ouster/tcl/RCS/tclUtil.c,v 1.63 92/07/02 08:50:54 ouster Exp $ SPRITE (Berkeley)";
                     19: #endif
                     20: 
                     21: #include "tclint.h"
                     22: 
                     23: /*
                     24:  * The following values are used in the flags returned by Tcl_ScanElement
                     25:  * and used by Tcl_ConvertElement.  The value TCL_DONT_USE_BRACES is also
                     26:  * defined in tcl.h;  make sure its value doesn't overlap with any of the
                     27:  * values below.
                     28:  *
                     29:  * TCL_DONT_USE_BRACES -       1 means the string mustn't be enclosed in
                     30:  *                             braces (e.g. it contains unmatched braces,
                     31:  *                             or ends in a backslash character, or user
                     32:  *                             just doesn't want braces);  handle all
                     33:  *                             special characters by adding backslashes.
                     34:  * USE_BRACES -                        1 means the string contains a special
                     35:  *                             character that can be handled simply by
                     36:  *                             enclosing the entire argument in braces.
                     37:  * BRACES_UNMATCHED -          1 means that braces aren't properly matched
                     38:  *                             in the argument.
                     39:  */
                     40: 
                     41: #define USE_BRACES             2
                     42: #define BRACES_UNMATCHED       4
                     43: 
                     44: /*
                     45:  * The variable below is set to NULL before invoking regexp functions
                     46:  * and checked after those functions.  If an error occurred then regerror
                     47:  * will set the variable to point to a (static) error message.  This
                     48:  * mechanism unfortunately does not support multi-threading, but then
                     49:  * neither does the rest of the regexp facilities.
                     50:  */
                     51: 
                     52: char *tclRegexpError = NULL;
                     53: 
                     54: /*
                     55:  * Function prototypes for local procedures in this file:
                     56:  */
                     57: 
                     58: static void            SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr,
                     59:                            int newSpace));
                     60: 
                     61: /*
                     62:  *----------------------------------------------------------------------
                     63:  *
                     64:  * TclFindElement --
                     65:  *
                     66:  *     Given a pointer into a Tcl list, locate the first (or next)
                     67:  *     element in the list.
                     68:  *
                     69:  * Results:
                     70:  *     The return value is normally TCL_OK, which means that the
                     71:  *     element was successfully located.  If TCL_ERROR is returned
                     72:  *     it means that list didn't have proper list structure;
                     73:  *     interp->result contains a more detailed error message.
                     74:  *
                     75:  *     If TCL_OK is returned, then *elementPtr will be set to point
                     76:  *     to the first element of list, and *nextPtr will be set to point
                     77:  *     to the character just after any white space following the last
                     78:  *     character that's part of the element.  If this is the last argument
                     79:  *     in the list, then *nextPtr will point to the NULL character at the
                     80:  *     end of list.  If sizePtr is non-NULL, *sizePtr is filled in with
                     81:  *     the number of characters in the element.  If the element is in
                     82:  *     braces, then *elementPtr will point to the character after the
                     83:  *     opening brace and *sizePtr will not include either of the braces.
                     84:  *     If there isn't an element in the list, *sizePtr will be zero, and
                     85:  *     both *elementPtr and *termPtr will refer to the null character at
                     86:  *     the end of list.  Note:  this procedure does NOT collapse backslash
                     87:  *     sequences.
                     88:  *
                     89:  * Side effects:
                     90:  *     None.
                     91:  *
                     92:  *----------------------------------------------------------------------
                     93:  */
                     94: 
                     95: int
                     96: TclFindElement(interp, list, elementPtr, nextPtr, sizePtr, bracePtr)
                     97:     Tcl_Interp *interp;                /* Interpreter to use for error reporting. */
                     98:     register char *list;       /* String containing Tcl list with zero
                     99:                                 * or more elements (possibly in braces). */
                    100:     char **elementPtr;         /* Fill in with location of first significant
                    101:                                 * character in first element of list. */
                    102:     char **nextPtr;            /* Fill in with location of character just
                    103:                                 * after all white space following end of
                    104:                                 * argument (i.e. next argument or end of
                    105:                                 * list). */
                    106:     int *sizePtr;              /* If non-zero, fill in with size of
                    107:                                 * element. */
                    108:     int *bracePtr;             /* If non-zero fill in with non-zero/zero
                    109:                                 * to indicate that arg was/wasn't
                    110:                                 * in braces. */
                    111: {
                    112:     register char *p;
                    113:     int openBraces = 0;
                    114:     int inQuotes = 0;
                    115:     int size;
                    116: 
                    117:     /*
                    118:      * Skim off leading white space and check for an opening brace or
                    119:      * quote.   Note:  use of "isascii" below and elsewhere in this
                    120:      * procedure is a temporary workaround (7/27/90) because Mx uses characters
                    121:      * with the high-order bit set for some things.  This should probably
                    122:      * be changed back eventually, or all of Tcl should call isascii.
                    123:      */
                    124: 
                    125:     while (isascii(*list) && isspace(*list)) {
                    126:        list++;
                    127:     }
                    128:     if (*list == '{') {
                    129:        openBraces = 1;
                    130:        list++;
                    131:     } else if (*list == '"') {
                    132:        inQuotes = 1;
                    133:        list++;
                    134:     }
                    135:     if (bracePtr != 0) {
                    136:        *bracePtr = openBraces;
                    137:     }
                    138:     p = list;
                    139: 
                    140:     /*
                    141:      * Find the end of the element (either a space or a close brace or
                    142:      * the end of the string).
                    143:      */
                    144: 
                    145:     while (1) {
                    146:        switch (*p) {
                    147: 
                    148:            /*
                    149:             * Open brace: don't treat specially unless the element is
                    150:             * in braces.  In this case, keep a nesting count.
                    151:             */
                    152: 
                    153:            case '{':
                    154:                if (openBraces != 0) {
                    155:                    openBraces++;
                    156:                }
                    157:                break;
                    158: 
                    159:            /*
                    160:             * Close brace: if element is in braces, keep nesting
                    161:             * count and quit when the last close brace is seen.
                    162:             */
                    163: 
                    164:            case '}':
                    165:                if (openBraces == 1) {
                    166:                    char *p2;
                    167: 
                    168:                    size = p - list;
                    169:                    p++;
                    170:                    if ((isascii(*p) && isspace(*p)) || (*p == 0)) {
                    171:                        goto done;
                    172:                    }
                    173:                    for (p2 = p; (*p2 != 0) && (!isspace(*p2)) && (p2 < p+20);
                    174:                            p2++) {
                    175:                        /* null body */
                    176:                    }
                    177:                    Tcl_ResetResult(interp);
                    178:                    sprintf(interp->result,
                    179:                            "list element in braces followed by \"%.*s\" instead of space",
                    180:                            p2-p, p);
                    181:                    return TCL_ERROR;
                    182:                } else if (openBraces != 0) {
                    183:                    openBraces--;
                    184:                }
                    185:                break;
                    186: 
                    187:            /*
                    188:             * Backslash:  skip over everything up to the end of the
                    189:             * backslash sequence.
                    190:             */
                    191: 
                    192:            case '\\': {
                    193:                int size;
                    194: 
                    195:                (void) Tcl_Backslash(p, &size);
                    196:                p += size - 1;
                    197:                break;
                    198:            }
                    199: 
                    200:            /*
                    201:             * Space: ignore if element is in braces or quotes;  otherwise
                    202:             * terminate element.
                    203:             */
                    204: 
                    205:            case ' ':
                    206:            case '\f':
                    207:            case '\n':
                    208:            case '\r':
                    209:            case '\t':
                    210:            case '\v':
                    211:                if ((openBraces == 0) && !inQuotes) {
                    212:                    size = p - list;
                    213:                    goto done;
                    214:                }
                    215:                break;
                    216: 
                    217:            /*
                    218:             * Double-quote:  if element is in quotes then terminate it.
                    219:             */
                    220: 
                    221:            case '"':
                    222:                if (inQuotes) {
                    223:                    char *p2;
                    224: 
                    225:                    size = p-list;
                    226:                    p++;
                    227:                    if ((isascii(*p) && isspace(*p)) || (*p == 0)) {
                    228:                        goto done;
                    229:                    }
                    230:                    for (p2 = p; (*p2 != 0) && (!isspace(*p2)) && (p2 < p+20);
                    231:                            p2++) {
                    232:                        /* null body */
                    233:                    }
                    234:                    Tcl_ResetResult(interp);
                    235:                    sprintf(interp->result,
                    236:                            "list element in quotes followed by \"%.*s\" %s",
                    237:                            p2-p, p, "instead of space");
                    238:                    return TCL_ERROR;
                    239:                }
                    240:                break;
                    241: 
                    242:            /*
                    243:             * End of list:  terminate element.
                    244:             */
                    245: 
                    246:            case 0:
                    247:                if (openBraces != 0) {
                    248:                    Tcl_SetResult(interp, "unmatched open brace in list",
                    249:                            TCL_STATIC);
                    250:                    return TCL_ERROR;
                    251:                } else if (inQuotes) {
                    252:                    Tcl_SetResult(interp, "unmatched open quote in list",
                    253:                            TCL_STATIC);
                    254:                    return TCL_ERROR;
                    255:                }
                    256:                size = p - list;
                    257:                goto done;
                    258: 
                    259:        }
                    260:        p++;
                    261:     }
                    262: 
                    263:     done:
                    264:     while (isascii(*p) && isspace(*p)) {
                    265:        p++;
                    266:     }
                    267:     *elementPtr = list;
                    268:     *nextPtr = p;
                    269:     if (sizePtr != 0) {
                    270:        *sizePtr = size;
                    271:     }
                    272:     return TCL_OK;
                    273: }
                    274: 
                    275: /*
                    276:  *----------------------------------------------------------------------
                    277:  *
                    278:  * TclCopyAndCollapse --
                    279:  *
                    280:  *     Copy a string and eliminate any backslashes that aren't in braces.
                    281:  *
                    282:  * Results:
                    283:  *     There is no return value.  Count chars. get copied from src
                    284:  *     to dst.  Along the way, if backslash sequences are found outside
                    285:  *     braces, the backslashes are eliminated in the copy.
                    286:  *     After scanning count chars. from source, a null character is
                    287:  *     placed at the end of dst.
                    288:  *
                    289:  * Side effects:
                    290:  *     None.
                    291:  *
                    292:  *----------------------------------------------------------------------
                    293:  */
                    294: 
                    295: void
                    296: TclCopyAndCollapse(count, src, dst)
                    297:     int count;                 /* Total number of characters to copy
                    298:                                 * from src. */
                    299:     register char *src;                /* Copy from here... */
                    300:     register char *dst;                /* ... to here. */
                    301: {
                    302:     register char c;
                    303:     int numRead;
                    304: 
                    305:     for (c = *src; count > 0; src++, c = *src, count--) {
                    306:        if (c == '\\') {
                    307:            *dst = Tcl_Backslash(src, &numRead);
                    308:            if (*dst != 0) {
                    309:                dst++;
                    310:            }
                    311:            src += numRead-1;
                    312:            count -= numRead-1;
                    313:        } else {
                    314:            *dst = c;
                    315:            dst++;
                    316:        }
                    317:     }
                    318:     *dst = 0;
                    319: }
                    320: 
                    321: /*
                    322:  *----------------------------------------------------------------------
                    323:  *
                    324:  * Tcl_SplitList --
                    325:  *
                    326:  *     Splits a list up into its constituent fields.
                    327:  *
                    328:  * Results
                    329:  *     The return value is normally TCL_OK, which means that
                    330:  *     the list was successfully split up.  If TCL_ERROR is
                    331:  *     returned, it means that "list" didn't have proper list
                    332:  *     structure;  interp->result will contain a more detailed
                    333:  *     error message.
                    334:  *
                    335:  *     *argvPtr will be filled in with the address of an array
                    336:  *     whose elements point to the elements of list, in order.
                    337:  *     *argcPtr will get filled in with the number of valid elements
                    338:  *     in the array.  A single block of memory is dynamically allocated
                    339:  *     to hold both the argv array and a copy of the list (with
                    340:  *     backslashes and braces removed in the standard way).
                    341:  *     The caller must eventually free this memory by calling free()
                    342:  *     on *argvPtr.  Note:  *argvPtr and *argcPtr are only modified
                    343:  *     if the procedure returns normally.
                    344:  *
                    345:  * Side effects:
                    346:  *     Memory is allocated.
                    347:  *
                    348:  *----------------------------------------------------------------------
                    349:  */
                    350: 
                    351: int
                    352: Tcl_SplitList(interp, list, argcPtr, argvPtr)
                    353:     Tcl_Interp *interp;                /* Interpreter to use for error reporting. */
                    354:     char *list;                        /* Pointer to string with list structure. */
                    355:     int *argcPtr;              /* Pointer to location to fill in with
                    356:                                 * the number of elements in the list. */
                    357:     char ***argvPtr;           /* Pointer to place to store pointer to array
                    358:                                 * of pointers to list elements. */
                    359: {
                    360:     char **argv;
                    361:     register char *p;
                    362:     int size, i, result, elSize, brace;
                    363:     char *element;
                    364: 
                    365:     /*
                    366:      * Figure out how much space to allocate.  There must be enough
                    367:      * space for both the array of pointers and also for a copy of
                    368:      * the list.  To estimate the number of pointers needed, count
                    369:      * the number of space characters in the list.
                    370:      */
                    371: 
                    372:     for (size = 1, p = list; *p != 0; p++) {
                    373:        if (isspace(*p)) {
                    374:            size++;
                    375:        }
                    376:     }
                    377:     size++;                    /* Leave space for final NULL pointer. */
                    378:     argv = (char **) ckalloc((unsigned)
                    379:            ((size * sizeof(char *)) + (p - list) + 1));
                    380:     for (i = 0, p = ((char *) argv) + size*sizeof(char *);
                    381:            *list != 0; i++) {
                    382:        result = TclFindElement(interp, list, &element, &list, &elSize, &brace);
                    383:        if (result != TCL_OK) {
                    384:            ckfree((char *) argv);
                    385:            return result;
                    386:        }
                    387:        if (*element == 0) {
                    388:            break;
                    389:        }
                    390:        if (i >= size) {
                    391:            ckfree((char *) argv);
                    392:            Tcl_SetResult(interp, "internal error in Tcl_SplitList",
                    393:                    TCL_STATIC);
                    394:            return TCL_ERROR;
                    395:        }
                    396:        argv[i] = p;
                    397:        if (brace) {
                    398:            strncpy(p, element, elSize);
                    399:            p += elSize;
                    400:            *p = 0;
                    401:            p++;
                    402:        } else {
                    403:            TclCopyAndCollapse(elSize, element, p);
                    404:            p += elSize+1;
                    405:        }
                    406:     }
                    407: 
                    408:     argv[i] = NULL;
                    409:     *argvPtr = argv;
                    410:     *argcPtr = i;
                    411:     return TCL_OK;
                    412: }
                    413: 
                    414: /*
                    415:  *----------------------------------------------------------------------
                    416:  *
                    417:  * Tcl_ScanElement --
                    418:  *
                    419:  *     This procedure is a companion procedure to Tcl_ConvertElement.
                    420:  *     It scans a string to see what needs to be done to it (e.g.
                    421:  *     add backslashes or enclosing braces) to make the string into
                    422:  *     a valid Tcl list element.
                    423:  *
                    424:  * Results:
                    425:  *     The return value is an overestimate of the number of characters
                    426:  *     that will be needed by Tcl_ConvertElement to produce a valid
                    427:  *     list element from string.  The word at *flagPtr is filled in
                    428:  *     with a value needed by Tcl_ConvertElement when doing the actual
                    429:  *     conversion.
                    430:  *
                    431:  * Side effects:
                    432:  *     None.
                    433:  *
                    434:  *----------------------------------------------------------------------
                    435:  */
                    436: 
                    437: int
                    438: Tcl_ScanElement(string, flagPtr)
                    439:     char *string;              /* String to convert to Tcl list element. */
                    440:     int *flagPtr;              /* Where to store information to guide
                    441:                                 * Tcl_ConvertElement. */
                    442: {
                    443:     int flags, nestingLevel;
                    444:     register char *p;
                    445: 
                    446:     /*
                    447:      * This procedure and Tcl_ConvertElement together do two things:
                    448:      *
                    449:      * 1. They produce a proper list, one that will yield back the
                    450:      * argument strings when evaluated or when disassembled with
                    451:      * Tcl_SplitList.  This is the most important thing.
                    452:      * 
                    453:      * 2. They try to produce legible output, which means minimizing the
                    454:      * use of backslashes (using braces instead).  However, there are
                    455:      * some situations where backslashes must be used (e.g. an element
                    456:      * like "{abc": the leading brace will have to be backslashed.  For
                    457:      * each element, one of three things must be done:
                    458:      *
                    459:      * (a) Use the element as-is (it doesn't contain anything special
                    460:      * characters).  This is the most desirable option.
                    461:      *
                    462:      * (b) Enclose the element in braces, but leave the contents alone.
                    463:      * This happens if the element contains embedded space, or if it
                    464:      * contains characters with special interpretation ($, [, ;, or \),
                    465:      * or if it starts with a brace or double-quote, or if there are
                    466:      * no characters in the element.
                    467:      *
                    468:      * (c) Don't enclose the element in braces, but add backslashes to
                    469:      * prevent special interpretation of special characters.  This is a
                    470:      * last resort used when the argument would normally fall under case
                    471:      * (b) but contains unmatched braces.  It also occurs if the last
                    472:      * character of the argument is a backslash.
                    473:      *
                    474:      * The procedure figures out how many bytes will be needed to store
                    475:      * the result (actually, it overestimates).  It also collects information
                    476:      * about the element in the form of a flags word.
                    477:      */
                    478: 
                    479:     nestingLevel = 0;
                    480:     flags = 0;
                    481:     p = string;
                    482:     if ((*p == '{') || (*p == '"') || (*p == 0)) {
                    483:        flags |= USE_BRACES;
                    484:     }
                    485:     for ( ; *p != 0; p++) {
                    486:        switch (*p) {
                    487:            case '{':
                    488:                nestingLevel++;
                    489:                break;
                    490:            case '}':
                    491:                nestingLevel--;
                    492:                if (nestingLevel < 0) {
                    493:                    flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
                    494:                }
                    495:                break;
                    496:            case '[':
                    497:            case '$':
                    498:            case ';':
                    499:            case ' ':
                    500:            case '\f':
                    501:            case '\n':
                    502:            case '\r':
                    503:            case '\t':
                    504:            case '\v':
                    505:                flags |= USE_BRACES;
                    506:                break;
                    507:            case '\\':
                    508:                if (p[1] == 0) {
                    509:                    flags = TCL_DONT_USE_BRACES;
                    510:                } else {
                    511:                    int size;
                    512: 
                    513:                    (void) Tcl_Backslash(p, &size);
                    514:                    p += size-1;
                    515:                    flags |= USE_BRACES;
                    516:                }
                    517:                break;
                    518:        }
                    519:     }
                    520:     if (nestingLevel != 0) {
                    521:        flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
                    522:     }
                    523:     *flagPtr = flags;
                    524: 
                    525:     /*
                    526:      * Allow enough space to backslash every character plus leave
                    527:      * two spaces for braces.
                    528:      */
                    529: 
                    530:     return 2*(p-string) + 2;
                    531: }
                    532: 
                    533: /*
                    534:  *----------------------------------------------------------------------
                    535:  *
                    536:  * Tcl_ConvertElement --
                    537:  *
                    538:  *     This is a companion procedure to Tcl_ScanElement.  Given the
                    539:  *     information produced by Tcl_ScanElement, this procedure converts
                    540:  *     a string to a list element equal to that string.
                    541:  *
                    542:  * Results:
                    543:  *     Information is copied to *dst in the form of a list element
                    544:  *     identical to src (i.e. if Tcl_SplitList is applied to dst it
                    545:  *     will produce a string identical to src).  The return value is
                    546:  *     a count of the number of characters copied (not including the
                    547:  *     terminating NULL character).
                    548:  *
                    549:  * Side effects:
                    550:  *     None.
                    551:  *
                    552:  *----------------------------------------------------------------------
                    553:  */
                    554: 
                    555: int
                    556: Tcl_ConvertElement(src, dst, flags)
                    557:     register char *src;                /* Source information for list element. */
                    558:     char *dst;                 /* Place to put list-ified element. */
                    559:     int flags;                 /* Flags produced by Tcl_ScanElement. */
                    560: {
                    561:     register char *p = dst;
                    562: 
                    563:     /*
                    564:      * See the comment block at the beginning of the Tcl_ScanElement
                    565:      * code for details of how this works.
                    566:      */
                    567: 
                    568:     if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
                    569:        *p = '{';
                    570:        p++;
                    571:        for ( ; *src != 0; src++, p++) {
                    572:            *p = *src;
                    573:        }
                    574:        *p = '}';
                    575:        p++;
                    576:     } else if (*src == 0) {
                    577:        /*
                    578:         * If string is empty but can't use braces, then use special
                    579:         * backslash sequence that maps to empty string.
                    580:         */
                    581: 
                    582:        p[0] = '\\';
                    583:        p[1] = '0';
                    584:        p += 2;
                    585:     } else {
                    586:        for (; *src != 0 ; src++) {
                    587:            switch (*src) {
                    588:                case ']':
                    589:                case '[':
                    590:                case '$':
                    591:                case ';':
                    592:                case ' ':
                    593:                case '\\':
                    594:                case '"':
                    595:                    *p = '\\';
                    596:                    p++;
                    597:                    break;
                    598:                case '{':
                    599:                case '}':
                    600:                    if (flags & BRACES_UNMATCHED) {
                    601:                        *p = '\\';
                    602:                        p++;
                    603:                    }
                    604:                    break;
                    605:                case '\f':
                    606:                    *p = '\\';
                    607:                    p++;
                    608:                    *p = 'f';
                    609:                    p++;
                    610:                    continue;
                    611:                case '\n':
                    612:                    *p = '\\';
                    613:                    p++;
                    614:                    *p = 'n';
                    615:                    p++;
                    616:                    continue;
                    617:                case '\r':
                    618:                    *p = '\\';
                    619:                    p++;
                    620:                    *p = 'r';
                    621:                    p++;
                    622:                    continue;
                    623:                case '\t':
                    624:                    *p = '\\';
                    625:                    p++;
                    626:                    *p = 't';
                    627:                    p++;
                    628:                    continue;
                    629:                case '\v':
                    630:                    *p = '\\';
                    631:                    p++;
                    632:                    *p = 'v';
                    633:                    p++;
                    634:                    continue;
                    635:            }
                    636:            *p = *src;
                    637:            p++;
                    638:        }
                    639:     }
                    640:     *p = '\0';
                    641:     return p-dst;
                    642: }
                    643: 
                    644: /*
                    645:  *----------------------------------------------------------------------
                    646:  *
                    647:  * Tcl_Merge --
                    648:  *
                    649:  *     Given a collection of strings, merge them together into a
                    650:  *     single string that has proper Tcl list structured (i.e.
                    651:  *     Tcl_SplitList may be used to retrieve strings equal to the
                    652:  *     original elements, and Tcl_Eval will parse the string back
                    653:  *     into its original elements).
                    654:  *
                    655:  * Results:
                    656:  *     The return value is the address of a dynamically-allocated
                    657:  *     string containing the merged list.
                    658:  *
                    659:  * Side effects:
                    660:  *     None.
                    661:  *
                    662:  *----------------------------------------------------------------------
                    663:  */
                    664: 
                    665: char *
                    666: Tcl_Merge(argc, argv)
                    667:     int argc;                  /* How many strings to merge. */
                    668:     char **argv;               /* Array of string values. */
                    669: {
                    670: #   define LOCAL_SIZE 20
                    671:     int localFlags[LOCAL_SIZE], *flagPtr;
                    672:     int numChars;
                    673:     char *result;
                    674:     register char *dst;
                    675:     int i;
                    676: 
                    677:     /*
                    678:      * Pass 1: estimate space, gather flags.
                    679:      */
                    680: 
                    681:     if (argc <= LOCAL_SIZE) {
                    682:        flagPtr = localFlags;
                    683:     } else {
                    684:        flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
                    685:     }
                    686:     numChars = 1;
                    687:     for (i = 0; i < argc; i++) {
                    688:        numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
                    689:     }
                    690: 
                    691:     /*
                    692:      * Pass two: copy into the result area.
                    693:      */
                    694: 
                    695:     result = (char *) ckalloc((unsigned) numChars);
                    696:     dst = result;
                    697:     for (i = 0; i < argc; i++) {
                    698:        numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]);
                    699:        dst += numChars;
                    700:        *dst = ' ';
                    701:        dst++;
                    702:     }
                    703:     if (dst == result) {
                    704:        *dst = 0;
                    705:     } else {
                    706:        dst[-1] = 0;
                    707:     }
                    708: 
                    709:     if (flagPtr != localFlags) {
                    710:        ckfree((char *) flagPtr);
                    711:     }
                    712:     return result;
                    713: }
                    714: 
                    715: /*
                    716:  *----------------------------------------------------------------------
                    717:  *
                    718:  * Tcl_Concat --
                    719:  *
                    720:  *     Concatenate a set of strings into a single large string.
                    721:  *
                    722:  * Results:
                    723:  *     The return value is dynamically-allocated string containing
                    724:  *     a concatenation of all the strings in argv, with spaces between
                    725:  *     the original argv elements.
                    726:  *
                    727:  * Side effects:
                    728:  *     Memory is allocated for the result;  the caller is responsible
                    729:  *     for freeing the memory.
                    730:  *
                    731:  *----------------------------------------------------------------------
                    732:  */
                    733: 
                    734: char *
                    735: Tcl_Concat(argc, argv)
                    736:     int argc;                  /* Number of strings to concatenate. */
                    737:     char **argv;               /* Array of strings to concatenate. */
                    738: {
                    739:     int totalSize, i;
                    740:     register char *p;
                    741:     char *result;
                    742: 
                    743:     for (totalSize = 1, i = 0; i < argc; i++) {
                    744:        totalSize += strlen(argv[i]) + 1;
                    745:     }
                    746:     result = (char *) ckalloc((unsigned) totalSize);
                    747:     if (argc == 0) {
                    748:        *result = '\0';
                    749:        return result;
                    750:     }
                    751:     for (p = result, i = 0; i < argc; i++) {
                    752:        char *element;
                    753:        int length;
                    754: 
                    755:        /*
                    756:         * Clip white space off the front and back of the string
                    757:         * to generate a neater result, and ignore any empty
                    758:         * elements.
                    759:         */
                    760: 
                    761:        element = argv[i];
                    762:        while (isspace(*element)) {
                    763:            element++;
                    764:        }
                    765:        for (length = strlen(element);
                    766:                (length > 0) && (isspace(element[length-1]));
                    767:                length--) {
                    768:            /* Null loop body. */
                    769:        }
                    770:        if (length == 0) {
                    771:            continue;
                    772:        }
                    773:        (void) strncpy(p, element, length);
                    774:        p += length;
                    775:        *p = ' ';
                    776:        p++;
                    777:     }
                    778:     if (p != result) {
                    779:        p[-1] = 0;
                    780:     } else {
                    781:        *p = 0;
                    782:     }
                    783:     return result;
                    784: }
                    785: 
                    786: /*
                    787:  *----------------------------------------------------------------------
                    788:  *
                    789:  * Tcl_StringMatch --
                    790:  *
                    791:  *     See if a particular string matches a particular pattern.
                    792:  *
                    793:  * Results:
                    794:  *     The return value is 1 if string matches pattern, and
                    795:  *     0 otherwise.  The matching operation permits the following
                    796:  *     special characters in the pattern: *?\[] (see the manual
                    797:  *     entry for details on what these mean).
                    798:  *
                    799:  * Side effects:
                    800:  *     None.
                    801:  *
                    802:  *----------------------------------------------------------------------
                    803:  */
                    804: 
                    805: int
                    806: Tcl_StringMatch(string, pattern)
                    807:     register char *string;     /* String. */
                    808:     register char *pattern;    /* Pattern, which may contain
                    809:                                 * special characters. */
                    810: {
                    811:     char c2;
                    812: 
                    813:     while (1) {
                    814:        /* See if we're at the end of both the pattern and the string.
                    815:         * If so, we succeeded.  If we're at the end of the pattern
                    816:         * but not at the end of the string, we failed.
                    817:         */
                    818:        
                    819:        if (*pattern == 0) {
                    820:            if (*string == 0) {
                    821:                return 1;
                    822:            } else {
                    823:                return 0;
                    824:            }
                    825:        }
                    826:        if ((*string == 0) && (*pattern != '*')) {
                    827:            return 0;
                    828:        }
                    829: 
                    830:        /* Check for a "*" as the next pattern character.  It matches
                    831:         * any substring.  We handle this by calling ourselves
                    832:         * recursively for each postfix of string, until either we
                    833:         * match or we reach the end of the string.
                    834:         */
                    835:        
                    836:        if (*pattern == '*') {
                    837:            pattern += 1;
                    838:            if (*pattern == 0) {
                    839:                return 1;
                    840:            }
                    841:            while (1) {
                    842:                if (Tcl_StringMatch(string, pattern)) {
                    843:                    return 1;
                    844:                }
                    845:                if (*string == 0) {
                    846:                    return 0;
                    847:                }
                    848:                string += 1;
                    849:            }
                    850:        }
                    851:     
                    852:        /* Check for a "?" as the next pattern character.  It matches
                    853:         * any single character.
                    854:         */
                    855: 
                    856:        if (*pattern == '?') {
                    857:            goto thisCharOK;
                    858:        }
                    859: 
                    860:        /* Check for a "[" as the next pattern character.  It is followed
                    861:         * by a list of characters that are acceptable, or by a range
                    862:         * (two characters separated by "-").
                    863:         */
                    864:        
                    865:        if (*pattern == '[') {
                    866:            pattern += 1;
                    867:            while (1) {
                    868:                if ((*pattern == ']') || (*pattern == 0)) {
                    869:                    return 0;
                    870:                }
                    871:                if (*pattern == *string) {
                    872:                    break;
                    873:                }
                    874:                if (pattern[1] == '-') {
                    875:                    c2 = pattern[2];
                    876:                    if (c2 == 0) {
                    877:                        return 0;
                    878:                    }
                    879:                    if ((*pattern <= *string) && (c2 >= *string)) {
                    880:                        break;
                    881:                    }
                    882:                    if ((*pattern >= *string) && (c2 <= *string)) {
                    883:                        break;
                    884:                    }
                    885:                    pattern += 2;
                    886:                }
                    887:                pattern += 1;
                    888:            }
                    889:            while ((*pattern != ']') && (*pattern != 0)) {
                    890:                pattern += 1;
                    891:            }
                    892:            goto thisCharOK;
                    893:        }
                    894:     
                    895:        /* If the next pattern character is '/', just strip off the '/'
                    896:         * so we do exact matching on the character that follows.
                    897:         */
                    898:        
                    899:        if (*pattern == '\\') {
                    900:            pattern += 1;
                    901:            if (*pattern == 0) {
                    902:                return 0;
                    903:            }
                    904:        }
                    905: 
                    906:        /* There's no special character.  Just make sure that the next
                    907:         * characters of each string match.
                    908:         */
                    909:        
                    910:        if (*pattern != *string) {
                    911:            return 0;
                    912:        }
                    913: 
                    914:        thisCharOK: pattern += 1;
                    915:        string += 1;
                    916:     }
                    917: }
                    918: 
                    919: /*
                    920:  *----------------------------------------------------------------------
                    921:  *
                    922:  * Tcl_SetResult --
                    923:  *
                    924:  *     Arrange for "string" to be the Tcl return value.
                    925:  *
                    926:  * Results:
                    927:  *     None.
                    928:  *
                    929:  * Side effects:
                    930:  *     interp->result is left pointing either to "string" (if "copy" is 0)
                    931:  *     or to a copy of string.
                    932:  *
                    933:  *----------------------------------------------------------------------
                    934:  */
                    935: 
                    936: void
                    937: Tcl_SetResult(interp, string, freeProc)
                    938:     Tcl_Interp *interp;                /* Interpreter with which to associate the
                    939:                                 * return value. */
                    940:     char *string;              /* Value to be returned.  If NULL,
                    941:                                 * the result is set to an empty string. */
                    942:     Tcl_FreeProc *freeProc;    /* Gives information about the string:
                    943:                                 * TCL_STATIC, TCL_VOLATILE, or the address
                    944:                                 * of a Tcl_FreeProc such as free. */
                    945: {
                    946:     register Interp *iPtr = (Interp *) interp;
                    947:     int length;
                    948:     Tcl_FreeProc *oldFreeProc = iPtr->freeProc;
                    949:     char *oldResult = iPtr->result;
                    950: 
                    951:     iPtr->freeProc = freeProc;
                    952:     if (string == NULL) {
                    953:        iPtr->resultSpace[0] = 0;
                    954:        iPtr->result = iPtr->resultSpace;
                    955:        iPtr->freeProc = 0;
                    956:     } else if (freeProc == TCL_VOLATILE) {
                    957:        length = strlen(string);
                    958:        if (length > TCL_RESULT_SIZE) {
                    959:            iPtr->result = (char *) ckalloc((unsigned) length+1);
                    960:            iPtr->freeProc = (Tcl_FreeProc *) free;
                    961:        } else {
                    962:            iPtr->result = iPtr->resultSpace;
                    963:            iPtr->freeProc = 0;
                    964:        }
                    965:        strcpy(iPtr->result, string);
                    966:     } else {
                    967:        iPtr->result = string;
                    968:     }
                    969: 
                    970:     /*
                    971:      * If the old result was dynamically-allocated, free it up.  Do it
                    972:      * here, rather than at the beginning, in case the new result value
                    973:      * was part of the old result value.
                    974:      */
                    975: 
                    976:     if (oldFreeProc != 0) {
                    977:        (*oldFreeProc)(oldResult);
                    978:     }
                    979: }
                    980: 
                    981: /*
                    982:  *----------------------------------------------------------------------
                    983:  *
                    984:  * Tcl_AppendResult --
                    985:  *
                    986:  *     Append a variable number of strings onto the result already
                    987:  *     present for an interpreter.
                    988:  *
                    989:  * Results:
                    990:  *     None.
                    991:  *
                    992:  * Side effects:
                    993:  *     The result in the interpreter given by the first argument
                    994:  *     is extended by the strings given by the second and following
                    995:  *     arguments (up to a terminating NULL argument).
                    996:  *
                    997:  *----------------------------------------------------------------------
                    998:  */
                    999: 
                   1000: void
                   1001: Tcl_AppendResult(Tcl_Interp *interp, ...)
                   1002: {
                   1003:     va_list argList;
                   1004:     register Interp *iPtr;
                   1005:     char *string;
                   1006:     int newSpace;
                   1007: 
                   1008:     /*
                   1009:      * First, scan through all the arguments to see how much space is
                   1010:      * needed.
                   1011:      */
                   1012: 
                   1013:     va_start(argList, interp);
                   1014:     iPtr = (Interp *)interp;
                   1015:     newSpace = 0;
                   1016:     while (1) {
                   1017:        string = va_arg(argList, char *);
                   1018:        if (string == NULL) {
                   1019:            break;
                   1020:        }
                   1021:        newSpace += strlen(string);
                   1022:     }
                   1023:     va_end(argList);
                   1024: 
                   1025:     /*
                   1026:      * If the append buffer isn't already setup and large enough
                   1027:      * to hold the new data, set it up.
                   1028:      */
                   1029: 
                   1030:     if ((iPtr->result != iPtr->appendResult)
                   1031:           || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) {
                   1032:        SetupAppendBuffer(iPtr, newSpace);
                   1033:     }
                   1034: 
                   1035:     /*
                   1036:      * Final step:  go through all the argument strings again, copying
                   1037:      * them into the buffer.
                   1038:      */
                   1039: 
                   1040:     va_start(argList, interp);
                   1041:     while (1) {
                   1042:        string = va_arg(argList, char *);
                   1043:        if (string == NULL) {
                   1044:            break;
                   1045:        }
                   1046:        strcpy(iPtr->appendResult + iPtr->appendUsed, string);
                   1047:        iPtr->appendUsed += strlen(string);
                   1048:     }
                   1049:     va_end(argList);
                   1050: }
                   1051: 
                   1052: /*
                   1053:  *----------------------------------------------------------------------
                   1054:  *
                   1055:  * Tcl_AppendElement --
                   1056:  *
                   1057:  *     Convert a string to a valid Tcl list element and append it
                   1058:  *     to the current result (which is ostensibly a list).
                   1059:  *
                   1060:  * Results:
                   1061:  *     None.
                   1062:  *
                   1063:  * Side effects:
                   1064:  *     The result in the interpreter given by the first argument
                   1065:  *     is extended with a list element converted from string.  If
                   1066:  *     the original result wasn't empty, then a blank is added before
                   1067:  *     the converted list element.
                   1068:  *
                   1069:  *----------------------------------------------------------------------
                   1070:  */
                   1071: 
                   1072: void
                   1073: Tcl_AppendElement(interp, string, noSep)
                   1074:     Tcl_Interp *interp;                /* Interpreter whose result is to be
                   1075:                                 * extended. */
                   1076:     char *string;              /* String to convert to list element and
                   1077:                                 * add to result. */
                   1078:     int noSep;                 /* If non-zero, then don't output a
                   1079:                                 * space character before this element,
                   1080:                                 * even if the element isn't the first
                   1081:                                 * thing in the output buffer. */
                   1082: {
                   1083:     register Interp *iPtr = (Interp *) interp;
                   1084:     int size, flags;
                   1085:     char *dst;
                   1086: 
                   1087:     /*
                   1088:      * See how much space is needed, and grow the append buffer if
                   1089:      * needed to accommodate the list element.
                   1090:      */
                   1091: 
                   1092:     size = Tcl_ScanElement(string, &flags) + 1;
                   1093:     if ((iPtr->result != iPtr->appendResult)
                   1094:           || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) {
                   1095:        SetupAppendBuffer(iPtr, size+iPtr->appendUsed);
                   1096:     }
                   1097: 
                   1098:     /*
                   1099:      * Convert the string into a list element and copy it to the
                   1100:      * buffer that's forming.
                   1101:      */
                   1102: 
                   1103:     dst = iPtr->appendResult + iPtr->appendUsed;
                   1104:     if (!noSep && (iPtr->appendUsed != 0)) {
                   1105:        iPtr->appendUsed++;
                   1106:        *dst = ' ';
                   1107:        dst++;
                   1108:     }
                   1109:     iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);
                   1110: }
                   1111: 
                   1112: /*
                   1113:  *----------------------------------------------------------------------
                   1114:  *
                   1115:  * SetupAppendBuffer --
                   1116:  *
                   1117:  *     This procedure makes sure that there is an append buffer
                   1118:  *     properly initialized for interp, and that it has at least
                   1119:  *     enough room to accommodate newSpace new bytes of information.
                   1120:  *
                   1121:  * Results:
                   1122:  *     None.
                   1123:  *
                   1124:  * Side effects:
                   1125:  *     None.
                   1126:  *
                   1127:  *----------------------------------------------------------------------
                   1128:  */
                   1129: 
                   1130: static void
                   1131: SetupAppendBuffer(iPtr, newSpace)
                   1132:     register Interp *iPtr;     /* Interpreter whose result is being set up. */
                   1133:     int newSpace;              /* Make sure that at least this many bytes
                   1134:                                 * of new information may be added. */
                   1135: {
                   1136:     int totalSpace;
                   1137: 
                   1138:     /*
                   1139:      * Make the append buffer larger, if that's necessary, then
                   1140:      * copy the current result into the append buffer and make the
                   1141:      * append buffer the official Tcl result.
                   1142:      */
                   1143: 
                   1144:     if (iPtr->result != iPtr->appendResult) {
                   1145:        /*
                   1146:         * If an oversized buffer was used recently, then free it up
                   1147:         * so we go back to a smaller buffer.  This avoids tying up
                   1148:         * memory forever after a large operation.
                   1149:         */
                   1150: 
                   1151:        if (iPtr->appendAvl > 500) {
                   1152:            ckfree(iPtr->appendResult);
                   1153:            iPtr->appendResult = NULL;
                   1154:            iPtr->appendAvl = 0;
                   1155:        }
                   1156:        iPtr->appendUsed = strlen(iPtr->result);
                   1157:     }
                   1158:     totalSpace = newSpace + iPtr->appendUsed;
                   1159:     if (totalSpace >= iPtr->appendAvl) {
                   1160:        char *new;
                   1161: 
                   1162:        if (totalSpace < 100) {
                   1163:            totalSpace = 200;
                   1164:        } else {
                   1165:            totalSpace *= 2;
                   1166:        }
                   1167:        new = (char *) ckalloc((unsigned) totalSpace);
                   1168:        strcpy(new, iPtr->result);
                   1169:        if (iPtr->appendResult != NULL) {
                   1170:            ckfree(iPtr->appendResult);
                   1171:        }
                   1172:        iPtr->appendResult = new;
                   1173:        iPtr->appendAvl = totalSpace;
                   1174:     } else if (iPtr->result != iPtr->appendResult) {
                   1175:        strcpy(iPtr->appendResult, iPtr->result);
                   1176:     }
                   1177:     Tcl_FreeResult(iPtr);
                   1178:     iPtr->result = iPtr->appendResult;
                   1179: }
                   1180: 
                   1181: /*
                   1182:  *----------------------------------------------------------------------
                   1183:  *
                   1184:  * Tcl_ResetResult --
                   1185:  *
                   1186:  *     This procedure restores the result area for an interpreter
                   1187:  *     to its default initialized state, freeing up any memory that
                   1188:  *     may have been allocated for the result and clearing any
                   1189:  *     error information for the interpreter.
                   1190:  *
                   1191:  * Results:
                   1192:  *     None.
                   1193:  *
                   1194:  * Side effects:
                   1195:  *     None.
                   1196:  *
                   1197:  *----------------------------------------------------------------------
                   1198:  */
                   1199: 
                   1200: void
                   1201: Tcl_ResetResult(interp)
                   1202:     Tcl_Interp *interp;                /* Interpreter for which to clear result. */
                   1203: {
                   1204:     register Interp *iPtr = (Interp *) interp;
                   1205: 
                   1206:     Tcl_FreeResult(iPtr);
                   1207:     iPtr->result = iPtr->resultSpace;
                   1208:     iPtr->resultSpace[0] = 0;
                   1209:     iPtr->flags &=
                   1210:            ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);
                   1211: }
                   1212: 
                   1213: /*
                   1214:  *----------------------------------------------------------------------
                   1215:  *
                   1216:  * Tcl_SetErrorCode --
                   1217:  *
                   1218:  *     This procedure is called to record machine-readable information
                   1219:  *     about an error that is about to be returned.
                   1220:  *
                   1221:  * Results:
                   1222:  *     None.
                   1223:  *
                   1224:  * Side effects:
                   1225:  *     The errorCode global variable is modified to hold all of the
                   1226:  *     arguments to this procedure, in a list form with each argument
                   1227:  *     becoming one element of the list.  A flag is set internally
                   1228:  *     to remember that errorCode has been set, so the variable doesn't
                   1229:  *     get set automatically when the error is returned.
                   1230:  *
                   1231:  *----------------------------------------------------------------------
                   1232:  */
                   1233: void
                   1234: Tcl_SetErrorCode(Tcl_Interp *interp, ...)
                   1235: {
                   1236:     va_list argList;
                   1237:     char *string;
                   1238:     int flags;
                   1239:     Interp *iPtr;
                   1240: 
                   1241:     /*
                   1242:      * Scan through the arguments one at a time, appending them to
                   1243:      * $errorCode as list elements.
                   1244:      */
                   1245: 
                   1246:     va_start(argList, interp);
                   1247:     iPtr = (Interp *)interp;
                   1248:     flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT;
                   1249:     while (1) {
                   1250:        string = va_arg(argList, char *);
                   1251:        if (string == NULL) {
                   1252:            break;
                   1253:        }
                   1254:        (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode",
                   1255:                (char *) NULL, string, flags);
                   1256:        flags |= TCL_APPEND_VALUE;
                   1257:     }
                   1258:     va_end(argList);
                   1259:     iPtr->flags |= ERROR_CODE_SET;
                   1260: }
                   1261: 
                   1262: /*
                   1263:  *----------------------------------------------------------------------
                   1264:  *
                   1265:  * TclGetListIndex --
                   1266:  *
                   1267:  *     Parse a list index, which may be either an integer or the
                   1268:  *     value "end".
                   1269:  *
                   1270:  * Results:
                   1271:  *     The return value is either TCL_OK or TCL_ERROR.  If it is
                   1272:  *     TCL_OK, then the index corresponding to string is left in
                   1273:  *     *indexPtr.  If the return value is TCL_ERROR, then string
                   1274:  *     was bogus;  an error message is returned in interp->result.
                   1275:  *     If a negative index is specified, it is rounded up to 0.
                   1276:  *     The index value may be larger than the size of the list
                   1277:  *     (this happens when "end" is specified).
                   1278:  *
                   1279:  * Side effects:
                   1280:  *     None.
                   1281:  *
                   1282:  *----------------------------------------------------------------------
                   1283:  */
                   1284: 
                   1285: int
                   1286: TclGetListIndex(interp, string, indexPtr)
                   1287:     Tcl_Interp *interp;                        /* Interpreter for error reporting. */
                   1288:     char *string;                      /* String containing list index. */
                   1289:     int *indexPtr;                     /* Where to store index. */
                   1290: {
                   1291:     if (isdigit(*string) || (*string == '-')) {
                   1292:        if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
                   1293:            return TCL_ERROR;
                   1294:        }
                   1295:        if (*indexPtr < 0) {
                   1296:            *indexPtr = 0;
                   1297:        }
                   1298:     } else if (strncmp(string, "end", strlen(string)) == 0) {
                   1299:        *indexPtr = 1<<30;
                   1300:     } else {
                   1301:        Tcl_AppendResult(interp, "bad index \"", string,
                   1302:                "\": must be integer or \"end\"", (char *) NULL);
                   1303:        return TCL_ERROR;
                   1304:     }
                   1305:     return TCL_OK;
                   1306: }
                   1307: 
                   1308: /*
                   1309:  *----------------------------------------------------------------------
                   1310:  *
                   1311:  * TclCompileRegexp --
                   1312:  *
                   1313:  *     Compile a regular expression into a form suitable for fast
                   1314:  *     matching.  This procedure retains a small cache of pre-compiled
                   1315:  *     regular expressions in the interpreter, in order to avoid
                   1316:  *     compilation costs as much as possible.
                   1317:  *
                   1318:  * Results:
                   1319:  *     The return value is a pointer to the compiled form of string,
                   1320:  *     suitable for passing to regexec.  If an error occurred while
                   1321:  *     compiling the pattern, then NULL is returned and an error
                   1322:  *     message is left in interp->result.
                   1323:  *
                   1324:  * Side effects:
                   1325:  *     The cache of compiled regexp's in interp will be modified to
                   1326:  *     hold information for string, if such information isn't already
                   1327:  *     present in the cache.
                   1328:  *
                   1329:  *----------------------------------------------------------------------
                   1330:  */
                   1331: 
                   1332: regexp *
                   1333: TclCompileRegexp(interp, string)
                   1334:     Tcl_Interp *interp;                        /* For use in error reporting. */
                   1335:     char *string;                      /* String for which to produce
                   1336:                                         * compiled regular expression. */
                   1337: {
                   1338:     register Interp *iPtr = (Interp *) interp;
                   1339:     int i, length;
                   1340:     regexp *result;
                   1341: 
                   1342:     length = strlen(string);
                   1343:     for (i = 0; i < NUM_REGEXPS; i++) {
                   1344:        if ((length == iPtr->patLengths[i])
                   1345:                && (strcmp(string, iPtr->patterns[i]) == 0)) {
                   1346:            /*
                   1347:             * Move the matched pattern to the first slot in the
                   1348:             * cache and shift the other patterns down one position.
                   1349:             */
                   1350: 
                   1351:            if (i != 0) {
                   1352:                int j;
                   1353:                char *cachedString;
                   1354: 
                   1355:                cachedString = iPtr->patterns[i];
                   1356:                result = iPtr->regexps[i];
                   1357:                for (j = i-1; j >= 0; j--) {
                   1358:                    iPtr->patterns[j+1] = iPtr->patterns[j];
                   1359:                    iPtr->patLengths[j+1] = iPtr->patLengths[j];
                   1360:                    iPtr->regexps[j+1] = iPtr->regexps[j];
                   1361:                }
                   1362:                iPtr->patterns[0] = cachedString;
                   1363:                iPtr->patLengths[0] = length;
                   1364:                iPtr->regexps[0] = result;
                   1365:            }
                   1366:            return iPtr->regexps[0];
                   1367:        }
                   1368:     }
                   1369: 
                   1370:     /*
                   1371:      * No match in the cache.  Compile the string and add it to the
                   1372:      * cache.
                   1373:      */
                   1374: 
                   1375:     tclRegexpError = NULL;
                   1376:     result = regcomp(string);
                   1377:     if (tclRegexpError != NULL) {
                   1378:        Tcl_AppendResult(interp,
                   1379:            "couldn't compile regular expression pattern: ",
                   1380:            tclRegexpError, (char *) NULL);
                   1381:        return NULL;
                   1382:     }
                   1383:     if (iPtr->patterns[NUM_REGEXPS-1] != NULL) {
                   1384:        ckfree(iPtr->patterns[NUM_REGEXPS-1]);
                   1385:        ckfree((char *) iPtr->regexps[NUM_REGEXPS-1]);
                   1386:     }
                   1387:     for (i = NUM_REGEXPS - 2; i >= 0; i--) {
                   1388:        iPtr->patterns[i+1] = iPtr->patterns[i];
                   1389:        iPtr->patLengths[i+1] = iPtr->patLengths[i];
                   1390:        iPtr->regexps[i+1] = iPtr->regexps[i];
                   1391:     }
                   1392:     iPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1));
                   1393:     strcpy(iPtr->patterns[0], string);
                   1394:     iPtr->patLengths[0] = length;
                   1395:     iPtr->regexps[0] = result;
                   1396:     return result;
                   1397: }
                   1398: 
                   1399: /*
                   1400:  *----------------------------------------------------------------------
                   1401:  *
                   1402:  * regerror --
                   1403:  *
                   1404:  *     This procedure is invoked by the Henry Spencer's regexp code
                   1405:  *     when an error occurs.  It saves the error message so it can
                   1406:  *     be seen by the code that called Spencer's code.
                   1407:  *
                   1408:  * Results:
                   1409:  *     None.
                   1410:  *
                   1411:  * Side effects:
                   1412:  *     The value of "string" is saved in "tclRegexpError".
                   1413:  *
                   1414:  *----------------------------------------------------------------------
                   1415:  */
                   1416: 
                   1417: void
                   1418: regerror(string)
                   1419:     char *string;                      /* Error message. */
                   1420: {
                   1421:     tclRegexpError = string;
                   1422: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.