home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / Mail / lex.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  7KB  |  358 lines

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