Annotation of micropolis/src/tk/tkargv.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * tkArgv.c --
                      3:  *
                      4:  *     This file contains a procedure that handles table-based
                      5:  *     argv-argc parsing.
                      6:  *
                      7:  * Copyright 1990 Regents of the University of California
                      8:  * Permission to use, copy, modify, and distribute this
                      9:  * software and its documentation for any purpose and without
                     10:  * fee is hereby granted, provided that the above copyright
                     11:  * notice appear in all copies.  The University of California
                     12:  * makes no representations about the suitability of this
                     13:  * software for any purpose.  It is provided "as is" without
                     14:  * express or implied warranty.
                     15:  */
                     16: 
                     17: #ifndef lint
                     18: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkArgv.c,v 1.12 92/08/07 08:39:48 ouster Exp $ SPRITE (Berkeley)";
                     19: #endif
                     20: 
                     21: #include "tkconfig.h"
                     22: #include "tk.h"
                     23: 
                     24: /*
                     25:  * Default table of argument descriptors.  These are normally available
                     26:  * in every application.
                     27:  */
                     28: 
                     29: static Tk_ArgvInfo defaultTable[] = {
                     30:     {"-help",  TK_ARGV_HELP,   (char *) NULL,  (char *) NULL,
                     31:        "Print summary of command-line options and abort"},
                     32:     {NULL,     TK_ARGV_END,    (char *) NULL,  (char *) NULL,
                     33:        (char *) NULL}
                     34: };
                     35: 
                     36: /*
                     37:  * Forward declarations for procedures defined in this file:
                     38:  */
                     39: 
                     40: static void    PrintUsage _ANSI_ARGS_((Tcl_Interp *interp,
                     41:                    Tk_ArgvInfo *argTable, int flags));
                     42: 
                     43: /*
                     44:  *----------------------------------------------------------------------
                     45:  *
                     46:  * Tk_ParseArgv --
                     47:  *
                     48:  *     Process an argv array according to a table of expected
                     49:  *     command-line options.  See the manual page for more details.
                     50:  *
                     51:  * Results:
                     52:  *     The return value is a standard Tcl return value.  If an
                     53:  *     error occurs then an error message is left in interp->result.
                     54:  *     Under normal conditions, both *argcPtr and *argv are modified
                     55:  *     to return the arguments that couldn't be processed here (they
                     56:  *     didn't match the option table, or followed an TK_ARGV_REST
                     57:  *     argument).
                     58:  *
                     59:  * Side effects:
                     60:  *     Variables may be modified, resources may be entered for tkwin,
                     61:  *     or procedures may be called.  It all depends on the arguments
                     62:  *     and their entries in argTable.  See the user documentation
                     63:  *     for details.
                     64:  *
                     65:  *----------------------------------------------------------------------
                     66:  */
                     67: 
                     68: int
                     69: Tk_ParseArgv(interp, tkwin, argcPtr, argv, argTable, flags)
                     70:     Tcl_Interp *interp;                /* Place to store error message. */
                     71:     Tk_Window tkwin;           /* Window to use for setting Tk options.
                     72:                                 * NULL means ignore Tk option specs. */
                     73:     int *argcPtr;              /* Number of arguments in argv.  Modified
                     74:                                 * to hold # args left in argv at end. */
                     75:     char **argv;               /* Array of arguments.  Modified to hold
                     76:                                 * those that couldn't be processed here. */
                     77:     Tk_ArgvInfo *argTable;     /* Array of option descriptions */
                     78:     int flags;                 /* Or'ed combination of various flag bits,
                     79:                                 * such as TK_ARGV_NO_DEFAULTS. */
                     80: {
                     81:     register Tk_ArgvInfo *infoPtr;
                     82:                                /* Pointer to the current entry in the
                     83:                                 * table of argument descriptions. */
                     84:     Tk_ArgvInfo *matchPtr;     /* Descriptor that matches current argument. */
                     85:     char *curArg;              /* Current argument */
                     86:     register char c;           /* Second character of current arg (used for
                     87:                                 * quick check for matching;  use 2nd char.
                     88:                                 * because first char. will almost always
                     89:                                 * be '-'). */
                     90:     int srcIndex;              /* Location from which to read next argument
                     91:                                 * from argv. */
                     92:     int dstIndex;              /* Index into argv to which next unused
                     93:                                 * argument should be copied (never greater
                     94:                                 * than srcIndex). */
                     95:     int argc;                  /* # arguments in argv still to process. */
                     96:     int length;                        /* Number of characters in current argument. */
                     97:     int i;
                     98: 
                     99:     if (flags & TK_ARGV_DONT_SKIP_FIRST_ARG) {
                    100:        srcIndex = dstIndex = 0;
                    101:        argc = *argcPtr;
                    102:     } else {
                    103:        srcIndex = dstIndex = 1;
                    104:        argc = *argcPtr-1;
                    105:     }
                    106: 
                    107:     while (argc > 0) {
                    108:        curArg = argv[srcIndex];
                    109:        srcIndex++;
                    110:        argc--;
                    111:        c = curArg[1];
                    112:        length = strlen(curArg);
                    113: 
                    114:        /*
                    115:         * Loop throught the argument descriptors searching for one with
                    116:         * the matching key string.  If found, leave a pointer to it in
                    117:         * matchPtr.
                    118:         */
                    119: 
                    120:        matchPtr = NULL;
                    121:        for (i = 0; i < 2; i++) {
                    122:            if (i == 0) {
                    123:                infoPtr = argTable;
                    124:            } else {
                    125:                infoPtr = defaultTable;
                    126:            }
                    127:            for (; infoPtr->type != TK_ARGV_END; infoPtr++) {
                    128:                 if (infoPtr->key == NULL) {
                    129:                     continue;
                    130:                 }
                    131:                 if ((infoPtr->key[1] != c)
                    132:                         || (strncmp(infoPtr->key, curArg, length) != 0)) {
                    133:                     continue;
                    134:                 }
                    135:                 if ((tkwin == NULL)
                    136:                         && ((infoPtr->type == TK_ARGV_CONST_OPTION)
                    137:                         || (infoPtr->type == TK_ARGV_OPTION_VALUE)
                    138:                         || (infoPtr->type == TK_ARGV_OPTION_NAME_VALUE))) {
                    139:                     continue;
                    140:                 }
                    141:                 if (infoPtr->key[length] == 0) {
                    142:                     matchPtr = infoPtr;
                    143:                     goto gotMatch;
                    144:                 }
                    145:                 if (flags & TK_ARGV_NO_ABBREV) {
                    146:                     continue;
                    147:                 }
                    148:                 if (matchPtr != NULL) {
                    149:                     Tcl_AppendResult(interp, "ambiguous option \"", curArg,
                    150:                             "\"", (char *) NULL);
                    151:                     return TCL_ERROR;
                    152:                 }
                    153:                 matchPtr = infoPtr;
                    154:            }
                    155:        }
                    156:        if (matchPtr == NULL) {
                    157: 
                    158:            /*
                    159:             * Unrecognized argument.  Just copy it down, unless the caller
                    160:             * prefers an error to be registered.
                    161:             */
                    162: 
                    163:            if (flags & TK_ARGV_NO_LEFTOVERS) {
                    164:                Tcl_AppendResult(interp, "unrecognized argument \"",
                    165:                        curArg, "\"", (char *) NULL);
                    166:                return TCL_ERROR;
                    167:            }
                    168:            argv[dstIndex] = curArg;
                    169:            dstIndex++;
                    170:            continue;
                    171:        }
                    172: 
                    173:        /*
                    174:         * Take the appropriate action based on the option type
                    175:         */
                    176: 
                    177:        gotMatch:
                    178:        infoPtr = matchPtr;
                    179:        switch (infoPtr->type) {
                    180:            case TK_ARGV_CONSTANT:
                    181:                *((int *) infoPtr->dst) = (int) infoPtr->src;
                    182:                break;
                    183:            case TK_ARGV_INT:
                    184:                if (argc == 0) {
                    185:                    goto missingArg;
                    186:                } else {
                    187:                    char *endPtr;
                    188: 
                    189:                    *((int *) infoPtr->dst) =
                    190:                            strtol(argv[srcIndex], &endPtr, 0);
                    191:                    if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
                    192:                        Tcl_AppendResult(interp, "expected integer argument ",
                    193:                                "for \"", infoPtr->key, "\" but got \"",
                    194:                                argv[srcIndex], "\"", (char *) NULL);
                    195:                        return TCL_ERROR;
                    196:                    }
                    197:                    srcIndex++;
                    198:                    argc--;
                    199:                }
                    200:                break;
                    201:            case TK_ARGV_STRING:
                    202:                if (argc == 0) {
                    203:                    goto missingArg;
                    204:                } else {
                    205:                    *((char **)infoPtr->dst) = argv[srcIndex];
                    206:                    srcIndex++;
                    207:                    argc--;
                    208:                }
                    209:                break;
                    210:            case TK_ARGV_UID:
                    211:                if (argc == 0) {
                    212:                    goto missingArg;
                    213:                } else {
                    214:                    *((Tk_Uid *)infoPtr->dst) = Tk_GetUid(argv[srcIndex]);
                    215:                    srcIndex++;
                    216:                    argc--;
                    217:                }
                    218:                break;
                    219:            case TK_ARGV_REST:
                    220:                *((int *) infoPtr->dst) = dstIndex;
                    221:                goto argsDone;
                    222:            case TK_ARGV_FLOAT:
                    223:                if (argc == 0) {
                    224:                    goto missingArg;
                    225:                } else {
                    226:                    char *endPtr;
                    227: 
                    228:                    *((double *) infoPtr->dst) =
                    229:                            strtod(argv[srcIndex], &endPtr);
                    230:                    if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
                    231:                        Tcl_AppendResult(interp, "expected floating-point ",
                    232:                                "argument for \"", infoPtr->key,
                    233:                                "\" but got \"", argv[srcIndex], "\"",
                    234:                                (char *) NULL);
                    235:                        return TCL_ERROR;
                    236:                    }
                    237:                    srcIndex++;
                    238:                    argc--;
                    239:                }
                    240:                break;
                    241:            case TK_ARGV_FUNC: {
                    242:                int (*handlerProc)();
                    243: 
                    244:                handlerProc = (int (*)())infoPtr->src;
                    245:                
                    246:                if ((*handlerProc)(infoPtr->dst, infoPtr->key,
                    247:                        argv[srcIndex])) {
                    248:                    srcIndex += 1;
                    249:                    argc -= 1;
                    250:                }
                    251:                break;
                    252:            }
                    253:            case TK_ARGV_GENFUNC: {
                    254:                int         (*handlerProc)();
                    255: 
                    256:                handlerProc = (int (*)())infoPtr->src;
                    257: 
                    258:                argc = (*handlerProc)(infoPtr->dst, interp, infoPtr->key,
                    259:                        argc, argv+srcIndex);
                    260:                if (argc < 0) {
                    261:                    return TCL_ERROR;
                    262:                }
                    263:                break;
                    264:            }
                    265:            case TK_ARGV_HELP:
                    266:                PrintUsage (interp, argTable, flags);
                    267:                return TCL_ERROR;
                    268:            case TK_ARGV_CONST_OPTION:
                    269:                Tk_AddOption(tkwin, infoPtr->dst, infoPtr->src,
                    270:                        TK_INTERACTIVE_PRIO);
                    271:                break;
                    272:            case TK_ARGV_OPTION_VALUE:
                    273:                if (argc < 1) {
                    274:                    goto missingArg;
                    275:                }
                    276:                Tk_AddOption(tkwin, infoPtr->dst, argv[srcIndex],
                    277:                        TK_INTERACTIVE_PRIO);
                    278:                srcIndex++;
                    279:                argc--;
                    280:                break;
                    281:            case TK_ARGV_OPTION_NAME_VALUE:
                    282:                if (argc < 2) {
                    283:                    Tcl_AppendResult(interp, "\"", curArg,
                    284:                            "\" option requires two following arguments",
                    285:                            (char *) NULL);
                    286:                    return TCL_ERROR;
                    287:                }
                    288:                Tk_AddOption(tkwin, argv[srcIndex], argv[srcIndex+1],
                    289:                        TK_INTERACTIVE_PRIO);
                    290:                srcIndex += 2;
                    291:                argc -= 2;
                    292:                break;
                    293:            default:
                    294:                sprintf(interp->result, "bad argument type %d in Tk_ArgvInfo",
                    295:                        infoPtr->type);
                    296:                return TCL_ERROR;
                    297:        }
                    298:     }
                    299: 
                    300:     /*
                    301:      * If we broke out of the loop because of an OPT_REST argument,
                    302:      * copy the remaining arguments down.
                    303:      */
                    304: 
                    305:     argsDone:
                    306:     while (argc) {
                    307:        argv[dstIndex] = argv[srcIndex];
                    308:        srcIndex++;
                    309:        dstIndex++;
                    310:        argc--;
                    311:     }
                    312:     argv[dstIndex] = (char *) NULL;
                    313:     *argcPtr = dstIndex;
                    314:     return TCL_OK;
                    315: 
                    316:     missingArg:
                    317:     Tcl_AppendResult(interp, "\"", curArg,
                    318:            "\" option requires an additional argument", (char *) NULL);
                    319:     return TCL_ERROR;
                    320: }
                    321: 
                    322: /*
                    323:  *----------------------------------------------------------------------
                    324:  *
                    325:  * PrintUsage --
                    326:  *
                    327:  *     Generate a help string describing command-line options.
                    328:  *
                    329:  * Results:
                    330:  *     Interp->result will be modified to hold a help string
                    331:  *     describing all the options in argTable, plus all those
                    332:  *     in the default table unless TK_ARGV_NO_DEFAULTS is
                    333:  *     specified in flags.
                    334:  *
                    335:  * Side effects:
                    336:  *     None.
                    337:  *
                    338:  *----------------------------------------------------------------------
                    339:  */
                    340: 
                    341: static void
                    342: PrintUsage(interp, argTable, flags)
                    343:     Tcl_Interp *interp;                /* Place information in this interp's
                    344:                                 * result area. */
                    345:     Tk_ArgvInfo *argTable;     /* Array of command-specific argument
                    346:                                 * descriptions. */
                    347:     int flags;                 /* If the TK_ARGV_NO_DEFAULTS bit is set
                    348:                                 * in this word, then don't generate
                    349:                                 * information for default options. */
                    350: {
                    351:     register Tk_ArgvInfo *infoPtr;
                    352:     int width, i, numSpaces;
                    353: #define NUM_SPACES 20
                    354:     static char spaces[] = "                    ";
                    355:     char tmp[30];
                    356: 
                    357:     /*
                    358:      * First, compute the width of the widest option key, so that we
                    359:      * can make everything line up.
                    360:      */
                    361: 
                    362:     width = 4;
                    363:     for (i = 0; i < 2; i++) {
                    364:        for (infoPtr = i ? defaultTable : argTable;
                    365:                infoPtr->type != TK_ARGV_END; infoPtr++) {
                    366:            int length;
                    367:            if (infoPtr->key == NULL) {
                    368:                continue;
                    369:            }
                    370:            length = strlen(infoPtr->key);
                    371:            if (length > width) {
                    372:                width = length;
                    373:            }
                    374:        }
                    375:     }
                    376: 
                    377:     Tcl_AppendResult(interp, "Command-specific options:", (char *) NULL);
                    378:     for (i = 0; ; i++) {
                    379:        for (infoPtr = i ? defaultTable : argTable;
                    380:                infoPtr->type != TK_ARGV_END; infoPtr++) {
                    381:            if ((infoPtr->type == TK_ARGV_HELP) && (infoPtr->key == NULL)) {
                    382:                Tcl_AppendResult(interp, "\n", infoPtr->help, (char *) NULL);
                    383:                continue;
                    384:            }
                    385:            Tcl_AppendResult(interp, "\n ", infoPtr->key, ":", (char *) NULL);
                    386:            numSpaces = width + 1 - strlen(infoPtr->key);
                    387:            while (numSpaces > 0) {
                    388:                if (numSpaces >= NUM_SPACES) {
                    389:                    Tcl_AppendResult(interp, spaces, (char *) NULL);
                    390:                } else {
                    391:                    Tcl_AppendResult(interp, spaces+NUM_SPACES-numSpaces,
                    392:                            (char *) NULL);
                    393:                }
                    394:                numSpaces -= NUM_SPACES;
                    395:            }
                    396:            Tcl_AppendResult(interp, infoPtr->help, (char *) NULL);
                    397:            switch (infoPtr->type) {
                    398:                case TK_ARGV_INT: {
                    399:                    sprintf(tmp, "%d", *((int *) infoPtr->dst));
                    400:                    Tcl_AppendResult(interp, "\n\t\tDefault value: ",
                    401:                            tmp, (char *) NULL);
                    402:                    break;
                    403:                }
                    404:                case TK_ARGV_FLOAT: {
                    405:                    sprintf(tmp, "%lg", *((double *) infoPtr->dst));
                    406:                    Tcl_AppendResult(interp, "\n\t\tDefault value: ",
                    407:                            tmp, (char *) NULL);
                    408:                    break;
                    409:                }
                    410:                case TK_ARGV_STRING: {
                    411:                    char *string;
                    412: 
                    413:                    string = *((char **) infoPtr->dst);
                    414:                    if (string != NULL) {
                    415:                        Tcl_AppendResult(interp, "\n\t\tDefault value: \"",
                    416:                                string, "\"", (char *) NULL);
                    417:                    }
                    418:                    break;
                    419:                }
                    420:                default: {
                    421:                    break;
                    422:                }
                    423:            }
                    424:        }
                    425: 
                    426:        if ((flags & TK_ARGV_NO_DEFAULTS) || (i > 0)) {
                    427:            break;
                    428:        }
                    429:        Tcl_AppendResult(interp, "\nGeneric options for all commands:",
                    430:                (char *) NULL);
                    431:     }
                    432: }

unix.superglobalmegacorp.com

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