# 2.11BSD#431 - /usr/src/ucb/Mail/lex.c

##### Functions

    announce          X
    commands          X
    execute           X
    hangup            X
    intr              X
    isprefix          X
    lex               X
    load              X
    newfileinfo       X
    pversion          X
    setfile           X
    setmsize          X
    stop              X

##### Variables

    inithdr           X
    msgvec            X
    prompt            X
    reset_on_stop     X

       1: /*
       2:  * Copyright (c) 1980 Regents of the University of California.
       3:  * All rights reserved.
       4:  *
       5:  * Redistribution and use in source and binary forms, with or without
       6:  * modification, are permitted provided that the following conditions
       7:  * are met:
       8:  * 1. Redistributions of source code must retain the above copyright
       9:  *    notice, this list of conditions and the following disclaimer.
      10:  * 2. Redistributions in binary form must reproduce the above copyright
      11:  *    notice, this list of conditions and the following disclaimer in the
      12:  *    documentation and/or other materials provided with the distribution.
      13:  * 3. All advertising materials mentioning features or use of this software
      14:  *    must display the following acknowledgement:
      15:  *	This product includes software developed by the University of
      16:  *	California, Berkeley and its contributors.
      17:  * 4. Neither the name of the University nor the names of its contributors
      18:  *    may be used to endorse or promote products derived from this software
      19:  *    without specific prior written permission.
      20:  *
      21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31:  * SUCH DAMAGE.
      32:  */
      33:
      34: #if !defined(lint) && defined(DOSCCS)
      35: static char sccsid[] = "@(#)lex.c	5.23 (Berkeley) 4/1/91";
      36: #endif
      37:
      38: #include "rcv.h"
      39: #include <sys/stat.h>
      40: #include <errno.h>
      41:
      42: /*
      43:  * Mail -- a mail program
      44:  *
      45:  * Lexical processing of commands.
      46:  */
      47:
      48: char    *prompt = "& ";
      49:
      50: /*
      51:  * Set up editing on the given file name.
      52:  * If the first character of name is %, we are considered to be
      53:  * editing the file, otherwise we are reading our mail which has
      54:  * signficance for mbox and so forth.
      55:  */
      56: setfile(name)
      57:     char *name;
      58: {
      59:     FILE *ibuf;
      60:     int i;
      61:     struct stat stb;
      62:     char isedit = *name != '%';
      63:     char *who = name[1] ? name + 1 : myname;
      64:     static int shudclob;
      65:     extern char tempMesg[];
      66:     extern int errno;
      67:
      68:     if ((name = expand(name)) == NOSTR)
      69:         return -1;
      70:
      71:     if ((ibuf = Fopen(name, "r")) == NULL) {
      72:         if (!isedit && errno == ENOENT)
      73:             goto nomail;
      74:         perror(name);
      75:         return(-1);
      76:     }
      77:
      78:     if (fstat(fileno(ibuf), &stb) < 0) {
      79:         perror("fstat");
      80:         Fclose(ibuf);
      81:         return (-1);
      82:     }
      83:
      84:     switch (stb.st_mode & S_IFMT) {
      85:     case S_IFDIR:
      86:         Fclose(ibuf);
      87:         errno = EISDIR;
      88:         perror(name);
      89:         return (-1);
      90:
      91:     case S_IFREG:
      92:         break;
      93:
      94:     default:
      95:         Fclose(ibuf);
      96:         errno = EINVAL;
      97:         perror(name);
      98:         return (-1);
      99:     }
     100:
     101:     /*
     102: 	 * Looks like all will be well.  We must now relinquish our
     103: 	 * hold on the current set of stuff.  Must hold signals
     104: 	 * while we are reading the new file, else we will ruin
     105: 	 * the message[] data structure.
     106: 	 */
     107:
     108:     holdsigs();
     109:     if (shudclob)
     110:         quit();
     111:
     112:     /*
     113: 	 * Copy the messages into /tmp
     114: 	 * and set pointers.
     115: 	 */
     116:
     117:     readonly = 0;
     118:     if ((i = open(name, 1)) < 0)
     119:         readonly++;
     120:     else
     121:         close(i);
     122:     if (shudclob) {
     123:         fclose(itf);
     124:         fclose(otf);
     125:     }
     126:     shudclob = 1;
     127:     edit = isedit;
     128:     strcpy(prevfile, mailname);
     129:     if (name != mailname)
     130:         strcpy(mailname, name);
     131:     mailsize = fsize(ibuf);
     132:     if ((otf = fopen(tempMesg, "w")) == NULL) {
     133:         perror(tempMesg);
     134:         exit(1);
     135:     }
     136:     if ((itf = fopen(tempMesg, "r")) == NULL) {
     137:         perror(tempMesg);
     138:         exit(1);
     139:     }
     140:     rm(tempMesg);
     141:     setptr(ibuf);
     142:     setmsize(msgCount);
     143:     Fclose(ibuf);
     144:     relsesigs();
     145:     sawcom = 0;
     146:     if (!edit && msgCount == 0) {
     147: nomail:
     148:         fprintf(stderr, "No mail for %s\n", who);
     149:         return -1;
     150:     }
     151:     return(0);
     152: }
     153:
     154: int *msgvec;
     155: int reset_on_stop;          /* do a reset() if stopped */
     156:
     157: /*
     158:  * Interpret user commands one by one.  If standard input is not a tty,
     159:  * print no prompt.
     160:  */
     161: commands()
     162: {
     163:     int eofloop = 0;
     164:     register int n;
     165:     char linebuf[LINESIZE];
     166:     void intr(), stop(), hangup();
     167:
     168:     if (!sourcing) {
     169:         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
     170:             signal(SIGINT, intr);
     171:         if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
     172:             signal(SIGHUP, hangup);
     173:         signal(SIGTSTP, stop);
     174:         signal(SIGTTOU, stop);
     175:         signal(SIGTTIN, stop);
     176:     }
     177:     setexit();
     178:     for (;;) {
     179:         /*
     180: 		 * Print the prompt, if needed.  Clear out
     181: 		 * string space, and flush the output.
     182: 		 */
     183:         if (!sourcing && value("interactive") != NOSTR) {
     184:             reset_on_stop = 1;
     185:             printf(prompt);
     186:         }
     187:         fflush(stdout);
     188:         sreset();
     189:         /*
     190: 		 * Read a line of commands from the current input
     191: 		 * and handle end of file specially.
     192: 		 */
     193:         n = 0;
     194:         for (;;) {
     195:             if (readline(input, &linebuf[n], LINESIZE - n) < 0) {
     196:                 if (n == 0)
     197:                     n = -1;
     198:                 break;
     199:             }
     200:             if ((n = strlen(linebuf)) == 0)
     201:                 break;
     202:             n--;
     203:             if (linebuf[n] != '\\')
     204:                 break;
     205:             linebuf[n++] = ' ';
     206:         }
     207:         reset_on_stop = 0;
     208:         if (n < 0) {
     209:                 /* eof */
     210:             if (loading)
     211:                 break;
     212:             if (sourcing) {
     213:                 unstack();
     214:                 continue;
     215:             }
     216:             if (value("interactive") != NOSTR &&
     217:                 value("ignoreeof") != NOSTR &&
     218:                 ++eofloop < 25) {
     219:                 printf("Use \"quit\" to quit.\n");
     220:                 continue;
     221:             }
     222:             break;
     223:         }
     224:         eofloop = 0;
     225:         if (execute(linebuf, 0))
     226:             break;
     227:     }
     228: }
     229:
     230: /*
     231:  * Execute a single command.
     232:  * Command functions return 0 for success, 1 for error, and -1
     233:  * for abort.  A 1 or -1 aborts a load or source.  A -1 aborts
     234:  * the interactive command loop.
     235:  * Contxt is non-zero if called while composing mail.
     236:  */
     237: execute(linebuf, contxt)
     238:     char linebuf[];
     239: {
     240:     char word[LINESIZE];
     241:     char *arglist[MAXARGC];
     242:     struct cmd *com;
     243:     register char *cp, *cp2;
     244:     register int c;
     245:     int muvec[2];
     246:     int e = 1;
     247:
     248:     /*
     249: 	 * Strip the white space away from the beginning
     250: 	 * of the command, then scan out a word, which
     251: 	 * consists of anything except digits and white space.
     252: 	 *
     253: 	 * Handle ! escapes differently to get the correct
     254: 	 * lexical conventions.
     255: 	 */
     256:
     257:     for (cp = linebuf; isspace(*cp); cp++)
     258:         ;
     259:     if (*cp == '!') {
     260:         if (sourcing) {
     261:             printf("Can't \"!\" while sourcing\n");
     262:             goto out;
     263:         }
     264:         shell(cp+1);
     265:         return(0);
     266:     }
     267:     cp2 = word;
     268:     while (*cp && index(" \t0123456789$^.:/-+*'\"", *cp) == NOSTR)
     269:         *cp2++ = *cp++;
     270:     *cp2 = '\0';
     271:
     272:     /*
     273: 	 * Look up the command; if not found, bitch.
     274: 	 * Normally, a blank command would map to the
     275: 	 * first command in the table; while sourcing,
     276: 	 * however, we ignore blank lines to eliminate
     277: 	 * confusion.
     278: 	 */
     279:
     280:     if (sourcing && *word == '\0')
     281:         return(0);
     282:     com = lex(word);
     283:     if (com == NONE) {
     284:         printf("Unknown command: \"%s\"\n", word);
     285:         goto out;
     286:     }
     287:
     288:     /*
     289: 	 * See if we should execute the command -- if a conditional
     290: 	 * we always execute it, otherwise, check the state of cond.
     291: 	 */
     292:
     293:     if ((com->c_argtype & F) == 0)
     294:         if (cond == CRCV && !rcvmode || cond == CSEND && rcvmode)
     295:             return(0);
     296:
     297:     /*
     298: 	 * Process the arguments to the command, depending
     299: 	 * on the type he expects.  Default to an error.
     300: 	 * If we are sourcing an interactive command, it's
     301: 	 * an error.
     302: 	 */
     303:
     304:     if (!rcvmode && (com->c_argtype & M) == 0) {
     305:         printf("May not execute \"%s\" while sending\n",
     306:             com->c_name);
     307:         goto out;
     308:     }
     309:     if (sourcing && com->c_argtype & I) {
     310:         printf("May not execute \"%s\" while sourcing\n",
     311:             com->c_name);
     312:         goto out;
     313:     }
     314:     if (readonly && com->c_argtype & W) {
     315:         printf("May not execute \"%s\" -- message file is read only\n",
     316:            com->c_name);
     317:         goto out;
     318:     }
     319:     if (contxt && com->c_argtype & R) {
     320:         printf("Cannot recursively invoke \"%s\"\n", com->c_name);
     321:         goto out;
     322:     }
     323:     switch (com->c_argtype & ~(F|P|I|M|T|W|R)) {
     324:     case MSGLIST:
     325:         /*
     326: 		 * A message list defaulting to nearest forward
     327: 		 * legal message.
     328: 		 */
     329:         if (msgvec == 0) {
     330:             printf("Illegal use of \"message list\"\n");
     331:             break;
     332:         }
     333:         if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0)
     334:             break;
     335:         if (c  == 0) {
     336:             *msgvec = first(com->c_msgflag,
     337:                 com->c_msgmask);
     338:             msgvec[1] = NULL;
     339:         }
     340:         if (*msgvec == NULL) {
     341:             printf("No applicable messages\n");
     342:             break;
     343:         }
     344:         e = (*com->c_func)(msgvec);
     345:         break;
     346:
     347:     case NDMLIST:
     348:         /*
     349: 		 * A message list with no defaults, but no error
     350: 		 * if none exist.
     351: 		 */
     352:         if (msgvec == 0) {
     353:             printf("Illegal use of \"message list\"\n");
     354:             break;
     355:         }
     356:         if (getmsglist(cp, msgvec, com->c_msgflag) < 0)
     357:             break;
     358:         e = (*com->c_func)(msgvec);
     359:         break;
     360:
     361:     case STRLIST:
     362:         /*
     363: 		 * Just the straight string, with
     364: 		 * leading blanks removed.
     365: 		 */
     366:         while (isspace(*cp))
     367:             cp++;
     368:         e = (*com->c_func)(cp);
     369:         break;
     370:
     371:     case RAWLIST:
     372:         /*
     373: 		 * A vector of strings, in shell style.
     374: 		 */
     375:         if ((c = getrawlist(cp, arglist,
     376:                 sizeof arglist / sizeof *arglist)) < 0)
     377:             break;
     378:         if (c < com->c_minargs) {
     379:             printf("%s requires at least %d arg(s)\n",
     380:                 com->c_name, com->c_minargs);
     381:             break;
     382:         }
     383:         if (c > com->c_maxargs) {
     384:             printf("%s takes no more than %d arg(s)\n",
     385:                 com->c_name, com->c_maxargs);
     386:             break;
     387:         }
     388:         e = (*com->c_func)(arglist);
     389:         break;
     390:
     391:     case NOLIST:
     392:         /*
     393: 		 * Just the constant zero, for exiting,
     394: 		 * eg.
     395: 		 */
     396:         e = (*com->c_func)(0);
     397:         break;
     398:
     399:     default:
     400:         panic("Unknown argtype");
     401:     }
     402:
     403: out:
     404:     /*
     405: 	 * Exit the current source file on
     406: 	 * error.
     407: 	 */
     408:     if (e) {
     409:         if (e < 0)
     410:             return 1;
     411:         if (loading)
     412:             return 1;
     413:         if (sourcing)
     414:             unstack();
     415:         return 0;
     416:     }
     417:     if (value("autoprint") != NOSTR && com->c_argtype & P)
     418:         if ((dot->m_flag & MDELETED) == 0) {
     419:             muvec[0] = dot - &message[0] + 1;
     420:             muvec[1] = 0;
     421:             type(muvec);
     422:         }
     423:     if (!sourcing && (com->c_argtype & T) == 0)
     424:         sawcom = 1;
     425:     return(0);
     426: }
     427:
     428: /*
     429:  * Set the size of the message vector used to construct argument
     430:  * lists to message list functions.
     431:  */
     432:
     433: setmsize(sz)
     434: {
     435:
     436:     if (msgvec != 0)
     437:         cfree((char *) msgvec);
     438:     msgvec = (int *) calloc((unsigned) (sz + 1), sizeof *msgvec);
     439: }
     440:
     441: /*
     442:  * Find the correct command in the command table corresponding
     443:  * to the passed command "word"
     444:  */
     445:
     446: struct cmd *
     447: lex(word)
     448:     char word[];
     449: {
     450:     register struct cmd *cp;
     451:     extern struct cmd cmdtab[];
     452:
     453:     for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++)
     454:         if (isprefix(word, cp->c_name))
     455:             return(cp);
     456:     return(NONE);
     457: }
     458:
     459: /*
     460:  * Determine if as1 is a valid prefix of as2.
     461:  * Return true if yep.
     462:  */
     463:
     464: isprefix(as1, as2)
     465:     char *as1, *as2;
     466: {
     467:     register char *s1, *s2;
     468:
     469:     s1 = as1;
     470:     s2 = as2;
     471:     while (*s1++ == *s2)
     472:         if (*s2++ == '\0')
     473:             return(1);
     474:     return(*--s1 == '\0');
     475: }
     476:
     477: /*
     478:  * The following gets called on receipt of an interrupt.  This is
     479:  * to abort printout of a command, mainly.
     480:  * Dispatching here when command() is inactive crashes rcv.
     481:  * Close all open files except 0, 1, 2, and the temporary.
     482:  * Also, unstack all source files.
     483:  */
     484:
     485: int inithdr;            /* am printing startup headers */
     486:
     487: /*ARGSUSED*/
     488: void
     489: intr(s)
     490: {
     491:
     492:     noreset = 0;
     493:     if (!inithdr)
     494:         sawcom++;
     495:     inithdr = 0;
     496:     while (sourcing)
     497:         unstack();
     498:
     499:     close_all_files();
     500:
     501:     if (image >= 0) {
     502:         close(image);
     503:         image = -1;
     504:     }
     505:     fprintf(stderr, "Interrupt\n");
     506:     reset(0);
     507: }
     508:
     509: /*
     510:  * When we wake up after ^Z, reprint the prompt.
     511:  */
     512: void
     513: stop(s)
     514: {
     515:     sig_t old_action = signal(s, SIG_DFL);
     516:
     517:     sigsetmask(sigblock(0L) & ~sigmask(s));
     518:     kill(0, s);
     519:     sigblock(sigmask(s));
     520:     signal(s, old_action);
     521:     if (reset_on_stop) {
     522:         reset_on_stop = 0;
     523:         reset(0);
     524:     }
     525: }
     526:
     527: /*
     528:  * Branch here on hangup signal and simulate "exit".
     529:  */
     530: /*ARGSUSED*/
     531: void
     532: hangup(s)
     533: {
     534:
     535:     /* nothing to do? */
     536:     exit(1);
     537: }
     538:
     539: /*
     540:  * Announce the presence of the current Mail version,
     541:  * give the message count, and print a header listing.
     542:  */
     543:
     544: announce()
     545: {
     546:     int vec[2], mdot;
     547:
     548:     mdot = newfileinfo();
     549:     vec[0] = mdot;
     550:     vec[1] = 0;
     551:     dot = &message[mdot - 1];
     552:     if (msgCount > 0 && value("noheader") == NOSTR) {
     553:         inithdr++;
     554:         headers(vec);
     555:         inithdr = 0;
     556:     }
     557: }
     558:
     559: /*
     560:  * Announce information about the file we are editing.
     561:  * Return a likely place to set dot.
     562:  */
     563: newfileinfo()
     564: {
     565:     register struct message *mp;
     566:     register int u, n, mdot, d, s;
     567:     char fname[BUFSIZ], zname[BUFSIZ], *ename;
     568:
     569:     for (mp = &message[0]; mp < &message[msgCount]; mp++)
     570:         if (mp->m_flag & MNEW)
     571:             break;
     572:     if (mp >= &message[msgCount])
     573:         for (mp = &message[0]; mp < &message[msgCount]; mp++)
     574:             if ((mp->m_flag & MREAD) == 0)
     575:                 break;
     576:     if (mp < &message[msgCount])
     577:         mdot = mp - &message[0] + 1;
     578:     else
     579:         mdot = 1;
     580:     s = d = 0;
     581:     for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) {
     582:         if (mp->m_flag & MNEW)
     583:             n++;
     584:         if ((mp->m_flag & MREAD) == 0)
     585:             u++;
     586:         if (mp->m_flag & MDELETED)
     587:             d++;
     588:         if (mp->m_flag & MSAVED)
     589:             s++;
     590:     }
     591:     ename = mailname;
     592:     if (getfold(fname) >= 0) {
     593:         strcat(fname, "/");
     594:         if (strncmp(fname, mailname, strlen(fname)) == 0) {
     595:             sprintf(zname, "+%s", mailname + strlen(fname));
     596:             ename = zname;
     597:         }
     598:     }
     599:     printf("\"%s\": ", ename);
     600:     if (msgCount == 1)
     601:         printf("1 message");
     602:     else
     603:         printf("%d messages", msgCount);
     604:     if (n > 0)
     605:         printf(" %d new", n);
     606:     if (u-n > 0)
     607:         printf(" %d unread", u);
     608:     if (d > 0)
     609:         printf(" %d deleted", d);
     610:     if (s > 0)
     611:         printf(" %d saved", s);
     612:     if (readonly)
     613:         printf(" [Read only]");
     614:     printf("\n");
     615:     return(mdot);
     616: }
     617:
     618: /*
     619:  * Print the current version number.
     620:  */
     621:
     622: /*ARGSUSED*/
     623: pversion(e)
     624: {
     625:     extern char *version;
     626:
     627:     printf("Version %s\n", version);
     628:     return(0);
     629: }
     630:
     631: /*
     632:  * Load a file of user definitions.
     633:  */
     634: load(name)
     635:     char *name;
     636: {
     637:     register FILE *in, *oldin;
     638:
     639:     if ((in = Fopen(name, "r")) == NULL)
     640:         return;
     641:     oldin = input;
     642:     input = in;
     643:     loading = 1;
     644:     sourcing = 1;
     645:     commands();
     646:     loading = 0;
     647:     sourcing = 0;
     648:     input = oldin;
     649:     Fclose(in);
     650: }

