Annotation of micropolis/src/tcl/tclparse.c, revision 1.1.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.