home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 11 Util
/
11-Util.zip
/
TIMEXSRC.ZIP
/
BA_DB.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-29
|
25KB
|
868 lines
/* ba_db.c -- Database management
February 1990 Mark E. Mallett, Personal Workstation Magazine
This file contains code that keeps the event database.
Included are the following routines:
db_read Read the events database
db_write Write the events database
Notes :
The events database is maintained as an ASCII file. This is to make
it maximally expandable and understandable by other programs or human
beings. The trade-off (vs a binary representation) is that it is also
easier for one of those other entities to mess up the data.
*/
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <os2.h>
#include "errhand.h"
#include "timex.h"
#include "ba_timex.h"
#include "evpack.h"
/* Local definitions */
/* External data referenced */
extern char *Dbfname; /* Name of the database file */
extern PEVENT *PendingL; /* List of pending events */
extern int Priclass; /* Priority class to run at */
extern int Prival; /* Priority value to run at */
/* External routines used */
extern int atoi( char *strP );
extern int gettkline( FILE *fP, char *bufP, int bufsize,
int *tokCP, char **tokV, int tokmax );
extern void schedule( PEVENT *peventP );
/* Local data publicly available */
/* Local routines and forward declarations */
static int atodayofwk( char *strP );
static int atomonth( char *strP );
static void getrange( char *strP, char *p1P, char *p2P );
static void putqs( FILE *fP, char *strP );
static void rdmkevent( void );
/* db_read() component routines */
static void rd_actarg( int lineN, char **tokV, int tokC );
static void rd_acttype( int lineN, char **tokV, int tokC );
static void rd_dayof( int lineN, char **tokV, int tokC );
static void rd_event( int lineN, char **tokV, int tokC );
static void rd_hour( int lineN, char **tokV, int tokC );
static void rd_minute( int lineN, char **tokV, int tokC );
static void rd_month( int lineN, char **tokV, int tokC );
static void rd_prio( int lineN, char **tokV, int tokC );
static void rd_year( int lineN, char **tokV, int tokC );
/* Private data */
static BOOL RdeventF; /* If currently in an event */
/* Dispatch table for db_read() event lines */
static struct {
char *rd_keyP; /* Ptr to keyword */
int rd_argmin; /* Minimum args required */
void (*rd_rtc)( int lineN, char **tokV, int tokC );
/* Routine to call */
} Rddisp[] = {
{ "Action-spec", 1, rd_actarg },
{ "Action-type", 1, rd_acttype },
{ "Day-of", 2, rd_dayof },
{ "Event", 1, rd_event },
{ "Hour", 1, rd_hour },
{ "Min", 1, rd_minute },
{ "Month", 1, rd_month },
{ "Priority", 2, rd_prio },
{ "Year", 1, rd_year },
{ NULL, 0, NULL }
};
/* Table of weekday name abbreviations in value order */
static char *Dowtbl[] = {
"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
};
/* Table of month name abbreviations in value order */
static char *Montbl[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
/*
*//* db_read()
Read the event database
Accepts :
Returns :
Notes :
This routine assumes that the caller has locked the event list;
i.e., that the current thread has complete access to the list.
Any current event list will be deleted by this routine before
reading in the new one.
*/
void
db_read( void ) {
BOOL inheader; /* If processing header */
BOOL gotid; /* If ID line seen */
int lineN; /* Line number */
int rdX; /* Dispatch table index */
int cC; /* Number of characters */
int tokC; /* Number of tokens */
FILE *fP; /* File ptr */
char *tokV[50]; /* Token vector */
char tokbuf[200]; /* Token buffer */
/* Open the database file for reading */
if ( ( fP = fopen( Dbfname, "r" ) ) == NULL ) {
warning( EC_OK, "db_read() can't access database \"%s\"", Dbfname );
return;
}
inheader = TRUE; /* Looking at header */
gotid = FALSE; /* Haven't seen file ID yet */
RdeventF = FALSE; /* Not in an event */
/* Process the lines from the file */
for( lineN = 1; ; ++lineN ) {
cC = gettkline( fP, &tokbuf[0], 200, &tokC, &tokV[0], 50 );
if ( cC < 0 )
break; /* End of file. */
/* Check for blank or comment line */
if ( ( tokC == 0 ) ||
( strcmp( tokV[0], "#" ) == 0 )
)
continue;
/* Make sure the first line of the file is the ID line */
if ( !gotid ) {
if ( stricmp( tokV[0], "TIMEX-Database" ) != 0 ) {
warning( EC_NOTOK, "\"%s\" is not a timex database.",
Dbfname );
break;
}
gotid = TRUE;
continue;
}
/* Check for other header lines */
if ( inheader ) {
if ( stricmp( tokV[0], "Version" ) == 0 ) {
continue;
}
else if ( stricmp( tokV[0], "Priority" ) == 0 ) {
continue;
}
}
/* Check for non-header line */
for( rdX = 0; Rddisp[rdX].rd_keyP != NULL; ++rdX ) {
if ( stricmp( Rddisp[rdX].rd_keyP, tokV[0] ) == 0 )
break;
}
/* Process if we got a match */
if ( Rddisp[rdX].rd_keyP != NULL ) {
inheader = FALSE;
/* Check for required # of tokens */
if ( tokC <= Rddisp[rdX].rd_argmin ) {
warning( EC_OK,
"db_read(), line %d: too few arguments for \"%s\".",
lineN, tokV[0] );
}
else {
/* Arg count OK: dispatch to handler */
(*Rddisp[rdX].rd_rtc)( lineN, &tokV[0], tokC );
}
}
else {
/* No match. */
warning( EC_OK,
"db_read(), line %d: Unrecognized element \"%s\".",
lineN, tokV[0] );
}
}
/* Close db file */
fclose( fP );
/* Finish up the last event if we were making one */
rdmkevent();
}
/*
*//* db_write()
Write the event database
Accepts :
Returns :
Notes :
This routine assumes that the caller has locked the event list.
*/
void
db_write( void ) {
int i; /* Scratch */
FILE *fP; /* File ptr */
PEVENT *peventP; /* Ptr to pending event thing */
EVENT *eventP; /* Ptr to event part of it */
/* Open the db file */
if ( ( fP = fopen( Dbfname, "w" ) ) == NULL )
error( EC_OPEN, "db_write() can't open database \"%s\"",
Dbfname );
/* Write the header */
fprintf( fP, "TIMEX-DATABASE\n" );
fprintf( fP, "\n" );
fprintf( fP, "# This is the events database for TIMEXBA.\n" );
fprintf( fP, "# It is normally maintained by TIMEXBA. It can be\n" );
fprintf( fP, "# edited by hand or by another program, but care must\n" );
fprintf( fP, "# be taken to preserve its integrity.\n" );
fprintf( fP, "#\n" );
fprintf( fP, "# Some hints:\n" );
fprintf( fP, "#\n" );
fprintf( fP, "# Strings should be quoted. Internal quotes can be\n" );
fprintf( fP, "# included by preceding them with a backslash.\n" );
fprintf( fP, "# Most numerical values (e.g., month, day of week) are\n" );
fprintf( fP, "# zero-based; monday is 0, January is 0, etc. Notable\n" );
fprintf( fP, "# exception is day of month, which is 1-based.\n" );
fprintf( fP, "# Months and weekdays can be expressed by their common\n" );
fprintf( fP, "# three-letter abbreviation.\n" );
fprintf( fP, "# Refer to the article (Personal Workstation Magazine,\n" );
fprintf( fP, "# March 1990, 'Programming in the main()') for more info.\n" );
fprintf( fP, "\n" );
fprintf( fP, "Version: %d %d\n", BAVERMAJ, BAVERMIN );
fprintf( fP, "Priority: %d %d\n", Priclass, Prival );
/* Write out the events */
for( peventP = PendingL; peventP != NULL; peventP = peventP->pe_nextP ) {
eventP = peventP->pe_eventP; /* Ptr to event proper */
/* Give a separator for readability */
fprintf( fP, "\n# ---------------\n\n" );
/* Write out the event specifics */
fprintf( fP, "Event: " );
putqs( fP, eventP->ev_nameP );
fprintf( fP, "\n" );
fprintf( fP, "Priority: %d %d\n", eventP->ev_priclass,
eventP->ev_prival );
fprintf( fP, "Action-type: %s\n",
eventP->ev_acttype == ACTION_RUN ? "Run" :
"unknown" );
fprintf( fP, "Action-spec: " );
putqs( fP, eventP->ev_actargP );
fprintf( fP, "\n" );
if ( eventP->ev_yearC > 0 ) {
fprintf( fP, "Year:" );
for( i = 0; i < eventP->ev_yearC; ++i ) {
fprintf( fP, " %d", eventP->ev_yearP[i].y_first );
if ( eventP->ev_yearP[i].y_last !=
eventP->ev_yearP[i].y_first )
fprintf( fP, "-%d", eventP->ev_yearP[i].y_last );
}
fprintf( fP, "\n" );
}
if ( eventP->ev_months != 0 ) {
fprintf( fP, "Month:" );
for( i = 0; i < 12; ++i )
if ( ( eventP->ev_months & ( 1 << i ) ) != 0 )
fprintf( fP, " %d", i );
fprintf( fP, "\n" );
}
if ( eventP->ev_dayofs != 0 ) {
fprintf( fP, "Day-of: " );
if ( eventP->ev_dayof == DAYOF_MONTH ) {
fprintf( fP, "month" );
for( i = 0; i < 31; ++i )
if ( ( eventP->ev_dayofs & ( 1 << i ) ) != 0 )
fprintf( fP, " %d", i+1 );
}
else {
fprintf( fP, "week" );
for( i = 0; i < 31; ++i )
if ( ( eventP->ev_dayofs & ( 1 << i ) ) != 0 )
fprintf( fP, " %d", i );
}
fprintf( fP, "\n" );
}
if ( eventP->ev_hours != 0 ) {
fprintf( fP, "Hour:" );
for( i = 0; i < 24; ++i )
if ( ( eventP->ev_hours & ( 1L << i ) ) != 0 )
fprintf( fP, " %d", i );
fprintf( fP, "\n" );
}
if ( ( eventP->ev_mins[0] != 0 ) || ( eventP->ev_mins[1] != 0 ) ) {
fprintf( fP, "Min:" );
for( i = 0; i < 32; ++i )
if ( ( eventP->ev_mins[0] & ( 1L << i ) ) != 0 )
fprintf( fP, " %d", i );
for( i = 0; i < 28; ++i )
if ( ( eventP->ev_mins[1] & ( 1L << i ) ) != 0 )
fprintf( fP, " %d", i + 32 );
fprintf( fP, "\n" );
}
}
fclose( fP );
}
/*
*//* putqs( fP, strP )
Output a quoted string, retaining internal quoting
Accepts :
fP File ptr for destination
strP The string to output
Returns :
*/
static void
putqs(
FILE *fP, /* Output file */
char *strP /* Thing to output */
) {
char ch; /* Char... */
fputc( '\"', fP );
while( ( ch = *strP++ ) != NUL ) {
if ( ( ch == '\"' ) || ( ch == '\\' ) )
fputc( '\\', fP );
fputc( ch, fP );
}
fputc( '\"', fP );
}
/*
*//* rd_xxxx( lineN, tokV, tokC )
Following are routines that process individual event item
lines from an event database. The interface is:
Accepts :
lineN Line number in the file (for error messaging)
tokV Ptr to the token vector, including the keyword
tokC Number of tokens in the token vector
Returns :
< nothing >
Notes :
These routines make use of the event-building routines in
the evpack module.
Caller has already ensured that the minimum required number
of arguments is present.
*/
/*
*//* rd_actarg( ... )
Process action argument.
*/
static void
rd_actarg(
int lineN, /* Current line number */
char **tokV, /* Token vector */
int tokC /* Token count */
) {
event_action( tokV[1] );
}
/*
*//* rd_acttype( ... )
Process action type
*/
static void
rd_acttype(
int lineN, /* Current line number */
char **tokV, /* Token vector */
int tokC /* Token count */
) {
if ( stricmp( tokV[1], "Run" ) == 0 )
event_acttype( ACTION_RUN );
else {
warning( EC_OK, "db_read(), line %d: invalid action type \"%s\".",
lineN, tokV[1] );
}
}
/*
*//* rd_dayof( ... )
Process "Day-of" information
*/
static void
rd_dayof(
int lineN, /* Current line number */
char **tokV, /* Token vector */
int tokC /* Token count */
) {
int v; /* Value */
int min, max; /* Min and max values */
int tokX; /* Token index */
char part1[20]; /* Part 1 of the range */
char part2[20]; /* Part 2 of the range */
/* Process according to the day-of type */
if ( stricmp( tokV[1], "Month" ) == 0 ) {
/* Process each token */
for( tokX = 2; tokX < tokC; ++tokX ) {
/* Break it apart into range components */
getrange( tokV[tokX], &part1[0], &part2[0] );
/* Process the range */
min = atoi( &part1[0] );
if ( part2[0] == NUL )
max = min;
else
max = atoi( &part2[0] );
for( v = min; v <= max; ++v )
event_dayofmon( v );
}
}
else if ( stricmp( tokV[1], "Week" ) == 0 ) {
/* Process each token */
for( tokX = 2; tokX < tokC; ++tokX ) {
/* Break the token apart into range components */
getrange( tokV[tokX], &part1[0], &part2[0] );
/* Process the range */
min = atodayofwk( &part1[0] );
if ( part2[0] == NUL )
max = min;
else
max = atodayofwk( &part2[0] );
for( v = min; v <= max; ++v )
event_dayofwk( v );
}
}
else
warning( EC_OK, "db_read(), line %d: invalid day-of: \"%s\".",
lineN, tokV[1] );
}
/*
*//* rd_event( ... )
Process event name
Note: The presence of an event name indicates the start of a new
event.
*/
static void
rd_event(
int lineN, /* Current line number */
char **tokV, /* Token vector */
int tokC /* Token count */
) {
/* Make any event that's being constructed */
rdmkevent();
/* Clear event info */
event_clear();
/* Begin new event */
RdeventF = TRUE;
event_name( tokV[1] );
}
/*
*//* rd_hour( ... )
Process "Hour" information
*/
static void
rd_hour(
int lineN, /* Current line number */
char **tokV, /* Token vector */
int tokC /* Token count */
) {
int v; /* Value */
int min, max; /* Parameters of the range */
int tokX; /* Token index */
char part1[20]; /* Part 1 of the range */
char part2[20]; /* Part 2 of the range */
/* Process each token */
for( tokX = 1; tokX < tokC; ++tokX ) {
/* Break it apart into range components */
getrange( tokV[tokX], &part1[0], &part2[0] );
/* Process the range */
min = atoi( &part1[0] );
if ( part2[0] == NUL )
max = min;
else
max = atoi( &part2[0] );
for( v = min; v <= max; ++v )
event_hour( v );
}
}
/*
*//* rd_minute( ... )
Process "Min" information
*/
static void
rd_minute(
int lineN, /* Current line number */
char **tokV, /* Token vector */
int tokC /* Token count */
) {
int v; /* Value */
int min, max; /* Parameters of the range */
int tokX; /* Token index */
char part1[20]; /* Part 1 of the range */
char part2[20]; /* Part 2 of the range */
/* Process each token */
for( tokX = 1; tokX < tokC; ++tokX ) {
/* Break it apart into range components */
getrange( tokV[tokX], &part1[0], &part2[0] );
/* Process the range */
min = atoi( &part1[0] );
if ( part2[0] == NUL )
max = min;
else
max = atoi( &part2[0] );
for( v = min; v <= max; ++v )
event_min( v );
}
}
/*
*//* rd_month( ... )
Process "Month" information
*/
static void
rd_month(
int lineN, /* Current line number */
char **tokV, /* Token vector */
int tokC /* Token count */
) {
int v; /* Value */
int min, max; /* Parameters of the range */
int tokX; /* Token index */
char part1[20]; /* Part 1 of the range */
char part2[20]; /* Part 2 of the range */
/* Process each token */
for( tokX = 1; tokX < tokC; ++tokX ) {
/* Break it apart into range components */
getrange( tokV[tokX], &part1[0], &part2[0] );
/* Process the range */
min = atomonth( &part1[0] );
if ( part2[0] == NUL )
max = min;
else
max = atomonth( &part2[0] );
for( v = min; v <= max; ++v )
event_month( v );
}
}
/*
*//* rd_prio( ... )
Process "Priority" information
*/
static void
rd_prio(
int lineN, /* Current line number */
char **tokV, /* Token vector */
int tokC /* Token count */
) {
/* Priority (class and value) is contained in the two arguments */
event_pri( atoi( tokV[1] ), atoi( tokV[2] ) );
}
/*
*//* rd_year( ... )
Process "year" information
*/
static void
rd_year(
int lineN, /* Current line number */
char **tokV, /* Token vector */
int tokC /* Token count */
) {
int tokX; /* Token index */
int min, max; /* Parameters of the range */
char part1[20]; /* Part 1 of the range */
char part2[20]; /* Part 2 of the range */
/* Process each token */
for( tokX = 1; tokX < tokC; ++tokX ) {
/* Break it apart into range components */
getrange( tokV[tokX], &part1[0], &part2[0] );
/* Process the range */
min = atoi( &part1[0] );
if ( part2[0] == NUL )
max = min;
else
max = atoi( &part2[0] );
event_year( min, max );
}
}
/*
*//* rdmkevent()
Finishes the reading of an event by making the internal
event structure and adding it to the list under construction.
*/
static void
rdmkevent( void ) {
EVENT *eventP; /* Ptr to event */
PEVENT *peventP; /* Ptr to pending event */
if ( !RdeventF ) /* If no event under construction */
return; /* just return. */
RdeventF = FALSE; /* No longer processing an event */
eventP = event_make(); /* Get event struct */
peventP = emalloc( "rdmkevent", "new event", sizeof( PEVENT ) );
peventP->pe_eventP = eventP;
/* Schedule the new event */
schedule( peventP );
}
/*
*//* getrange( strP, p1P, p2P )
Break a string into component parts of a range
Accepts :
strP Ptr to string
p1P Where to put first part
p2P Where to put second part
Returns :
*p1P First part
*p2P Second part, if any
Notes :
Parts are separated by a hyphen. If no second part, second part
will be a null string.
*/
static void
getrange(
char *strP, /* Source string */
char *p1P, /* First part */
char *p2P /* Second part */
) {
char ch; /* Char */
/* Do first part */
for( ; ( ch = *strP ) != NUL; ++strP ) {
if ( ch == '-' ) {
++strP;
break;
}
*p1P++ = ch;
}
*p1P = NUL;
/* Do second part */
do
*p2P++ = ch = *strP++;
while ( ch != NUL );
}
/*
*//* atodayofwk( strP )
Convert a string into a day of week number
Accepts :
strP Ptr to string with day of week abbreviation
or number, 0-based (0 = mon, 1 = tue, etc.)
Returns :
< value > Day of week value, 0-based (0 = mon, etc.)
Notes :
It's assumed that the string is of proper range.
*/
static int
atodayofwk(
char *strP /* Day of week string */
) {
int v; /* Value */
/* Check for number */
if ( isdigit( *strP ) )
v = atoi( strP );
else {
/* Look it up in the table */
for( v = 0; v < 7; ++v )
if ( stricmp( strP, Dowtbl[v] ) == 0 )
break;
}
return( v );
}
/*
*//* atomonth( strP )
Convert a string into a month number
Accepts :
strP Ptr to string with month abbreviation
or number, 0-based (0 = Jan, 1 = Feb, etc.)
Returns :
< value > Month value, 0-based (0 = Jan, etc.)
Notes :
It's assumed that the string is of proper range.
*/
static int
atomonth(
char *strP /* Month string */
) {
int v; /* Value */
/* Check for number */
if ( isdigit( *strP ) )
v = atoi( strP );
else {
/* Look it up in the table */
for( v = 0; v < 12; ++v )
if ( stricmp( strP, Montbl[v] ) == 0 )
break;
}
return( v );
}