home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / remind-03.00.19.tgz / remind-03.00.19.tar / remind-03.00.19 / src / token.c < prev    next >
C/C++ Source or Header  |  1998-03-01  |  12KB  |  376 lines

  1. /***************************************************************/
  2. /*                                                             */
  3. /*  TOKEN.C                                                    */
  4. /*                                                             */
  5. /*  Contains routines for parsing the reminder file and        */
  6. /*  classifying the tokens parsed.                             */
  7. /*                                                             */
  8. /*  This file is part of REMIND.                               */
  9. /*  Copyright (C) 1992-1998 by David F. Skoll                  */
  10. /*                                                             */
  11. /***************************************************************/
  12.  
  13. #include "config.h"
  14. static char const RCSID[] = "$Id: token.c,v 1.7 1998/03/01 20:43:57 dfs Exp $";
  15.  
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19.  
  20. #ifdef HAVE_STDLIB_H
  21. #include <stdlib.h>
  22. #endif
  23.  
  24. #ifdef HAVE_MALLOC_H
  25. #include <malloc.h>
  26. #endif
  27.  
  28. #include "types.h"
  29. #include "globals.h"
  30. #include "protos.h"
  31. #include "err.h"
  32.  
  33. /* The macro PARSENUM parses a char pointer as an integer.  It simply
  34.    executes 'return' if an initial non-numeric char is found. */
  35. #define PARSENUM(var, string) \
  36. if (!isdigit(*(string))) return; \
  37. var = 0; \
  38. while (isdigit(*(string))) { \
  39.     var *= 10; \
  40.     var += *(string) - '0'; \
  41.     string++; \
  42. }
  43.  
  44. #define UPPER(c) (islower(c) ? toupper(c) : c)
  45.  
  46. /* The big array holding all recognized (literal) tokens in reminder file.
  47.    Keep this array sorted, or software will not work. */
  48. Token TokArray[] = {
  49.     /* NAME          MINLEN      TYPE           VALUE */
  50.  
  51.     { "after",         3,     T_Skip,     AFTER_SKIP },
  52.     { "april",        3,    T_Month,    3 },
  53.     { "at",        2,    T_At,        0 },
  54.     { "august",        3,    T_Month,    7 },
  55.     { "banner",        3,    T_Banner,    0 },
  56.     { "before",         3,     T_Skip,     BEFORE_SKIP },
  57.     { "cal",         3,     T_RemType,     CAL_TYPE },
  58.     { "clear-omit-context", 5,   T_Clr,         0 },
  59.     { "debug",          5,      T_Debug,       0 },
  60.     { "december",    3,    T_Month,       11 },
  61.     { "dumpvars",       4,      T_Dumpvars,    0 },
  62.     { "duration",       3,      T_Duration,     0 },
  63.     { "else",         4,     T_Else,     0 },
  64.     { "endif",         5,     T_EndIf,     0 },
  65.     { "errmsg",         6,      T_ErrMsg,      0 },
  66.     { "exit",        4,    T_Exit,        0 },
  67.     { "february",    3,     T_Month,    1 },
  68.     { "flush",        5,    T_Flush,    0 },
  69.     { "friday",        3,    T_WkDay,    4 },
  70.     { "fset",        4,    T_Fset,        0 },
  71.     { "if",        2,    T_If,        0 },
  72.     { "iftrig",        6,    T_IfTrig,    0 },
  73.     { "include",     3,     T_Include,     0 },
  74.     { "january",    3,     T_Month,    0 },
  75.     { "july",        3,    T_Month,    6 },
  76.     { "june",        3,    T_Month,    5 },
  77.     { "march",        3,    T_Month,    2 },
  78.     { "may",        3,     T_Month,     4 },
  79.     { "monday",        3,    T_WkDay,    0 },
  80.     { "msf",        3,    T_RemType,    MSF_TYPE },
  81.     { "msg",         3,     T_RemType,     MSG_TYPE },
  82.     { "november",    3,     T_Month,    10 },
  83.     { "october",    3,     T_Month,    9 },
  84.     { "omit",        3,    T_Omit,        0 },
  85.     { "once",         3,     T_Once,        0 },
  86.     { "pop-omit-context", 3,    T_Pop,        0 },
  87.     { "preserve",       8,      T_Preserve,     0 },
  88.     { "priority",    8,    T_Priority,    0 },
  89.     { "ps",         2,     T_RemType,     PS_TYPE },
  90.     { "psfile",     6,     T_RemType,     PSF_TYPE },
  91.     { "push-omit-context", 4,     T_Push,        0 },
  92.     { "rem",        3,    T_Rem,        0 },
  93.     { "run",         3,     T_RemType,     RUN_TYPE },
  94.     { "satisfy",    7,    T_RemType,      SAT_TYPE },
  95.     { "saturday",    3,    T_WkDay,    5 },
  96.     { "scanfrom",    4,    T_Scanfrom,    0 },
  97.     { "sched",        5,    T_Sched,    0 },
  98.     { "september",    3,     T_Month,     8 },
  99.     { "set",        3,    T_Set,        0 },
  100.     { "skip",         3,     T_Skip,     SKIP_SKIP },
  101.     { "special",        7,      T_RemType,      PASSTHRU_TYPE },
  102.     { "sunday",        3,    T_WkDay,    6 },
  103.     { "tag",            3,      T_Tag,          0 },
  104.     { "thursday",    3,    T_WkDay,    3 },
  105.     { "tuesday",    3,    T_WkDay,    1 },
  106.     { "unset",         5,     T_UnSet,     0 },
  107.     { "until",         3,     T_Until,    0 },
  108.     { "warn",           4,      T_Warn,         0 },
  109.     { "wednesday",    3,    T_WkDay,    2 }
  110. };
  111.  
  112. /* If language != English, we must also search the following... */
  113. #if LANG != ENGLISH
  114. Token NonEnglishToks[] = {
  115.     /* NAME          MINLEN      TYPE           VALUE */
  116.  
  117.     { L_MONDAY,           3,       T_WkDay,        0 },
  118.     { L_TUESDAY,       3,       T_WkDay,        1 },
  119.     { L_WEDNESDAY,     3,       T_WkDay,        2 },
  120.     { L_THURSDAY,      3,       T_WkDay,        3 },
  121.     { L_FRIDAY,           3,       T_WkDay,        4 },
  122.     { L_SATURDAY,      3,       T_WkDay,        5 },
  123.     { L_SUNDAY,           3,       T_WkDay,        6 },
  124.     { L_JAN,           3,       T_Month,        0 },
  125.     { L_FEB,           3,       T_Month,        1 },
  126.     { L_MAR,           3,       T_Month,        2 },
  127.     { L_APR,           3,       T_Month,        3 },
  128.     { L_MAY,           3,       T_Month,        4 },
  129.     { L_JUN,           3,       T_Month,        5 },
  130.     { L_JUL,           3,       T_Month,        6 },
  131.     { L_AUG,           3,       T_Month,        7 },
  132.     { L_SEP,           3,       T_Month,        8 },
  133.     { L_OCT,           3,       T_Month,        9 },
  134.     { L_NOV,           3,       T_Month,        10 },
  135.     { L_DEC,           3,       T_Month,        11 }
  136. };
  137. #endif
  138.  
  139. PRIVATE int TokStrCmp ARGS((const Token *t, const char *s));
  140.  
  141. /***************************************************************/
  142. /*                                                             */
  143. /*  FindInitialToken                                           */
  144. /*                                                             */
  145. /*  Find the initial token on the command line.  If it's a     */
  146. /*  left square bracket, return a T_Illegal type.              */
  147. /*                                                             */
  148. /***************************************************************/
  149. #ifdef HAVE_PROTOS
  150. PUBLIC char *FindInitialToken(Token *tok, char *s)
  151. #else
  152. char *FindInitialToken(tok, s)
  153. Token *tok;
  154. char *s;
  155. #endif
  156. {
  157.     DynamicBuffer buf;
  158.     DBufInit(&buf);
  159.  
  160.     tok->type = T_Illegal;
  161.  
  162.     while (isspace(*s)) s++;
  163.  
  164.     while (*s && !isspace(*s)) {
  165.     if (DBufPutc(&buf, *s++) != OK) return s;
  166.     }
  167.  
  168.     FindToken(DBufValue(&buf), tok);
  169.     DBufFree(&buf);
  170.  
  171.     return s;
  172. }
  173.      
  174.  
  175. /***************************************************************/
  176. /*                                                             */
  177. /*  FindToken                                                  */
  178. /*                                                             */
  179. /*  Given a string, which token is it?                         */
  180. /*                                                             */
  181. /***************************************************************/
  182. #ifdef HAVE_PROTOS
  183. PUBLIC void FindToken(const char *s, Token *tok)
  184. #else
  185. void FindToken(s, tok)
  186. char *s;
  187. Token *tok;
  188. #endif
  189. {
  190.     register int top, bot, mid, r;
  191.     int l;
  192.  
  193.     tok->type = T_Illegal;
  194.     if (! *s) {
  195.     tok->type = T_Empty;
  196.     return;
  197.     }
  198.        
  199.     if (*s == '#' || *s == ';') {
  200.     tok->type = T_Comment;
  201.     return;
  202.     }
  203.  
  204.     /* Quickly give up the search if first char not a letter */
  205.     if ( ! isalpha(*s)) {
  206.     FindNumericToken(s, tok);
  207.     return;
  208.     }
  209.  
  210.     l = strlen(s);
  211.  
  212.     /* Ignore trailing commas */
  213.     if (l > 0 && s[l-1] == ',') {
  214.     l--;
  215.     }
  216.     bot = 0;
  217.     top = sizeof(TokArray) / sizeof(TokArray[0]) - 1;
  218.  
  219.     while(top >= bot) {
  220.     mid = (top + bot) / 2;
  221.     r = TokStrCmp(&TokArray[mid], s);
  222.     if (!r) {
  223.         if (l >= TokArray[mid].MinLen) {
  224.         tok->type = TokArray[mid].type;
  225.         tok->val  = TokArray[mid].val;
  226.         return;
  227.         } else {
  228.         while (mid && !TokStrCmp(&TokArray[mid-1],s)) mid--;
  229.         while (!TokStrCmp(&TokArray[mid], s) && l < TokArray[mid].MinLen)
  230.             mid++;
  231.         if (!TokStrCmp(&TokArray[mid], s)) {
  232.             tok->type = TokArray[mid].type;
  233.             tok->val = TokArray[mid].val;
  234.             return;
  235.         }
  236.         }
  237.         break;
  238.     }
  239.     if (r > 0) top = mid-1; else bot=mid+1;
  240.     }
  241.  
  242. /* If language is other than English, search the DayNames[] and MonthNames[]
  243.    array. */
  244. #if LANG != ENGLISH
  245.     for (r=0; r<(sizeof(NonEnglishToks) / sizeof(Token)); r++) {
  246.     if (l >= NonEnglishToks[r].MinLen && 
  247.         !TokStrCmp(&NonEnglishToks[r], s)) {
  248.         tok->type = NonEnglishToks[r].type;
  249.         tok->val = NonEnglishToks[r].val;
  250.         return;
  251.     }
  252.     }
  253. #endif
  254.  
  255.     return;
  256. }
  257.  
  258. /***************************************************************/
  259. /*                                                             */
  260. /*  FindNumericToken                                           */
  261. /*                                                             */
  262. /*  Parse a numeric token:                                     */
  263. /*  Year - number between 1990 and 2085, or 90-99.             */
  264. /*  Day - number between 1 and 31                              */
  265. /*  Delta - +[+]n                                              */
  266. /*  Back - -[-]n                                               */
  267. /*  Rep - *n                                                   */
  268. /*                                                             */
  269. /***************************************************************/
  270. #ifdef HAVE_PROTOS
  271. PUBLIC void FindNumericToken(const char *s, Token *t)
  272. #else
  273. void FindNumericToken(s, t)
  274. char *s;
  275. Token *t;
  276. #endif
  277. {
  278.     int mult = 1, hour, min;
  279.  
  280.     t->type = T_Illegal;
  281.     t->val = 0;
  282.     if (isdigit(*s)) {
  283.     PARSENUM(t->val, s);
  284.  
  285.     /* If we hit a comma, swallow it.  This allows stuff
  286.        like Jan 6, 1998 */
  287.     if (*s == ',') {
  288.         s++;
  289.         /* Special hack - convert years between 90 and
  290.            99 to 1990 and 1999 */
  291.         if (t->val >= 90 && t->val <= 99) t->val += 1900;
  292.  
  293.         /* Classify the number we've got */
  294.         if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
  295.         else if (t->val >= 1 && t->val <= 31) t->type = T_Day;
  296.         else t->type = T_Number;
  297.         return;
  298.     }
  299.     /* If we hit a colon or a period, we've probably got a time hr:min */
  300.     if (*s == ':' || *s == '.' || *s == TIMESEP) {
  301.         s++;
  302.         hour = t->val;
  303.         PARSENUM(min, s);
  304.         if (*s || hour > 23 || min > 59) return;  /* Illegal time */
  305.         t->val = hour*60 + min;  /* Convert to minutes past midnight */
  306.         t->type = T_Time;
  307.         return;
  308.     }
  309.  
  310.     /* If we hit a non-digit, error! */
  311.     if (*s) return;
  312.  
  313.     /* Special hack - convert years between 90 and 99 to 1990 and 1999 */
  314.     if (t->val >= 90 && t->val <= 99) t->val += 1900;
  315.  
  316.     /* Classify the number we've got */
  317.     if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
  318.     else if (t->val >= 1 && t->val <= 31) t->type = T_Day;
  319.     else t->type = T_Number;
  320.     return;
  321.     } else if (*s == '*') {
  322.     s++;
  323.     PARSENUM(t->val, s);
  324.     if (*s) return;  /* Illegal token if followed by non-numeric char */
  325.     t->type = T_Rep;
  326.     return;
  327.     } else if (*s == '+') {
  328.     s++;
  329.     if (*s == '+') { mult = -1; s++; }
  330.     PARSENUM(t->val, s);
  331.     if (*s) return;  /* Illegal token if followed by non-numeric char */
  332.     t->type = T_Delta;
  333.     t->val *= mult;
  334.     return;
  335.     } else if (*s == '-') {
  336.     s++;
  337.     if (*s == '-') { mult = -1; s++; }
  338.     PARSENUM(t->val, s);
  339.     if (*s) return;  /* Illegal token if followed by non-numeric char */
  340.     t->type = T_Back;
  341.     t->val *= mult;
  342.     return;
  343.     }
  344.     return;  /* Unknown token type */
  345. }
  346.  
  347.  
  348. /***************************************************************/
  349. /*                                                             */
  350. /*  TokStrCmp                                                  */
  351. /*                                                             */
  352. /*  Compare a token to a string.                               */
  353. /*                                                             */
  354. /***************************************************************/
  355. #ifdef HAVE_PROTOS
  356. PRIVATE int TokStrCmp(const Token *t, const char *s)
  357. #else
  358. static int TokStrCmp(t, s)
  359. Token *t;
  360. char *s;
  361. #endif
  362. {
  363.     register int r;
  364.     char *tk = t->name;
  365.     while(*tk && *s && !(*s == ',' && *(s+1) == 0)) {
  366.     r = UPPER(*tk) - UPPER(*s);
  367.     tk++;
  368.     s++;
  369.     if (r) return r;
  370.     }
  371.     /* Ignore trailing commas on s */
  372.  
  373.     if (!*s || (*s == ',' && !*(s+1))) return 0;
  374.     return (*tk - *s);
  375. }
  376.