home *** CD-ROM | disk | FTP | other *** search
/ ftp.freefriends.org / ftp.freefriends.org.tar / ftp.freefriends.org / arnold / Source / mush.rstevens.tar.gz / mush.tar / expr.c < prev    next >
C/C++ Source or Header  |  1990-05-03  |  5KB  |  193 lines

  1. /* @(#)expr.c    2.3    (c) copyright 10/15/86 (Dan Heller) */
  2.  
  3. #include "mush.h"
  4.  
  5. char *eval_expr();
  6.  
  7. /* Parse a string (p) to interpret numbers and ranges of numbers (n-m)
  8.  * delimited by whitespace or comma's. Set msg_list bitfields using
  9.  * macros in mush.h.
  10.  * Return the address of the end of whatever we parsed (in case there's
  11.  * more that the calling routine cares to deal with).
  12.  * Finally, remember that user specifies one more than actual message number
  13.  */
  14. char *
  15. do_range(p, list1)
  16. register char *p, *list1;
  17. {
  18.     register int num1 = -1, num2 = -1, except = 0;
  19.     register char *p2;
  20.     char list2[MAXMSGS_BITS];
  21.  
  22.     if (!p)
  23.     return "";
  24.     while (*p) {
  25.     if (isdigit(*p) || *p == '$' || *p == '.' || *p == '^') {
  26.         if (isdigit(*p)) {
  27.         char c;
  28.         p2 = p;
  29.         skipdigits(0);  /* find the end of the digits */
  30.         c = *p, *p = 0; /* temporarily plug a null */
  31.         if (!(num2 = chk_msg(p2))) {
  32.             clear_msg_list(list1);
  33.             return NULL;
  34.         }
  35.         *p = c;
  36.         } else if (*p == '$')
  37.         p++, num2 = msg_cnt;
  38.         else if (*p == '.')
  39.         p++, num2 = current_msg+1;
  40.         else if (*p == '^')
  41.         p++, num2 = 1;
  42.         if (except)
  43.         unset_msg_bit(list1, num2-1);
  44.         else
  45.         set_msg_bit(list1, num2-1);
  46.         if (num1 >= 0) {
  47.         if (num1 > num2) {
  48.             print("syntax error: range sequence order reversed.\n");
  49.             clear_msg_list(list1);
  50.             return NULL;
  51.         }
  52.         while (++num1 < num2)
  53.             if (except)
  54.             unset_msg_bit(list1, num1-1);
  55.             else
  56.             set_msg_bit(list1, num1-1);
  57.         num1 = num2 = -1;
  58.         }
  59.     }
  60.     /* expressions to evaluate start with a `
  61.      * p2 points to first char passed the last char parsed.
  62.      */
  63.     if (*p == '`') {
  64.         clear_msg_list(list2);
  65.         if (!(p = eval_expr(p, list2))) {
  66.         clear_msg_list(list1);
  67.         return NULL;
  68.         } else {
  69.         if (except)
  70.             bitput(list2, list1, msg_cnt, &=~); /* MACRO */
  71.         else
  72.             bitput(list2, list1, msg_cnt, |=); /* MACRO */
  73.         }
  74.     }
  75.     /* NOT operator: `* {5}' (everything except for 5)
  76.      * `4-16 {8-10}'  (4 thru 16 except for 8,9,10)
  77.      */
  78.     if (*p == '{' || *p == '}') {
  79.         if (*p == '{' && (except || num1 >= 0))
  80.         break;
  81.         if (*p == '}' && !except) {
  82.         print("syntax error: missing {\n"); /* } */
  83.         break;
  84.         }
  85.         except = !except;
  86.     } else if (*p == '-')
  87.         if (num1 >= 0 || num2 < 0
  88.             || !index(" \t{},.*`$", *(p+1)) && !isdigit(*(p+1)))
  89.         break;
  90.         else
  91.         num1 = num2;
  92.     else if (*p == ',' || *p == '*') {
  93.         if (num1 >= 0)
  94.         break;
  95.         else if (*p == '*') {
  96.         if (except)
  97.             clear_msg_list(list1);
  98.         else
  99.             for (num1 = 0; num1 < msg_cnt; num1++)
  100.             set_msg_bit(list1, num1);
  101.         num1 = -1;
  102.         }
  103.     } else if (!index(" \t`", *p))
  104.         break;
  105.     if (*p)
  106.         skipspaces(1); /* don't make user type stuff squished together */
  107.     }
  108.     if (num1 >= 0 || except) {
  109.     if (except)
  110.         /* { */ print("syntax error: unmatched }\n");
  111.     else
  112.         print("syntax error: unfinished range\n");
  113.     clear_msg_list(list1);
  114.     return NULL;
  115.     }
  116.     return p;
  117. }
  118.  
  119. /*
  120.  * convert a message list to an ascii string.
  121.  */
  122. void
  123. list_to_str(list, str)
  124. char list[], *str;
  125. {
  126.     int n, m = -1;
  127.  
  128.     for (n = 0; n < msg_cnt; n++) {
  129.     if (msg_bit(list, n)) {
  130.         if (m == -1)
  131.         str += strlen(sprintf(str, "%d", (m = n) + 1 ));
  132.         continue;
  133.     }
  134.     if (m == -1)
  135.         continue;
  136.     if (n - m > 2)
  137.         str += strlen(sprintf(str, "-%d", n));
  138.     else if (n - m == 2)
  139.         str += strlen(sprintf(str, " %d", n));
  140.     *str++ = ' ';
  141.     m = -1;
  142.     }
  143.     if (m > -1 && m != n - 1) {
  144.     if (n - m > 2)
  145.         *str++ = '-';
  146.     else
  147.         *str++ = ' ';
  148.     str += Strcpy(str, itoa(msg_cnt));
  149.     }
  150.     *str = 0;
  151. }
  152.  
  153. /* evaluate expressions:
  154.  * mail> delete `pick -f root`     deletes all messages from root.
  155.  * mail> save * {`pick -s "Re:"`}  save all message that don't have "Re:"
  156.  *                   in the subject header.
  157.  * mail> save `pick -x -s "Re:"`   same
  158.  * args as follows:
  159.  *   p should point to the first ` -- check for it.
  160.  *   on tells whether to turn bits on or off if messages match.
  161.  */
  162. char *
  163. eval_expr(p, new_list)
  164. register char *p, new_list[];
  165. {
  166.     register char *p2, **argv;
  167.     int       argc;
  168.     u_long      save_flags = glob_flags;
  169.  
  170.     if (!(p2 = index(++p, '`'))) {
  171.     print("unmatched backquote (`)\n");
  172.     return NULL;
  173.     }
  174.     *p2 = 0;
  175.  
  176.     skipspaces(0);
  177.     if (!*p) {
  178.     print("Invalid null command\n");
  179.     return NULL;
  180.     }
  181.     turnon(glob_flags, DO_PIPE);
  182.     /* ignore sigs only because if user interrupts the do_command,
  183.      * the longjmp will corrupt the stack and the program is hosed.
  184.      * fix is to have layers of jmp_bufs to return to different levels.
  185.      */
  186.     turnon(glob_flags, IGN_SIGS);
  187.     if (*p && (argv = make_command(p, TRPL_NULL, &argc)))
  188.     (void) do_command(argc, argv, new_list);
  189.     glob_flags = save_flags;
  190.     *p2 = '`';
  191.     return p2+1;
  192. }
  193.