Annotation of 3BSD/cmd/ucbmail/lex.c, revision 1.1.1.1

1.1       root        1: #
                      2: 
                      3: #include "rcv.h"
                      4: 
                      5: /*
                      6:  * Mail -- a mail program
                      7:  *
                      8:  * Lexical processing of commands.
                      9:  */
                     10: 
                     11: /*
                     12:  * Interpret user commands one by one.  If standard input is not a tty,
                     13:  * print no prompt.
                     14:  */
                     15: 
                     16: int    *msgvec;
                     17: 
                     18: commands()
                     19: {
                     20:        int prompt, firstsw, stop();
                     21:        char linebuf[LINESIZE];
                     22: 
                     23:        msgvec = (int *) calloc((unsigned) (msgCount + 1), sizeof *msgvec);
                     24:        if (rcvmode)
                     25:                if (signal(SIGINT, SIG_IGN) == SIG_DFL)
                     26:                        signal(SIGINT, stop);
                     27:        input = stdin;
                     28:        prompt = 1;
                     29:        if (!intty)
                     30:                prompt = 0;
                     31:        firstsw = 1;
                     32:        for (;;) {
                     33:                setexit();
                     34:                if (firstsw > 0) {
                     35:                        firstsw = 0;
                     36:                        source1(mailrc);
                     37:                        source1(MASTER);
                     38:                        source1(AUX);
                     39:                }
                     40: 
                     41:                /*
                     42:                 * How's this for obscure:  after we
                     43:                 * finish sourcing for the first time,
                     44:                 * go off and print the headers!
                     45:                 */
                     46: 
                     47:                if (firstsw == 0 && !sourcing) {
                     48:                        firstsw = -1;
                     49:                        if (rcvmode)
                     50:                                announce();
                     51:                }
                     52: 
                     53:                /*
                     54:                 * Print the prompt, if needed.  Clear out
                     55:                 * string space, and flush the output.
                     56:                 */
                     57: 
                     58:                if (!rcvmode && !sourcing)
                     59:                        return;
                     60:                if (prompt && !sourcing)
                     61:                        printf("_\r");
                     62:                flush();
                     63:                sreset();
                     64: 
                     65:                /*
                     66:                 * Read a line of commands from the current input
                     67:                 * and handle end of file specially.
                     68:                 */
                     69: 
                     70:                if (readline(input, linebuf) <= 0) {
                     71:                        if (sourcing) {
                     72:                                unstack();
                     73:                                continue;
                     74:                        }
                     75:                        if (!edit) {
                     76:                                signal(SIGINT, SIG_IGN);
                     77:                                return;
                     78:                        }
                     79:                        edstop();
                     80:                        return;
                     81:                }
                     82:                if (execute(linebuf))
                     83:                        return;
                     84:        }
                     85: }
                     86: 
                     87: /*
                     88:  * Execute a single command.  If the command executed
                     89:  * is "quit," then return non-zero so that the caller
                     90:  * will know to return back to main, if he cares.
                     91:  */
                     92: 
                     93: execute(linebuf)
                     94:        char linebuf[];
                     95: {
                     96:        char word[LINESIZE];
                     97:        char *arglist[MAXARGC];
                     98:        struct cmd *com;
                     99:        register char *cp, *cp2;
                    100:        register int c;
                    101:        int edstop(), e;
                    102: 
                    103:        /*
                    104:         * Strip the white space away from the beginning
                    105:         * of the command, then scan out a word, which
                    106:         * consists of anything except digits and white space.
                    107:         *
                    108:         * Handle ! escapes differently to get the correct
                    109:         * lexical conventions.
                    110:         */
                    111: 
                    112:        cp = linebuf;
                    113:        while (any(*cp, " \t"))
                    114:                cp++;
                    115:        if (*cp == '!') {
                    116:                if (sourcing) {
                    117:                        printf("Can't \"!\" while sourcing\n");
                    118:                        unstack();
                    119:                        return(0);
                    120:                }
                    121:                shell(cp+1);
                    122:                return(0);
                    123:        }
                    124:        cp2 = word;
                    125:        while (*cp && !any(*cp, " \t0123456789$^.+*'\""))
                    126:                *cp2++ = *cp++;
                    127:        *cp2 = '\0';
                    128: 
                    129:        /*
                    130:         * Look up the command; if not found, bitch.
                    131:         * Normally, a blank command would map to the
                    132:         * first command in the table; while sourcing,
                    133:         * however, we ignore blank lines to eliminate
                    134:         * confusion.
                    135:         */
                    136: 
                    137:        if (sourcing && equal(word, ""))
                    138:                return(0);
                    139:        com = lex(word);
                    140:        if (com == NONE) {
                    141:                printf("What?\n");
                    142:                if (sourcing)
                    143:                        unstack();
                    144:                return(0);
                    145:        }
                    146: 
                    147:        /*
                    148:         * Special case so that quit causes a return to
                    149:         * main, who will call the quit code directly.
                    150:         * If we are in a source file, just unstack.
                    151:         */
                    152: 
                    153:        if (com->c_func == edstop && sourcing) {
                    154:                unstack();
                    155:                return(0);
                    156:        }
                    157:        if (!edit && com->c_func == edstop) {
                    158:                signal(SIGINT, SIG_IGN);
                    159:                return(1);
                    160:        }
                    161: 
                    162:        /*
                    163:         * Process the arguments to the command, depending
                    164:         * on the type he expects.  Default to an error.
                    165:         * If we are sourcing an interactive command, it's
                    166:         * an error.
                    167:         */
                    168: 
                    169:        if (!rcvmode && (com->c_argtype & M) == 0) {
                    170:                printf("May not execute \"%s\" while sending\n",
                    171:                    com->c_name);
                    172:                unstack();
                    173:                return(0);
                    174:        }
                    175:        if (sourcing && com->c_argtype & I) {
                    176:                printf("May not execute \"%s\" while sourcing\n",
                    177:                    com->c_name);
                    178:                unstack();
                    179:                return(0);
                    180:        }
                    181:        e = 1;
                    182:        switch (com->c_argtype & ~(P|I|M)) {
                    183:        case MSGLIST:
                    184:                /*
                    185:                 * A message list defaulting to nearest forward
                    186:                 * legal message.
                    187:                 */
                    188:                if ((c = getmsglist(cp, msgvec, com->c_msgflags)) < 0)
                    189:                        break;
                    190:                if (c  == 0) {
                    191:                        *msgvec = first(com->c_msgflags,
                    192:                                com->c_msgmask);
                    193:                        msgvec[1] = NULL;
                    194:                }
                    195:                if (*msgvec == NULL) {
                    196:                        printf("No applicable messages\n");
                    197:                        break;
                    198:                }
                    199:                e = (*com->c_func)(msgvec);
                    200:                break;
                    201: 
                    202:        case NDMLIST:
                    203:                /*
                    204:                 * A message list with no defaults, but no error
                    205:                 * if none exist.
                    206:                 */
                    207:                if (getmsglist(cp, msgvec, com->c_msgflags) < 0)
                    208:                        break;
                    209:                e = (*com->c_func)(msgvec);
                    210:                break;
                    211: 
                    212:        case STRLIST:
                    213:                /*
                    214:                 * Just the straight string, with
                    215:                 * leading blanks removed.
                    216:                 */
                    217:                while (any(*cp, " \t"))
                    218:                        cp++;
                    219:                e = (*com->c_func)(cp);
                    220:                break;
                    221: 
                    222:        case RAWLIST:
                    223:                /*
                    224:                 * A vector of strings, in shell style.
                    225:                 */
                    226:                if ((c = getrawlist(cp, arglist)) < 0)
                    227:                        break;
                    228:                if (c < com->c_minargs) {
                    229:                        printf("%s requires at least %d arg(s)\n",
                    230:                                com->c_name, com->c_minargs);
                    231:                        break;
                    232:                }
                    233:                if (c > com->c_maxargs) {
                    234:                        printf("%s takes no more than %d arg(s)\n",
                    235:                                com->c_name, com->c_maxargs);
                    236:                        break;
                    237:                }
                    238:                e = (*com->c_func)(arglist);
                    239:                break;
                    240: 
                    241:        case NOLIST:
                    242:                /*
                    243:                 * Just the constant zero, for exiting,
                    244:                 * eg.
                    245:                 */
                    246:                e = (*com->c_func)(0);
                    247:                break;
                    248: 
                    249:        default:
                    250:                panic("Unknown argtype");
                    251:        }
                    252: 
                    253:        /*
                    254:         * Exit the current source file on
                    255:         * error.
                    256:         */
                    257: 
                    258:        if (e && sourcing)
                    259:                unstack();
                    260:        if (com->c_func == edstop)
                    261:                return(1);
                    262:        if (value("autoprint") != NOSTR && com->c_argtype & P)
                    263:                if ((dot->m_flag & MDELETED) == 0)
                    264:                        print(dot);
                    265:        if (!sourcing)
                    266:                sawcom = 1;
                    267:        return(0);
                    268: }
                    269: 
                    270: /*
                    271:  * Find the correct command in the command table corresponding
                    272:  * to the passed command "word"
                    273:  */
                    274: 
                    275: struct cmd *
                    276: lex(word)
                    277:        char word[];
                    278: {
                    279:        register struct cmd *cp;
                    280:        extern struct cmd cmdtab[];
                    281: 
                    282:        for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++)
                    283:                if (isprefix(word, cp->c_name))
                    284:                        return(cp);
                    285:        return(NONE);
                    286: }
                    287: 
                    288: /*
                    289:  * Determine if as1 is a valid prefix of as2.
                    290:  * Return true if yep.
                    291:  */
                    292: 
                    293: isprefix(as1, as2)
                    294:        char *as1, *as2;
                    295: {
                    296:        register char *s1, *s2;
                    297: 
                    298:        s1 = as1;
                    299:        s2 = as2;
                    300:        while (*s1++ == *s2)
                    301:                if (*s2++ == '\0')
                    302:                        return(1);
                    303:        return(*--s1 == '\0');
                    304: }
                    305: 
                    306: /*
                    307:  * The following gets called on receipt of a rubout.  This is
                    308:  * to abort printout of a command, mainly.
                    309:  * Dispatching here when command() is inactive crashes rcv.
                    310:  * Close all open files except 0, 1, 2, and the temporary.
                    311:  * The special call to getuserid() is needed so it won't get
                    312:  * annoyed about losing its open file.
                    313:  * Also, unstack all source files.
                    314:  */
                    315: 
                    316: stop()
                    317: {
                    318:        register FILE *fp;
                    319: 
                    320:        signal(SIGINT, SIG_IGN);
                    321:        sawcom++;
                    322:        while (sourcing)
                    323:                unstack();
                    324:        getuserid((char *) -1);
                    325:        for (fp = &_iob[0]; fp < &_iob[_NFILE]; fp++) {
                    326:                if (fp == stdin || fp == stdout)
                    327:                        continue;
                    328:                if (fp == itf || fp == otf)
                    329:                        continue;
                    330:                if (fp == stderr)
                    331:                        continue;
                    332:                fclose(fp);
                    333:        }
                    334:        if (image >= 0) {
                    335:                close(image);
                    336:                image = -1;
                    337:        }
                    338:        clrbuf(stdout);
                    339:        printf("Interrupt\n");
                    340:        signal(SIGINT, stop);
                    341:        reset(0);
                    342: }
                    343: 
                    344: /*
                    345:  * Announce the presence of the current Mail version,
                    346:  * give the message count, and print a header listing.
                    347:  */
                    348: 
                    349: char   *greeting       = "Mail version 1.3 %s.  Type ? for help.\n";
                    350: 
                    351: announce()
                    352: {
                    353:        char *vec[2];
                    354:        extern char *version;
                    355: 
                    356:        vec[0] = "0";
                    357:        vec[1] = NULL;
                    358:        if (value("quiet") == NOSTR)
                    359:                printf(greeting, version);
                    360:        if (msgCount == 1)
                    361:                printf("1 message:\n");
                    362:        else
                    363:                printf("%d messages:\n", msgCount);
                    364:        headers(vec);
                    365: }
                    366: 
                    367: strace() {}
                    368: 
                    369: /*
                    370:  * Print the current version number.
                    371:  */
                    372: 
                    373: pversion(e)
                    374: {
                    375:        printf(greeting, version);
                    376:        return(0);
                    377: }

unix.superglobalmegacorp.com

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