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

unix.superglobalmegacorp.com

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