[alt.sources] Pcal v4.0, part 5 of 5

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