jbr0@cbnews.att.com (joseph.a.brownlee) (03/14/91)
#!/bin/sh # This is part 05 of a multipart archive # ============= protos.h ============== if test -f 'protos.h' -a X"$1" != X"-c"; then echo 'x - skipping protos.h (File already exists)' else echo 'x - extracting protos.h (Text)' sed 's/^X//' << 'SHAR_EOF' > 'protos.h' && /* X * protos.h - ANSI-style function prototypes for Pcal sources X * X * Revision history: X * X * 4.0 AWR 03/01/91 use <stdlib.h> where possible X * X * AWR 02/19/91 adapted from Bill Hogsett's source X * X */ X X /* X * Prototypes for functions defined in exprpars.c: X */ int parse_expr(char *pbuf); X X /* X * Prototypes for functions defined in moonphas.c: X */ double calc_phase(int month, int day, int year); double find_phase(int month, int day, int year, int *pquarter); char *find_moonfile(int year); int read_moonfile(int year); X X /* X * Prototypes for functions defined in pcal.c: X */ FILE *alt_fopen(char *fullpath, char *name, char *pathlist[], char *access); char *color_msg(void); int get_args(char **argv, int curr_pass, char *where); FLAG_USAGE *get_flag(char flag); int main(int argc, char **argv); void set_color(char *day, int col); void usage(FILE *fp, int fullmsg); X X /* X * Prototypes for functions defined in pcalutil.c: X */ char *alloc(int size); int calc_day(int ord, int wkd, int mm); int calc_weekday(int mm, int dd, int yy); int calc_year_day(int ord, int wkd, DATE *pdate); int ci_strcmp(register char *s1, register char *s2); int ci_strncmp(register char *s1, register char *s2, int n); void copy_text(char *pbuf, char **ptext); int getline(FILE *fp, int *pline); int is_valid(register int m, register int d, register int y); int loadwords(void); char *mk_filespec(char *filespec, char *path, char *name); char *mk_path(char *path, char *filespec); void normalize(DATE *pd); int split_date(char *pstr, int *pn1, int *pn2, int *pn3); char *trnlog(char *logname); X X /* X * Prototypes for functions defined in readfile.c: X */ void cleanup(void); void clear_syms(void); int date_type(char *cp, int *pn, int *pv); int do_define(char *sym); int do_ifdef(char *expr); int do_ifndef(char *expr); int do_include(char *path, char *name); int do_undef(char *sym); int enter_day_info(int m, int d, int y, int text_type, char **pword); int find_sym(char *sym); year_info *find_year(int year, int insert); int get_keywd(char *cp); int get_month(char *cp, int numeric_ok, int year_ok); int get_ordinal(char *cp, int *pval); int get_prep(char *cp); int get_token(char *token); int get_weekday(char *cp, int wild_ok); int is_anyday(int mm, int dd, int yy); int is_holiday(int mm, int dd, int yy); int is_weekday(int mm, int dd, int yy); int is_workday(int mm, int dd, int yy); int not_holiday(int mm, int dd, int yy); int not_weekday(int mm, int dd, int yy); int not_workday(int mm, int dd, int yy); int parse(char **pword, char *filename); int parse_date(char **pword, int *ptype, char ***pptext); int parse_ord(int ord, int val, char **pword); int parse_rel(int wkd, char **pword, int *ptype, char ***pptext); void read_datefile(FILE *fp, char *filename); X X /* X * Prototypes for functions defined in writefil.c: X */ void def_footstring(char *p, char c); void find_daytext(int month, int year, int is_holiday); void find_holidays(int month, int year); void print_julian_info(int month, int year); void print_month(int month, int year); void print_moon_info(int month, int year); void print_text(char *p); char *print_word(char *p); void write_psfile(int month, int year, int nmonths); X X /* X * Prototypes for miscellaneous library routines (if not already included X * via <stdlib.h> - cf. pcaldefs.h): X */ #ifndef STDLIB extern int atoi(char *); extern char *calloc(unsigned int, unsigned int); extern char *getenv(char *); #endif SHAR_EOF chmod 0666 protos.h || echo 'restore of protos.h failed' Wc_c="`wc -c < 'protos.h'`" test 3428 -eq "$Wc_c" || echo 'protos.h: original size 3428, current size' "$Wc_c" fi # ============= readfile.c ============== if test -f 'readfile.c' -a X"$1" != X"-c"; then echo 'x - skipping readfile.c (File already exists)' else echo 'x - extracting readfile.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'readfile.c' && /* X * readfile.c - Pcal routines concerned with reading and parsing the datefile X * X * Contents: X * X * cleanup X * clear_syms X * date_type X * do_define X * do_ifdef X * do_ifndef X * do_include X * do_undef X * enter_day_info X * find_sym X * find_year X * get_keywd X * get_month X * get_ordinal X * get_prep X * get_token X * get_weekday X * is_anyday X * is_holiday X * is_weekday X * is_workday X * not_holiday X * not_weekday X * not_workday X * parse X * parse_date X * parse_ord X * parse_rel X * read_datefile X * X * Revision history: X * X * 4.0 AWR 02/19/91 Support negative ordinals X * X * AWR 02/06/91 Support expressions in "if{n}def" X * X * AWR 02/04/91 Support "even" and "odd" ordinals X * and ordinals > 5th; support "year" X * X * AWR 01/15/91 Extracted from pcal.c X * X */ X /* X * Standard headers: X */ X #include <stdio.h> #include <string.h> #include <ctype.h> X /* X * Pcal-specific definitions: X */ X #include "pcaldefs.h" #include "pcalglob.h" #include "pcallang.h" X /* X * Macros: X */ X /* status codes returned by parse(), enter_day_info() */ #define PARSE_OK 0 /* successful date parse */ #define PARSE_INVDATE 1 /* nonexistent date */ #define PARSE_INVLINE 2 /* syntax error */ X /* append date to list; terminate list */ #define ADD_DATE(m, d, y) pdate->mm = m, pdate->dd = d, pdate++->yy = y #define TERM_DATES pdate->mm = pdate->dd = pdate->yy = 0 X /* X * Globals: X */ X static DATE dates[MAX_DATES+1]; /* array of date structures */ static char *pp_sym[MAX_PP_SYMS]; /* preprocessor defined symbols */ X X /* X * read_datefile - read and parse date file, handling preprocessor lines X * X * This is the main routine of this module. It calls getline() to read each X * non-null line (stripped of leading blanks and trailing comments), loadwords() X * to "tokenize" it, and get_token() to classify it as a preprocessor directive X * or "other". A switch{} statement takes the appropriate action for each X * token type; "other" lines are further classified by parse() (q.v.) which X * calls parse_date() (q.v.) to parse date entries and enter them in the data X * structure (as described in pcaldefs.h). X * X */ #ifdef PROTOS void read_datefile(FILE *fp, X char *filename) #else void read_datefile(fp, filename) X FILE *fp; /* file pointer (assumed open) */ X char *filename; /* file name (for error messages) */ #endif { X static int file_level = 0; X int if_level = 0; X int restart_level = 0; X int line = 0; X int processing = TRUE; X X int pptype, extra, ntokens, save_year, expr; X int (*pfcn)(); X char *ptok; X char **pword; X char msg[STRSIZ], incpath[STRSIZ]; X X if (fp == NULL) /* whoops, no date file */ X return; X X if (++file_level > MAX_NESTING) { /* nesting too deep? */ X ERR(E_NESTING); X exit(EXIT_FAILURE); X } X X save_year = curr_year; /* save default year */ X X /* read lines until EOF */ X X while (getline(fp, &line)) { X X ntokens = loadwords(); /* split line into tokens */ X pword = words; /* point to the first */ X X /* get token type and pointers to function and name */ X X pptype = get_token(*pword++); X pfcn = pp_info[pptype].pfcn; X ptok = pp_info[pptype].name; X X switch (pptype) { X X case PP_DEFINE: X case PP_UNDEF: X if (processing) X (void) (*pfcn)(*pword); X extra = ntokens > 2; X break; X X case PP_ELSE: X if (if_level < 1) { X ERR(E_ELSE_ERR); X break; X } X X if (processing) { X processing = FALSE; /* disable processing */ X restart_level = if_level; X } X else X if (if_level == restart_level) { X processing = TRUE; /* re-enable processing */ X restart_level = 0; X } X extra = ntokens > 1; X break; X X case PP_ENDIF: X if (if_level < 1) { X ERR(E_END_ERR); X break; X } X X if (! processing && if_level == restart_level) { X processing = TRUE; /* re-enable processing */ X restart_level = 0; X } X if_level--; X extra = ntokens > 1; X break; X X case PP_IFDEF: X case PP_IFNDEF: X if_level++; X if (processing) { X copy_text(lbuf, pword); /* reconstruct string */ X if ((expr = (*pfcn)(lbuf)) == EXPR_ERR) { X ERR(E_EXPR_SYNTAX); X expr = FALSE; X } X if (! expr) { /* disable processing */ X processing = FALSE; X restart_level = if_level; X } X } X extra = FALSE; X break; X X case PP_INCLUDE: X if (processing) X do_include(mk_path(incpath, filename), *pword); X extra = ntokens > 2; X break; X X case PP_OTHER: /* none of the above - parse as date */ X if (processing) { X switch (parse(words, filename)) { X X case PARSE_INVDATE: X ERR(E_INV_DATE); X break; X X case PARSE_INVLINE: X ERR(E_INV_LINE); X break; X X } X } X extra = FALSE; X break; X X } /* end switch */ X X if (extra) { /* extraneous data? */ X sprintf(msg, E_GARBAGE, ptok); X ERR(msg); X } X X } /* end while */ X X if (if_level > 0) X FPR(stderr, E_UNT_IFDEF, progname, filename); X X file_level--; X curr_year = save_year; /* restore default year */ } X X /* X * Routines to free allocated data (symbol table and data structure) X */ X X /* X * clear_syms - clear and deallocate the symbol table X */ #ifdef PROTOS void clear_syms(void) #else void clear_syms() #endif { X int i; X X for (i = 0; i < MAX_PP_SYMS; i++) X if (pp_sym[i]) { X free(pp_sym[i]); X pp_sym[i] = NULL; X } } X X /* X * cleanup - free all allocated data X */ #ifdef PROTOS void cleanup(void) #else void cleanup() #endif { X int i, j; X year_info *py, *pny; X month_info *pm; X day_info *pd, *pnd; X X for (py = head; py; py = pny) { /* main data structure */ X pny = py->next; X for (i = 0; i < 12; i++) { X if ((pm = py->month[i]) == NULL) X continue; X for (j = 0; j < NOTE_DAY; j++) X for (pd = pm->day[j]; pd; pd = pnd) { X pnd = pd->next; X free(pd->text); X free(pd); X } X free(pm); X } X free(py); X } X X clear_syms(); /* symbol table */ X } X X /* X * Preprocessor token and symbol table routines X */ X X /* X * find_sym - look up symbol; return symbol table index if found, PP_SYM_UNDEF X * if not found X */ #ifdef PROTOS int find_sym(char *sym) #else int find_sym(sym) X char *sym; #endif { X int i; X X if (!sym) X return PP_SYM_UNDEF; X X for (i = 0; i < MAX_PP_SYMS; i++) X if (pp_sym[i] && ci_strcmp(pp_sym[i], sym) == 0) X return i; X X return PP_SYM_UNDEF; } X X /* X * do_ifdef - return TRUE if 'expr' is true; FALSE if not; EXPR_ERR if invalid X */ #ifdef PROTOS int do_ifdef(char *expr) #else int do_ifdef(expr) X char *expr; #endif { X return parse_expr(expr); } X X /* X * do_ifndef - return FALSE if 'expr' is true; TRUE if not; EXPR_ERR if invalid X */ #ifdef PROTOS int do_ifndef(char *expr) #else int do_ifndef(expr) X char *expr; #endif { X int val; X X return (val = parse_expr(expr)) == EXPR_ERR ? EXPR_ERR : ! val; } X X /* X * do_define - enter 'sym' into symbol table; if 'sym' NULL, clear symbol table. X * Always returns 0 (for compatibility with other dispatch functions). X */ #ifdef PROTOS int do_define(char *sym) #else int do_define(sym) X char *sym; #endif { X int i; X X if (! sym) { /* null argument - clear all definitions */ X clear_syms(); X return 0; X } X X if (do_ifdef(sym)) /* already defined? */ X return 0; X X for (i = 0; i < MAX_PP_SYMS; i++) /* find room for it */ X if (! pp_sym[i]) { X strcpy(pp_sym[i] = alloc(strlen(sym)+1), sym); X return 0; X } X X FPR(stderr, E_SYMFULL, progname, sym); X return 0; } X X /* X * do_undef - undefine 'sym' and free its space; no error if not defined. X * Always return 0 (for compatibility with other dispatch fcns). X */ #ifdef PROTOS int do_undef(char *sym) #else int do_undef(sym) X char *sym; #endif { X int i; X X if (! sym) X return 0; X X if ((i = find_sym(sym)) != PP_SYM_UNDEF) { X free(pp_sym[i]); X pp_sym[i] = NULL; X } X X return 0; } X X /* X * do_include - include specified file (optionally in "" or <>); always X * returns 0 (for compatibility with related functions returning int) X */ #ifdef PROTOS int do_include(char *path, X char *name) #else int do_include(path, name) X char *path; /* path to file */ X char *name; /* file name */ #endif { X FILE *fp; X char *p, incfile[STRSIZ], tmpnam[STRSIZ]; X X if (! name) /* whoops, no date file */ X return 0; X X /* copy name, stripping "" or <> */ X strcpy(tmpnam, name + (*name == '"' || *name == '<')); X if ((p = P_LASTCHAR(tmpnam)) && *p == '"' || *p == '>') X *p = '\0'; X X if ((fp = fopen(mk_filespec(incfile, path, tmpnam), "r")) == NULL) { X FPR(stderr, E_FOPEN_ERR, progname, incfile); X exit(EXIT_FAILURE); X } X X read_datefile(fp, incfile); /* recursive call */ X fclose(fp); X X return 0; } X X X /* X * Dispatch functions for wildcard matching X */ X X /* X * is_anyday - dummy function which always returns TRUE X */ #ifdef PROTOS int is_anyday(int mm, X int dd, X int yy) #else int is_anyday(mm, dd, yy) X int mm; X int dd; X int yy; #endif { X return TRUE; } X X /* X * is_weekday - determine whether or not mm/dd/yy is a weekday (i.e., the X * day of the week normally prints in black) X */ #ifdef PROTOS int is_weekday(int mm, X int dd, X int yy) #else int is_weekday(mm, dd, yy) X int mm; X int dd; X int yy; #endif { X return day_color[calc_weekday(mm, dd, yy)] == BLACK; } X X /* X * is_workday - determine whether or not mm/dd/yy is a workday (i.e., the X * day of the week normally prints in black and the date is not a holiday) X */ #ifdef PROTOS int is_workday(int mm, X int dd, X int yy) #else int is_workday(mm, dd, yy) X int mm; X int dd; X int yy; #endif { X return is_weekday(mm, dd, yy) && ! is_holiday(mm, dd, yy); } X X /* X * is_holiday - determine whether or not mm/dd/yy is a holiday X */ #ifdef PROTOS int is_holiday(int mm, X int dd, X int yy) #else int is_holiday(mm, dd, yy) X int mm; X int dd; X int yy; #endif { X year_info *py; X month_info *pm; X X pm = (py = find_year(yy, FALSE)) ? py->month[mm-1] : NULL; X return pm ? (pm->holidays & (1L << (dd-1))) != 0 : FALSE; } X X /* X * not_XXXXX - converses of is_XXXXX above X */ #ifdef PROTOS int not_weekday(int mm, X int dd, X int yy) #else int not_weekday(mm, dd, yy) X int mm; X int dd; X int yy; #endif { X return !is_weekday(mm, dd, yy); } X X #ifdef PROTOS int not_workday(int mm, X int dd, X int yy) #else int not_workday(mm, dd, yy) X int mm; X int dd; X int yy; #endif { X return !is_workday(mm, dd, yy); } X X #ifdef PROTOS int not_holiday(int mm, X int dd, X int yy) #else int not_holiday(mm, dd, yy) X int mm; X int dd; X int yy; #endif { X return !is_holiday(mm, dd, yy); } X X X /* X * Keyword classification routines X */ X /* X * get_month - convert alpha (or, optionally, numeric) string to month; return X * 1..12 if valid, NOT_MONTH if not, ALL_MONTHS if "all", ENTIRE_YEAR if "year" X */ #ifdef PROTOS int get_month(char *cp, X int numeric_ok, X int year_ok) #else int get_month(cp, numeric_ok, year_ok) X char *cp; /* string to convert */ X int numeric_ok; /* accept numeric string ? */ X int year_ok; /* accept "year"? */ #endif { X int mm; X X if (! cp) X return NOT_MONTH; X X if (get_keywd(cp) == DT_ALL) X return ALL_MONTHS; X X if (year_ok && get_keywd(cp) == DT_YEAR) X return ENTIRE_YEAR; X X if (numeric_ok && isdigit(*cp)) X mm = atoi(cp); X else X for (mm = JAN; X mm <= DEC && ci_strncmp(cp, months[mm-1], MIN_MONTH_LEN); X mm++) X ; X X return mm >= JAN && mm <= DEC ? mm : NOT_MONTH; } X X /* X * get_weekday - look up string in weekday list; return 0-6 if valid, X * NOT_WEEKDAY if not. If wild_ok flag is set, accept "day", "weekday", X * "workday", or "holiday" and return appropriate value. X */ #ifdef PROTOS int get_weekday(char *cp, X int wild_ok) #else int get_weekday(cp, wild_ok) X char *cp; X int wild_ok; #endif { X int w; X X if (!cp) X return NOT_WEEKDAY; X X if (wild_ok) { /* try wildcards first */ X for (w = WILD_FIRST; w <= WILD_LAST; w++) X if (ci_strncmp(cp, days[w], strlen(days[w])) == 0) X return w; X } X X for (w = SUN; w <= SAT; w++) X if (ci_strncmp(cp, days[w], MIN_DAY_LEN) == 0) X return w; X X return NOT_WEEKDAY; } X X /* X * get_keywd - look up string in misc. keyword list; return keyword code X * if valid, DT_OTHER if not X */ #ifdef PROTOS int get_keywd(char *cp) #else int get_keywd(cp) X char *cp; #endif { X KWD *k; X X if (!cp) X return DT_OTHER; X X for (k = keywds; X k->name && ci_strncmp(cp, k->name, strlen(k->name)); X k++) X ; X X return k->code; } X X /* X * get_ordinal - look up string in ordinal list; return ordinal code (and X * fill in ordinal value) if valid, return ORD_OTHER if not X */ #ifdef PROTOS int get_ordinal(char *cp, X int *pval) #else int get_ordinal(cp, pval) X char *cp; X int *pval; #endif { X KWD_O *o; X int val; X char **psuf; X X if (!cp) X return ORD_OTHER; X X if (isdigit(*cp) || *cp == '-') { /* numeric? */ X if ((val = atoi(cp)) == 0) X return ORD_OTHER; X X if (*cp == '-') /* skip over number */ X cp++; X cp += strspn(cp, DIGITS); X X for (psuf = ord_suffix; *psuf; psuf++) /* find suffix */ X if (ci_strcmp(cp, *psuf) == 0) { X *pval = val; X return val < 0 ? ORD_NEGNUM : ORD_POSNUM; X } X X return ORD_OTHER; X } X X /* look for word in ordinals list */ X X for (o = ordinals; o->name && ci_strncmp(cp, o->name, MIN_ORD_LEN); o++) X ; X X *pval = o->value; X return o->code; } X X /* X * get_prep - look up string in preposition list; return preposition code if X * valid, PR_OTHER if not X */ #ifdef PROTOS int get_prep(char *cp) #else int get_prep(cp) X char *cp; #endif { X KWD *p; X X if (!cp) X return PR_OTHER; X X for (p = preps; p->name && ci_strncmp(cp, p->name, MIN_PREP_LEN); p++) X ; X X return p->code; } X X /* X * get_token - look up 'token' in list of preprocessor tokens; return its X * index if found, PP_OTHER if not X */ #ifdef PROTOS int get_token(char *token) #else int get_token(token) X char *token; #endif { X KWD_F *p; X X for (p = pp_info; X p->name && ci_strncmp(token, p->name, MIN_PPTOK_LEN); X p++) X ; X X return p->code; } X X /* X * date_type - examine token and return date type code; if DT_MONTH, DT_ORDINAL, X * or DT_WEEKDAY, fill in appropriate code (and value if DT_ORDINAL) X */ #ifdef PROTOS int date_type(char *cp, X int *pn, X int *pv) #else int date_type(cp, pn, pv) X char *cp; /* pointer to start of token */ X int *pn; /* token type code (returned) */ X int *pv; /* ordinal value (returned) */ #endif { X int n, v; X X if ((n = get_ordinal(cp, &v)) != ORD_OTHER) /* ordinal? */ X return (*pn = n, *pv = v, DT_ORDINAL); X X if (isdigit(*cp)) /* other digit? */ X return IS_NUMERIC(cp) ? DT_EURDATE : DT_DATE; X X if ((n = get_weekday(cp, TRUE)) != NOT_WEEKDAY) /* weekday name? */ X return (*pn = n, DT_WEEKDAY); X X /* "all" can be either a keyword or a month wildcard - look for X the former usage first */ X X if ((n = get_keywd(cp)) != DT_OTHER) X return n; X X if ((n = get_month(cp, FALSE, FALSE)) != NOT_MONTH) /* month name? */ X return (*pn = n, DT_MONTH); X X return DT_OTHER; /* unrecognized keyword - give up */ X } X X X /* X * Routines for entering data in the data structure (described in pcaldefs.h) X */ X X /* X * find_year - find record in year list; optionally create if not present X */ #ifdef PROTOS year_info *find_year(int year, X int insert) #else year_info *find_year(year, insert) /* find record in year list */ X int year; X int insert; /* insert if missing */ #endif { X year_info *pyear, *plast, *p; X X for (plast = NULL, pyear = head; /* search linked list */ X pyear && pyear->year < year; X plast = pyear, pyear = pyear->next) X ; X X if (pyear && pyear->year == year) /* found - return it */ X return pyear; X X if (insert) { /* not found - insert it if requested */ X p = (year_info *) alloc((int) sizeof(year_info)); /* create new record */ X p->year = year; X X p->next = pyear; /* link it in */ X return *(plast ? &plast->next : &head) = p; X } X else X return NULL; } X X /* X * enter_day_info - enter text for specified day; avoid entering duplicates. X * Returns PARSE_INVDATE if date invalid, PARSE_OK if OK; if symbol FEB_29_OK X * is non-zero (cf. pcaldefs.h), will silently ignore Feb 29 of common year. X */ #ifdef PROTOS int enter_day_info(int m, X int d, X int y, X int text_type, X char **pword) #else int enter_day_info(m, d, y, text_type, pword) /* fill in information for given day */ X int m, d, y; X int text_type; X char **pword; #endif { X static year_info *pyear; X static int prev_year = 0; X month_info *pmonth; X day_info *pday, *plast; X int is_holiday = text_type == HOLIDAY_TEXT; X char text[LINSIZ]; X X if (! is_valid(m, d == NOTE_DAY && text_type == NOTE_TEXT ? 1 : d, y)) X return (m == FEB && d == 29 && FEB_29_OK) ? PARSE_OK : PARSE_INVDATE; X X if (y != prev_year) /* avoid unnecessary year lookup */ X pyear = find_year(y, 1); X X --m, --d; /* adjust for use as subscripts */ X X if ((pmonth = pyear->month[m]) == NULL) /* find/create month record */ X pyear->month[m] = pmonth = (month_info *) alloc((int) sizeof(month_info)); X X if (is_holiday) X pmonth->holidays |= (1L << d); X X /* insert text for day at end of list (preserving the order of entry X * for multiple lines on same day); eliminate those differing only X * in spacing and capitalization from existing entries X */ X X copy_text(text, pword); /* consolidate text from lbuf into text */ X #ifdef DATE_DEBUG X { X char *p; X fprintf(stderr, "%02d/%02d/%d%c '", m+1, d+1, y, is_holiday ? '*' : ' '); X for (p = text; *p; p++) X fprintf(stderr, isprint(*p) ? "%c" : "\\%03o", *p & 0377); X fprintf(stderr, "'\n"); X } #endif X X if (*text) { X for (plast = NULL, pday = pmonth->day[d]; X pday; X plast = pday, pday = pday->next) X if (ci_strcmp(pday->text, text) == 0) { X pday->is_holiday |= is_holiday; X return PARSE_OK; X } X X /* unique - add to end of list */ X X pday = (day_info *) alloc(sizeof(day_info)); X pday->is_holiday = is_holiday; X strcpy(pday->text = (char *) alloc(strlen(text)+1), text); X pday->next = NULL; X *(plast ? &plast->next : &pmonth->day[d]) = pday; X } X X return PARSE_OK; } X X X /* X * Date parsing routines: X */ X X /* X * parse_ord - parse an ordinal date spec (e.g. "first Monday in September", X * "every Sunday in October", "last workday in all"); return PARSE_OK if line X * syntax valid, PARSE_INVLINE if not. Write all matching dates (if any) to X * global array dates[]; terminate date list with null entry. X */ #ifdef PROTOS int parse_ord(int ord, X int val, X char **pword) #else int parse_ord(ord, val, pword) X int ord; /* valid ordinal code - from get_ordinal() */ X int val; /* ordinal value - also from get_ordinal() */ X char **pword; /* pointer to word after ordinal */ #endif { X int wkd, mon, mm, dd, len, (*pfcn)(), doit; X int val_first, val_last, val_incr, mon_first, mon_last; X DATE *pdate, date; X X if ((wkd = get_weekday(*pword, TRUE)) == NOT_WEEKDAY || /* weekday */ X *++pword == NULL || /* any word */ X (mon = get_month(*++pword, FALSE, TRUE)) == NOT_MONTH) /* month */ X return PARSE_INVLINE; X X /* set up loop boundaries for month loop */ X X mon_first = mon == ALL_MONTHS || mon == ENTIRE_YEAR ? JAN : mon; X mon_last = mon == ALL_MONTHS || mon == ENTIRE_YEAR ? DEC : mon; X X pdate = dates; /* start of date array */ X X /* special case of "all|odd|even <wildcard> in <month>|all|year" */ X X if ((ord == ORD_ALL || ord == ORD_EVEN || ord == ORD_ODD) && X IS_WILD(wkd)) { X pfcn = pdatefcn[wkd - ANY_DAY]; X doit = ord != ORD_EVEN; X for (mm = mon_first; mm <= mon_last; mm++) { X len = LENGTH_OF(mm, curr_year); X if (mon != ENTIRE_YEAR) X doit = ord != ORD_EVEN; X for (dd = 1; dd <= len; dd++) X if ((*pfcn)(mm, dd, curr_year)) { X if (doit) X ADD_DATE(mm, dd, curr_year); X if (ord != ORD_ALL) X doit = ! doit; X } X } X } X X /* special case of "odd|even <weekday> in year" */ X X else if ((ord == ORD_EVEN || ord == ORD_ODD) && mon == ENTIRE_YEAR) { X date.mm = JAN; /* starting date */ X date.dd = calc_day(ord == ORD_EVEN ? 2 : 1, wkd, JAN); X date.yy = curr_year; X do { /* alternates throughout year */ X ADD_DATE(date.mm, date.dd, date.yy); X date.dd += 14; X normalize(&date); X } while (date.yy == curr_year); X } X X /* special case of "<ordinal>|last <weekday>|<wildcard> in year" */ X X else if ((ord == ORD_NEGNUM || ord == ORD_POSNUM) && X mon == ENTIRE_YEAR) { X if (calc_year_day(val, wkd, &date)) X ADD_DATE(date.mm, date.dd, date.yy); X } X X /* all other combinations of ordinal and day */ X X else { X /* set up loop boundaries for "wildcard" ordinals */ X X val_first = ord == ORD_ALL || ord == ORD_ODD ? 1 : X ord == ORD_EVEN ? 2 : val; X val_last = ord == ORD_ALL || ord == ORD_ODD ? 5 : X ord == ORD_EVEN ? 4 : val; X val_incr = ord == ORD_ODD || ord == ORD_EVEN ? 2 : 1; X X for (mm = mon_first; mm <= mon_last; mm++) X for (val = val_first; val <= val_last; val += val_incr) X if ((dd = calc_day(val, wkd, mm)) != 0) X ADD_DATE(mm, dd, curr_year); X } X X TERM_DATES; /* terminate array with null entry */ X return PARSE_OK; X } X X /* X * parse_rel - parse a relative date spec (e.g. "Friday after fourth Thursday X * in November", "Saturday after first Friday in all"; return PARSE_OK if X * line syntax valid, PARSE_INVLINE if not. Transform all dates that match X * the base date to the appropriate day, month, and year. X * X * This calls parse_date() recursively in order to handle cases such as X * "Friday after Tuesday before last day in all". X */ #ifdef PROTOS int parse_rel(int wkd, X char **pword, X int *ptype, X char ***pptext) #else int parse_rel(wkd, pword, ptype, pptext) X int wkd; /* valid weekday code - from get_weekday() */ X char **pword; /* pointer to word after weekday */ X int *ptype; /* return text type (holiday/non-holiday) */ X char ***pptext; /* return pointer to first word of text */ #endif { X int prep, rtn, base_wkd, incr, (*pfcn)(); X DATE *pd; X X /* we have the weekday - now look for the preposition */ X if ((prep = get_prep(*pword++)) == PR_OTHER) X return PARSE_INVLINE; X X /* get the base date */ X if ((rtn = parse_date(pword, ptype, pptext)) != PARSE_OK) X return rtn; X X /* transform date array in place - note that the relative date may X not be in the same month or even year */ X X if (IS_WILD(wkd)) { /* wildcard for weekday name? */ X pfcn = pdatefcn[wkd - ANY_DAY]; X incr = prep == PR_BEFORE || prep == PR_ON_BEFORE ? -1 : 1; X X for (pd = dates; pd->mm; pd++) { X /* search for nearest matching date */ X X if (prep == PR_BEFORE || prep == PR_AFTER) { X pd->dd += incr; X normalize(pd); X } X while (!(*pfcn)(pd->mm, pd->dd, pd->yy)) { X pd->dd += incr; X normalize(pd); X } X } X X } else { /* explicit weekday name */ X for (pd = dates; pd->mm; pd++) { X /* calculate nearest matching date */ X X base_wkd = calc_weekday(pd->mm, pd->dd, pd->yy); X X if (prep == PR_BEFORE || X (prep == PR_ON_BEFORE && wkd != base_wkd)) X pd->dd -= 7 - (wkd - base_wkd + 7) % 7; X X if (prep == PR_AFTER || X (prep == PR_ON_AFTER && wkd != base_wkd)) X pd->dd += (wkd - base_wkd + 6) % 7 + 1; X X normalize(pd); /* adjust for month/year crossing */ X } X } X X return PARSE_OK; } X X /* X * parse_date - parse a date specification in any of its myriad forms; upon X * return, array dates[] will contain a list of all the dates that matched, X * terminated by a null entry. Also fill in the date type (holiday/non- X * holiday) code and the pointer to the first word of text. X */ #ifdef PROTOS int parse_date(char **pword, X int *ptype, X char ***pptext) #else int parse_date(pword, ptype, pptext) X char **pword; /* first word to parse */ X int *ptype; /* return date type (holiday/non-holiday) */ X char ***pptext; /* return pointer to first word of text */ #endif { X int mm, dd, yy; X int token, n, v, ord, val, wkd, rtn; X DATE *pdate; X char *cp; X X pdate = dates; X X switch (token = date_type(*pword, &n, &v)) { X X case DT_MONTH: /* <month> dd */ X if (date_style != USA_DATES) X return PARSE_INVLINE; X X if ((cp = *++pword) == NULL) X return PARSE_INVLINE; X X ADD_DATE(n, atoi(cp), curr_year); X TERM_DATES; X X break; X X case DT_DATE: /* mm/dd{/yy} | dd/mm{/yy} */ X n = split_date(*pword, X date_style == USA_DATES ? &mm : &dd, X date_style == USA_DATES ? &dd : &mm, X &yy); X X if (n > 2) { /* year present? */ X if (yy < 100) X yy += CENTURY; X curr_year = yy; /* reset current year */ X } X X ADD_DATE(mm, dd, curr_year); X TERM_DATES; X X break; X X case DT_EURDATE: /* dd [ <month> | "all" ] */ X if (date_style != EUR_DATES) X return PARSE_INVLINE; X X dd = atoi(*pword); X X if (get_keywd(*++pword) == DT_ALL) { X for (mm = JAN; mm <= DEC; mm++) /* wildcard */ X ADD_DATE(mm, dd, curr_year); X } X else { /* one month */ X if ((mm = get_month(*pword, FALSE, FALSE)) == NOT_MONTH) X return PARSE_INVLINE; X X ADD_DATE(mm, dd, curr_year); X } X X TERM_DATES; X break; X X case DT_ALL: /* "all" <weekday> "in" [ <month> | "all" ] */ X /* or "all" <day>" */ X X if ((cp = *(pword+1)) && (*(cp += strspn(cp, DIGITS)) == '\0' || X *cp == '*')) { X dd = atoi(*++pword); /* "all" <day> */ X for (mm = JAN; mm <= DEC; mm++) X ADD_DATE(mm, dd, curr_year); X TERM_DATES; X break; /* leave switch */ X } X X n = ORD_ALL; /* "all" <weekday> ... */ X v = 0; X /* fall through */ X X case DT_ORDINAL: /* <ordinal> <weekday> in [ <month> | "all" ] */ X ord = n; X val = v; X if ((rtn = parse_ord(ord, val, pword + 1)) != PARSE_OK) X return rtn; X X pword += 3; /* last word of date */ X break; X X case DT_WEEKDAY: /* <weekday> <prep> <date> */ X wkd = n; X X /* parse_rel() calls parse_date() recursively */ X return parse_rel(wkd, ++pword, ptype, pptext); X break; X X default: X return PARSE_INVLINE; X break; X } X X /* at this point, pword points to the last component of the date; X * fill in type code and pointer to following word (start of text) X */ X *ptype = LASTCHAR(*pword) == '*' ? HOLIDAY_TEXT : DAY_TEXT; X *pptext = ++pword; X X return PARSE_OK; } X /* X * parse - parse non-preprocessor lines in date file X * X * This routine parses "year", "opt", "note", and date entries in the date X * file. It calls parse_date() to parse date entries (and enter the date(s) X * matched in global array "dates"), and then calls enter_day_info() to X * enter each date found (and its associated text) in the date file. X * X * N.B.: "inc" and other cpp-like lines are handled in read_datefile(). X * X */ #ifdef PROTOS int parse(char **pword, X char *filename) #else int parse(pword, filename) X char **pword; /* pointer to first word to parse */ X char *filename; /* name of file (for error messages) */ #endif { X register char *cp; X char **ptext; X int mm, yy; X int text_type, n, v, rtn, match; X int token; X DATE *pd; X X /* X * Get first field and call date_type() to decode it X */ X cp = *pword; X X switch (token = date_type(cp, &n, &v)) { X X case DT_YEAR: X if ((cp = *++pword) != NULL && (yy = atoi(cp)) > 0) { X if (yy < 100) X yy += CENTURY; X curr_year = yy; X return PARSE_OK; X } X return PARSE_INVLINE; /* year missing or non-numeric */ X break; X X case DT_OPT: X if (!get_args(pword, P_OPT, filename)) { X usage(stderr, FALSE); X exit(EXIT_FAILURE); X } X return PARSE_OK; X break; X X case DT_NOTE: X if ((mm = get_month(*++pword, TRUE, TRUE)) == NOT_MONTH) X return PARSE_INVLINE; X X if (mm == ALL_MONTHS || mm == ENTIRE_YEAR) /* "note all"? */ X for (mm = JAN; mm <= DEC; mm++) X enter_day_info(mm, NOTE_DAY, curr_year, X NOTE_TEXT, pword+1); X else X enter_day_info(mm, NOTE_DAY, curr_year, NOTE_TEXT, X pword+1); X X return PARSE_OK; X break; X X case DT_OTHER: /* unrecognized token */ X return PARSE_INVLINE; X break; X X /* assume anything else is a date */ X X default: X if ((rtn = parse_date(pword, &text_type, &ptext)) == PARSE_OK) { X match = FALSE; /* is at least one date valid? */ X for (pd = dates; pd->mm; pd++) X match |= enter_day_info(pd->mm, pd->dd, pd->yy, X text_type, ptext) == PARSE_OK; X rtn = match ? PARSE_OK : PARSE_INVDATE; X } X return rtn; X break; X X } } SHAR_EOF chmod 0644 readfile.c || echo 'restore of readfile.c failed' Wc_c="`wc -c < 'readfile.c'`" test 27599 -eq "$Wc_c" || echo 'readfile.c: original size 27599, current size' "$Wc_c" fi # ============= writefil.c ============== if test -f 'writefil.c' -a X"$1" != X"-c"; then echo 'x - skipping writefil.c (File already exists)' else echo 'x - extracting writefil.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'writefil.c' && /* X * writefil.c - Pcal routines concerned with writing the PostScript output X * X * Contents: X * X * def_footstring X * find_daytext X * find_holidays X * print_julian_info X * print_month X * print_moon_info X * print_text X * print_word X * write_psfile X * X * Revision history: X * X * 4.0 AWR 01/28/91 Support -B, -w flags and moon file X * X * 01/15/91 Extracted from pcal.c X * X */ X /* X * Standard headers: X */ X #include <stdio.h> #include <ctype.h> X /* X * Pcal-specific definitions: X */ X #include "pcaldefs.h" #include "pcalglob.h" #include "pcallang.h" #include "pcalinit.h" /* PostScript boilerplate */ X /* X * Macros: X */ X /* convert "ph" (approximate quarter moon) to exact quarter moon */ #define EXACT_QUARTER(ph) ((((int) (((ph) + .05) * 4.0)) % 4) / 4.0) X /* make sure printf() doesn't round "ph" up to 1.0 when printing it */ #define PRT_TWEAK(ph) ((ph) >= 0.9995 ? 0.0 : (ph)) X /* X * Globals: X */ X static char *cond[3] = {"false", "true", "(some)"}; X X /* X * write_psfile - write PostScript code to stdout X * X * The actual output of the PostScript code is straightforward. This routine X * writes a PostScript header followed by declarations of all the PostScript X * variables affected by command-line flags and/or language dependencies. It X * the generates the PostScript boilerplate generated from pcalinit.ps, and X * finally calls print_month() to generate the PostScript code for each X * requested month. X */ #ifdef PROTOS void write_psfile(int month, X int year, X int nmonths) #else void write_psfile(month, year, nmonths) X int month; /* starting month */ X int year; /* starting year */ X int nmonths; /* number of months */ #endif { X int i, ngray; X char **ap, tmp[20]; X X /* X * Write out PostScript prolog X */ X X PRT("%%!\n%%\t"); X PRT(VERSION_MSG, progname, version); X if (*datefile) X PRT(DATEFILE_MSG, datefile); X PRT("\n%%\n"); X X /* font names */ X X PRT("/titlefont /%s def\n/dayfont /%s def\n/notesfont /%s def\n", X titlefont, dayfont, notesfont); X X /* foot strings */ X X def_footstring(lfoot, 'L'); X def_footstring(cfoot, 'C'); X def_footstring(rfoot, 'R'); X X /* month names */ X X PRT("/month_names ["); X for (i = JAN; i <= DEC; i++) { X PRT(i % 6 == 1 ? "\n\t" : " "); X (void) print_word(months[i-1]); X } X PRT(" ] def\n"); X X /* day names - abbreviate if printing entire year on page */ X X PRT("/day_names ["); X for (i = SUN; i <= SAT; i++) { X PRT(i % 6 == 0 && ! do_whole_year ? "\n\t" : " "); X strcpy(tmp, days[(i + first_day_of_week) % 7]); X if (do_whole_year) X tmp[MIN_DAY_LEN] = '\0'; X (void) print_word(tmp); X } X PRT(" ] def\n"); X X /* title for "notes" box */ X X PRT("/notesheading ("); X PUTSTR(NOTES_HDR); X PRT(") def\n"); X X /* line separator */ X X PRT("/linesep "); X print_word(LINE_SEP); X PRT(" def\n"); X X /* colors (black/gray) to print weekdays and holidays */ X X PRT("/day_gray ["); X for (ngray = 0, i = SUN; i <= SAT; ngray += day_color[i++] == GRAY) X PRT(" %s", cond[day_color[(i + first_day_of_week) % 7]]); X PRT(" ] def\n"); X PRT("/holiday_gray %s def\n", cond[ngray <= 3]); X X /* rotation, scale, and translate values. */ X X PRT("/rval %d def\n", rotate); X PRT("/xsval %s def\n/ysval %s def\n", xsval, ysval); X PRT("/xtval %s def\n/ytval %s def\n", xtval, ytval); X X /* moon, Julian date, box fill, and outline flags */ X X PRT("/draw-moons %s def\n", cond[draw_moons]); X PRT("/julian-dates %s def\n", cond[julian_dates]); X PRT("/fill-boxes %s def\n", cond[! blank_boxes]); X PRT("/outline %s def\n", cond[outline_nums]); X X /* PostScript boilerplate (part 1 of 1) */ X X for (ap = header; *ap; ap++) X PRT("%s\n", *ap); X PRT("\n"); X X /* X * Write out PostScript code to print calendars X */ X X if (do_whole_year) /* round up to multiple of 12 months */ X nmonths = ((nmonths + 11) / 12) * 12; X X while (nmonths--) { X print_month(month, year); X year = NEXT_YEAR(month, year); X month = NEXT_MONTH(month, year); X } X } X X /* X * low-level utilities for PostScript generation X */ X X /* X * print_word - print a single word, representing parentheses and non-ASCII X * characters as octal literals; return pointer to character following word X * (NULL if no word follows) X */ #ifdef PROTOS char *print_word(char *p) #else char *print_word(p) X char *p; #endif { X char c; X X if (*p == '\0' || *(p += strspn(p, WHITESPACE)) == '\0') X return NULL; X X PRT("("); X for ( ; (c = *p) && !isspace(c); p++) X PUTCHAR(c); X PRT(")"); X X return p; } X X /* X * print_text - print tokens in text (assumed separated by single blank) X * in PostScript format X */ #ifdef PROTOS void print_text(char *p) #else void print_text(p) X char *p; #endif { X X while (p = print_word(p)) X PRT(" "); } X X /* X * def_footstring - print definition for foot string, again converting X * all characters other than letters, digits, or space to octal escape X */ #ifdef PROTOS void def_footstring(char *p, X char c) #else void def_footstring(p, c) X char *p; /* definition */ X char c; /* L, C, or R */ #endif { X X PRT("/%cfootstring (", c); X PUTSTR(p); X PRT(") def\n"); } X X /* X * Routines to extract and print data X */ X X /* X * find_daytext - find and print the day (including notes) or holiday text X * for the specified month/year X */ #ifdef PROTOS void find_daytext(int month, X int year, X int is_holiday) #else void find_daytext(month, year, is_holiday) X int month, year; X int is_holiday; /* TRUE: print holiday text */ #endif { X register int day; X year_info *py; X month_info *pm; X register day_info *pd; X int first; X char *fcn = is_holiday ? "holidaytext" : "daytext"; X X /* if no text for this year and month, return */ X X if ((py = find_year(year, FALSE)) == NULL || X (pm = py->month[month-1]) == NULL) X return; X X /* walk array of day text pointers and linked lists of text */ X X for (day = 1; day <= NOTE_DAY; day++) { X for (pd = pm->day[day-1], first = TRUE; X pd; X pd = pd->next) { X if (pd->is_holiday != is_holiday) X continue; X if (first) { X if (day != NOTE_DAY) /* set up call */ X PRT("%d ", day); X printf("[ \n"); X } X else { X PRT("\n"); X print_word(LINE_SEP); /* separate lines */ X PRT("\n"); X } X print_text(pd->text); X first = FALSE; X } X if (! first) /* wrap up call (if one made) */ X PRT("\n] %s\n", day == NOTE_DAY ? "notetext" : fcn); X } } X X /* X * find_holidays - find and print the note block flag and holidays for X * specified month/year X */ #ifdef PROTOS void find_holidays(int month, X int year) #else void find_holidays(month, year) X int month, year; #endif { X register int day; X register unsigned long holidays; X year_info *py; X month_info *pm; X X pm = (py = find_year(year, FALSE)) ? py->month[month-1] : NULL; X X if (! do_whole_year) X PRT("/note_block %s def\n", cond[pm && pm->day[NOTE_DAY-1]]); X X PRT("/holidays ["); /* start definition of list */ X X for (holidays = pm ? pm->holidays : 0, day = 1; X holidays; X holidays >>= 1, day++) X if (holidays & 01) X PRT(" %d", day); X X PRT(" ] def\n"); X } X X /* X * print_moon_info - print the information necessary to draw moons. If X * printing moons on all days, print the phase for each day; if printing X * only quarter moons, tweak the phase to an exact quarter (so the icon X * is printed correctly) and generate a list of the quarter-moon dates X */ #ifdef PROTOS void print_moon_info(int month, X int year) #else void print_moon_info(month, year) X int month, year; #endif { X int n, ndays, day, is_q; X char *p; X unsigned long qdays; X double phase; X X if (draw_moons == NO_MOONS) X return; X X /* print the phase of the moon for each day of the month */ X X PRT("/moon_phases [\t\t%% from %s\n\t", X (p = find_moonfile(year)) ? p : "algorithm"); X X for (n = 0, qdays = 0L, day = 1, ndays = LENGTH_OF(month, year); X day <= ndays; X day++) { X phase = find_phase(month, day, year, &is_q); X if (draw_moons == SOME_MOONS && is_q) X phase = EXACT_QUARTER(phase); X if (draw_moons == ALL_MOONS || is_q) X PRT("%.3f%s", PRT_TWEAK(phase), ++n % 10 == 0 ? X "\n\t" : " "); X if (is_q) X qdays |= 1L << (day - 1); X } X PRT("] def\n"); X X /* if drawing only quarter moons, print days when they occur */ X X if (draw_moons == SOME_MOONS) { X PRT("/quarter_moons [ "); X for (day = 1; qdays; day++, qdays >>= 1) X if (qdays & 01) X PRT("%d ", day); X PRT("] def\n"); X } } X X /* X * print_julian_info - print the information necessary to print Julian dates X */ #ifdef PROTOS void print_julian_info(int month, X int year) #else void print_julian_info(month, year) X int month, year; #endif { X X if (julian_dates != NO_JULIANS) X PRT("/jdstart %d def\n", DAY_OF_YEAR(month, 1, year)); X if (julian_dates == ALL_JULIANS) X PRT("/yearlen %d def\n", YEAR_LEN(year)); } X X /* X * print_month - generate calendar for specified month/year X */ #ifdef PROTOS void print_month(int month, X int year) #else void print_month(month, year) X int month, year; #endif { X static int nmonths = 0; X X PRT("/year %d def\n", year); /* set up year and month */ X PRT("/month %d def\n", month); X PRT("/startday %d def\n", X (FIRST_OF(month, year) - first_day_of_week + 7) % 7); X PRT("/ndays %d def\n", LENGTH_OF(month, year)); X X find_holidays(month, year); /* make list of holidays */ X X /* are we printing 12 months per page or only one? */ X X if (do_whole_year) { X PRT("/posn %d def\n", nmonths % 12); /* location on page */ X PRT("printmonth_%c\n", rotate == LANDSCAPE ? 'l' : 'p'); X if (++nmonths % 12 == 0) X PRT("showpage\n"); X } X else { X /* generate lengths of previous and next months */ X PRT("/lndays %d def\n", LENGTH_OF(PREV_MONTH(month, year), X PREV_YEAR(month, year))); X PRT("/nndays %d def\n", LENGTH_OF(NEXT_MONTH(month, year), X NEXT_YEAR(month, year))); X X print_julian_info(month, year); /* Julian date info */ X print_moon_info(month, year); /* moon info */ X X PRT("printmonth\n"); X find_daytext(month, year, TRUE); /* holiday text */ X find_daytext(month, year, FALSE); /* day and note text */ X PRT("showpage\n"); X } } SHAR_EOF chmod 0644 writefil.c || echo 'restore of writefil.c failed' Wc_c="`wc -c < 'writefil.c'`" test 9889 -eq "$Wc_c" || echo 'writefil.c: original size 9889, current size' "$Wc_c" fi exit 0