#include #include #include #include "structs.h" /* #define STAND */ /* for now */ #ifdef STAND #define XtMalloc malloc #define XtFree free #define filename "structs.dat" #endif int ampm = 1; int assume_day = 1; /* * The purpose of matchbits is to return a boolean (though it * really doesn't) indicating whether bit num is set in bits. * This is used to help check if a simple date is included in * a complicated one. */ int matchBits( num, bits ) int num, bits; { return (bits & (1<<(num-1))); } /* * Turn a string expression into a set of bits (in an int) * The bits would probably be appropriately be abstracted into * a type set. * * expression: bits: * * * all * a-b bits a to b set * if b is less than a, then * bits from b to max, and * 0 to a are set. * a bit a is set * * All expressions but * must be enclosed in {}, and multiple * expressions may be separated by commas. Thus * {a-b, c-d, e, f, g-h} is a valid expression, as is *. */ int expToBits( e, max ) char *e; int max; { int i, j, n, first = 0, range; /* shutup! */ int rtn = 0; if ( e[0] == '*' ) return (int)~0; if ( e[0] != '{' ) return ( 1<<(atoi(e)-1) ); i = 1; n = 0; range = 0; while ( i < strlen( e ) ) { while ( e[i] == ' ' || e[i] == '-' || e[i] == ',' || e[i] == '}' ) i++; while ( e[i] != ' ' && e[i] != '-' && e[i] != ',' && e[i] != '}' ) n = 10 * n + e[i++] - '0'; switch( e[i] ) { case ' ': break; case '-': range = 1; first = n; n = 0; break; case ',': case '}': if ( range ) { range = 0; if ( n < first ) n += max; /* this with mod to wrap */ for ( j = first; j <= n; j++ ) rtn |= (1<<((j-1)%max)); } else rtn |= (1<<(n-1)); n = 0; if ( e[i] == '}' ) i = strlen( e ); break; default: /* buggy stuff */ fprintf( stderr, "expToBits: %c\n", e[i] ); break; } } return rtn; } /* * Converts a day string expression to its bits */ int dayToRep( w ) char *w; { return expToBits( w, 7 ) & wildDays; } /* * Converts a month string expression to its bits */ int monthToRep( m ) char *m; { return expToBits( m, 12 ) & wildMonths; } /* * Converts a date string expression to its bits */ int dateToRep( d ) char *d; { return expToBits( d, 31 ) & wildDates; } /* * Converts a year string expression (limited) to an int. * No ranges are allowed in its representation, except for wild. */ int yearToRep( y ) char *y; { if ( y[0] == '*' ) return wildYear; else return atoi( y ); } /* * Takes a file and adds it to an events list. * An events list is a fully general list of all events the program * knows about. * * file format: * * w m/d/y h:m:s h:m:s * # Header text line (for single line display) * # description text line 1... * # description text line n... * * any of {w,m,d} may be formed {n1,n2-n3,n5}; y may be * or n1. */ int addFileToEvents( file, events ) char *file; event **events; { FILE *f; event *new; date *w, **wm; char wk[10], m[10], d[100], y[10]; char l, t[DESCMAX]; int used; int hs, ms, ss, he, me, se; int version = 0; f = fopen( file, "r" ); if ( f == NULL ) /* needs better stuff here */ { *events = NULL; return 0; } while ( !feof( f ) ) { new = (event *) XtMalloc( sizeof( event ) ); new->next = *events; new->info = (desc *) XtMalloc( sizeof( desc ) ); new->info->desc = NULL; *events = new; wm = &new->when; l = getc( f ); /* i think this dies on null files *bug* */ ungetc( l, f ); if ( l == '_' ) { fscanf( f, "_version %d\n", &version ); l = getc( f ); ungetc( l, f ); } while ( l != EOF && l != '#' ) { w = (date *) XtMalloc( sizeof( date ) ); *wm = w; w->more = NULL; wm = &w->more; if ( version == 0 ) { fscanf( f, "%[^ ] %[^/]/%[^/]/%[^ ] %d:%d:%d %d:%d:%d\n", wk, m, d, y, &hs, &ms, &ss, &he, &me, &se ); new->info->activity = 0; new->info->scheduled = 1; new->info->daylike = 0; } else { fscanf( f, "%[^ ] %[^/]/%[^/]/%[^ ] %d:%d:%d %d:%d:%d %d %d %d\n", wk, m, d, y, &hs, &ms, &ss, &he, &me, &se, &new->info->activity, &new->info->scheduled, &new->info->daylike ); } w->days = dayToRep( wk ); w->months = monthToRep( m ); w->dates = dateToRep( d ); w->year = yearToRep( y ); /* must restructure */ w->starttime.hour = hs; /* bogus */ w->starttime.minute = ms; w->starttime.second = ss; w->endtime.hour = he; w->endtime.minute = me; w->endtime.second = se; l = getc( f ); ungetc( l, f ); } used = 0; while ( l != EOF && l == '#' && used != DESCMAX-1 ) { l = getc( f ); fgets( &t[used], DESCMAX-used, f ); /* includes cr */ used = strlen( t ); l = getc( f ); ungetc( l, f ); } /* bug; put in code to skip characters over DESCMAX */ if ( used != 0 ) { new->info->desc = (char *) XtMalloc( used+1 ); memmove( new->info->desc, t, used+1 ); } } fclose( f ); return 1; } void all( bits, str ) int bits; char *str; { char work[10]; char bld[100]; int i, first; int multi = 0, range = 0, started = 0; sprintf( bld, "" ); for ( i = 1; i < 32; i++ ) { if ( (!range) && (bits & 1) ) { range = 1; first = i; } else if ( range && !(bits & 1) ) { if ( !started ) started = 1; else strcat( bld, "," ); range = 0; if ( i == first+1 ) sprintf( work, "%d", first ); else { multi = 1; sprintf( work, "%d-%d", first, i-1 ); } strcat( bld, work ); } if ( i == 32 && range ) { if ( i == first+1 ) sprintf( work, "%d", first ); else { multi = 1; sprintf( work, "%d-%d", first, i-1 ); } strcat( bld, work ); } bits = bits >> 1; } if ( multi || index( bld, ',' ) ) sprintf( str, "{%s}", bld ); else strcpy( str, bld ); } int first( bits ) int bits; { int i; for ( i = 0; i < 31; i++ ) { if ( bits & 1 ) return i + 1; bits = bits >> 1; } } int dumpEventsToFile( events, file ) char *file; event *events; { FILE *f; char *s, *e, ms[100], ds[100]; date *w; f = fopen( file, "w" ); if ( f == NULL ) return 0; fprintf( f, "_version 1\n" ); while (events != NULL) { w = events->when; while ( w != NULL ) { all( w->months, ms ); all( w->dates, ds ); fprintf( f, "* %s/%s/%d %d:%d:%d %d:%d:%d %d %d %d\n", ms, ds, w->year, w->starttime.hour, w->starttime.minute, w->starttime.second, w->endtime.hour, w->endtime.minute, w->endtime.second, events->info->activity, events->info->scheduled, events->info->daylike ); w = w->more; } s = events->info->desc; while ( s != NULL ) { e = index( s, '\n' ); if ( e == 0 ) e = index( s, '\0' ); fprintf( f, "#%.*s\n", e-s, s ); s = e + ( (*e == '\0') ? 0 : 1); if (*s == '\0') s = NULL; } events = events->next; } fclose( f ); return 1; } deleteFromEvents( e, what ) event **e; desc *what; { event *last = NULL, *current; date *w1, *w2; current = *e; while ( current != NULL ) { if ( current->info == what ) { w1 = current->when; while ( w1 != NULL ) { w2 = w1; w1 = w1->more; XtFree( w2 ); } XtFree( current->info->desc ); XtFree( current->info ); if ( last == NULL ) *e = current->next; else last->next = current->next; XtFree( current ); current = NULL; } else { last = current; current = current->next; } } } void addToEvents( e, sels, numsels, start, end, ofni ) event **e; CalendarSelection *(sels[]); int numsels; CalTime start, end; desc *ofni; { int i, j; event *new; date *ptr; new = (event *) XtMalloc( sizeof( event ) ); new->next = *e; new->info = (desc *) XtMalloc( sizeof( desc ) ); new->info->desc = NULL; ptr = (date *) XtMalloc( sizeof( date ) ); new->when = ptr; /* bugs for null selections... */ *e = new; for ( i = 0; i < numsels; i++ ) { if ( i > 0 ) { ptr->more = (date *) XtMalloc( sizeof( date ) ); ptr = ptr->more; } ptr->more = NULL; ptr->starttime = start; ptr->endtime = end; ptr->days = wildDays; ptr->months = 1 << ( (sels[i])[0].month - 1); ptr->year = (sels[i])[0].year; ptr->dates = 0; for ( j = 0; (sels[i])[j].day != 0; j++ ) ptr->dates |= 1 << ( (sels[i])[j].day - 1); } new->info->desc = (char *) XtMalloc( strlen( ofni->desc ) + 1 ); /* bug */ memmove( new->info->desc, ofni->desc, strlen( ofni->desc ) + 1 ); new->info->activity = ofni->activity; new->info->scheduled = ofni->scheduled; new->info->daylike = ofni->daylike; } /* * Used by cvtEventToSimple to copy a simple event into * a list it is building. Enters it sorted. */ void addSimpToList( simp, list ) simpleEvent *simp, **list; { simpleEvent *temp; simpleEvent *ptr; simpleEvent **lastPtr; temp = (simpleEvent *) XtMalloc( sizeof( simpleEvent ) ); temp->starttime = simp->starttime; temp->endtime = simp->endtime; temp->info = simp->info; if ( *list == NULL ) { *list = temp; temp->next = NULL; return; } ptr = *list; lastPtr = list; while ( ptr != NULL ) if ( (((ptr->starttime.hour * 60) + ptr->starttime.minute) > ((temp->starttime.hour * 60) + temp->starttime.minute )) || ptr->info->daylike < temp->info->daylike ) { temp->next = ptr; *lastPtr = temp; return; } else { lastPtr = &(ptr->next); ptr = ptr->next; } if ( ptr == NULL ) { temp->next = NULL; *lastPtr = temp; } } static int py=0, pm=0, p[42]; getp( year, month ) int year, month; { if ( year != py || month != pm ) { py = year; pm = month; cal( pm, py, p ); } } /* * return day of week (1 - 7) (Sun - Sat) */ int dayof( year, month, day ) { int i; getp( year, month ); for ( i = 0; i < 42; i++ ) if ( p[i] == day ) return ( i%7 + 1 ); } /* * return a calendarselection array containing the days that d occurs * in a given month */ getalldates( e, d, sels, numsels ) event *e; desc *d; CalendarSelection *(sels[]); int *numsels; { int day, dw; date *when; int i = 0, j; int month, year; while ( e != NULL ) { if ( d == e->info ) { when = e->when; while ( when != NULL ) { j = 0; month = first( when->months ); year = when->year; dw = dayof( year, month, 1 ); /* this is scrod in 1752 */ for ( day = 1; day < 32; day++ ) { /* shit... structure being blown away */ if ( sels[i] == NULL ) sels[i] = (CalendarSelection *) XtMalloc( 32 * sizeof( CalendarSelection ) ); if ( matchBits( day, when->dates ) && matchBits( dw, when->days )) { (sels[i])[j].month = month; (sels[i])[j].year = year; (sels[i])[j].day = day; j++; } dw = dw%7 + 1; } (sels[i])[j].month = month; (sels[i])[j].year = year; (sels[i])[j].day = 0; when = when->more; i++; } e = NULL; } else e = e->next; } *numsels = i; } /* * return a calendarselection array containing the days that d occurs * in a given month */ getdates( e, d, year, month, s ) event *e; desc *d; int month, year; CalendarSelection s[]; { int day, dw; date *when; int i = 0; while ( e != NULL ) { if ( d == e->info ) { when = e->when; while ( when != NULL ) { if ( when->year == year || when->year == 0 ) if ( matchBits( month, when->months ) ) { dw = dayof( year, month, 1 ); /* this is scrod in 1752 */ for ( day = 1; day < 32; day++ ) { if ( matchBits( day, when->dates ) && matchBits( dw, when->days )) { s[i].year = year; s[i].month = month; s[i].day = day; i++; } dw = dw%7 + 1; } } when = when->more; } e = NULL; } else e = e->next; } s[i].month = month; s[i].day = 0; s[i].year = year; } /* * Return a list of simpleEvents containing all entries in the * event list e that match to month/day/year. * SimpleEvents are useful structures to higher level routines * that want to print the events for a day; events are in a * slightly difficult format to use, which is why this conversion * abstraction exists. The event structure format is also likely * to change. */ simpleEvent *cvtEventToSimple( e, year, month, day ) event *e; int year, month, day; { simpleEvent *list, s; date *when; list = NULL; while ( e != NULL ) { when = e->when; while ( when != NULL ) { if ( when->year == year || when->year == 0 ) if ( matchBits( month, when->months ) ) if ( matchBits( day, when->dates ) ) if ( matchBits( dayof( year, month, day ), when->days ) ) { s.starttime = when->starttime; s.endtime = when->endtime; s.info = e->info; addSimpToList( &s, &list ); } when = when->more; } e = e->next; } return list; } /* * Free a list of simpleEvents that is not needed anymore. */ freeSimple( s ) simpleEvent *s; { simpleEvent *p; p = s; while ( p != NULL ) { /* don't free description - something else points to it */ XtFree( p ); p = p->next; /* "contents undisturbed" */ } } /* * Free a list of events */ void freeEvents( e ) event **e; { event *p, *q; date *d, *f; p = *e; while ( p != NULL ) { XtFree( p->info->desc ); /* free description text */ XtFree( p->info ); /* free description */ d = p->when; while ( d != NULL ) /* free date list */ { f = d; d = d->more; XtFree( f ); } q = p; p = p->next; XtFree( q ); } *e = NULL; } /* * Debugging routine */ void printSimp( list ) simpleEvent *list; { simpleEvent *here; here = list; while ( here != NULL ) { fprintf( stdout, "%d %d %d\n", here->starttime.hour, here->starttime.minute, here->starttime.second ); if ( here->info->desc != NULL ) fprintf( stdout, "%s\n", here->info->desc ); here = here->next; } } void timeToStr( t, str ) CalTime t; char *str; { char ap[] = {' ','m','\0'}; int h; if ( !ampm ) sprintf( str, "%02d:%02d", t.hour, t.minute ); else { h = t.hour; if ( h < 12 ) { if ( h == 0 ) h = 12; ap[0] = 'a'; } else { ap[0] = 'p'; if ( h > 12 ) h -= 12; } sprintf( str, "%2d:%02d %s", h, t.minute, ap ); } } char *suffix( d ) int d; { static char *suff[] = { "st", "nd", "rd", "th",}; if ( d > 9 && d < 21 ) return suff[3]; if ( ((d-1)%10) > 2 ) return suff[3]; return suff[(d%10) - 1]; } char *smon1[]= { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", }; char *month( i ) int i; { return smon1[i - 1]; } void getTimeNum( s, n ) char **s; int *n; { char *e; int q; while ( isspace( **s ) ) (*s)++; e = *s; q = 0; while ( isdigit( *e ) ) { q = 10*q + ( *e - '0' ); e++; } if ( e == *s ) q = -1; *n = q; *s = e; while ( isspace( **s ) ) (*s)++; if ( **s == ':' ) (*s)++; } void strToTime( s, t ) char *s; CalTime *t; { int spec = 0; getTimeNum( &s, &t->hour ); getTimeNum( &s, &t->minute ); getTimeNum( &s, &t->second ); if ( t->minute == -1 ) t->minute = 0; if ( t->second == -1 ) t->second = 0; if ( (islower( *s ) ? toupper( *s ) : *s) == 'P' ) { if ( t->hour < 12 ) t->hour += 12; spec = 1; } if ( (islower( *s ) ? toupper( *s ) : *s) == 'A' ) { if ( t->hour > 11 ) t->hour -= 12; spec = 1; /* if they said 15:00AM, tough */ } if ( !spec && assume_day ) if ( t->hour < 8 ) t->hour += 12; } /* #ifdef STAND main() { event *events; simpleEvent *simp; events = NULL; addFileToEvents( filename, &events ); simp = cvtEventToSimple( events, 1573, 9, 2 ); printSimp( simp ); } #endif */