home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / TIMEXSRC.ZIP / BA_DB.C < prev    next >
C/C++ Source or Header  |  1990-03-29  |  25KB  |  868 lines

  1. /* ba_db.c -- Database management
  2.  
  3.     February 1990    Mark E. Mallett, Personal Workstation Magazine
  4.  
  5. This file contains code that keeps the event database.
  6.  
  7. Included are the following routines:
  8.  
  9.         db_read         Read the events database
  10.         db_write        Write the events database
  11.  
  12. Notes :
  13.  
  14. The events database is maintained as an ASCII file.  This is to make
  15. it maximally expandable and understandable by other programs or human
  16. beings.  The trade-off (vs a binary representation) is that it is also
  17. easier for one of those other entities to mess up the data.
  18.  
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <sys/types.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25. #include <os2.h>
  26.  
  27. #include "errhand.h"
  28. #include "timex.h"
  29. #include "ba_timex.h"
  30. #include "evpack.h"
  31.  
  32.  
  33. /* Local definitions */
  34.  
  35.  
  36. /* External data referenced */
  37.  
  38. extern  char    *Dbfname;               /* Name of the database file */
  39. extern  PEVENT  *PendingL;              /* List of pending events */
  40. extern  int     Priclass;               /* Priority class to run at */
  41. extern  int     Prival;                 /* Priority value to run at */
  42.  
  43. /* External routines used */
  44.  
  45. extern  int     atoi( char *strP );
  46. extern  int     gettkline( FILE *fP, char *bufP, int bufsize,
  47.                                 int *tokCP, char **tokV, int tokmax );
  48. extern  void    schedule( PEVENT *peventP );
  49.  
  50. /* Local data publicly available */
  51.  
  52.  
  53. /* Local routines and forward declarations */
  54.  
  55. static  int     atodayofwk( char *strP );
  56. static  int     atomonth( char *strP );
  57. static  void    getrange( char *strP, char *p1P, char *p2P );
  58. static  void    putqs( FILE *fP, char *strP );
  59. static  void    rdmkevent( void );
  60.  
  61.     /* db_read() component routines */
  62. static  void    rd_actarg( int lineN, char **tokV, int tokC );
  63. static  void    rd_acttype( int lineN, char **tokV, int tokC );
  64. static  void    rd_dayof( int lineN, char **tokV, int tokC );
  65. static  void    rd_event( int lineN, char **tokV, int tokC );
  66. static  void    rd_hour( int lineN, char **tokV, int tokC );
  67. static  void    rd_minute( int lineN, char **tokV, int tokC );
  68. static  void    rd_month( int lineN, char **tokV, int tokC );
  69. static  void    rd_prio( int lineN, char **tokV, int tokC );
  70. static  void    rd_year( int lineN, char **tokV, int tokC );
  71.  
  72. /* Private data */
  73.  
  74. static  BOOL    RdeventF;               /* If currently in an event */
  75.  
  76.     /* Dispatch table for db_read() event lines */
  77. static  struct {
  78.           char    *rd_keyP;             /* Ptr to keyword */
  79.           int     rd_argmin;            /* Minimum args required */
  80.           void    (*rd_rtc)( int lineN, char **tokV, int tokC );
  81.                                         /* Routine to call */
  82.         } Rddisp[] = {
  83.  
  84.     {   "Action-spec",  1,      rd_actarg       },
  85.     {   "Action-type",  1,      rd_acttype      },
  86.     {   "Day-of",       2,      rd_dayof        },
  87.     {   "Event",        1,      rd_event        },
  88.     {   "Hour",         1,      rd_hour         },
  89.     {   "Min",          1,      rd_minute       },
  90.     {   "Month",        1,      rd_month        },
  91.     {   "Priority",     2,      rd_prio         },
  92.     {   "Year",         1,      rd_year         },
  93.  
  94.     {   NULL,           0,      NULL }
  95.                      };
  96.  
  97.  
  98.  
  99.     /* Table of weekday name abbreviations in value order */
  100. static  char    *Dowtbl[] = {
  101.         "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
  102.                             };
  103.  
  104.     /* Table of month name abbreviations in value order */
  105. static  char    *Montbl[] = {
  106.         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  107.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  108.                             };
  109.  
  110. /*
  111.  
  112. *//* db_read()
  113.  
  114.         Read the event database
  115.  
  116. Accepts :
  117.  
  118. Returns :
  119.  
  120. Notes :
  121.  
  122.         This routine assumes that the caller has locked the event list;
  123.         i.e., that the current thread has complete access to the list.
  124.  
  125.         Any current event list will be deleted by this routine before
  126.         reading in the new one.
  127.  
  128. */
  129.  
  130. void
  131. db_read( void ) {
  132.  
  133.         BOOL            inheader;       /* If processing header */
  134.         BOOL            gotid;          /* If ID line seen */
  135.         int             lineN;          /* Line number */
  136.         int             rdX;            /* Dispatch table index */
  137.         int             cC;             /* Number of characters */
  138.         int             tokC;           /* Number of tokens */
  139.         FILE            *fP;            /* File ptr */
  140.         char            *tokV[50];      /* Token vector */
  141.         char            tokbuf[200];    /* Token buffer */
  142.  
  143.     /* Open the database file for reading */
  144.     if ( ( fP = fopen( Dbfname, "r" ) ) == NULL ) {
  145.         warning( EC_OK, "db_read() can't access database \"%s\"", Dbfname );
  146.         return;
  147.     }
  148.  
  149.     inheader = TRUE;                    /* Looking at header */
  150.     gotid = FALSE;                      /* Haven't seen file ID yet */
  151.     RdeventF = FALSE;                   /* Not in an event */
  152.  
  153.     /* Process the lines from the file */
  154.     for( lineN = 1; ; ++lineN ) {
  155.         cC = gettkline( fP, &tokbuf[0], 200, &tokC, &tokV[0], 50 );
  156.  
  157.         if ( cC < 0 )
  158.             break;                      /* End of file. */
  159.  
  160.         /* Check for blank or comment line */
  161.         if ( ( tokC == 0 ) ||
  162.              ( strcmp( tokV[0], "#" ) == 0 )
  163.            )
  164.             continue;
  165.  
  166.         /* Make sure the first line of the file is the ID line */
  167.         if ( !gotid ) {
  168.             if ( stricmp( tokV[0], "TIMEX-Database" ) != 0 ) {
  169.                 warning( EC_NOTOK, "\"%s\" is not a timex database.",
  170.                         Dbfname );
  171.                 break;
  172.             }
  173.             gotid = TRUE;
  174.             continue;
  175.         }
  176.  
  177.         /* Check for other header lines */
  178.         if ( inheader ) {
  179.             if ( stricmp( tokV[0], "Version" ) == 0 ) {
  180.                 continue;
  181.             }
  182.  
  183.             else if ( stricmp( tokV[0], "Priority" ) == 0 ) {
  184.                 continue;
  185.             }
  186.         }
  187.  
  188.         /* Check for non-header line */
  189.         for( rdX = 0; Rddisp[rdX].rd_keyP != NULL; ++rdX ) {
  190.             if ( stricmp( Rddisp[rdX].rd_keyP, tokV[0] ) == 0 )
  191.                 break;
  192.         }
  193.  
  194.         /* Process if we got a match */
  195.         if ( Rddisp[rdX].rd_keyP != NULL ) {
  196.             inheader = FALSE;
  197.  
  198.             /* Check for required # of tokens */
  199.             if ( tokC <= Rddisp[rdX].rd_argmin ) {
  200.                 warning( EC_OK,
  201.                     "db_read(), line %d: too few arguments for \"%s\".",
  202.                          lineN, tokV[0] );
  203.             }
  204.             else {
  205.                 /* Arg count OK: dispatch to handler */
  206.                 (*Rddisp[rdX].rd_rtc)( lineN, &tokV[0], tokC );
  207.             }
  208.         }
  209.         else {
  210.             /* No match. */
  211.             warning( EC_OK,
  212.                 "db_read(), line %d: Unrecognized element \"%s\".",
  213.                         lineN, tokV[0] );
  214.         }
  215.     }
  216.  
  217.     /* Close db file */
  218.     fclose( fP );
  219.  
  220.     /* Finish up the last event if we were making one */
  221.     rdmkevent();
  222. }
  223. /*
  224.  
  225. *//* db_write()
  226.  
  227.         Write the event database
  228.  
  229. Accepts :
  230.  
  231. Returns :
  232.  
  233. Notes :
  234.  
  235.         This routine assumes that the caller has locked the event list.
  236.  
  237. */
  238.  
  239. void
  240. db_write( void ) {
  241.  
  242.         int             i;              /* Scratch */
  243.         FILE            *fP;            /* File ptr */
  244.         PEVENT          *peventP;       /* Ptr to pending event thing */
  245.         EVENT           *eventP;        /* Ptr to event part of it */
  246.  
  247.     /* Open the db file */
  248.     if ( ( fP = fopen( Dbfname, "w" ) ) == NULL )
  249.         error( EC_OPEN, "db_write() can't open database \"%s\"",
  250.                 Dbfname );
  251.  
  252.     /* Write the header */
  253.     fprintf( fP, "TIMEX-DATABASE\n" );
  254.     fprintf( fP, "\n" );
  255.     fprintf( fP, "# This is the events database for TIMEXBA.\n" );
  256.     fprintf( fP, "# It is normally maintained by TIMEXBA.  It can be\n" );
  257.     fprintf( fP, "# edited by hand or by another program, but care must\n" );
  258.     fprintf( fP, "# be taken to preserve its integrity.\n" );
  259.     fprintf( fP, "#\n" );
  260.     fprintf( fP, "# Some hints:\n" );
  261.     fprintf( fP, "#\n" );
  262.     fprintf( fP, "# Strings should be quoted.  Internal quotes can be\n" );
  263.     fprintf( fP, "#  included by preceding them with a backslash.\n" );
  264.     fprintf( fP, "# Most numerical values (e.g., month, day of week) are\n" );
  265.     fprintf( fP, "#  zero-based; monday is 0, January is 0, etc.  Notable\n" );
  266.     fprintf( fP, "#  exception is day of month, which is 1-based.\n" );
  267.     fprintf( fP, "#  Months and weekdays can be expressed by their common\n" );
  268.     fprintf( fP, "#  three-letter abbreviation.\n" );
  269.     fprintf( fP, "# Refer to the article (Personal Workstation Magazine,\n" );
  270.     fprintf( fP, "#  March 1990, 'Programming in the main()') for more info.\n" );
  271.     fprintf( fP, "\n" );
  272.     fprintf( fP, "Version: %d %d\n", BAVERMAJ, BAVERMIN );
  273.     fprintf( fP, "Priority: %d %d\n", Priclass, Prival );
  274.  
  275.     /* Write out the events */
  276.     for( peventP = PendingL; peventP != NULL; peventP = peventP->pe_nextP ) {
  277.         eventP = peventP->pe_eventP;    /* Ptr to event proper */
  278.  
  279.         /* Give a separator for readability */
  280.         fprintf( fP, "\n# ---------------\n\n" );
  281.  
  282.         /* Write out the event specifics */
  283.  
  284.         fprintf( fP, "Event: " );
  285.         putqs( fP, eventP->ev_nameP );
  286.         fprintf( fP, "\n" );
  287.  
  288.         fprintf( fP, "Priority: %d %d\n", eventP->ev_priclass,
  289.                                                 eventP->ev_prival );
  290.  
  291.         fprintf( fP, "Action-type: %s\n",
  292.                         eventP->ev_acttype == ACTION_RUN ? "Run" :
  293.                            "unknown" );
  294.  
  295.         fprintf( fP, "Action-spec: " );
  296.         putqs( fP, eventP->ev_actargP );
  297.         fprintf( fP, "\n" );
  298.  
  299.         if ( eventP->ev_yearC > 0 ) {
  300.             fprintf( fP, "Year:" );
  301.             for( i = 0; i < eventP->ev_yearC; ++i ) {
  302.                 fprintf( fP, " %d", eventP->ev_yearP[i].y_first );
  303.                 if ( eventP->ev_yearP[i].y_last !=
  304.                         eventP->ev_yearP[i].y_first )
  305.                     fprintf( fP, "-%d", eventP->ev_yearP[i].y_last );
  306.             }
  307.             fprintf( fP, "\n" );
  308.         }
  309.  
  310.         if ( eventP->ev_months != 0 ) {
  311.             fprintf( fP, "Month:" );
  312.             for( i = 0; i < 12; ++i )
  313.                 if ( ( eventP->ev_months & ( 1 << i ) ) != 0 )
  314.                     fprintf( fP, " %d", i );
  315.             fprintf( fP, "\n" );
  316.         }
  317.  
  318.         if ( eventP->ev_dayofs != 0 ) {
  319.             fprintf( fP, "Day-of: " );
  320.             if ( eventP->ev_dayof == DAYOF_MONTH ) {
  321.                 fprintf( fP, "month" );
  322.                 for( i = 0; i < 31; ++i )
  323.                     if ( ( eventP->ev_dayofs & ( 1 << i ) ) != 0 )
  324.                         fprintf( fP, " %d", i+1 );
  325.             }
  326.             else {
  327.                 fprintf( fP, "week" );
  328.                 for( i = 0; i < 31; ++i )
  329.                     if ( ( eventP->ev_dayofs & ( 1 << i ) ) != 0 )
  330.                         fprintf( fP, " %d", i );
  331.             }
  332.             fprintf( fP, "\n" );
  333.         }
  334.  
  335.         if ( eventP->ev_hours != 0 ) {
  336.             fprintf( fP, "Hour:" );
  337.             for( i = 0; i < 24; ++i )
  338.                 if ( ( eventP->ev_hours & ( 1L << i ) ) != 0 )
  339.                     fprintf( fP, " %d", i );
  340.             fprintf( fP, "\n" );
  341.         }
  342.  
  343.         if ( ( eventP->ev_mins[0] != 0 ) || ( eventP->ev_mins[1] != 0 ) ) {
  344.             fprintf( fP, "Min:" );
  345.             for( i = 0; i < 32; ++i )
  346.                 if ( ( eventP->ev_mins[0] & ( 1L << i ) ) != 0 )
  347.                     fprintf( fP, " %d", i );
  348.             for( i = 0; i < 28; ++i )
  349.                 if ( ( eventP->ev_mins[1] & ( 1L << i ) ) != 0 )
  350.                     fprintf( fP, " %d", i + 32 );
  351.             fprintf( fP, "\n" );
  352.         }
  353.  
  354.     }
  355.  
  356.     fclose( fP );
  357. }
  358. /*
  359.  
  360. *//* putqs( fP, strP )
  361.  
  362.         Output a quoted string, retaining internal quoting
  363.  
  364. Accepts :
  365.  
  366.         fP              File ptr for destination
  367.         strP            The string to output
  368.  
  369. Returns :
  370.  
  371. */
  372.  
  373. static void
  374. putqs(
  375.         FILE            *fP,            /* Output file */
  376.         char            *strP           /* Thing to output */
  377.     ) {
  378.  
  379.         char            ch;             /* Char... */
  380.  
  381.     fputc( '\"', fP );
  382.     while( ( ch = *strP++ ) != NUL ) {
  383.         if ( ( ch == '\"' ) || ( ch == '\\' ) )
  384.             fputc( '\\', fP );
  385.         fputc( ch, fP );
  386.     }
  387.     fputc( '\"', fP );
  388. }
  389. /*
  390.  
  391. *//* rd_xxxx( lineN, tokV, tokC )
  392.  
  393.         Following are routines that process individual event item
  394.         lines from an event database.  The interface is:
  395.  
  396. Accepts :
  397.  
  398.         lineN           Line number in the file (for error messaging)
  399.         tokV            Ptr to the token vector, including the keyword
  400.         tokC            Number of tokens in the token vector
  401.  
  402. Returns :
  403.  
  404.         < nothing >
  405.  
  406. Notes :
  407.  
  408.         These routines make use of the event-building routines in
  409.         the evpack module.
  410.  
  411.         Caller has already ensured that the minimum required number
  412.         of arguments is present.
  413.  
  414. */
  415.  
  416.  
  417.  
  418.  
  419. /*
  420.  
  421. *//* rd_actarg( ... )
  422.  
  423.         Process action argument.
  424.  
  425. */
  426.  
  427. static void
  428. rd_actarg(
  429.         int             lineN,          /* Current line number */
  430.         char            **tokV,         /* Token vector */
  431.         int             tokC            /* Token count */
  432. ) {
  433.  
  434.     event_action( tokV[1] );
  435. }
  436. /*
  437.  
  438. *//* rd_acttype( ... )
  439.  
  440.         Process action type
  441.  
  442. */
  443.  
  444. static void
  445. rd_acttype(
  446.         int             lineN,          /* Current line number */
  447.         char            **tokV,         /* Token vector */
  448.         int             tokC            /* Token count */
  449. ) {
  450.  
  451.     if ( stricmp( tokV[1], "Run" ) == 0 )
  452.         event_acttype( ACTION_RUN );
  453.     else {
  454.  
  455.         warning( EC_OK, "db_read(), line %d: invalid action type \"%s\".",
  456.                 lineN, tokV[1] );
  457.     }
  458. }
  459. /*
  460.  
  461. *//* rd_dayof( ... )
  462.  
  463.         Process "Day-of" information
  464.  
  465. */
  466.  
  467. static void
  468. rd_dayof(
  469.         int             lineN,          /* Current line number */
  470.         char            **tokV,         /* Token vector */
  471.         int             tokC            /* Token count */
  472. ) {
  473.         int             v;              /* Value */
  474.         int             min, max;       /* Min and max values */
  475.         int             tokX;           /* Token index */
  476.         char            part1[20];      /* Part 1 of the range */
  477.         char            part2[20];      /* Part 2 of the range */
  478.  
  479.     /* Process according to the day-of type */
  480.     if ( stricmp( tokV[1], "Month" ) == 0 ) {
  481.         /* Process each token */
  482.         for( tokX = 2; tokX < tokC; ++tokX ) {
  483.             /* Break it apart into range components */
  484.             getrange( tokV[tokX], &part1[0], &part2[0] );
  485.  
  486.             /* Process the range */
  487.             min = atoi( &part1[0] );
  488.             if ( part2[0] == NUL )
  489.                 max = min;
  490.             else
  491.                 max = atoi( &part2[0] );
  492.             for( v = min; v <= max; ++v )
  493.                 event_dayofmon( v );
  494.         }
  495.     }
  496.     else if ( stricmp( tokV[1], "Week" ) == 0 ) {
  497.         /* Process each token */
  498.         for( tokX = 2; tokX < tokC; ++tokX ) {
  499.             /* Break the token apart into range components */
  500.             getrange( tokV[tokX], &part1[0], &part2[0] );
  501.  
  502.             /* Process the range */
  503.             min = atodayofwk( &part1[0] );
  504.             if ( part2[0] == NUL )
  505.                 max = min;
  506.             else
  507.                 max = atodayofwk( &part2[0] );
  508.  
  509.             for( v = min; v <= max; ++v )
  510.                 event_dayofwk( v );
  511.         }
  512.     }
  513.     else
  514.         warning( EC_OK, "db_read(), line %d: invalid day-of: \"%s\".",
  515.                                 lineN, tokV[1] );
  516. }
  517. /*
  518.  
  519. *//* rd_event( ... )
  520.  
  521.         Process event name
  522.  
  523. Note:   The presence of an event name indicates the start of a new
  524.         event.
  525.  
  526. */
  527.  
  528. static void
  529. rd_event(
  530.         int             lineN,          /* Current line number */
  531.         char            **tokV,         /* Token vector */
  532.         int             tokC            /* Token count */
  533. ) {
  534.  
  535.     /* Make any event that's being constructed */
  536.     rdmkevent();
  537.  
  538.     /* Clear event info */
  539.     event_clear();
  540.  
  541.     /* Begin new event */
  542.     RdeventF = TRUE;
  543.     event_name( tokV[1] );
  544. }
  545. /*
  546.  
  547. *//* rd_hour( ... )
  548.  
  549.         Process "Hour" information
  550.  
  551. */
  552.  
  553. static void
  554. rd_hour(
  555.         int             lineN,          /* Current line number */
  556.         char            **tokV,         /* Token vector */
  557.         int             tokC            /* Token count */
  558. ) {
  559.         int             v;              /* Value */
  560.         int             min, max;       /* Parameters of the range */
  561.         int             tokX;           /* Token index */
  562.         char            part1[20];      /* Part 1 of the range */
  563.         char            part2[20];      /* Part 2 of the range */
  564.  
  565.     /* Process each token */
  566.     for( tokX = 1; tokX < tokC; ++tokX ) {
  567.         /* Break it apart into range components */
  568.         getrange( tokV[tokX], &part1[0], &part2[0] );
  569.  
  570.         /* Process the range */
  571.         min = atoi( &part1[0] );
  572.         if ( part2[0] == NUL )
  573.             max = min;
  574.         else
  575.             max = atoi( &part2[0] );
  576.  
  577.         for( v = min; v <= max; ++v )
  578.             event_hour( v );
  579.     }
  580. }
  581. /*
  582.  
  583. *//* rd_minute( ... )
  584.  
  585.         Process "Min" information
  586.  
  587. */
  588.  
  589. static void
  590. rd_minute(
  591.         int             lineN,          /* Current line number */
  592.         char            **tokV,         /* Token vector */
  593.         int             tokC            /* Token count */
  594. ) {
  595.         int             v;              /* Value */
  596.         int             min, max;       /* Parameters of the range */
  597.         int             tokX;           /* Token index */
  598.         char            part1[20];      /* Part 1 of the range */
  599.         char            part2[20];      /* Part 2 of the range */
  600.  
  601.     /* Process each token */
  602.     for( tokX = 1; tokX < tokC; ++tokX ) {
  603.         /* Break it apart into range components */
  604.         getrange( tokV[tokX], &part1[0], &part2[0] );
  605.  
  606.         /* Process the range */
  607.         min = atoi( &part1[0] );
  608.         if ( part2[0] == NUL )
  609.             max = min;
  610.         else
  611.             max = atoi( &part2[0] );
  612.  
  613.         for( v = min; v <= max; ++v )
  614.             event_min( v );
  615.     }
  616. }
  617. /*
  618.  
  619. *//* rd_month( ... )
  620.  
  621.         Process "Month" information
  622.  
  623. */
  624.  
  625. static void
  626. rd_month(
  627.         int             lineN,          /* Current line number */
  628.         char            **tokV,         /* Token vector */
  629.         int             tokC            /* Token count */
  630. ) {
  631.         int             v;              /* Value */
  632.         int             min, max;       /* Parameters of the range */
  633.         int             tokX;           /* Token index */
  634.         char            part1[20];      /* Part 1 of the range */
  635.         char            part2[20];      /* Part 2 of the range */
  636.  
  637.     /* Process each token */
  638.     for( tokX = 1; tokX < tokC; ++tokX ) {
  639.         /* Break it apart into range components */
  640.         getrange( tokV[tokX], &part1[0], &part2[0] );
  641.  
  642.         /* Process the range */
  643.         min = atomonth( &part1[0] );
  644.         if ( part2[0] == NUL )
  645.             max = min;
  646.         else
  647.             max = atomonth( &part2[0] );
  648.  
  649.         for( v = min; v <= max; ++v )
  650.             event_month( v );
  651.     }
  652. }
  653. /*
  654.  
  655. *//* rd_prio( ... )
  656.  
  657.         Process "Priority" information
  658.  
  659. */
  660.  
  661. static void
  662. rd_prio(
  663.         int             lineN,          /* Current line number */
  664.         char            **tokV,         /* Token vector */
  665.         int             tokC            /* Token count */
  666. ) {
  667.  
  668.     /* Priority (class and value) is contained in the two arguments */
  669.     event_pri( atoi( tokV[1] ), atoi( tokV[2] ) );
  670. }
  671. /*
  672.  
  673. *//* rd_year( ... )
  674.  
  675.         Process "year" information
  676.  
  677. */
  678.  
  679. static void
  680. rd_year(
  681.         int             lineN,          /* Current line number */
  682.         char            **tokV,         /* Token vector */
  683.         int             tokC            /* Token count */
  684. ) {
  685.         int             tokX;           /* Token index */
  686.         int             min, max;       /* Parameters of the range */
  687.         char            part1[20];      /* Part 1 of the range */
  688.         char            part2[20];      /* Part 2 of the range */
  689.  
  690.     /* Process each token */
  691.     for( tokX = 1; tokX < tokC; ++tokX ) {
  692.         /* Break it apart into range components */
  693.         getrange( tokV[tokX], &part1[0], &part2[0] );
  694.  
  695.         /* Process the range */
  696.         min = atoi( &part1[0] );
  697.         if ( part2[0] == NUL )
  698.             max = min;
  699.         else
  700.             max = atoi( &part2[0] );
  701.  
  702.         event_year( min, max );
  703.     }
  704. }
  705.  
  706.  
  707.  
  708.  
  709.  
  710.  
  711. /*
  712.  
  713. *//* rdmkevent()
  714.  
  715.         Finishes the reading of an event by making the internal
  716.         event structure and adding it to the list under construction.
  717.  
  718. */
  719.  
  720. static void
  721. rdmkevent( void ) {
  722.  
  723.         EVENT           *eventP;        /* Ptr to event */
  724.         PEVENT          *peventP;       /* Ptr to pending event */
  725.  
  726.     if ( !RdeventF )                    /* If no event under construction */
  727.         return;                         /*  just return. */
  728.  
  729.     RdeventF = FALSE;                   /* No longer processing an event */
  730.  
  731.     eventP = event_make();              /* Get event struct */
  732.     peventP = emalloc( "rdmkevent", "new event", sizeof( PEVENT ) );
  733.     peventP->pe_eventP = eventP;
  734.  
  735.     /* Schedule the new event */
  736.     schedule( peventP );
  737. }
  738. /*
  739.  
  740. *//* getrange( strP, p1P, p2P )
  741.  
  742.         Break a string into component parts of a range
  743.  
  744. Accepts :
  745.  
  746.         strP            Ptr to string
  747.         p1P             Where to put first part
  748.         p2P             Where to put second part
  749.  
  750. Returns :
  751.  
  752.         *p1P            First part
  753.         *p2P            Second part, if any
  754.  
  755. Notes :
  756.  
  757.         Parts are separated by a hyphen.  If no second part, second part
  758.          will be a null string.
  759.  
  760. */
  761.  
  762. static void
  763. getrange(
  764.         char            *strP,          /* Source string */
  765.         char            *p1P,           /* First part */
  766.         char            *p2P            /* Second part */
  767.         ) {
  768.  
  769.         char            ch;             /* Char */
  770.  
  771.     /* Do first part */
  772.     for( ; ( ch = *strP ) != NUL; ++strP ) {
  773.         if ( ch == '-' ) {
  774.             ++strP;
  775.             break;
  776.         }
  777.         *p1P++ = ch;
  778.     }
  779.     *p1P = NUL;
  780.  
  781.     /* Do second part */
  782.     do
  783.         *p2P++ = ch = *strP++;
  784.     while ( ch != NUL );
  785.  
  786. }
  787. /*
  788.  
  789. *//* atodayofwk( strP )
  790.  
  791.         Convert a string into a day of week number
  792.  
  793. Accepts :
  794.  
  795.         strP            Ptr to string with day of week abbreviation
  796.                          or number, 0-based (0 = mon, 1 = tue, etc.)
  797.  
  798. Returns :
  799.  
  800.         < value >       Day of week value, 0-based (0 = mon, etc.)
  801.  
  802. Notes :
  803.  
  804.         It's assumed that the string is of proper range.
  805.  
  806.  
  807. */
  808.  
  809. static int
  810. atodayofwk(
  811.         char            *strP           /* Day of week string */
  812.         ) {
  813.  
  814.         int             v;              /* Value */
  815.  
  816.     /* Check for number */
  817.     if ( isdigit( *strP ) )
  818.         v = atoi( strP );
  819.     else {
  820.         /* Look it up in the table */
  821.         for( v = 0; v < 7; ++v )
  822.             if ( stricmp( strP, Dowtbl[v] ) == 0 )
  823.                 break;
  824.     }
  825.  
  826.     return( v );
  827. }
  828. /*
  829.  
  830. *//* atomonth( strP )
  831.  
  832.         Convert a string into a month number
  833.  
  834. Accepts :
  835.  
  836.         strP            Ptr to string with month abbreviation
  837.                          or number, 0-based (0 = Jan, 1 = Feb, etc.)
  838.  
  839. Returns :
  840.  
  841.         < value >       Month value, 0-based (0 = Jan, etc.)
  842.  
  843. Notes :
  844.  
  845.         It's assumed that the string is of proper range.
  846.  
  847. */
  848.  
  849. static int
  850. atomonth(
  851.         char            *strP           /* Month string */
  852.         ) {
  853.  
  854.         int             v;              /* Value */
  855.  
  856.     /* Check for number */
  857.     if ( isdigit( *strP ) )
  858.         v = atoi( strP );
  859.     else {
  860.         /* Look it up in the table */
  861.         for( v = 0; v < 12; ++v )
  862.             if ( stricmp( strP, Montbl[v] ) == 0 )
  863.                 break;
  864.     }
  865.  
  866.     return( v );
  867. }
  868.