Annotation of micropolis/src/tcl/tclparse.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * tclParse.c --
        !             3:  *
        !             4:  *     This file contains a collection of procedures that are used
        !             5:  *     to parse Tcl commands or parts of commands (like quoted
        !             6:  *     strings or nested sub-commands).
        !             7:  *
        !             8:  * Copyright 1991 Regents of the University of California.
        !             9:  * Permission to use, copy, modify, and distribute this
        !            10:  * software and its documentation for any purpose and without
        !            11:  * fee is hereby granted, provided that the above copyright
        !            12:  * notice appear in all copies.  The University of California
        !            13:  * makes no representations about the suitability of this
        !            14:  * software for any purpose.  It is provided "as is" without
        !            15:  * express or implied warranty.
        !            16:  */
        !            17: 
        !            18: #ifndef lint
        !            19: static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclParse.c,v 1.21 92/06/08 09:32:37 ouster Exp $ SPRITE (Berkeley)";
        !            20: #endif
        !            21: 
        !            22: #include "tclint.h"
        !            23: 
        !            24: /*
        !            25:  * The following table assigns a type to each character.  Only types
        !            26:  * meaningful to Tcl parsing are represented here.  The table indexes
        !            27:  * all 256 characters, with the negative ones first, then the positive
        !            28:  * ones.
        !            29:  */
        !            30: 
        !            31: char tclTypeTable[] = {
        !            32:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            33:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            34:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            35:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            36:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            37:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            38:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            39:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            40:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            41:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            42:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            43:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            44:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            45:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            46:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            47:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            48:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            49:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            50:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            51:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            52:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            53:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            54:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            55:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            56:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            57:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            58:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            59:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            60:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            61:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            62:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            63:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            64:     TCL_COMMAND_END,   TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            65:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            66:     TCL_NORMAL,        TCL_SPACE,         TCL_COMMAND_END,   TCL_SPACE,
        !            67:     TCL_SPACE,         TCL_SPACE,         TCL_NORMAL,        TCL_NORMAL,
        !            68:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            69:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            70:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            71:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            72:     TCL_SPACE,         TCL_NORMAL,        TCL_QUOTE,         TCL_NORMAL,
        !            73:     TCL_DOLLAR,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            74:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            75:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            76:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            77:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            78:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_COMMAND_END,
        !            79:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            80:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            81:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            82:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            83:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            84:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            85:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            86:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_OPEN_BRACKET,
        !            87:     TCL_BACKSLASH,     TCL_COMMAND_END,   TCL_NORMAL,        TCL_NORMAL,
        !            88:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            89:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            90:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            91:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            92:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            93:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
        !            94:     TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_OPEN_BRACE,
        !            95:     TCL_NORMAL,        TCL_CLOSE_BRACE,   TCL_NORMAL,        TCL_NORMAL,
        !            96: };
        !            97: 
        !            98: /*
        !            99:  * Function prototypes for procedures local to this file:
        !           100:  */
        !           101: 
        !           102: static char *  QuoteEnd _ANSI_ARGS_((char *string, int term));
        !           103: static char *  VarNameEnd _ANSI_ARGS_((char *string));
        !           104: 
        !           105: /*
        !           106:  *----------------------------------------------------------------------
        !           107:  *
        !           108:  * Tcl_Backslash --
        !           109:  *
        !           110:  *     Figure out how to handle a backslash sequence.
        !           111:  *
        !           112:  * Results:
        !           113:  *     The return value is the character that should be substituted
        !           114:  *     in place of the backslash sequence that starts at src, or 0
        !           115:  *     if the backslash sequence should be replace by nothing (e.g.
        !           116:  *     backslash followed by newline).  If readPtr isn't NULL then
        !           117:  *     it is filled in with a count of the number of characters in
        !           118:  *     the backslash sequence.  Note:  if the backslash isn't followed
        !           119:  *     by characters that are understood here, then the backslash
        !           120:  *     sequence is only considered to be one character long, and it
        !           121:  *     is replaced by a backslash char.
        !           122:  *
        !           123:  * Side effects:
        !           124:  *     None.
        !           125:  *
        !           126:  *----------------------------------------------------------------------
        !           127:  */
        !           128: 
        !           129: char
        !           130: Tcl_Backslash(src, readPtr)
        !           131:     char *src;                 /* Points to the backslash character of
        !           132:                                 * a backslash sequence. */
        !           133:     int *readPtr;              /* Fill in with number of characters read
        !           134:                                 * from src, unless NULL. */
        !           135: {
        !           136:     register char *p = src+1;
        !           137:     char result;
        !           138:     int count;
        !           139: 
        !           140:     count = 2;
        !           141: 
        !           142:     switch (*p) {
        !           143:        case 'b':
        !           144:            result = '\b';
        !           145:            break;
        !           146:        case 'e':
        !           147:            result = 033;
        !           148:            break;
        !           149:        case 'f':
        !           150:            result = '\f';
        !           151:            break;
        !           152:        case 'n':
        !           153:            result = '\n';
        !           154:            break;
        !           155:        case 'r':
        !           156:            result = '\r';
        !           157:            break;
        !           158:        case 't':
        !           159:            result = '\t';
        !           160:            break;
        !           161:        case 'v':
        !           162:            result = '\v';
        !           163:            break;
        !           164:        case 'C':
        !           165:            p++;
        !           166:            if (isspace(*p) || (*p == 0)) {
        !           167:                result = 'C';
        !           168:                count = 1;
        !           169:                break;
        !           170:            }
        !           171:            count = 3;
        !           172:            if (*p == 'M') {
        !           173:                p++;
        !           174:                if (isspace(*p) || (*p == 0)) {
        !           175:                    result = 'M' & 037;
        !           176:                    break;
        !           177:                }
        !           178:                count = 4;
        !           179:                result = (*p & 037) | 0200;
        !           180:                break;
        !           181:            }
        !           182:            count = 3;
        !           183:            result = *p & 037;
        !           184:            break;
        !           185:        case 'M':
        !           186:            p++;
        !           187:            if (isspace(*p) || (*p == 0)) {
        !           188:                result = 'M';
        !           189:                count = 1;
        !           190:                break;
        !           191:            }
        !           192:            count = 3;
        !           193:            result = *p + 0200;
        !           194:            break;
        !           195:        case '}':
        !           196:        case '{':
        !           197:        case ']':
        !           198:        case '[':
        !           199:        case '$':
        !           200:        case ' ':
        !           201:        case ';':
        !           202:        case '"':
        !           203:        case '\\':
        !           204:            result = *p;
        !           205:            break;
        !           206:        case '\n':
        !           207:            result = 0;
        !           208:            break;
        !           209:        default:
        !           210:            if (isdigit(*p)) {
        !           211:                result = *p - '0';
        !           212:                p++;
        !           213:                if (!isdigit(*p)) {
        !           214:                    break;
        !           215:                }
        !           216:                count = 3;
        !           217:                result = (result << 3) + (*p - '0');
        !           218:                p++;
        !           219:                if (!isdigit(*p)) {
        !           220:                    break;
        !           221:                }
        !           222:                count = 4;
        !           223:                result = (result << 3) + (*p - '0');
        !           224:                break;
        !           225:            }
        !           226:            result = '\\';
        !           227:            count = 1;
        !           228:            break;
        !           229:     }
        !           230: 
        !           231:     if (readPtr != NULL) {
        !           232:        *readPtr = count;
        !           233:     }
        !           234:     return result;
        !           235: }
        !           236: 
        !           237: /*
        !           238:  *--------------------------------------------------------------
        !           239:  *
        !           240:  * TclParseQuotes --
        !           241:  *
        !           242:  *     This procedure parses a double-quoted string such as a
        !           243:  *     quoted Tcl command argument or a quoted value in a Tcl
        !           244:  *     expression.  This procedure is also used to parse array
        !           245:  *     element names within parentheses, or anything else that
        !           246:  *     needs all the substitutions that happen in quotes.
        !           247:  *
        !           248:  * Results:
        !           249:  *     The return value is a standard Tcl result, which is
        !           250:  *     TCL_OK unless there was an error while parsing the
        !           251:  *     quoted string.  If an error occurs then interp->result
        !           252:  *     contains a standard error message.  *TermPtr is filled
        !           253:  *     in with the address of the character just after the
        !           254:  *     last one successfully processed;  this is usually the
        !           255:  *     character just after the matching close-quote.  The
        !           256:  *     fully-substituted contents of the quotes are stored in
        !           257:  *     standard fashion in *pvPtr, null-terminated with
        !           258:  *     pvPtr->next pointing to the terminating null character.
        !           259:  *
        !           260:  * Side effects:
        !           261:  *     The buffer space in pvPtr may be enlarged by calling its
        !           262:  *     expandProc.
        !           263:  *
        !           264:  *--------------------------------------------------------------
        !           265:  */
        !           266: 
        !           267: int
        !           268: TclParseQuotes(interp, string, termChar, flags, termPtr, pvPtr)
        !           269:     Tcl_Interp *interp;                /* Interpreter to use for nested command
        !           270:                                 * evaluations and error messages. */
        !           271:     char *string;              /* Character just after opening double-
        !           272:                                 * quote. */
        !           273:     int termChar;              /* Character that terminates "quoted" string
        !           274:                                 * (usually double-quote, but sometimes
        !           275:                                 * right-paren or something else). */
        !           276:     int flags;                 /* Flags to pass to nested Tcl_Eval calls. */
        !           277:     char **termPtr;            /* Store address of terminating character
        !           278:                                 * here. */
        !           279:     ParseValue *pvPtr;         /* Information about where to place
        !           280:                                 * fully-substituted result of parse. */
        !           281: {
        !           282:     register char *src, *dst, c;
        !           283: 
        !           284:     src = string;
        !           285:     dst = pvPtr->next;
        !           286: 
        !           287:     while (1) {
        !           288:        if (dst == pvPtr->end) {
        !           289:            /*
        !           290:             * Target buffer space is about to run out.  Make more space.
        !           291:             */
        !           292: 
        !           293:            pvPtr->next = dst;
        !           294:            (*pvPtr->expandProc)(pvPtr, 1);
        !           295:            dst = pvPtr->next;
        !           296:        }
        !           297: 
        !           298:        c = *src;
        !           299:        src++;
        !           300:        if (c == termChar) {
        !           301:            *dst = '\0';
        !           302:            pvPtr->next = dst;
        !           303:            *termPtr = src;
        !           304:            return TCL_OK;
        !           305:        } else if (CHAR_TYPE(c) == TCL_NORMAL) {
        !           306:            copy:
        !           307:            *dst = c;
        !           308:            dst++;
        !           309:            continue;
        !           310:        } else if (c == '$') {
        !           311:            int length;
        !           312:            char *value;
        !           313: 
        !           314:            value = Tcl_ParseVar(interp, src-1, termPtr);
        !           315:            if (value == NULL) {
        !           316:                return TCL_ERROR;
        !           317:            }
        !           318:            src = *termPtr;
        !           319:            length = strlen(value);
        !           320:            if ((pvPtr->end - dst) <= length) {
        !           321:                pvPtr->next = dst;
        !           322:                (*pvPtr->expandProc)(pvPtr, length);
        !           323:                dst = pvPtr->next;
        !           324:            }
        !           325:            strcpy(dst, value);
        !           326:            dst += length;
        !           327:            continue;
        !           328:        } else if (c == '[') {
        !           329:            int result;
        !           330: 
        !           331:            pvPtr->next = dst;
        !           332:            result = TclParseNestedCmd(interp, src, flags, termPtr, pvPtr);
        !           333:            if (result != TCL_OK) {
        !           334:                return result;
        !           335:            }
        !           336:            src = *termPtr;
        !           337:            dst = pvPtr->next;
        !           338:            continue;
        !           339:        } else if (c == '\\') {
        !           340:            int numRead;
        !           341: 
        !           342:            src--;
        !           343:            *dst = Tcl_Backslash(src, &numRead);
        !           344:            if (*dst != 0) {
        !           345:                dst++;
        !           346:            }
        !           347:            src += numRead;
        !           348:            continue;
        !           349:        } else if (c == '\0') {
        !           350:            Tcl_ResetResult(interp);
        !           351:            sprintf(interp->result, "missing %c", termChar);
        !           352:            *termPtr = string-1;
        !           353:            return TCL_ERROR;
        !           354:        } else {
        !           355:            goto copy;
        !           356:        }
        !           357:     }
        !           358: }
        !           359: 
        !           360: /*
        !           361:  *--------------------------------------------------------------
        !           362:  *
        !           363:  * TclParseNestedCmd --
        !           364:  *
        !           365:  *     This procedure parses a nested Tcl command between
        !           366:  *     brackets, returning the result of the command.
        !           367:  *
        !           368:  * Results:
        !           369:  *     The return value is a standard Tcl result, which is
        !           370:  *     TCL_OK unless there was an error while executing the
        !           371:  *     nested command.  If an error occurs then interp->result
        !           372:  *     contains a standard error message.  *TermPtr is filled
        !           373:  *     in with the address of the character just after the
        !           374:  *     last one processed;  this is usually the character just
        !           375:  *     after the matching close-bracket, or the null character
        !           376:  *     at the end of the string if the close-bracket was missing
        !           377:  *     (a missing close bracket is an error).  The result returned
        !           378:  *     by the command is stored in standard fashion in *pvPtr,
        !           379:  *     null-terminated, with pvPtr->next pointing to the null
        !           380:  *     character.
        !           381:  *
        !           382:  * Side effects:
        !           383:  *     The storage space at *pvPtr may be expanded.
        !           384:  *
        !           385:  *--------------------------------------------------------------
        !           386:  */
        !           387: 
        !           388: int
        !           389: TclParseNestedCmd(interp, string, flags, termPtr, pvPtr)
        !           390:     Tcl_Interp *interp;                /* Interpreter to use for nested command
        !           391:                                 * evaluations and error messages. */
        !           392:     char *string;              /* Character just after opening bracket. */
        !           393:     int flags;                 /* Flags to pass to nested Tcl_Eval. */
        !           394:     char **termPtr;            /* Store address of terminating character
        !           395:                                 * here. */
        !           396:     register ParseValue *pvPtr;        /* Information about where to place
        !           397:                                 * result of command. */
        !           398: {
        !           399:     int result, length, shortfall;
        !           400:     Interp *iPtr = (Interp *) interp;
        !           401: 
        !           402:     result = Tcl_Eval(interp, string, flags | TCL_BRACKET_TERM, termPtr);
        !           403:     if (result != TCL_OK) {
        !           404:        /*
        !           405:         * The increment below results in slightly cleaner message in
        !           406:         * the errorInfo variable (the close-bracket will appear).
        !           407:         */
        !           408: 
        !           409:        if (**termPtr == ']') {
        !           410:            *termPtr += 1;
        !           411:        }
        !           412:        return result;
        !           413:     }
        !           414:     (*termPtr) += 1;
        !           415:     length = strlen(iPtr->result);
        !           416:     shortfall = length + 1 - (pvPtr->end - pvPtr->next);
        !           417:     if (shortfall > 0) {
        !           418:        (*pvPtr->expandProc)(pvPtr, shortfall);
        !           419:     }
        !           420:     strcpy(pvPtr->next, iPtr->result);
        !           421:     pvPtr->next += length;
        !           422:     Tcl_FreeResult(iPtr);
        !           423:     iPtr->result = iPtr->resultSpace;
        !           424:     iPtr->resultSpace[0] = '\0';
        !           425:     return TCL_OK;
        !           426: }
        !           427: 
        !           428: /*
        !           429:  *--------------------------------------------------------------
        !           430:  *
        !           431:  * TclParseBraces --
        !           432:  *
        !           433:  *     This procedure scans the information between matching
        !           434:  *     curly braces.
        !           435:  *
        !           436:  * Results:
        !           437:  *     The return value is a standard Tcl result, which is
        !           438:  *     TCL_OK unless there was an error while parsing string.
        !           439:  *     If an error occurs then interp->result contains a
        !           440:  *     standard error message.  *TermPtr is filled
        !           441:  *     in with the address of the character just after the
        !           442:  *     last one successfully processed;  this is usually the
        !           443:  *     character just after the matching close-brace.  The
        !           444:  *     information between curly braces is stored in standard
        !           445:  *     fashion in *pvPtr, null-terminated with pvPtr->next
        !           446:  *     pointing to the terminating null character.
        !           447:  *
        !           448:  * Side effects:
        !           449:  *     The storage space at *pvPtr may be expanded.
        !           450:  *
        !           451:  *--------------------------------------------------------------
        !           452:  */
        !           453: 
        !           454: int
        !           455: TclParseBraces(interp, string, termPtr, pvPtr)
        !           456:     Tcl_Interp *interp;                /* Interpreter to use for nested command
        !           457:                                 * evaluations and error messages. */
        !           458:     char *string;              /* Character just after opening bracket. */
        !           459:     char **termPtr;            /* Store address of terminating character
        !           460:                                 * here. */
        !           461:     register ParseValue *pvPtr;        /* Information about where to place
        !           462:                                 * result of command. */
        !           463: {
        !           464:     int level;
        !           465:     register char *src, *dst, *end;
        !           466:     register char c;
        !           467: 
        !           468:     src = string;
        !           469:     dst = pvPtr->next;
        !           470:     end = pvPtr->end;
        !           471:     level = 1;
        !           472: 
        !           473:     /*
        !           474:      * Copy the characters one at a time to the result area, stopping
        !           475:      * when the matching close-brace is found.
        !           476:      */
        !           477: 
        !           478:     while (1) {
        !           479:        c = *src;
        !           480:        src++;
        !           481:        if (dst == end) {
        !           482:            pvPtr->next = dst;
        !           483:            (*pvPtr->expandProc)(pvPtr, 20);
        !           484:            dst = pvPtr->next;
        !           485:            end = pvPtr->end;
        !           486:        }
        !           487:        *dst = c;
        !           488:        dst++;
        !           489:        if (CHAR_TYPE(c) == TCL_NORMAL) {
        !           490:            continue;
        !           491:        } else if (c == '{') {
        !           492:            level++;
        !           493:        } else if (c == '}') {
        !           494:            level--;
        !           495:            if (level == 0) {
        !           496:                dst--;                  /* Don't copy the last close brace. */
        !           497:                break;
        !           498:            }
        !           499:        } else if (c == '\\') {
        !           500:            int count;
        !           501: 
        !           502:            /*
        !           503:             * Must always squish out backslash-newlines, even when in
        !           504:             * braces.  This is needed so that this sequence can appear
        !           505:             * anywhere in a command, such as the middle of an expression.
        !           506:             */
        !           507: 
        !           508:            if (*src == '\n') {
        !           509:                dst--;
        !           510:                src++;
        !           511:            } else {
        !           512:                (void) Tcl_Backslash(src-1, &count);
        !           513:                while (count > 1) {
        !           514:                     if (dst == end) {
        !           515:                         pvPtr->next = dst;
        !           516:                         (*pvPtr->expandProc)(pvPtr, 20);
        !           517:                         dst = pvPtr->next;
        !           518:                         end = pvPtr->end;
        !           519:                     }
        !           520:                    *dst = *src;
        !           521:                    dst++;
        !           522:                    src++;
        !           523:                    count--;
        !           524:                }
        !           525:            }
        !           526:        } else if (c == '\0') {
        !           527:            Tcl_SetResult(interp, "missing close-brace", TCL_STATIC);
        !           528:            *termPtr = string-1;
        !           529:            return TCL_ERROR;
        !           530:        }
        !           531:     }
        !           532: 
        !           533:     *dst = '\0';
        !           534:     pvPtr->next = dst;
        !           535:     *termPtr = src;
        !           536:     return TCL_OK;
        !           537: }
        !           538: 
        !           539: /*
        !           540:  *--------------------------------------------------------------
        !           541:  *
        !           542:  * TclParseWords --
        !           543:  *
        !           544:  *     This procedure parses one or more words from a command
        !           545:  *     string and creates argv-style pointers to fully-substituted
        !           546:  *     copies of those words.
        !           547:  *
        !           548:  * Results:
        !           549:  *     The return value is a standard Tcl result.
        !           550:  *     
        !           551:  *     *argcPtr is modified to hold a count of the number of words
        !           552:  *     successfully parsed, which may be 0.  At most maxWords words
        !           553:  *     will be parsed.  If 0 <= *argcPtr < maxWords then it
        !           554:  *     means that a command separator was seen.  If *argcPtr
        !           555:  *     is maxWords then it means that a command separator was
        !           556:  *     not seen yet.
        !           557:  *
        !           558:  *     *TermPtr is filled in with the address of the character
        !           559:  *     just after the last one successfully processed in the
        !           560:  *     last word.  This is either the command terminator (if
        !           561:  *     *argcPtr < maxWords), the character just after the last
        !           562:  *     one in a word (if *argcPtr is maxWords), or the vicinity
        !           563:  *     of an error (if the result is not TCL_OK).
        !           564:  *     
        !           565:  *     The pointers at *argv are filled in with pointers to the
        !           566:  *     fully-substituted words, and the actual contents of the
        !           567:  *     words are copied to the buffer at pvPtr.
        !           568:  *
        !           569:  *     If an error occurrs then an error message is left in
        !           570:  *     interp->result and the information at *argv, *argcPtr,
        !           571:  *     and *pvPtr may be incomplete.
        !           572:  *
        !           573:  * Side effects:
        !           574:  *     The buffer space in pvPtr may be enlarged by calling its
        !           575:  *     expandProc.
        !           576:  *
        !           577:  *--------------------------------------------------------------
        !           578:  */
        !           579: 
        !           580: int
        !           581: TclParseWords(interp, string, flags, maxWords, termPtr, argcPtr, argv, pvPtr)
        !           582:     Tcl_Interp *interp;                /* Interpreter to use for nested command
        !           583:                                 * evaluations and error messages. */
        !           584:     char *string;              /* First character of word. */
        !           585:     int flags;                 /* Flags to control parsing (same values as
        !           586:                                 * passed to Tcl_Eval). */
        !           587:     int maxWords;              /* Maximum number of words to parse. */
        !           588:     char **termPtr;            /* Store address of terminating character
        !           589:                                 * here. */
        !           590:     int *argcPtr;              /* Filled in with actual number of words
        !           591:                                 * parsed. */
        !           592:     char **argv;               /* Store addresses of individual words here. */
        !           593:     register ParseValue *pvPtr;        /* Information about where to place
        !           594:                                 * fully-substituted word. */
        !           595: {
        !           596:     register char *src, *dst;
        !           597:     register char c;
        !           598:     int type, result, argc;
        !           599:     char *oldBuffer;           /* Used to detect when pvPtr's buffer gets
        !           600:                                 * reallocated, so we can adjust all of the
        !           601:                                 * argv pointers. */
        !           602: 
        !           603:     src = string;
        !           604:     oldBuffer = pvPtr->buffer;
        !           605:     dst = pvPtr->next;
        !           606:     for (argc = 0; argc < maxWords; argc++) {
        !           607:        argv[argc] = dst;
        !           608: 
        !           609:        /*
        !           610:         * Skip leading space.
        !           611:         */
        !           612:     
        !           613:        skipSpace:
        !           614:        c = *src;
        !           615:        type = CHAR_TYPE(c);
        !           616:        while (type == TCL_SPACE) {
        !           617:            src++;
        !           618:            c = *src;
        !           619:            type = CHAR_TYPE(c);
        !           620:        }
        !           621:     
        !           622:        /*
        !           623:         * Handle the normal case (i.e. no leading double-quote or brace).
        !           624:         */
        !           625: 
        !           626:        if (type == TCL_NORMAL) {
        !           627:            normalArg:
        !           628:            while (1) {
        !           629:                if (dst == pvPtr->end) {
        !           630:                    /*
        !           631:                     * Target buffer space is about to run out.  Make
        !           632:                     * more space.
        !           633:                     */
        !           634:        
        !           635:                    pvPtr->next = dst;
        !           636:                    (*pvPtr->expandProc)(pvPtr, 1);
        !           637:                    dst = pvPtr->next;
        !           638:                }
        !           639:        
        !           640:                if (type == TCL_NORMAL) {
        !           641:                    copy:
        !           642:                    *dst = c;
        !           643:                    dst++;
        !           644:                    src++;
        !           645:                } else if (type == TCL_SPACE) {
        !           646:                    goto wordEnd;
        !           647:                } else if (type == TCL_DOLLAR) {
        !           648:                    int length;
        !           649:                    char *value;
        !           650:        
        !           651:                    value = Tcl_ParseVar(interp, src, termPtr);
        !           652:                    if (value == NULL) {
        !           653:                        return TCL_ERROR;
        !           654:                    }
        !           655:                    src = *termPtr;
        !           656:                    length = strlen(value);
        !           657:                    if ((pvPtr->end - dst) <= length) {
        !           658:                        pvPtr->next = dst;
        !           659:                        (*pvPtr->expandProc)(pvPtr, length);
        !           660:                        dst = pvPtr->next;
        !           661:                    }
        !           662:                    strcpy(dst, value);
        !           663:                    dst += length;
        !           664:                } else if (type == TCL_COMMAND_END) {
        !           665:                    if ((c == ']') && !(flags & TCL_BRACKET_TERM)) {
        !           666:                        goto copy;
        !           667:                    }
        !           668: 
        !           669:                    /*
        !           670:                     * End of command;  simulate a word-end first, so
        !           671:                     * that the end-of-command can be processed as the
        !           672:                     * first thing in a new word.
        !           673:                     */
        !           674: 
        !           675:                    goto wordEnd;
        !           676:                } else if (type == TCL_OPEN_BRACKET) {
        !           677:                    pvPtr->next = dst;
        !           678:                    result = TclParseNestedCmd(interp, src+1, flags, termPtr,
        !           679:                            pvPtr);
        !           680:                    if (result != TCL_OK) {
        !           681:                        return result;
        !           682:                    }
        !           683:                    src = *termPtr;
        !           684:                    dst = pvPtr->next;
        !           685:                } else if (type == TCL_BACKSLASH) {
        !           686:                    int numRead;
        !           687:     
        !           688:                    *dst = Tcl_Backslash(src, &numRead);
        !           689:                    if (*dst != 0) {
        !           690:                        dst++;
        !           691:                    }
        !           692:                    src += numRead;
        !           693:                } else {
        !           694:                    goto copy;
        !           695:                }
        !           696:                c = *src;
        !           697:                type = CHAR_TYPE(c);
        !           698:            }
        !           699:        } else {
        !           700:     
        !           701:            /*
        !           702:             * Check for the end of the command.
        !           703:             */
        !           704:        
        !           705:            if (type == TCL_COMMAND_END) {
        !           706:                if (flags & TCL_BRACKET_TERM) {
        !           707:                    if (c == '\0') {
        !           708:                        Tcl_SetResult(interp, "missing close-bracket",
        !           709:                                TCL_STATIC);
        !           710:                        return TCL_ERROR;
        !           711:                    }
        !           712:                } else {
        !           713:                    if (c == ']') {
        !           714:                        goto normalArg;
        !           715:                    }
        !           716:                }
        !           717:                goto done;
        !           718:            }
        !           719:        
        !           720:            /*
        !           721:             * Now handle the special cases: open braces, double-quotes,
        !           722:             * and backslash-newline.
        !           723:             */
        !           724: 
        !           725:            pvPtr->next = dst;
        !           726:            if (type == TCL_QUOTE) {
        !           727:                result = TclParseQuotes(interp, src+1, '"', flags,
        !           728:                        termPtr, pvPtr);
        !           729:            } else if (type == TCL_OPEN_BRACE) {
        !           730:                result = TclParseBraces(interp, src+1, termPtr, pvPtr);
        !           731:            } else if ((type == TCL_BACKSLASH) && (src[1] == '\n')) {
        !           732:                src += 2;
        !           733:                goto skipSpace;
        !           734:            } else {
        !           735:                goto normalArg;
        !           736:            }
        !           737:            if (result != TCL_OK) {
        !           738:                return result;
        !           739:            }
        !           740:        
        !           741:            /*
        !           742:             * Back from quotes or braces;  make sure that the terminating
        !           743:             * character was the end of the word.  Have to be careful here
        !           744:             * to handle continuation lines (i.e. lines ending in backslash).
        !           745:             */
        !           746:        
        !           747:            c = **termPtr;
        !           748:            if ((c == '\\') && ((*termPtr)[1] == '\n')) {
        !           749:                c = (*termPtr)[2];
        !           750:            }
        !           751:            type = CHAR_TYPE(c);
        !           752:            if ((type != TCL_SPACE) && (type != TCL_COMMAND_END)) {
        !           753:                if (*src == '"') {
        !           754:                    Tcl_SetResult(interp, "extra characters after close-quote",
        !           755:                            TCL_STATIC);
        !           756:                } else {
        !           757:                    Tcl_SetResult(interp, "extra characters after close-brace",
        !           758:                            TCL_STATIC);
        !           759:                }
        !           760:                return TCL_ERROR;
        !           761:            }
        !           762:            src = *termPtr;
        !           763:            dst = pvPtr->next;
        !           764: 
        !           765:        }
        !           766: 
        !           767:        /*
        !           768:         * We're at the end of a word, so add a null terminator.  Then
        !           769:         * see if the buffer was re-allocated during this word.  If so,
        !           770:         * update all of the argv pointers.
        !           771:         */
        !           772: 
        !           773:        wordEnd:
        !           774:        *dst = '\0';
        !           775:        dst++;
        !           776:        if (oldBuffer != pvPtr->buffer) {
        !           777:            int i;
        !           778: 
        !           779:            for (i = 0; i <= argc; i++) {
        !           780:                argv[i] = pvPtr->buffer + (argv[i] - oldBuffer);
        !           781:            }
        !           782:            oldBuffer = pvPtr->buffer;
        !           783:        }
        !           784:     }
        !           785: 
        !           786:     done:
        !           787:     pvPtr->next = dst;
        !           788:     *termPtr = src;
        !           789:     *argcPtr = argc;
        !           790:     return TCL_OK;
        !           791: }
        !           792: 
        !           793: /*
        !           794:  *--------------------------------------------------------------
        !           795:  *
        !           796:  * TclExpandParseValue --
        !           797:  *
        !           798:  *     This procedure is commonly used as the value of the
        !           799:  *     expandProc in a ParseValue.  It uses malloc to allocate
        !           800:  *     more space for the result of a parse.
        !           801:  *
        !           802:  * Results:
        !           803:  *     The buffer space in *pvPtr is reallocated to something
        !           804:  *     larger, and if pvPtr->clientData is non-zero the old
        !           805:  *     buffer is freed.  Information is copied from the old
        !           806:  *     buffer to the new one.
        !           807:  *
        !           808:  * Side effects:
        !           809:  *     None.
        !           810:  *
        !           811:  *--------------------------------------------------------------
        !           812:  */
        !           813: 
        !           814: void
        !           815: TclExpandParseValue(pvPtr, needed)
        !           816:     register ParseValue *pvPtr;                /* Information about buffer that
        !           817:                                         * must be expanded.  If the clientData
        !           818:                                         * in the structure is non-zero, it
        !           819:                                         * means that the current buffer is
        !           820:                                         * dynamically allocated. */
        !           821:     int needed;                                /* Minimum amount of additional space
        !           822:                                         * to allocate. */
        !           823: {
        !           824:     int newSpace;
        !           825:     char *new;
        !           826: 
        !           827:     /*
        !           828:      * Either double the size of the buffer or add enough new space
        !           829:      * to meet the demand, whichever produces a larger new buffer.
        !           830:      */
        !           831: 
        !           832:     newSpace = (pvPtr->end - pvPtr->buffer) + 1;
        !           833:     if (newSpace < needed) {
        !           834:        newSpace += needed;
        !           835:     } else {
        !           836:        newSpace += newSpace;
        !           837:     }
        !           838:     new = (char *) ckalloc((unsigned) newSpace);
        !           839: 
        !           840:     /*
        !           841:      * Copy from old buffer to new, free old buffer if needed, and
        !           842:      * mark new buffer as malloc-ed.
        !           843:      */
        !           844: 
        !           845:     memcpy((VOID *) new, (VOID *) pvPtr->buffer, pvPtr->next - pvPtr->buffer);
        !           846:     pvPtr->next = new + (pvPtr->next - pvPtr->buffer);
        !           847:     if (pvPtr->clientData != 0) {
        !           848:        ckfree(pvPtr->buffer);
        !           849:     }
        !           850:     pvPtr->buffer = new;
        !           851:     pvPtr->end = new + newSpace - 1;
        !           852:     pvPtr->clientData = (ClientData) 1;
        !           853: }
        !           854: 
        !           855: /*
        !           856:  *----------------------------------------------------------------------
        !           857:  *
        !           858:  * TclWordEnd --
        !           859:  *
        !           860:  *     Given a pointer into a Tcl command, find the end of the next
        !           861:  *     word of the command.
        !           862:  *
        !           863:  * Results:
        !           864:  *     The return value is a pointer to the character just after the
        !           865:  *     last one that's part of the word pointed to by "start".  This
        !           866:  *     may be the address of the NULL character at the end of the
        !           867:  *     string.
        !           868:  *
        !           869:  * Side effects:
        !           870:  *     None.
        !           871:  *
        !           872:  *----------------------------------------------------------------------
        !           873:  */
        !           874: 
        !           875: char *
        !           876: TclWordEnd(start, nested)
        !           877:     char *start;               /* Beginning of a word of a Tcl command. */
        !           878:     int nested;                        /* Zero means this is a top-level command.
        !           879:                                 * One means this is a nested command (close
        !           880:                                 * brace is a word terminator). */
        !           881: {
        !           882:     register char *p;
        !           883:     int count;
        !           884: 
        !           885:     p = start;
        !           886:     while (isspace(*p)) {
        !           887:        p++;
        !           888:     }
        !           889: 
        !           890:     /*
        !           891:      * Handle words beginning with a double-quote or a brace.
        !           892:      */
        !           893: 
        !           894:     if (*p == '"') {
        !           895:        p = QuoteEnd(p+1, '"');
        !           896:     } else if (*p == '{') {
        !           897:        int braces = 1;
        !           898:        while (braces != 0) {
        !           899:            p++;
        !           900:            while (*p == '\\') {
        !           901:                (void) Tcl_Backslash(p, &count);
        !           902:                p += count;
        !           903:            }
        !           904:            if (*p == '}') {
        !           905:                braces--;
        !           906:            } else if (*p == '{') {
        !           907:                braces++;
        !           908:            } else if (*p == 0) {
        !           909:                return p;
        !           910:            }
        !           911:        }
        !           912:     }
        !           913: 
        !           914:     /*
        !           915:      * Handle words that don't start with a brace or double-quote.
        !           916:      * This code is also invoked if the word starts with a brace or
        !           917:      * double-quote and there is garbage after the closing brace or
        !           918:      * quote.  This is an error as far as Tcl_Eval is concerned, but
        !           919:      * for here the garbage is treated as part of the word.
        !           920:      */
        !           921: 
        !           922:     while (*p != 0) {
        !           923:        if (*p == '[') {
        !           924:            p++;
        !           925:            while ((*p != ']') && (*p != 0)) {
        !           926:                p = TclWordEnd(p, 1);
        !           927:            }
        !           928:            if (*p == ']') {
        !           929:                p++;
        !           930:            }
        !           931:        } else if (*p == '\\') {
        !           932:            (void) Tcl_Backslash(p, &count);
        !           933:            p += count;
        !           934:        } else if (*p == '$') {
        !           935:            p = VarNameEnd(p);
        !           936:        } else if (*p == ';') {
        !           937:            /*
        !           938:             * Note:  semi-colon terminates a word
        !           939:             * and also counts as a word by itself.
        !           940:             */
        !           941: 
        !           942:            if (p == start) {
        !           943:                p++;
        !           944:            }
        !           945:            break;
        !           946:        } else if (isspace(*p)) {
        !           947:            break;
        !           948:        } else if ((*p == ']') && nested) {
        !           949:            break;
        !           950:        } else {
        !           951:            p++;
        !           952:        }
        !           953:     }
        !           954:     return p;
        !           955: }
        !           956: 
        !           957: /*
        !           958:  *----------------------------------------------------------------------
        !           959:  *
        !           960:  * QuoteEnd --
        !           961:  *
        !           962:  *     Given a pointer to a string that obeys the parsing conventions
        !           963:  *     for quoted things in Tcl, find the end of that quoted thing.
        !           964:  *     The actual thing may be a quoted argument or a parenthesized
        !           965:  *     index name.
        !           966:  *
        !           967:  * Results:
        !           968:  *     The return value is a pointer to the character just after the
        !           969:  *     last one that is part of the quoted string.
        !           970:  *
        !           971:  * Side effects:
        !           972:  *     None.
        !           973:  *
        !           974:  *----------------------------------------------------------------------
        !           975:  */
        !           976: 
        !           977: static char *
        !           978: QuoteEnd(string, term)
        !           979:     char *string;              /* Pointer to character just after opening
        !           980:                                 * "quote". */
        !           981:     int term;                  /* This character will terminate the
        !           982:                                 * quoted string (e.g. '"' or ')'). */
        !           983: {
        !           984:     register char *p = string;
        !           985:     int count;
        !           986: 
        !           987:     while ((*p != 0) && (*p != term)) {
        !           988:        if (*p == '\\') {
        !           989:            (void) Tcl_Backslash(p, &count);
        !           990:            p += count;
        !           991:        } else if (*p == '[') {
        !           992:            p++;
        !           993:            while ((*p != ']') && (*p != 0)) {
        !           994:                p = TclWordEnd(p, 1);
        !           995:            }
        !           996:            if (*p == ']') {
        !           997:                p++;
        !           998:            }
        !           999:        } else if (*p == '$') {
        !          1000:            p = VarNameEnd(p);
        !          1001:        } else {
        !          1002:            p++;
        !          1003:        }
        !          1004:     }
        !          1005:     return p;
        !          1006: }
        !          1007: 
        !          1008: /*
        !          1009:  *----------------------------------------------------------------------
        !          1010:  *
        !          1011:  * VarNameEnd --
        !          1012:  *
        !          1013:  *     Given a pointer to a variable reference using $-notation, find
        !          1014:  *     the end of the variable name spec.
        !          1015:  *
        !          1016:  * Results:
        !          1017:  *     The return value is a pointer to the character just after the
        !          1018:  *     last one that is part of the variable name.
        !          1019:  *
        !          1020:  * Side effects:
        !          1021:  *     None.
        !          1022:  *
        !          1023:  *----------------------------------------------------------------------
        !          1024:  */
        !          1025: 
        !          1026: static char *
        !          1027: VarNameEnd(string)
        !          1028:     char *string;              /* Pointer to dollar-sign character. */
        !          1029: {
        !          1030:     register char *p = string+1;
        !          1031: 
        !          1032:     if (*p == '{') {
        !          1033:        do {
        !          1034:            p++;
        !          1035:        } while ((*p != '}') && (*p != 0));
        !          1036:     } else {
        !          1037:        while (isalnum(*p) || (*p == '_')) {
        !          1038:            p++;
        !          1039:        }
        !          1040:        if ((*p == '(') && (p != string+1)) {
        !          1041:            p = QuoteEnd(p+1, ')');
        !          1042:        }
        !          1043:     }
        !          1044:     return p;
        !          1045: }
        !          1046: 
        !          1047: /*
        !          1048:  *----------------------------------------------------------------------
        !          1049:  *
        !          1050:  * Tcl_ParseVar --
        !          1051:  *
        !          1052:  *     Given a string starting with a $ sign, parse off a variable
        !          1053:  *     name and return its value.
        !          1054:  *
        !          1055:  * Results:
        !          1056:  *     The return value is the contents of the variable given by
        !          1057:  *     the leading characters of string.  If termPtr isn't NULL,
        !          1058:  *     *termPtr gets filled in with the address of the character
        !          1059:  *     just after the last one in the variable specifier.  If the
        !          1060:  *     variable doesn't exist, then the return value is NULL and
        !          1061:  *     an error message will be left in interp->result.
        !          1062:  *
        !          1063:  * Side effects:
        !          1064:  *     None.
        !          1065:  *
        !          1066:  *----------------------------------------------------------------------
        !          1067:  */
        !          1068: 
        !          1069: char *
        !          1070: Tcl_ParseVar(interp, string, termPtr)
        !          1071:     Tcl_Interp *interp;                        /* Context for looking up variable. */
        !          1072:     register char *string;             /* String containing variable name.
        !          1073:                                         * First character must be "$". */
        !          1074:     char **termPtr;                    /* If non-NULL, points to word to fill
        !          1075:                                         * in with character just after last
        !          1076:                                         * one in the variable specifier. */
        !          1077: 
        !          1078: {
        !          1079:     char *name1, *name1End, c, *result;
        !          1080:     register char *name2;
        !          1081: #define NUM_CHARS 200
        !          1082:     char copyStorage[NUM_CHARS];
        !          1083:     ParseValue pv;
        !          1084: 
        !          1085:     /*
        !          1086:      * There are three cases:
        !          1087:      * 1. The $ sign is followed by an open curly brace.  Then the variable
        !          1088:      *    name is everything up to the next close curly brace, and the
        !          1089:      *    variable is a scalar variable.
        !          1090:      * 2. The $ sign is not followed by an open curly brace.  Then the
        !          1091:      *    variable name is everything up to the next character that isn't
        !          1092:      *    a letter, digit, or underscore.  If the following character is an
        !          1093:      *    open parenthesis, then the information between parentheses is
        !          1094:      *    the array element name, which can include any of the substitutions
        !          1095:      *    permissible between quotes.
        !          1096:      * 3. The $ sign is followed by something that isn't a letter, digit,
        !          1097:      *    or underscore:  in this case, there is no variable name, and "$"
        !          1098:      *    is returned.
        !          1099:      */
        !          1100: 
        !          1101:     name2 = NULL;
        !          1102:     string++;
        !          1103:     if (*string == '{') {
        !          1104:        string++;
        !          1105:        name1 = string;
        !          1106:        while (*string != '}') {
        !          1107:            if (*string == 0) {
        !          1108:                Tcl_SetResult(interp, "missing close-brace for variable name",
        !          1109:                        TCL_STATIC);
        !          1110:                if (termPtr != 0) {
        !          1111:                    *termPtr = string;
        !          1112:                }
        !          1113:                return NULL;
        !          1114:            }
        !          1115:            string++;
        !          1116:        }
        !          1117:        name1End = string;
        !          1118:        string++;
        !          1119:     } else {
        !          1120:        name1 = string;
        !          1121:        while (isalnum(*string) || (*string == '_')) {
        !          1122:            string++;
        !          1123:        }
        !          1124:        if (string == name1) {
        !          1125:            if (termPtr != 0) {
        !          1126:                *termPtr = string;
        !          1127:            }
        !          1128:            return "$";
        !          1129:        }
        !          1130:        name1End = string;
        !          1131:        if (*string == '(') {
        !          1132:            char *end;
        !          1133: 
        !          1134:            /*
        !          1135:             * Perform substitutions on the array element name, just as
        !          1136:             * is done for quotes.
        !          1137:             */
        !          1138: 
        !          1139:            pv.buffer = pv.next = copyStorage;
        !          1140:            pv.end = copyStorage + NUM_CHARS - 1;
        !          1141:            pv.expandProc = TclExpandParseValue;
        !          1142:            pv.clientData = (ClientData) NULL;
        !          1143:            if (TclParseQuotes(interp, string+1, ')', 0, &end, &pv)
        !          1144:                    != TCL_OK) {
        !          1145:                char msg[100];
        !          1146:                sprintf(msg, "\n    (parsing index for array \"%.*s\")",
        !          1147:                        string-name1, name1);
        !          1148:                Tcl_AddErrorInfo(interp, msg);
        !          1149:                result = NULL;
        !          1150:                name2 = pv.buffer;
        !          1151:                if (termPtr != 0) {
        !          1152:                    *termPtr = end;
        !          1153:                }
        !          1154:                goto done;
        !          1155:            }
        !          1156:            string = end;
        !          1157:            name2 = pv.buffer;
        !          1158:        }
        !          1159:     }
        !          1160:     if (termPtr != 0) {
        !          1161:        *termPtr = string;
        !          1162:     }
        !          1163: 
        !          1164:     c = *name1End;
        !          1165:     *name1End = 0;
        !          1166:     result = Tcl_GetVar2(interp, name1, name2, TCL_LEAVE_ERR_MSG);
        !          1167:     *name1End = c;
        !          1168: 
        !          1169:     done:
        !          1170:     if ((name2 != NULL) && (pv.buffer != copyStorage)) {
        !          1171:        ckfree(pv.buffer);
        !          1172:     }
        !          1173:     return result;
        !          1174: }

unix.superglobalmegacorp.com

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