#### Defined functions

announce defined in line 544; used 2 times

- in /usr/src/ucb/Mail/cmd3.c line 540
- in /usr/src/ucb/Mail/main.c line 237

commands defined in line 161; used 2 times

- in line 645
- in /usr/src/ucb/Mail/main.c line 241

execute defined in line 237; used 2 times

- in line 225
- in /usr/src/ucb/Mail/collect.c line 206

hangup defined in line 531; used 2 times

- in line 166, 172

intr defined in line 488; used 2 times

- in line 166-170(2)

isprefix defined in line 464; used 1 times

- in line 454

lex defined in line 446; used 2 times

- in line 282
- in /usr/src/ucb/Mail/def.h line 311

load defined in line 634; used 2 times

- in /usr/src/ucb/Mail/main.c line 207-212(2)

newfileinfo defined in line 563; used 2 times

- in line 548
- in /usr/src/ucb/Mail/cmd3.c line 535

pversion defined in line 623; used 2 times

- in /usr/src/ucb/Mail/cmdtab.c line 50, 88

setfile defined in line 56; used 2 times

- in /usr/src/ucb/Mail/cmd3.c line 538
- in /usr/src/ucb/Mail/main.c line 227

setmsize defined in line 433; used 1 times

- in line 142

stop defined in line 512; used 4 times

- in line 166, 173-175(3)

#### Defined variables

inithdr defined in line 485; used 4 times

- in line 493-495(2), 553-555(2)

msgvec defined in line 154; used 13 times

- in line 329-344(6), 352-358(3), 436-438(4)

prompt defined in line 48; used 1 times

- in line 185

reset_on_stop defined in line 155; used 4 times

- in line 184, 207, 521-522(2)

sccsid defined in line 35; never used

Last modified: 1992-10-27 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1375 |