home *** CD-ROM | disk | FTP | other *** search
- From: rogers@sud509.ed.ray.com (Andrew Rogers)
- Newsgroups: alt.sources
- Subject: Pcal 2.3
- Message-ID: <2483@sud509.ed.ray.com>
- Date: 19 Sep 90 17:31:55 GMT
-
- You guessed it - another revision of Pcal. Probably my last, as it turns
- out, since I will be leaving my current job at the end of the month and
- may not have net access (or access to the alt.* groups) at my next job.
- Anyway, version 2.3 (2.2 was not released to alt.sources) merges the
- following changes:
-
- Joe Brownlee added a mechanism by which notes can be specified in
- one of the unused calendar boxes. The date file may now contain
- lines of the form
-
- note <month> <text>
-
- where <month> may be numeric or alphabetic in form; any text
- specified is placed in the box next to the small calendars.
-
- Jamie Zawinski added a command-line option to print the phase
- of the moon: -m prints it only on full, new, and half moons,
- while -M prints it on all days. He also wrote a program,
- pcalinit.c, which generates pcalinit.h automatically from
- PostScript source in pcalinit.ps and tweaked the Makefile
- accordingly.
-
- Richard Dyson supplied a more VMS-specific usage() message.
-
- My own contributions were basically merging all of the above,
- revising the logic of parse(), and supplying a VMS script,
- make_pcal.com, to generate pcalinit.h and build pcal.
-
- The accompanying file called "ReadMe.orig" came with the original distribution
- as README and states this program is copyrighted but with permission to modify
- and redistribute.
-
- Andrew W. Rogers
- 9/18/90
-
- PS: Suggestion for future direction - my desk calendar has the number of
- each day (1-365) and days remaining (364-0) on each page. Anyone want to
- add that feature?
-
-
- Additional note: This distribution includes a VMS HELP file written by
- Richard Dyson. Countless other people worked on pcal long before me; see
- the ReadMe.orig file and topline comments in pcal.c.
-
-
-
- -------------------------------- cut here --------------------------------
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # Makefile
- # ReadMe
- # ReadMe.orig
- # calendar
- # make_pcal.com
- # pcal.c
- # pcal.hlp
- # pcal.man
- # pcalinit.c
- # pcalinit.ps
- # This archive created: Wed Sep 19 13:23:15 EDT 1990
- export PATH; PATH=/bin:/usr/bin:$PATH
- if test -f 'Makefile'
- then
- echo shar: will not over-write existing file 'Makefile'
- else
- cat << \SHAR_EOF > 'Makefile'
- #
- MANDIR=/usr1/jad/man # must change this
-
- pcal: pcal.c pcalinit.h
- $(CC) $(CFLAGS) $(LDFLAGS) $(COPTS) -o pcal pcal.c
-
- pcalinit: pcalinit.c
- $(CC) $(CFLAGS) $(LDFLAGS) $(COPTS) -o pcalinit pcalinit.c
-
- pcalinit.h: pcalinit pcalinit.ps
- pcalinit pcalinit.ps pcalinit.h
-
- man: pcal.man
- nroff -man pcal.man > pcal.1
- pack pcal.1
- # mv pcal.1.z $(MANDIR)
- SHAR_EOF
- fi
- if test -f 'ReadMe'
- then
- echo shar: will not over-write existing file 'ReadMe'
- else
- cat << \SHAR_EOF > 'ReadMe'
- Version 2.3 (2.2 was not released to alt.sources) merges the following changes:
-
- Joe Brownlee added a mechanism by which notes can be specified in
- one of the unused calendar boxes. The date file may now contain
- lines of the form
-
- note <month> <text>
-
- where <month> may be numeric or alphabetic in form; any text
- specified is placed in the box next to the small calendars.
-
- Jamie Zawinski added a command-line option to print the phase
- of the moon: -m prints it only on full, new, and half moons,
- while -M prints it on all days. He also wrote a program,
- pcalinit.c, which generates pcalinit.h automatically from
- PostScript source in pcalinit.ps and tweaked the Makefile
- accordingly.
-
- Richard Dyson supplied a more VMS-specific usage() message.
-
- My own contributions were basically merging all of the above,
- revising the logic of parse(), and supplying a VMS script,
- make_pcal.com, to generate pcalinit.h and build pcal.
-
- The accompanying file called "ReadMe.orig" came with the original distribution
- as README and states this program is copyrighted but with permission to modify
- and redistribute.
-
- Andrew W. Rogers
-
- Additional note: This distribution includes a VMS HELP file written by
- Richard Dyson. Countless other people worked on pcal long before me; see
- the ReadMe.orig file and topline comments in pcal.c.
- SHAR_EOF
- fi
- if test -f 'ReadMe.orig'
- then
- echo shar: will not over-write existing file 'ReadMe.orig'
- else
- cat << \SHAR_EOF > 'ReadMe.orig'
- "Pcal" is a program to print PostScript calendars for any month and year.
- By default, it looks for a file in the home directory named "calendar"
- for entries with leading dates matching dates on the calendar, and prints
- any following text under the appropriate day.
-
- The program may be a little System V flavored (getopt, time routines)
- but should be easily portable to other vintages of UNIX.
-
- Pcal is the combined effort of several people, most notably Patrick Wood
- of Pipeline Associates, Inc. for the original PostScript code and Bill
- Vogel of AT&T for the calendar file mechanism. My part was simple
- translation to a "C" program, the addition of a couple options and a more
- generalized date searching routine (oh yes, and a manual page :-).
-
- The original calendar PostScript was Copyright (c) 1987 by Patrick Wood
- and Pipeline Associates, Inc. with permission to modify and redistribute.
- Please retain this README file with the package.
-
-
- Ken Keirnan
- Pacific Bell
- San Ramon, CA.
- SHAR_EOF
- fi
- if test -f 'calendar'
- then
- echo shar: will not over-write existing file 'calendar'
- else
- cat << \SHAR_EOF > 'calendar'
- # Sample calendar file for pcal
- #
- # This should be ~/.calendar on Unix, SYS$LOGIN:CALENDAR.DAT on VMS
- #
- # Valid entries are of the following forms:
- #
- # opt <options>
- # year <year>
- # <month_name> <day>{*} {<text>}
- # <month><sep><day>{<sep><year>}{*} {<text>}
- # note <month> {<text>}
- # note <month_name> {<text>}
- #
- # where:
- # <options> := one or more valid command-line options (except -e and -f)
- # <month_name> := first 3+ characters of name of month (in English)
- # <sep> := one or more non-numeric, non-space, non-'*' characters
- # <text> is the text to be printed in the calendar box
- # <day>, <month>, and <year> are appropriate integers
- #
- # whitespace is to be used/avoided as implied by the above productions
- # '*' flags the date as a holiday (to be printed in gray)
- # comments run from '#' through end-of-line
-
- # A sample "opt" line to change the fonts and output file names, to print
- # only Sundays in gray, and to print moons on all days:
- #
- #opt -d Helvetica-Bold -t Helvetica-Bold -o myfile.ps -b all -g sun -M
-
- year 1990 # set year explicitly
-
- 5/28* Memorial Day (observed) # '*' prints holiday in gray
- 5/31 Memorial Day
-
- 7/4/90* Independence Day # full date format
-
- Sep 3* Labor Day # month written out
-
- 10/8* Columbus Day (observed)
- 10/12 Columbus Day
-
- 11/22* Thanksgiving
- 11/23* # holiday without text
-
- 12/24* # Christmas Eve
- 12/25* Christmas
-
- note Dec Some consider Christmas Eve a holiday
-
- 1/1/91* New Year's Day # set new year implicitly
- SHAR_EOF
- fi
- if test -f 'make_pcal.com'
- then
- echo shar: will not over-write existing file 'make_pcal.com'
- else
- cat << \SHAR_EOF > 'make_pcal.com'
- $! make_pcal.com - VMS command script to build/run pcalinit, create pcalinit.h
- $! from pcalinit.ps, and compile/link pcalinit.c
- $
- $ cc pcalinit.c
- $ link pcalinit
- $ pcalinit = "$" + f$environment("DEFAULT") + "pcalinit"
- $ pcalinit pcalinit.ps pcalinit.h
- $ delete/exclude=(*.c,*.h,*.ps) pcalinit.*;*
- $
- $ cc pcal.c
- $ link pcal.obj
- $ pcal == "$" + f$environment("DEFAULT") + "pcal"
- $ show symbol pcal
- SHAR_EOF
- fi
- if test -f 'pcal.c'
- then
- echo shar: will not over-write existing file 'pcal.c'
- else
- cat << \SHAR_EOF > 'pcal.c'
- /*
- * pcal.c - generate PostScript file to print calendar for any month and year
- *
- * The original PostScript code to generate the calendars was written by
- * Patrick Wood (Copyright (c) 1987 by Patrick Wood of Pipeline Associates,
- * Inc.), and authorized for modification and redistribution. The calendar
- * file inclusion code was originally written in "bs(1)" by Bill Vogel of
- * AT&T. Patrick's original PostScript was modified and enhanced several
- * times by others whose names have regrettably been lost. This C version
- * was originally created by Ken Keirnan of Pacific Bell; additional
- * enhancements by Joseph P. Larson, Ed Hand, and Andrew Rogers (who also
- * did the VMS port), Mark Kantrowitz, and Joe Brownlee. The moon routines
- * were originally written by Mark Hanson <cs62a12@wind.ucsd.edu>, and were
- * improved and incorporated into this version by Jamie Zawinski
- * <jwz@lucid.com>.
- *
- * Revision history:
- *
- * 2.3 jwz 09/18/90 Added moon routines
- *
- * 2.2 AWR 09/17/90 revise logic of parse(); new usage
- * message
- *
- * JAB/AWR 09/14/90 support "note" lines in date file
- *
- * 2.1 MK/AWR 08/27/90 support -L, -C, -R, -n options;
- * print holiday text next to date
- *
- * AWR 08/24/90 incorporate cpp-like functionality;
- * add -D and -U options; save date file
- * information in internal data structure;
- * look for PCAL_OPTS and PCAL_DIR; look
- * for ~/.calendar and ~/calendar
- *
- * 2.0 AWR 08/08/90 included revision history; replaced -r
- * flag with -l and -p; replaced -s and -S
- * flags with -b and -g; recognize flags
- * set in date file; translate ( and ) in
- * text to octal escape sequence; usage()
- * message condensed to fit 24x80 screen
- *
- * Parameters:
- *
- * pcal [opts] generate calendar for current month/year
- *
- * pcal [opts] yy generate calendar for entire year yy
- *
- * pcal [opts] mm yy generate calendar for month mm
- * (Jan = 1), year yy (19yy if yy < 100)
- *
- * pcal [opts] mm yy n as above, for n consecutive months
- *
- * Output:
- *
- * PostScript file to print calendars for all selected months.
- *
- * Options:
- *
- * -b <DAY> print specified weekday in black
- * -g <DAY> print specified weekday in gray
- * (default: print Saturdays and Sundays in gray)
- *
- * -d <FONT> specify alternate font for day names
- * (default: Times-Bold)
- *
- * -n <FONT> specify alternate font for notes in boxes
- * (default: Helvetica-Narrow)
- *
- * -t <FONT> specify alternate font for titles
- * (default: Times-Bold)
- *
- * -D <SYM> define preprocessor symbol
- * -U <SYM> un-define preprocessor symbol
- *
- * -e generate empty calendar (ignore date file)
- *
- * -f <FILE> specify alternate date file (default:
- * ~/.calendar on Un*x, SYS$LOGIN:CALENDAR.DAT
- * on VMS; if environment variable [logical
- * name on VMS] PCAL_DIR exists, looks there
- * instead)
- *
- * -o <FILE> specify alternate output file (default:
- * stdout on Un*x, CALENDAR.PS on VMS)
- *
- * -L <STRING> specify left foot string (default: "")
- * -C <STRING> specify center foot string (default: "")
- * -R <STRING> specify right foot string (default: "")
- *
- * -l generate landscape-mode calendars
- * -p generate portrait-mode calendars
- * (default: landscape-mode)
- *
- * -m draw a small moon icon on the days of the
- * full, new, and half moons.
- * -M draw a small moon icon every day.
- * (default: no moons).
- *
- * There are many ways to specify these options in addition to using the
- * command line; this facilitates customization to the user's needs.
- *
- * If the environment variable (global symbol on VMS) PCAL_OPTS is
- * present, its value will be parsed as if it were a command line.
- * Any options specified will override the program defaults.
- *
- * All but the -e, -f, -D, and -U options may be specified in the date
- * file by the inclusion of one or more lines of the form "opt <options>".
- * Any such options override any previous values set either as program
- * defaults, via PCAL_OPTS, or in previous "opt" lines.
- *
- * Options explicitly specified on the command line in turn override all
- * of the above.
- *
- * Any flag which normally takes an argument may also be specified without
- * an argument; this resets the corresponding option to its default. -D
- * alone un-defines all symbols; -U alone has no effect.
- *
- * Parameters and flags may be mixed on the command line. In some cases
- * (e.g., when a parameter follows a flag without its optional argument)
- * this may lead to ambiguity; the dummy flag '-' (or '--') may be used
- * to separate them, i.e. "pcal -t - 9 90".
- *
- * Simple cpp-like functionality is provided. The date file may include
- * the following commands, which work like their cpp counterparts:
- *
- * define <sym>
- * undef <sym>
- *
- * if{n}def <sym>
- * ...
- * { else
- * ... }
- * endif
- *
- * include <file>
- *
- * Note that these do not start with '#', which is reserved as a comment
- * character.
- *
- * "define" alone deletes all the current definitions; "ifdef" alone is
- * always false; "ifndef" alone is always true. All defined symbols are
- * treated in a case-insensitive manner.
- *
- * The file name in the "include" directive may optionally be surrounded
- * by "" or <>.
- *
- * Additional notes may be propagated to an empty calendar box by the
- * inclusion of one or more lines of the form "note <month> <text>",
- * where <month> may be numeric or alphabetic.
- *
- */
-
-
- #include <stdio.h>
- #include <ctype.h>
- #include <time.h>
- #include <string.h>
-
- #ifdef VMS /* VMS oddities isolated here */
-
- #include <ssdef.h> /* required for trnlog() */
- #include <descrip.h>
-
- #define HOME_DIR "SYS$LOGIN"
- #define DATEFILE "calendar.dat"
- #define OUTFILE "calendar.ps"
- #define START_PATH '['
- #define END_PATH ']'
-
- #define EXIT_SUCCESS 1
- #define EXIT_FAILURE 3
-
- #else /* non-VMS - assume Un*x of some sort */
-
- #define HOME_DIR "HOME"
- #define DATEFILE ".calendar"
- #define ALT_DATEFILE "calendar" /* for backward compatibility */
- #define OUTFILE ""
- #define START_PATH '/'
- #define END_PATH '/'
-
- #define EXIT_SUCCESS 0
- #define EXIT_FAILURE 1
-
- #endif
-
- #define PCAL_OPTS "PCAL_OPTS" /* environment variables */
- #define PCAL_DIR "PCAL_DIR"
-
- #define IS_LEAP(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
- #define INIT_COLORS memcpy(color, default_color, sizeof(color))
- #define LASTCHAR(p) ((p) && *(p) ? (p) + strlen(p) - 1 : NULL)
-
- #ifdef __STDC__
- #define TOLOWER(c) tolower(c)
- #else
- #define TOLOWER(c) (isupper(c) ? tolower(c) : (c))
- #endif
-
- #define PRT (void)printf
- #define FPR (void)fprintf
-
- #define FALSE 0
- #define TRUE 1
-
- #define ALL_FLAGS "bCDdefgLlMmnopRtU" /* all command-line flags */
- #define DATEFILE_FLAGS "DefU" /* parsed before opening datefile */
- #define OTHER_FLAGS "bCdgLlMmnopRt" /* parsed inside datefile */
-
- #define DAYFONT "Times-Bold" /* default font names */
- #define TITLEFONT "Times-Bold"
- #define NOTESFONT "Helvetica-Narrow"
-
- #define LFOOT "" /* default foot strings */
- #define CFOOT ""
- #define RFOOT ""
-
- #define LANDSCAPE 90 /* degrees to rotate for landscape/portrait */
- #define PORTRAIT 0
- #define ROTATE LANDSCAPE /* default */
-
- #define BLACK 0 /* colors for dates */
- #define GRAY 1
-
- #define NO_DATEFILE 0 /* date file (if any) to use */
- #define USER_DATEFILE 1
- #define SYS_DATEFILE 2
-
- /* preprocessor token codes - must be contiguous range of integers starting
- * at 0 and ending with code for non-tokens (cf. pp_info[], pp_token())
- */
- #define PP_DEFINE 0
- #define PP_ELSE 1
- #define PP_ENDIF 2
- #define PP_IFDEF 3
- #define PP_IFNDEF 4
- #define PP_INCLUDE 5
- #define PP_UNDEF 6
- #define PP_OTHER 7 /* not pp token */
-
- #define MAX_NESTING 10 /* maximum nesting level for file inclusion */
-
- #define MAX_PP_SYMS 100 /* number of definable preprocessor symbols */
- #define PP_SYM_UNDEF -1 /* flag for undefined symbol */
-
- #define MIN_YR 1900 /* significant years (calendar limits) */
- #define MAX_YR 9999
-
- #define JAN 1 /* significant months */
- #define FEB 2
- #define DEC 12
-
- #define DAY_TEXT 0 /* types of text in data structure */
- #define HOLIDAY_TEXT 1
- #define NOTE_TEXT 2
-
- #define NOTE_DAY 32 /* dummy day for notes text */
-
- #define DF_YEAR 0 /* returns from date_type() */
- #define DF_OPT 1
- #define DF_NOTE 2
- #define DF_MONTH 3
- #define DF_DATE 4
- #define DF_OTHER 5
-
- #define PARSE_OK 0 /* returns from parse(), enter_day_info() */
- #define PARSE_INVDATE 1
- #define PARSE_INVLINE 2
-
- #define STRSIZ 200 /* size of misc. strings */
-
- #define MAXARGS 3 /* numeric command-line args */
-
- #define WHITESPACE " \t" /* token delimiters in date file */
-
- /*
- * Global typedef declarations for data structure
- */
-
- typedef struct d_i {
- int is_holiday;
- char *text;
- struct d_i *next;
- } day_info;
-
- typedef struct m_i {
- unsigned long holidays;
- day_info *day[32]; /* including NOTE_DAY */
- } month_info;
-
- typedef struct y_i {
- int year;
- month_info *month[12];
- struct y_i *next;
- } year_info;
-
-
- /*
- * Global variables:
- */
-
- int do_define(), do_ifdef(), do_ifndef(), do_include(), do_undef();
- char *trnlog(), *mk_path(), *mk_filespec();
-
- extern char *getenv();
-
- year_info *head = NULL; /* head of internal data structure */
- int nesting_level = 0; /* level of include file nesting */
- int init_month; /* initial month, year, number of months */
- int init_year;
- int nmonths;
- int curr_year; /* current default year for date file entries */
- char *words[100]; /* maximum number of words per date file line */
- char lbuf[512]; /* maximum date file line size */
- char *pp_sym[MAX_PP_SYMS]; /* preprocessor defined symbols */
- char progname[STRSIZ]; /* program name (for error messages) */
- char color[7]; /* colors of weekdays - cf. default_color[] */
-
- /*
- * Default values for command-line options:
- */
-
- char default_color[7] = { /* -b, -g */
- GRAY, BLACK, BLACK, BLACK, BLACK, BLACK, GRAY /* cf. COLOR_MSG */
- };
-
- int datefile_type = SYS_DATEFILE; /* -e, -f */
- char datefile[STRSIZ] = "";
- char default_dir[STRSIZ] = "";
-
- int rotate = ROTATE; /* -l, -p */
-
- char *draw_moons = "false"; /* -m, -M */
-
- char dayfont[STRSIZ] = DAYFONT; /* -d, -t, -n */
- char titlefont[STRSIZ] = TITLEFONT;
- char notesfont[STRSIZ] = NOTESFONT;
-
- char lfoot[STRSIZ] = LFOOT; /* -L, -C, -R */
- char cfoot[STRSIZ] = CFOOT;
- char rfoot[STRSIZ] = RFOOT;
-
- char outfile[STRSIZ] = OUTFILE; /* -o */
-
- /*
- * Language-dependent strings (month and day names, option file keywords,
- * preprocessor tokens):
- */
-
- static char *months[12] = {
- "January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December"
- };
-
- static char *days[7] = {
- "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
- "Saturday"
- };
-
- /* preprocessor tokens - must be in same order as PP_XXXXX (cf. pp_token()) */
- static struct pp {
- char *token; /* name */
- int (*pfcn)(); /* dispatch routine */
- } pp_info[] = {
- { "define", do_define }, /* PP_DEFINE */
- { "else", NULL }, /* PP_ELSE */
- { "endif", NULL }, /* PP_ENDIF */
- { "ifdef", do_ifdef }, /* PP_IFDEF */
- { "ifndef", do_ifndef }, /* PP_IFNDEF */
- { "include", do_include }, /* PP_INCLUDE */
- { "undef", do_undef }, /* PP_UNDEF */
- { NULL, NULL } /* PP_OTHER */
- };
-
- #define MIN_DAY_LEN 2 /* minimum size of abbreviations */
- #define MIN_MONTH_LEN 3
- #define MIN_PPTOK_LEN 3
-
- #define ALL "all" /* command-line or date file keywords */
- #define NOTE "note"
- #define OPT "opt"
- #define YEAR "year"
-
- #define COLOR_MSG "Sat/Sun in gray, others in black" /* cf. usage() */
-
- /*
- * PostScript boilerplate
- */
-
- #include "pcalinit.h"
-
-
- /*
- * Main program - parse and validate command-line arguments, open files,
- * generate PostScript boilerplate and code to generate calendars.
- *
- * Program structure:
- *
- * main() looks for the environment variable (global symbol on VMS) PCAL_OPTS
- * and calles get_args() to parse it. It then calls get_args() again to parse
- * the command line for the date file name, -D and -U options to be in effect
- * prior to reading the date file, and any numeric arguments (month, year,
- * number of months). It then calls read_datefile() to read and parse the
- * date file; any "opt" lines present will override the defaults for the
- * command-line flags. It then calls get_args() again to process the other
- * command-line flags, which in turn override any specified earlier.
- *
- * main() then generates the common PostScript code and then calls pmonth() to
- * print the calendars.
- *
- * read_datefile() calls getline() to read the date file, do_xxxxx() to process
- * the preprocessor tokens, and parse() to parse each date line.
- *
- * getline() reads one or more lines from the date file, stripping comments
- * (# through end-of-line) and ignoring blank lines.
- *
- * parse() parses a line from the date file and processes it. If "opt", it
- * calls loadwords() to split the line into tokens and get_args() to
- * process them. If the line contains "note" or a date, it calls
- * enter_day_info() to enter the day and related text into the data structure.
- *
- * pmonth() calls find_holidays() to generate the list of holidays to be
- * printed in gray; it then calls find_daytext() to generate the text to
- * be printed inside the calendar boxes.
- *
- */
- main(argc, argv)
- int argc;
- char **argv;
- {
- FILE *dfp = NULL; /* date file pointer */
- char *p, **ap;
- int i, month, year, ngray;
-
- #define DO_HEADER(phdr) for (ap = phdr; *ap; ap++) PRT("%s\n", *ap)
-
- INIT_COLORS; /* set up default colors */
-
- /* isolate root program name (for use in error messages) */
-
- strcpy(progname, **argv ? *argv : "pcal");
-
- if ((p = strrchr(progname, END_PATH)) != NULL)
- strcpy(progname, ++p);
- if ((p = strchr(progname, '.')) != NULL)
- *p = '\0';
-
- /*
- * Get the arguments from a) the environment variable, b) "opt" lines
- * in the date file, and c) the command line, in that order
- */
-
- /* look for environment variable for options */
-
- if ((p = getenv(PCAL_OPTS)) != NULL) {
- strcpy(lbuf, "x "); /* prepend a dummy token */
- strcat(lbuf, p);
- loadwords();
- if (! get_args(words, ALL_FLAGS, FALSE)) {
- usage();
- exit(EXIT_FAILURE);
- }
- }
-
- /* parse command-line arguments once to find name of date file, etc. */
-
- if (!get_args(argv, DATEFILE_FLAGS, TRUE)) {
- usage();
- exit(EXIT_FAILURE);
- }
-
- /* Attempt to open the date file as specified by the [-e | -f] flags */
-
- switch (datefile_type) {
- case NO_DATEFILE:
- dfp = NULL;
- break;
-
- case USER_DATEFILE:
- /* Attempt to open user-specified calendar file */
- if ((dfp = fopen(datefile, "r")) == NULL) {
- FPR(stderr, "%s: can't open file %s\n", progname,
- datefile);
- exit(EXIT_FAILURE);
- }
- mk_path(default_dir, datefile); /* extract path */
- break;
-
- case SYS_DATEFILE:
- /* Attempt to open system-specified calendar file */
- if ((p = trnlog(PCAL_DIR)) || (p = trnlog(HOME_DIR)))
- strcpy(default_dir, p);
-
- mk_filespec(datefile, default_dir, DATEFILE);
- dfp = fopen(datefile, "r"); /* no error if nonexistent */
- #ifdef ALT_DATEFILE
- if (!dfp) { /* try again with alternate file */
- mk_filespec(datefile, default_dir, ALT_DATEFILE);
- dfp = fopen(datefile, "r");
- }
- #endif
- break;
- }
-
- /* read the date file (if any) and build internal data structure */
-
- if (dfp) {
- curr_year = init_year;
- read_datefile(dfp, datefile);
- fclose(dfp);
- }
-
- /* reparse command line - flags there supersede those in date file */
-
- get_args(argv, OTHER_FLAGS, FALSE);
-
- /* done with the arguments and flags - try to open the output file */
-
- if (*outfile && freopen(outfile, "w", stdout) == (FILE *) NULL) {
- FPR(stderr, "%s: can't open file %s\n", progname, outfile);
- exit(EXIT_FAILURE);
- }
-
- /*
- * Write out PostScript prolog
- */
-
-
- /*
- * Write out PostScript prolog
- */
-
- /* font names */
-
- PRT("%%!\n");
- PRT("/titlefont /%s def\n/dayfont /%s def\n/notesfont /%s def\n", titlefont, dayfont, notesfont);
-
- /* foot strings */
-
- def_footstring(lfoot, 'L');
- def_footstring(cfoot, 'C');
- def_footstring(rfoot, 'R');
-
- /* month names */
-
- PRT("/month_names [");
- for (i = 0; i < 12; i++)
- PRT("%s(%s) ", i % 6 == 0 ? "\n\t" : "", months[i]);
- PRT("] def\n");
-
- /* day names */
-
- PRT("/day_names [");
- for (i = 0; i < 7; i++)
- PRT("%s(%s) ", i % 6 == 0 ? "\n\t" : "", days[i]);
- PRT("] def\n");
-
- /* colors (black/gray) to print weekdays and holidays */
-
- PRT("/day_gray [");
- for (ngray = i = 0; i < 7; ngray += color[i++] == GRAY)
- PRT(" %s", color[i] == GRAY ? "true" : "false");
- PRT(" ] def\n");
- PRT("/holiday_gray %s def\n", ngray <= 3 ? "true" : "false");
-
- /* PostScript boilerplate (part 1 of 1) */
- DO_HEADER(header);
-
- /* landscape or portrait mode */
-
- PRT("\n/landscape-p %s def\n", (rotate == LANDSCAPE) ? "true":"false");
- PRT("/draw-moons %s def\n", draw_moons);
-
- /*
- * Write out PostScript code to print calendars
- */
-
- month = init_month;
- year = init_year;
-
- while (nmonths--) {
- pmonth(month, year);
- if (++month > DEC) {
- month = JAN;
- year++;
- }
- }
-
- cleanup();
-
- #ifdef VMS
- FPR(stderr, "Output is in file %s\n", outfile);
- #endif
- exit(EXIT_SUCCESS);
- }
-
- /*
- * get_args - walk the argument list, parsing all arguments but processing only
- * those specified in "flags". If "do_numargs" is TRUE, processes numeric
- * arguments (month, year, number of months) as well.
- */
- int get_args(argv, flags, do_numargs)
- char **argv; /* argument list */
- char *flags; /* which flags to process */
- int do_numargs; /* process numeric arguments? */
- {
- char *p, *opt;
- int i, do_flag;
- long tmp; /* for getting current month/year */
- struct tm *p_tm;
- int badopt = FALSE; /* flag set if bad param */
- int nargs = 0; /* count of non-flag args */
- int numargs[MAXARGS]; /* non-flag (numeric) args */
-
- /* Look for the argument following flag - may be separated by spaces or
- * not (bumps argv in former case). If no non-flag argument appears, set
- * "arg" to NULL (-b, -C, -d, -g, -L, -n, -o, -R, and -t without an argument
- * reset the corresponding option to its default value).
- */
- #define GETARG(arg) arg = *(*argv + 2) ? *argv + 2 : \
- (*(argv+1) && **(argv+1) != '-' ? *++argv : NULL)
-
- /* Walk argument list, ignoring first element (program name) */
-
- while (*++argv) {
-
- /* Assume that any non-flag argument is a numeric argument */
- if (**argv != '-') {
- if (do_numargs && nargs < MAXARGS)
- numargs[nargs++] = atoi(*argv);
- continue;
- }
-
- /* Is this flag among those to be processed beyond parsing? */
-
- do_flag = strchr(flags, *(opt = *argv + 1)) != NULL;
-
- switch (*opt) {
-
- case '\0': /* take - or -- as dummy flags */
- case '-' :
- break;
-
- case 'b': /* print day in black or gray */
- case 'g':
- GETARG(p);
- if (do_flag)
- if (p)
- set_color(p, *opt == 'b' ? BLACK : GRAY);
- else
- INIT_COLORS; /* reset to defaults */
- break;
-
- case 'C': /* specify alternate center foot */
- GETARG(p);
- if (do_flag)
- strcpy(cfoot, p ? p : CFOOT);
- break;
-
- case 'd': /* specify alternate day font */
- GETARG(p);
- if (do_flag)
- strcpy(dayfont, p ? p : DAYFONT);
- break;
-
- case 'D': /* define preprocessor symbol */
- GETARG(p);
- if (do_flag)
- do_define(p);
- break;
-
- case 'e': /* generate empty calendar */
- if (do_flag) {
- datefile_type = NO_DATEFILE;
- datefile[0] = '\0';
- }
- break;
-
- case 'f': /* specify alternate date file */
- GETARG(p);
- if (p && do_flag) {
- datefile_type = USER_DATEFILE;
- strcpy(datefile, p);
- }
- break;
-
- case 'L': /* specify alternate left foot */
- GETARG(p);
- if (do_flag)
- strcpy(lfoot, p ? p : LFOOT);
- break;
-
- case 'l': /* generate landscape calendar */
- if (do_flag)
- rotate = LANDSCAPE;
- break;
-
- case 'n': /* specify alternate notes font */
- GETARG(p);
- if (do_flag)
- strcpy(notesfont, p ? p : NOTESFONT);
- break;
-
- case 'o': /* specify alternate output file */
- GETARG(p);
- if (do_flag)
- strcpy(outfile, p ? p : OUTFILE);
- break;
-
- case 'p': /* generate portrait calendar */
- if (do_flag)
- rotate = PORTRAIT;
- break;
-
- case 'R': /* specify alternate right foot */
- GETARG(p);
- if (do_flag)
- strcpy(rfoot, p ? p : RFOOT);
- break;
-
-
- case 't': /* specify alternate title font */
- GETARG(p);
- if (do_flag)
- strcpy(titlefont, p ? p : TITLEFONT);
- break;
-
- case 'U': /* undef preprocessor symbol */
- GETARG(p);
- if (do_flag)
- do_undef(p);
- break;
-
- case 'm': /* draw four moons */
- if (do_flag)
- draw_moons = "4";
- break;
-
- case 'M': /* draw a moon for each day */
- if (do_flag)
- draw_moons = "true";
- break;
-
- default: /* unrecognized flag */
- FPR(stderr, "%s: illegal option -%s\n", progname, opt);
- badopt = TRUE;
- break;
- }
- }
-
- if (!do_numargs)
- return !badopt; /* return TRUE if OK, FALSE if error */
-
- /* Validate non-flag (numeric) parameters */
-
- switch (nargs) {
- case 0: /* no arguments - print current month/year */
- time(&tmp);
- p_tm = localtime(&tmp);
- init_month = p_tm->tm_mon + 1;
- init_year = p_tm->tm_year;
- nmonths = 1;
- break;
- case 1: /* one argument - print entire year */
- init_month = JAN;
- init_year = numargs[0];
- nmonths = 12;
- break;
- default: /* two or three arguments - print one or more months */
- init_month = numargs[0];
- init_year = numargs[1];
- nmonths = nargs > 2 ? numargs[2] : 1;
- break;
- }
-
- if (nmonths < 1) /* ensure at least one month */
- nmonths = 1;
-
- /* check range of month and year */
-
- if (init_month < JAN || init_month > DEC) {
- FPR(stderr, "%s: month %d not in range 1 .. 12\n", progname,
- init_month);
- badopt = TRUE;
- }
-
- if (init_year > 0 && init_year < 100) /* treat nn as 19nn */
- init_year += 1900;
-
- if (init_year < MIN_YR || init_year > MAX_YR) {
- FPR(stderr, "%s year %d not in range %d .. %d\n", progname,
- init_year, MIN_YR, MAX_YR);
- badopt = TRUE;
- }
-
- return !badopt; /* return TRUE if OK, FALSE if error */
- }
-
-
-
- /*
- * usage - print message explaining correct usage of the command-line
- * arguments and flags
- */
- usage()
- {
- FPR(stderr, "\nUsage:\t%s [-b|-g DAY]* [-d|-n|-t FONT] [-e | -f FILE] [-o FILE] [-l | -p]\n", progname);
- FPR(stderr, "\t[-m|-M] [-D|-U SYM] [-L|-C|-R STRING] [ [ [mm] yy ] | [mm yy n] ]\n");
- FPR(stderr, "\n");
- FPR(stderr, "\t-b DAY\t\tprint weekday DAY in black\n");
- FPR(stderr, "\t-g DAY\t\tprint weekday DAY in gray\n");
- FPR(stderr, "\t\t\t(default: %s)\n", COLOR_MSG);
- FPR(stderr, "\n");
- FPR(stderr, "\t-d FONT\t\tspecify alternate day name font (default: %s)\n",
- DAYFONT);
- FPR(stderr, "\t-n FONT\t\tspecify alternate notes font (default: %s)\n",
- NOTESFONT);
- FPR(stderr, "\t-t FONT\t\tspecify alternate title font (default: %s)\n",
- TITLEFONT);
- FPR(stderr, "\n");
- FPR(stderr, "\t-e\t\tgenerate empty calendar (ignore date file)\n");
- FPR(stderr, "\t-f FILE\t\tspecify alternate date file (default: %s)\n",
- DATEFILE);
- FPR(stderr, "\t-o FILE\t\tspecify alternate output file (default: %s)\n",
- OUTFILE[0] ? OUTFILE : "stdout");
- FPR(stderr, "\n");
- FPR(stderr, "\t-l\t\tgenerate landscape-style calendars");
- #if (ROTATE == LANDSCAPE)
- FPR(stderr, " (default)");
- #endif
- FPR(stderr, "\n\t-p\t\tgenerate portrait-style calendars");
- #if (ROTATE == PORTRAIT)
- FPR(stderr, " (default)");
- #endif
- FPR(stderr, "\n\n");
- FPR(stderr, "\t-m\t\t\draw a \"moon\" icon on days of full, new, and half moons\n");
- #ifdef VMS
- FPR(stderr, "\t-\"M\"\t\t\draw a \"moon\" icon every day (default: no moons)\n");
- FPR(stderr, "\n");
- FPR(stderr, "\t-\"D\" SYM\tdefine preprocessor symbol\n");
- FPR(stderr, "\t-\"U\" SYM\tundefine preprocessor symbol\n");
- FPR(stderr, "\n");
- FPR(stderr, "\t-\"L\" STRING\tspecify left foot string (default: \"%s\")\n",
- LFOOT);
- FPR(stderr, "\t-\"C\" STRING\tspecify center foot string (default: \"%s\")\n",
- CFOOT);
- FPR(stderr, "\t-\"R\" STRING\tspecify right foot string (default: \"%s\")\n",
- RFOOT);
- #else
- FPR(stderr, "\t-M\t\t\draw a \"moon\" icon every day (default: no moons)\n");
- FPR(stderr, "\n");
- FPR(stderr, "\t-D SYM\t\tdefine preprocessor symbol\n");
- FPR(stderr, "\t-U SYM\t\tundefine preprocessor symbol\n");
- FPR(stderr, "\n");
- FPR(stderr, "\t-L STRING\tspecify left foot string (default: \"%s\")\n",
- LFOOT);
- FPR(stderr, "\t-C STRING\tspecify center foot string (default: \"%s\")\n",
- CFOOT);
- FPR(stderr, "\t-R STRING\tspecify right foot string (default: \"%s\")\n",
- RFOOT);
- #endif
- FPR(stderr, "\n");
- FPR(stderr, "\tyy\t\tgenerate calendar for year yy (19yy if yy < 100)\n");
- FPR(stderr, "\tmm yy\t\tgenerate calendar for month mm (Jan = 1), year yy\n");
- FPR(stderr, "\tmm yy n\t\tgenerate calendars for n months, starting at mm/yy\n");
- FPR(stderr, "\t(default)\tgenerate calendar for current month/year\n");
- }
-
-
- /*
- * General-purpose utility routines
- */
-
-
- /*
- * alloc - interface to calloc(); terminates if unsuccessful
- */
- char *alloc(size)
- int size;
- {
- char *p;
- extern char *calloc();
-
- if (size == 0) /* not all calloc()s like null requests */
- size = 1;
-
- if ((p = calloc(1, size)) == NULL) {
- FPR(stderr, "%s: out of memory\n", progname);
- exit(EXIT_FAILURE);
- }
-
- return p;
- }
-
-
- /*
- * ci_str{n}cmp - case-insensitive flavors of strcmp(), strncmp()
- */
- int ci_strcmp(s1, s2)
- register char *s1, *s2;
- {
- register char c1, c2;
-
- for ( ; (c1 = TOLOWER(*s1)) == (c2 = TOLOWER(*s2)); s1++, s2++)
- if (c1 == '\0')
- return 0;
-
- return c1 - c2;
- }
-
-
- int ci_strncmp(s1, s2, n)
- register char *s1, *s2;
- int n;
- {
- register char c1, c2;
-
- for ( ; --n >= 0 && (c1 = TOLOWER(*s1)) == (c2 = TOLOWER(*s2)); s1++, s2++)
- if (c1 == '\0')
- return 0;
-
- return n < 0 ? 0 : c1 - c2;
- }
-
-
- /*
- * Preprocessor token and symbol table routines
- */
-
-
- /*
- * find_sym - look up symbol; return symbol table index if found, PP_SYM_UNDEF
- * if not found
- */
- int find_sym(sym)
- char *sym;
- {
- int i;
-
- if (!sym)
- return PP_SYM_UNDEF;
-
- for (i = 0; i < MAX_PP_SYMS; i++)
- if (pp_sym[i] && ci_strcmp(pp_sym[i], sym) == 0)
- return i;
-
- return PP_SYM_UNDEF;
- }
-
-
- /*
- * do_ifdef - return TRUE if 'sym' is currently defined; FALSE if not
- */
- int do_ifdef(sym)
- char *sym;
- {
- return find_sym(sym) != PP_SYM_UNDEF;
- }
-
-
- /*
- * do_ifndef - return FALSE if 'sym' is currently defined; TRUE if not
- */
- int do_ifndef(sym)
- char *sym;
- {
- return find_sym(sym) == PP_SYM_UNDEF;
- }
-
-
- /*
- * do_define - enter 'sym' into symbol table; if 'sym' NULL, clear symbol table
- */
- do_define(sym)
- char *sym;
- {
- int i;
-
- if (! sym) { /* null argument - clear all definitions */
- clear_syms();
- return;
- }
-
- if (do_ifdef(sym)) /* already defined? */
- return;
-
- for (i = 0; i < MAX_PP_SYMS; i++) /* find room for it */
- if (! pp_sym[i]) {
- strcpy(pp_sym[i] = alloc(strlen(sym)+1), sym);
- return;
- }
-
- FPR(stderr, "%s: no room to define %s\n", progname, sym);
- }
-
-
- /*
- * do_undef - undefine 'sym' and free its space; no error if not defined
- */
- do_undef(sym)
- char *sym;
- {
- int i;
-
- if (! sym)
- return;
-
- if ((i = find_sym(sym)) != PP_SYM_UNDEF) {
- free(pp_sym[i]);
- pp_sym[i] = NULL;
- }
- }
-
-
- /*
- * do_include - include specified file (optionally in "" or <>)
- */
- do_include(path, name)
- char *path; /* path to file */
- char *name; /* file name */
- {
- FILE *fp;
- char *p, incfile[STRSIZ], tmpnam[STRSIZ];
-
- if (! name) /* whoops, no date file */
- return;
-
- /* copy name, stripping "" or <> */
- strcpy(tmpnam, name + (*name == '"' || *name == '<'));
- if ((p = LASTCHAR(tmpnam)) && *p == '"' || *p == '>')
- *p = '\0';
-
- if ((fp = fopen(mk_filespec(incfile, path, tmpnam), "r")) == NULL) {
- FPR(stderr, "%s: can't open file %s\n", progname, incfile);
- exit(EXIT_FAILURE);
- }
-
- read_datefile(fp, incfile);
- fclose(fp);
- }
-
-
- /*
- * pp_token - look up 'token' in list of preprocessor tokens; return its
- * index if found, PP_OTHER if not (N.B.: this relies on the ordering of
- * PP_XXXXX and pp_info[]; see comments at their definitions).
- */
- int pp_token(token)
- char *token;
- {
- struct pp *p;
-
- for (p = pp_info;
- p->token && ci_strncmp(token, p->token, MIN_PPTOK_LEN);
- p++)
- ;
-
- return p - pp_info;
- }
-
- /*
- * Internal data structure routines
- */
-
-
- /*
- * find_year - find record in year list; optionally create if not present
- */
- year_info *find_year(year, insert) /* find record in year list */
- int year;
- int insert; /* insert if missing */
- {
- year_info *pyear, *plast, *p;
-
- for (plast = NULL, pyear = head; /* search linked list */
- pyear && pyear->year < year;
- plast = pyear, pyear = pyear->next)
- ;
-
- if (pyear && pyear->year == year) /* found - return it */
- return pyear;
-
- if (insert) { /* not found - insert it if requested */
- p = (year_info *) alloc(sizeof(year_info)); /* create new record */
- p->year = year;
-
- p->next = pyear; /* link it in */
- return *(plast ? &plast->next : &head) = p;
- }
- else
- return NULL;
- }
-
-
- /*
- * enter_day_info - enter text for specified day; avoid entering duplicates.
- * returns PARSE_INVDATE if date invalid, PARSE_OK if OK
- */
- int enter_day_info(m, d, y, text_type, pword) /* fill in information for given day */
- int m, d, y;
- int text_type;
- char **pword;
- {
- static year_info *pyear;
- static int prev_year = 0;
- month_info *pmonth;
- day_info *pday, *plast;
- int is_holiday = text_type == HOLIDAY_TEXT;
-
- if (! is_valid(m, d == NOTE_DAY && text_type == NOTE_TEXT ? 1 : d, y))
- return PARSE_INVDATE;
-
- if (y != prev_year) /* avoid unnecessary year lookup */
- pyear = find_year(y, 1);
-
- --m, --d; /* adjust for use as subscripts */
-
- if ((pmonth = pyear->month[m]) == NULL) /* find/create month record */
- pyear->month[m] = pmonth = (month_info *) alloc(sizeof(month_info));
-
- if (is_holiday)
- pmonth->holidays |= (1 << d);
-
- /* insert text for day at end of list (preserving the order of entry
- * for multiple lines on same day); eliminate those differing only
- * in spacing and capitalization from existing entries
- */
-
- get_text(pword); /* consolidate text into lbuf */
-
- if (*lbuf) {
- for (plast = NULL, pday = pmonth->day[d];
- pday;
- plast = pday, pday = pday->next)
- if (ci_strcmp(pday->text, lbuf) == 0) {
- pday->is_holiday |= is_holiday;
- return PARSE_OK;
- }
-
- /* unique - add to end of list */
-
- pday = (day_info *) alloc(sizeof(day_info));
- pday->is_holiday = is_holiday;
- strcpy(pday->text = (char *) alloc(strlen(lbuf)+1), lbuf);
- pday->next = NULL;
- *(plast ? &plast->next : &pmonth->day[d]) = pday;
- }
-
- return PARSE_OK;
- }
-
-
- /*
- * Housekeeping routines to free allocated data
- */
-
-
- /*
- * clear_syms - clear and deallocate the symbol table
- */
- clear_syms()
- {
- int i;
-
- for (i = 0; i < MAX_PP_SYMS; i++)
- if (pp_sym[i]) {
- free(pp_sym[i]);
- pp_sym[i] = NULL;
- }
- }
-
-
- /*
- * cleanup - free all allocated data
- */
- cleanup()
- {
- int i, j;
- year_info *py, *pny;
- month_info *pm;
- day_info *pd, *pnd;
-
- for (py = head; py; py = pny) { /* main data structure */
- pny = py->next;
- for (i = 0; i < 12; i++) {
- if ((pm = py->month[i]) == NULL)
- continue;
- for (j = 0; j < NOTE_DAY; j++)
- for (pd = pm->day[j]; pd; pd = pnd) {
- pnd = pd->next;
- free(pd->text);
- free(pd);
- }
- free(pm);
- }
- free(py);
- }
-
- clear_syms(); /* symbol table */
-
- }
-
-
- /*
- * Utility routines for date and text parsing and entry
- */
-
- /*
- * get_month - convert numeric or alpha string to month; return 1-12 if valid,
- * 0 if not valid
- */
- int get_month(cp)
- char *cp;
- {
- int mm;
-
- if (! cp)
- return 0;
-
- if (isdigit(*cp))
- mm = atoi(cp);
- else
- for (mm = JAN;
- mm <= DEC && ci_strncmp(cp, months[mm-1], MIN_MONTH_LEN);
- mm++)
- ;
-
- return mm >= JAN && mm <= DEC ? mm : 0;
- }
-
-
- /*
- * date_type - examine token and return date type code; if DF_MONTH, fill
- * in number of month
- */
- int date_type(cp, pm)
- char *cp; /* pointer to start of token */
- int *pm; /* month value (returned) */
- {
- int mm;
-
- if (isdigit(*cp))
- return DF_DATE;
-
- if (ci_strncmp(cp, YEAR, strlen(YEAR)) == 0)
- return DF_YEAR;
-
- if (ci_strncmp(cp, OPT, strlen(OPT)) == 0)
- return DF_OPT;
-
- if (ci_strncmp(cp, NOTE, strlen(NOTE)) == 0)
- return DF_NOTE;
-
- return (mm = get_month(cp)) != 0 ? (*pm = mm, DF_MONTH) : DF_OTHER;
- }
-
-
- /*
- * is_valid - return TRUE if m/d/y is a valid date
- */
- int is_valid(m, d, y)
- register int m, d, y;
- {
- static char len[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
- return m >= JAN && m <= DEC &&
- d >= 1 && d <= (len[m] + (m == FEB && IS_LEAP(y)));
- }
-
-
- /*
- * loadwords - tokenize line buffer into word array, return word count.
- * differs from old loadwords() in that it handles quoted (" or ') strings
- */
-
- int loadwords()
- {
- register char *pstr, *ptok;
- char *delim, **ap;
- register int i;
-
- pstr = lbuf;
-
- for (i = 0, ap = words; TRUE; i++, ap++) {
- delim = *pstr == '"' ? "\"" :
- *pstr == '\'' ? "'" :
- WHITESPACE;
-
- ptok = pstr += strspn(pstr, delim); /* look for next token */
-
- if (! *pstr) { /* end of lbuf? */
- *ap = NULL; /* add null ptr at end */
- return i; /* return count of non-null ptrs */
- }
-
- if (*ptok == '"' || *ptok == '\'') /* bump past quote */
- ptok++;
-
- *ap = ptok; /* save token ptr */
-
- pstr += strcspn(pstr, delim); /* skip past token */
-
- if (*pstr) /* terminate token */
- *pstr++ = '\0';
- }
-
- }
-
-
- /*
- * get_text - retrieve remaining text in lbuf and transform in place, removing
- * leading/trailing whitespace and condensing runs of whitespace to one blank
- */
- get_text(pword)
- char **pword; /* pointer to first desired word in "words" */
- {
- char *pbuf, *p;
-
- /* copy words back to lbuf in place, separating by one blank */
-
- for (pbuf = lbuf; p = *pword; *pbuf++ = *++pword ? ' ' : '\0')
- while (*p)
- *pbuf++ = *p++;
-
- if (pbuf == lbuf)
- *lbuf = '\0';
- }
-
-
- /*
- * print_text - print tokens in text (assumed separated by single blank)
- * in PostScript format; convert '(' or ')' to octal escape
- */
- print_text(p)
- char *p;
- {
- char c;
-
- PRT("(");
- for ( ; c = *p ; p++) {
- if (c == ' ')
- PRT(")\n(");
- else
- PRT(c == '(' || c == ')' ? "\\%03o" : "%c", c);
- }
- PRT(")\n");
- }
-
-
- /*
- * def_footstring - print definition for foot string, again converting '('
- * or ')' to octal escape
- */
- def_footstring(p, c)
- char *p; /* definition */
- char c; /* L, C, or R */
- {
-
- PRT("/%cfootstring (", c);
-
- while (c = *p++)
- PRT(c == '(' || c == ')' ? "\\%03o" : "%c", c);
-
- PRT(") def\n");
- }
-
-
- /*
- * set_color - set one or all weekdays to print in black or gray
- */
- set_color(day, col)
- char *day; /* weekday name (or "all") */
- int col; /* select black or gray */
- {
- int i, do_all;
-
- do_all = ci_strncmp(day, ALL, strlen(ALL)) == 0; /* set all days? */
-
- for (i = 0; i < 7; i++)
- if (do_all || ci_strncmp(day, days[i], MIN_DAY_LEN) == 0)
- color[i] = col;
- }
-
- /*
- * parse - enter date file data (in lbuf[]) into data structure
- *
- * Looks for an entry of one of the following forms:
- *
- * year <year>
- * <month_name> <day>{*} {<text>}
- * <month><sep><day>{<sep><year>}{*} {<text>}
- * opt <options>
- * note <month_name> <text>
- * note <month> <text>
- *
- * where
- * <month_name> := first 3+ characters of name of month (in English)
- * <sep> := one or more non-numeric, non-space, non-'*' characters
- * <options> := any command-line option except -e, -f, -D, -U
- *
- * Enters information for year, month, and day into data structure for
- * subsequent retrieval. Lines of form "opt <options>" override any
- * defaults.
- *
- * N.B.: "inc" and other cpp-like lines are handled in read_datefile().
- *
- */
- int parse()
- {
- register char *cp;
- char **pword, *p;
- int mm, dd, yy;
- int text_type;
-
- /* macro to skip numeric field */
-
- #define SKIP_FIELD(p) \
- if (1) {while (isdigit(*p)) p++; while (*p && !isdigit(*p)) p++;} else
-
- /*
- * Get first field - can be either "year", "opt", "note", a month
- * name, or a (complete) numeric date spec
- */
-
- cp = *(pword = words);
-
- switch (date_type(cp, &mm)) {
-
- case DF_YEAR:
- if ((cp = *++pword) != NULL && (yy = atoi(cp)) > 0) {
- if (yy < 100)
- yy += 1900;
- curr_year = yy;
- return PARSE_OK;
- }
- return PARSE_INVDATE; /* year missing or invalid */
- break;
-
- case DF_OPT:
- if (!get_args(words, OTHER_FLAGS, FALSE)) {
- usage();
- exit(EXIT_FAILURE);
- }
- return PARSE_OK;
- break;
-
- case DF_NOTE:
- mm = get_month(*++pword);
- return enter_day_info(mm, NOTE_DAY, curr_year, NOTE_TEXT,
- ++pword);
- break;
-
- case DF_MONTH:
- if ((cp = *++pword) == NULL || (dd = atoi(cp)) == 0)
- return PARSE_INVDATE;
- text_type = cp[strlen(cp) - 1] == '*' ? HOLIDAY_TEXT : DAY_TEXT;
-
- return enter_day_info(mm, dd, curr_year, text_type, ++pword);
- break;
-
- case DF_DATE:
- text_type = cp[strlen(cp) - 1] == '*' ? HOLIDAY_TEXT : DAY_TEXT;
-
- /* extract month and day fields */
-
- mm = atoi(cp);
- SKIP_FIELD(cp);
-
- dd = atoi(cp);
- SKIP_FIELD(cp);
-
- /* Numeric dates may (or may not) have a year */
-
- if ((yy = atoi(cp)) > 0) {
- if (yy < 100)
- yy += 1900;
- curr_year = yy; /* if present, reset current year */
- }
-
- return enter_day_info(mm, dd, curr_year, text_type, ++pword);
- break;
-
- case DF_OTHER:
- return PARSE_INVLINE; /* line not recognized */
- break;
- }
- }
-
-
- /*
- * getline - read next non-null line of input file into lbuf; return 0 on EOF
- */
- int getline(dfp, pline)
- FILE *dfp;
- int *pline;
- {
- register char *cp;
- register int c;
- int in_comment; /* comments: from '#' to end-of-line */
-
- cp = lbuf;
- do {
- in_comment = FALSE;
- while ((c = getc(dfp)) != '\n' && c != EOF) {
- if (c == '#')
- in_comment = TRUE;
-
- /* ignore comments and leading white space */
- if (in_comment ||
- (cp == lbuf && (c == ' ' || c == '\t')))
- continue;
- *cp++ = c;
- }
- if (c == EOF)
- return FALSE;
-
- (*pline)++; /* bump line number */
-
- } while (cp == lbuf); /* ignore empty lines */
-
- *cp = '\0';
- return TRUE;
- }
-
-
- /*
- * read_datefile - read and parse date file, handling preprocessor lines
- */
- read_datefile(fp, filename)
- FILE *fp; /* file pointer (assumed open) */
- char *filename; /* file name (for error messages) */
- {
- static int file_level = 0;
- int if_level = 0;
- int restart_level = 0;
- int line = 0;
- int processing = TRUE;
-
- int pptype, extra, ntokens, save_year;
- int (*pfcn)();
- char *ptok;
- char **pword;
- char msg[STRSIZ], incpath[STRSIZ];
-
- #define ERR(errmsg) FPR(stderr, "%s: %s in file %s, line %d\n", \
- progname, errmsg, filename, line);
-
- if (fp == NULL) /* whoops, no date file */
- return;
-
- if (++file_level > MAX_NESTING) {
- ERR("maximum file nesting level exceeded");
- exit(EXIT_FAILURE);
- }
-
- save_year = curr_year; /* save default year */
-
- /* read lines until EOF */
-
- while (getline(fp, &line)) {
-
- ntokens = loadwords(); /* split line into tokens */
- pword = words; /* point to the first */
-
- /* get token type and pointers to function and name */
-
- pptype = pp_token(*pword++);
- pfcn = pp_info[pptype].pfcn;
- ptok = pp_info[pptype].token;
-
- switch (pptype) {
-
- case PP_DEFINE:
- case PP_UNDEF:
- if (processing)
- (*pfcn)(*pword);
- extra = ntokens > 2;
- break;
-
- case PP_ELSE:
- if (if_level < 1) {
- ERR("unmatched \"else\"");
- break;
- }
-
- if (processing) {
- processing = FALSE; /* disable processing */
- restart_level = if_level;
- } else if (if_level == restart_level) {
- processing = TRUE; /* re-enable processing */
- restart_level = 0;
- }
- extra = ntokens > 1;
- break;
-
- case PP_ENDIF:
- if (if_level < 1) {
- ERR("unmatched \"end\"");
- break;
- }
-
- if (! processing && if_level == restart_level) {
- processing = TRUE; /* re-enable processing */
- restart_level = 0;
- }
- if_level--;
- extra = ntokens > 1;
- break;
-
- case PP_IFDEF:
- case PP_IFNDEF:
- if_level++;
- if (processing) {
- if (! (*pfcn)(*pword)) {
- processing = FALSE;
- restart_level = if_level;
- }
- }
- extra = ntokens > 2;
- break;
-
- case PP_INCLUDE:
- if (processing)
- do_include(mk_path(incpath, filename), *pword);
- extra = ntokens > 2;
- break;
-
- case PP_OTHER: /* none of the above - parse as date */
- if (processing) {
- switch (parse()) {
-
- case PARSE_INVDATE:
- ERR("invalid date");
- break;
-
- case PARSE_INVLINE:
- ERR("unrecognized line");
- break;
-
- }
- }
- extra = FALSE;
- break;
-
- } /* end switch */
-
- if (extra) { /* extraneous data? */
- sprintf(msg, "extraneous data on \"%s\" line", ptok);
- ERR(msg);
- }
-
- } /* end while */
-
- if (if_level > 0)
- FPR(stderr, "%s: unterminated if{n}def..{else..}endif in %s\n",
- progname, filename);
-
- file_level--;
- curr_year = save_year; /* restore default year */
- }
-
- /*
- * Routines to extract and print data
- */
-
-
- /*
- * Browse through the data structure looking for day, holiday, or notes text
- * in the specified month/year
- */
- find_daytext(month, year, is_holiday)
- int month, year;
- int is_holiday;
- {
- register int day;
- year_info *py;
- month_info *pm;
- register day_info *pd;
- int first;
- char *fcn = is_holiday ? "holidaytext" : "daytext";
-
- /* if no text for this year and month, return */
-
- if ((py = find_year(year, FALSE)) == NULL ||
- (pm = py->month[month-1]) == NULL)
- return;
-
- /* walk array of day text pointers and linked lists of text */
-
- for (day = 1; day <= NOTE_DAY; day++) {
- for (pd = pm->day[day-1], first = TRUE;
- pd;
- pd = pd->next) {
- if (pd->is_holiday != is_holiday)
- continue;
- if (first) {
- if (day != NOTE_DAY) /* set up call */
- PRT("%d ", day);
- printf("[ \n");
- } else
- PRT("(.p)\n"); /* separate text */
- print_text(pd->text);
- first = FALSE;
- }
- if (! first) /* wrap up call (if one made) */
- PRT("] %s\n", day == NOTE_DAY ? "notetext" : fcn);
- }
- }
-
-
- /*
- * Browse through the date file looking for holidays in specified month/year
- */
- find_holidays(month, year)
- int month, year;
- {
- register int day;
- register unsigned long holidays;
- year_info *py;
- month_info *pm;
-
- pm = (py = find_year(year, FALSE)) ? py->month[month-1] : NULL;
-
- PRT("/note_block %s def\n", pm && pm->day[NOTE_DAY-1] ? "true" :
- "false"); /* are there notes? */
-
- PRT("/holidays ["); /* start definition of list */
-
- for (holidays = pm ? pm->holidays : 0, day = 1;
- holidays;
- holidays >>= 1, day++)
- if (holidays & 01)
- PRT(" %d", day);
-
- PRT(" 99 ] def\n"); /* terminate with dummy entry */
-
- }
-
-
- /*
- * pmonth - generate calendar for specified month/year
- */
- pmonth(month, year)
- int month, year;
- {
-
- PRT("/year %d def\n", year); /* set up year and month */
- PRT("/month %d def\n", month);
- find_holidays(month, year); /* make list of holidays */
- PRT("printmonth\n");
- find_daytext(month, year, TRUE); /* holiday text */
- find_daytext(month, year, FALSE); /* day and note text */
- PRT("showpage\n");
- }
-
-
- /*
- * Routines dealing with translation of file specifications (VMS, Un*x)
- */
-
- #ifdef VMS
- /*
- * mk_path - extract the path component from VMS file spec
- */
- char *mk_path(path, filespec)
- char *path; /* output path */
- char *filespec; /* input filespec */
- {
- char *p;
-
- strcpy(path, filespec);
- if (!(p = strchr(path, ']')) && !(p = strchr(path, ':')))
- p = path - 1; /* return null string if no path */
- *++p = '\0';
-
- return path;
- }
-
-
- /*
- * mk_filespec - merge VMS path and file names, where latter can be relative
- */
-
- char *mk_filespec(filespec, path, name)
- char *filespec; /* output filespec */
- char *path; /* input path */
- char *name; /* input file name */
- {
- char *p;
-
- *filespec = '\0';
-
- /* copy name intact if absolute; else merge path and relative name */
- if (!strchr(name, ':')) {
- strcpy(filespec, path);
- if ((p = LASTCHAR(filespec)) && *p == END_PATH &&
- name[0] == START_PATH && strchr(".-", name[1]))
- *p = *++name == '-' ? '.' : '\0';
- }
-
- return strcat(filespec, name);
- }
-
-
- /*
- * trnlog - return translation of VMS logical name (null if missing)
- */
- char *trnlog(logname) /* look up logical name */
- char *logname;
- {
- static char trnbuf[STRSIZ];
-
- $DESCRIPTOR(src, logname);
- $DESCRIPTOR(dst, trnbuf);
- short len;
- int ret;
-
- src.dsc$w_length = strlen(logname);
- ret = LIB$SYS_TRNLOG(&src, &len, &dst);
- return ret == SS$_NORMAL ? (trnbuf[len] = '\0', trnbuf) : NULL;
- }
-
- #else
-
- /*
- * mk_path - extract the path component from a Un*x file spec
- */
- char *mk_path(path, filespec)
- char *path; /* output path */
- char *filespec; /* input filespec */
- {
- char *p;
-
- strcpy(path, filespec);
- if (! (p = strrchr(path, END_PATH)) )
- p = path - 1; /* return null string if no path */
-
- *++p = '\0';
- return path;
- }
-
-
- /*
- * mk_filespec - merge Un*x path and file names, where latter can be relative
- */
-
- char *mk_filespec(filespec, path, name)
- char *filespec; /* output filespec */
- char *path; /* input path */
- char *name; /* input file name */
- {
- char *p;
-
- *filespec = '\0';
-
- /* copy name intact if absolute; else merge path and relative name */
-
- /* if path starts with "~/", translate it for user */
- if (strncmp(name, "~/", 2) == 0 && (p = trnlog(HOME_DIR)) != NULL) {
- strcpy(filespec, p);
- if ((p = LASTCHAR(filespec)) && *p != END_PATH)
- *++p = END_PATH, *++p = '\0';
- name += 2; /* skip "~/" */
- }
- else if (*name != START_PATH) { /* relative path */
- strcpy(filespec, path);
- if ((p = LASTCHAR(filespec)) && *p != END_PATH)
- *++p = END_PATH, *++p = '\0';
- }
-
- return strcat(filespec, name);
- }
-
-
- /*
- * trnlog - return translation of Un*x environment variable
- */
- char *trnlog(logname) /* look up logical name */
- char *logname;
- {
- return getenv(logname);
- }
-
- #endif
- SHAR_EOF
- fi
- if test -f 'pcal.hlp'
- then
- echo shar: will not over-write existing file 'pcal.hlp'
- else
- cat << \SHAR_EOF > 'pcal.hlp'
- 1 PCAL
- Pcal generates PostScript to produce landscape or portrait
- orientated calendars for any month and year. The defaults for
- month and year are the current month and year.
-
- VMS Version
- Execution format:
-
- pcal [options] [mm yy] [n]
-
- If a file named CALENDAR.DAT resides in the caller's home
- directory (or in a directory defined by the logical name PCAL_DIR,
- if it exists), it will be searched for lines with leading dates
- matching the requested month and year (current by default). Any
- text following the date will be printed on the calendar under the
- appropriate day of the month. Dates in the CALENDAR.DAT file may
- consist of a numeric or alpha month (at least the first 3
- characters for month names) followed by a numeric day and
- optionally followed by a year. Any non-numeric character may
- separate numeric dates. Holidays may be flagged by following the
- date immediately with '*'; this will cause the date to be printed
- in gray. Lines in the CALENDAR.DAT file consisting of "year xxxx"
- (where xxxx is a numeric year) can be used to set the year for
- following entries. This assumes that the following entries do not
- contain a year; any date entries containing year information will
- set the remembered year to that year. Lines consisting of
- "opt <options>" can be used to override defaults for all command-
- line flags except -e, -f, -D, and -U; any flags set in this manner
- are themselves overridden by flags specified explicitly on the
- command line. Comments ('#' through end-of-line) are permitted.
-
- Example:
-
- # sample CALENDAR.DAT file - Raytheon holidays and exempt paydays, 1990
-
- opt -t Helvetica-Bold -d Helvetica-Bold # override default fonts
- opt -M # print moon phase
-
- year 1990 # set default year
-
- 7/4* Independence Day # '*' flags 7/4 as holiday
- 7/12/90 Exempt payday # full numeric date
- Aug 16 Exempt payday # alternate date format
- 9/3* Labor Day
- 9/20 Exempt payday
- 10/8* Columbus Day (observed)
- 10/25 Exempt payday
- 11/20 Exempt payday
- 11/22* Thanksgiving
- 11/23*
- 12/13 Exempt payday
- 12/24*
- 12/25* Christmas
-
- Release 2.3 of pcal adds rudimentary cpp-like functionality to the
- date file, supporting define|undef, if{n}def ... {else ...} endif,
- and include:
-
- define meetings
-
- ifdef meetings
- include meetings.dat
- undef meetings
- endif
-
- Symbol names are case-insensitive. It is not an error to "undef"
- an undefined symbol, nor to "define" a previously-defined one.
-
- "ifdef" alone is always false; "ifndef" alone is always true.
-
- The name of the file in the "include" directive may optionally be
- surrounded by either "" or <>, both of which are ignored. If the
- name is not an absolute path, it is taken to be relative to the
- directory where the file containing the directive is located.
-
- Release 2.3 allows the user to print additional notes in an unused
- unused calendar box via lines of the form "note <month> <text>",
- where <month> specifies the month (numeric or alphabetic form) and
- <text> is the text to add. All such text will appear in the
- "Thursday" box on the last line (next to the small calendars).
-
- Release 2.3 also looks for global symbol PCAL_OPTS; if defined,
- its contents are parsed as command-line flags. These override the
- program defaults, but are overridden by any specified via "opt"
- lines in the date file or on the command line. Example:
-
- $ define PCAL_OPTS "-n Helvetica -D meetings" ! login.com
-
- $ pcal -"U" meetings 9 90 ! un-define symbol at runtime
-
- 2 parameters
- mm yy n
- "mm" and "yy" are numeric values of the month (1-12) and year
- (0-99) (i.e., July 1990 would be 7 90). If you just include the
- "yy" option, an entire 12 months of calendars will be generated.
- A specific month can be produced by including the "mm" parameter.
- The "n" parameter will produce the "n" consecutive months of
- calendars starting with the requested month.
-
- The following flags may be specified (in increasing order of
- precedence) in global symbol PCAL_OPTS, in "opt" lines in the date
- file (all but -e, -f, -D, -U), or on the command line. Any flag
- which normally takes an argument may be specified without the
- argument; this resets its value to the program default. (-D
- alone thus clears all defined symbols; -U alone has no effect.)
-
- The '-' flag has been added to disambiguate cases where an
- argument-less flag has been specified immediately before a numeric
- parameter:
-
- $ pcal -t - 9 90
-
- 2 -e
- Print an empty calendar (i.e., do not print entries from a
- CALENDAR.DAT file.)
-
- 2 -f <FILE>
- Directs pcal to use the file name <FILE> as the input file in
- place of the default CALENDAR.DAT file in the callers home
- directory or in the directory specified by logical name PCAL_DIR.
-
- 2 -o <FILE>
- Directs pcal to write the PostScript calendar into FILE
- (default: CALENDAR.PS in the current directory.)
-
- 2 -l
- This will cause the output to come out in landscape mode
- (default).
-
- 2 -p
- This will cause the output to come out in portrait mode
- instead of landscape mode.
-
- 2 -b <DAY> | all
- This will cause all dates on weekday DAY to be printed in
- black; "-b all" causes all dates to be printed in black unless
- explicitly flagged as a holiday.
-
- 2 -g <DAY> | all
- This will cause all dates on weekday DAY to be printed in
- gray; "-g all" causes all dates to be printed in gray. Default is
- to print Saturdays and Sundays in gray and other dates in black.
-
- 2 -t <FONT>
- This option can be used to change the font the title is
- printed in (ie. pcal -t Times-Roman). The default is Times-Bold.
-
- 2 -d <FONT>
- This option is the same as -t except that the font used to
- print the day numbers is changed. The default is Times-Bold.
-
- 2 -n <FONT>
- This option is the same as -n except that the font used to
- print the notes in the calendar boxes is changed. The default is
- Helvetica-Narrow.
-
- 2 -m
- This option causes a moon to be printed on days corresponding
- to a full, half, or new moon (default: no moons).
-
- 2 -"M"
- This option causes a moon to be printed on all days (default:
- no moons).
-
- 2 -"L" <STRING>
- This will cause STRING to be printed as a left footer.
-
- 2 -"C" <STRING>
- This will cause STRING to be printed as a center footer.
-
- 2 -"R" <STRING>
- This will cause STRING to be printed as a right footer.
-
- 2 -"D" <SYM>
- This will define symbol SYM prior to reading the date file;
- -D alone clears all defined symbols.
-
- 2 -"U" <SYM>
- This will undefine symbol SYM prior to reading the date file.
-
- 2 CREDITS
- The original PostScript code to generate the calendars was
- written by Patrick Wood (Copywrite (c) 1987 by Patrick Wood of
- Pipeline Associates, Inc.), and authorized for modification and
- redistribution. The CALENDAR.DAT file inclusion code was
- originally written in "bs(1)" by Bill Vogel of AT&T. Patrick's
- original PostScript was modified and enhanced several times by
- others whose names have regrettably been lost. Ken Keirnan of
- Pacific Bell assembled the original "C" version upon which this is
- based; additional modifications and enhancements were the work of
- Joseph P. Larson, Ed Hand, Andrew W. Rogers, Mark Kantrowitz, Joe
- Brownlee, and Jamie Zawinski. This VMS HELP file was written by
- Richard Dyson and updated by Andrew W. Rogers.
-
- SHAR_EOF
- fi
- if test -f 'pcal.man'
- then
- echo shar: will not over-write existing file 'pcal.man'
- else
- cat << \SHAR_EOF > 'pcal.man'
- .TH PCAL 1
- .SH NAME
- pcal \- generate PostScript calendars
- .SH SYNOPSIS
- .B pcal
- [
- .BR \-e
- |
- .BR \-f
- <cal>
- ]
- [
- .BR \-o
- <file>
- ]
- [
- .BR \-l
- |
- .BR \-p
- ]
- [
- .BR \-m
- |
- .BR \-M
- ]
- [
- .BR \-b
- <day>
- |
- all
- ]*
- [
- .BR \-g
- <day>
- |
- all
- ]*
- [
- .B -t
- <titlefont name>
- ]
- [
- .B -d
- <dayfont name>
- ]
- [
- .B -n
- <notesfont name>
- ]
- [
- .B -L
- <foot string>
- ]
- [
- .B -C
- <foot string>
- ]
- [
- .B -R
- <foot string>
- ]
- [
- .B -D
- <symbol>
- ]
- [
- .B -U
- <symbol>
- ]
- [
- .B month
- ] [
- .B year
- ] [
- .B nmonths
- ]
- .SH DESCRIPTION
- .I Pcal
- generates PostScript to produce landscape or portrait calendars for any
- month and year. The arguments
- .BR month ,
- .BR year ,
- and
- .BR nmonths ,
- if provided, should be numeric. The month should be in the range 1 - 12,
- and year should be specified as 1 or 2 digits or as the full 4 digit year.
- .P
- If no numeric arguments are provided, the current month and year will be
- generated.
- .P
- If one numeric argument is provided, it is interpreted as the year; the
- entire year will be generated. Otherwise,
- .I nmonth
- months, starting with
- .I month
- and
- .I year,
- will be generated.
- .PP
- If a file named
- .I \.calendar
- or
- .I calendar
- (for compatibility with older versions)
- exists in the caller's home directory (or in the directory pointed to by
- environment variable PCAL_DIR), it will be searched for lines with
- leading dates matching the requested month and year (current by default).
- Any text following the date will be printed on the calendar under the
- appropriate day of the month. Dates in the
- .I \.calendar
- file may consist of a numeric or alpha month (at least the first 3 characters
- for month names) followed by a numeric day and optionally followed by a
- year. Any non-numeric character may separate numeric dates. Holidays may
- be flagged by following the date immediately with '*'; this will cause the
- date to be printed in gray.
- .PP
- Lines in the
- .I \.calendar
- file consisting of "year xxxx" (where xxxx is a numeric year) can be used
- to set the year for following entries. This assumes that the following
- entries do not contain a year; any date entries containing year information
- will set the remembered year to that year.
- .PP
- Lines in the
- .I \.calendar
- file consisting of "opt <options>" can be used to override the defaults for
- any command-line flags except -e, -f, -D, and -U. Any flags specified in this
- manner
- are, in turn, overridden by those specified explicitly on the command line.
- .PP
- Lines in the
- .I \.calendar
- file consisting of "note <month>" can be used to place notes regarding the
- entire month is one of the unused blocks of the calendar. The <month>
- indicator may be either a number 1 through 12 or an alphabetic month name
- as described above.
- .PP
- Comments ('#' through end-of-line) are supported.
- .PP
- .I Pcal
- supports rudimentary cpp-like functionality in the
- date file, allowing the following constructs:
- .BR define |
- .BR undef ,
- .B if{n}def ... {else ...} endif,
- and
- .BR include.
- Note that these are not preceded by '#' as they are in C.
- .PP
- Symbol names are case-insensitive. It is not an error to "undef"
- an undefined symbol, nor to "define" a previously-defined one.
- .PP
- "ifdef" alone is always false; "ifndef" alone is always true.
- .PP
- The name of the file in the "include" directive may optionally be
- surrounded by either "" or <>, both of which are ignored. If the
- name is not an absolute path, it is taken to be relative to the
- directory where the file containing the directive is located.
- .I Pcal
- is smart enough to translate "~/" to the user's home directory.
- .PP
- .I Pcal
- has many options:
- .P
- .TP
- .B \-e
- Print an empty calendar. Do not print entries from a calendar file.
- .TP
- .B \-f <cal>
- Directs
- .I pcal
- to use the file name <cal> as the input file in place of the default
- .I \.calendar
- file in the callers home directory (or directory pointed to
- by PCAL_DIR).
- .TP
- .B \-o <file>
- Directs
- .I pcal
- to write the output to <file> instead of to stdout.
- .TP
- .B \-l
- This will cause the output to come out in landscape mode (default).
- .TP
- .B \-p
- This will cause the output to come out in portrait mode.
- .TP
- .B \-m
- This will cause moon icons to be printed on dates corresponding to
- new, half, and full moons (default: no moons).
- .TP
- .B \-M
- This will cause moon icons to be printed on all dates (default: no moons).
- .TP
- .B \-b <day> | all
- This will cause all dates falling on weekday <day> to be printed in black;
- "-b all" causes all weekdays to be printed in black.
- .TP
- .B \-g <day> | all
- This will cause all dates falling on weekday <day> to be printed in gray;
- "-g all" causes all weekdays to be printed in gray.
- .IP
- (The default for the -b and -g flags is to print Saturdays and Sundays in
- gray and other days - unless flagged as holidays - in black.)
- .TP
- .B \-t <titlefont name>
- This option can be used to change the font the title
- is printed in. (ie. pcal -t Times-Roman).
- .TP
- .B \-d <dayfont name>
- This option is the same as -t except that the font used
- to print the day numbers is changed.
- .TP
- .B \-n <notesfont name>
- This option is the same as -n except that the font used
- to print the notes in the calendar boxes is changed.
- .TP
- .B \-D <symbol>
- This option defines the named symbol prior to reading the date file.
- .TP
- .B \-U <symbol>
- This option un-defines the named symbol prior to reading the date file.
- .TP
- .B \-L <string>
- This option causes the accompanying string to be printed as a left footer.
- .TP
- .B \-C <string>
- This option causes the accompanying string to be printed as a center footer.
- .TP
- .B \-R <string>
- This option causes the accompanying string to be printed as a right footer.
- .IP
- Any option which normally takes an argument may be specified without
- the argument in order to reset the value to the program default.
- .B \-D
- alone clears all the defined symbols;
- .B \-U
- alone has no effect. The
- .B \-
- (or
- .BR \-\- ,
- System V people)
- flag may be used to disambiguate cases such as "pcal -t 9 90"; this
- could be written instead as "pcal -t - 9 90" or "pcal -t -- 9 90".
- .IP
- If the environment variable PCAL_OPTS is defined, its contents are
- parsed as a command line. Flags set via PCAL_OPTS override the
- program defaults, but are overridden by flags set via "opt" lines
- in the date file or explicitly on the command line.
- .SH SEE ALSO
- cal(1)
- .SH CAVEATS
- The original PostScript code to generate the calendars was written by
- Patrick Wood (Copywrite (c) 1987 by Patrick Wood of Pipeline Associates,
- Inc.), and authorized for modification and redistribution. The calendar
- file inclusion code was originally written in "bs(1)" by Bill Vogel of
- AT&T. Patrick's original PostScript was modified and enhanced several
- times by others whos names have regrettably been lost. Ken Keirnan of
- Pacific Bell assembled the original "C" version upon which this is based;
- additional modifications and enhancements were the work of Joseph P.
- Larson, Ed Hand, Andrew W. Rogers, Mark Kantrowitz, Joe Brownlee, and
- Jamie Zawinski.
- SHAR_EOF
- fi
- if test -f 'pcalinit.c'
- then
- echo shar: will not over-write existing file 'pcalinit.c'
- else
- cat << \SHAR_EOF > 'pcalinit.c'
- /* create a .h file from a .ps file. Strips out leading and trailing
- * whitespace, blank lines, and lines consisting solely of comments,
- * except for the very first block of comments/blanklines, which are
- * turned into C comments at the top of the file.
- *
- * 14-sep-90 Jamie Zawinski created.
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
-
- char *strip_white (string)
- char *string;
- {
- int n;
- for (; *string == ' ' || *string == '\t' || *string == '\n'; string++);
- n = strlen(string)-1;
- for (; string[n] == ' ' || string[n] == '\t' || string[n] == '\n'; n--)
- string[n] = '\0';
- return string;
- }
-
- main (argc, argv)
- int argc; char *argv[];
- {
- FILE *in, *out;
- char line[256], *L;
- int in_initial_comments = 1;
- if (argc != 3) {
- fprintf(stderr, "usage: %s <infile>.ps <outfile>.h\n", argv[0]);
- exit(-1); }
-
- in = fopen(argv[1], "r");
- if (NULL == in) {
- fprintf(stderr, "%s: couldn't open %s\n", argv[0], argv[1]);
- exit(-1); }
-
- out = fopen(argv[2], "w");
- if (NULL == out) {
- fprintf(stderr, "%s: couldn't open %s\n", argv[0], argv[2]);
- exit(-1); }
-
- fprintf (out,
- "/* automatically generated from \"%s\" - DO NOT EDIT THIS FILE!\n *\n",
- argv[1]);
- for (;;) {
- if (NULL == fgets (line, 255, in)) break;
- L = strip_white(line);
- if ( in_initial_comments ) {
- if ( L[0] != '%' && L[0] != '\0' ) {
- in_initial_comments = 0;
- fprintf(out, " */\n\nchar *header[] = {\n \"%s\",\n", L); }
- else
- fprintf(out, " * %s\n", L);
- }
- else if (L[0] != '%' && L[0] != '\0' )
- fprintf(out, " \"%s\",\n", L);
- }
- fprintf(out, " (char *)0,\n};\n");
- fclose(out);
- fclose(in);
- }
- SHAR_EOF
- fi
- if test -f 'pcalinit.ps'
- then
- echo shar: will not over-write existing file 'pcalinit.ps'
- else
- cat << \SHAR_EOF > 'pcalinit.ps'
- %!ps
- % pcalinit.ps - provides the PostScript routines for v2.3 of pcal.c
- %
- % 2.3 modified by Jamie Zawinski <jwz@lucid.com>:
- %
- % merged in moon routines (originally by Mark Hanson)
- %
- % 2.2 modified by Joe Brownlee:
- %
- % add "notetext" to print notes in unused calendar box
- %
- % 2.1 modified by Mark Kantrowitz:
- %
- % use symbolic names instead of magic numbers throughout
- % support -L, -C, -R, -n options (all new)
- % print holiday text in otherwise-wasted space next to date
- % use larger text for dates in large calendars
- %
- % 2.0 modified by Andrew W. Rogers:
- %
- % skip printing days of week on small calendars
- % center month and year at top of calendar
- % use correct algorithm for leap year calculation
- % get month and day names from main program
- % use table to determine color (black/gray) of weekdays and holidays
- % use hanging indent to print continued text lines
-
- /titlefontsize 48 def
- /weekdayfontsize 12 def
- /footfontsize 12 def
- /datefontsize 30 def
- /savedatefontsize datefontsize def
- /notesfontsize 6 def
- /daywidth 100 def
- /dayheight 80 def
- /negdaywidth 0 daywidth sub def
- /negdayheight 0 dayheight sub def
- /prtnum { 3 string cvs show} def
-
- /drawgrid { % draw calendar boxes
- dayfont findfont weekdayfontsize scalefont setfont
- 0 1 6 {
- /i exch def
- submonth 0 eq {
- i daywidth mul 40 moveto
- day_names i get
- daywidth center
- } if
- i daywidth mul 35 moveto
- 1.0 setlinewidth
- 0 1 5 {
- gsave
- daywidth 0 rlineto
- 0 negdayheight rlineto
- negdaywidth 0 rlineto
- closepath stroke
- grestore
- 0 negdayheight rmoveto
- pop } for
- } for
- } def
-
-
- /drawnums { % place day numbers on calendar
- dayfont findfont datefontsize scalefont setfont
- /start startday def
- /days ndays def
- /fontdiff datefontsize savedatefontsize sub def
- /n 0 def
- start daywidth mul 5 add 10 fontdiff sub rmoveto
- 1 1 days {
- /day exch def
- gsave
- submonth 0 eq {
- /gray day_gray day start add 1 sub 7 mod get def
- day holidays n get eq {
- /gray holiday_gray def
- /n n 1 add def
- } if
- gray {
- 0.8 setgray
- } if
- } if
- day prtnum
- grestore
- day start add 7 mod 0 eq
- {
- currentpoint exch pop dayheight sub 5 exch moveto
- }
- {
- daywidth 0 rmoveto
- } ifelse
- } for
- } def
-
-
- /drawfill { % place fill squares on calendar
- /start startday def
- /days ndays def
- 0 35 rmoveto
- 1.0 setlinewidth
- 0 1 start 1 sub {
- gsave
- .9 setgray
- daywidth 0 rlineto
- 0 negdayheight rlineto
- negdaywidth 0 rlineto
- closepath fill
- grestore
- daywidth 0 rmoveto
- pop } for
- submonth 1 eq
- {
- /lastday 42 def
- 600 -365 moveto
- }
- {
- note_block
- {
- /lastday 39 def
- 300 -365 moveto
- }
- {
- /lastday 40 def
- 400 -365 moveto
- } ifelse
- } ifelse
- lastday -1 ndays start 1 add add
- {
- /day exch def
- gsave
- .9 setgray
- daywidth 0 rlineto
- 0 negdayheight rlineto
- negdaywidth 0 rlineto
- closepath fill
- grestore
- day 7 mod 1 eq
- { 600 -365 dayheight add moveto }
- { negdaywidth 0 rmoveto }
- ifelse
- } for
- } def
-
-
- /isleap { % is this a leap year?
- year 4 mod 0 eq % multiple of 4
- year 100 mod 0 ne % not century
- year 400 mod 0 eq or and % or divisible by 400
- } def
-
- /isleap_2 { % is some other year a leap year?
- /a_year exch def
- a_year 4 mod 0 eq % multiple of 4
- a_year 100 mod 0 ne % not century
- a_year 400 mod 0 eq or and % or divisible by 400
- } def
-
- /days_month [ 31 28 31 30 31 30 31 31 30 31 30 31 ] def
-
- /ndays { % number of days in this month
- days_month month 1 sub get
- month 2 eq % Feb
- isleap and
- {
- 1 add
- } if
- } def
-
- /ndays_2 { % number of days in some other month
- /a_month exch def
- /a_year exch def
- days_month a_month 1 sub get
- a_month 2 eq % February
- a_year isleap_2 and
- { 1 add }
- if
- } def
-
-
- /startday { % starting day-of-week for this month
- /off year 2000 sub def % offset from start of epoch
- off
- off 4 idiv add % number of leap years
- off 100 idiv sub % number of centuries
- off 400 idiv add % number of years divisible by 400
- 6 add 7 mod 7 add % offset from Jan 1 2000
- /off exch def
- 1 1 month 1 sub {
- /idx exch def
- days_month idx 1 sub get
- idx 2 eq
- isleap and
- {
- 1 add
- } if
- /off exch off add def
- } for
- off 7 mod % 0--Sunday, 1--monday, etc.
- } def
-
-
- /center { % center string in given width
- /width exch def
- /str exch def width str
- stringwidth pop sub 2 div 0 rmoveto str show
- } def
-
-
- /strcat { % concatenate two strings
- 2 copy
- length exch length
- dup 3 -1 roll add
- string
- dup 0 6 -1 roll putinterval
- dup 3 -1 roll 4 -1 roll putinterval
- } def
-
-
- /calendar
- {
- titlefont findfont titlefontsize scalefont setfont
- /month_name month_names month 1 sub get def
- /yearstring year 10 string cvs def
- 0 60 moveto
- month_name ( ) strcat yearstring strcat 700 center
- % month_name show
- % daywidth 7 mul yearstring stringwidth pop sub 60 moveto
- % yearstring show
-
- submonth 0 eq {
- titlefont findfont footfontsize scalefont setfont
- /bottomrow { dayheight 6 mul 20 sub neg } def
- 0 bottomrow moveto
- Lfootstring show
- daywidth 7 mul Rfootstring stringwidth pop sub
- bottomrow moveto
- Rfootstring show
- daywidth 7 mul Cfootstring stringwidth pop sub 2 div
- bottomrow moveto
- Cfootstring show
- } if
- 0 0 moveto
- drawnums
- 0 0 moveto
- drawfill
- 0 0 moveto
- drawgrid
- 0 0 moveto
- submonth 0 eq { drawmoons } if
- } def
-
-
- /daytext {
- notesfont findfont notesfontsize scalefont setfont
- /mytext exch def /myday exch def
- startday myday 1 sub add dup 7 mod daywidth mul 2 add % gives column
- exch 7 idiv negdayheight mul % gives row
- dup /ypos exch def moveto
- /LM currentpoint pop def /RM LM 95 add def
- mytext { dup (.p) eq { crlf pop} {prstr ( ) show} ifelse } forall
- } def
-
-
- /holidaytext {
- notesfont findfont notesfontsize scalefont setfont
- /mytext exch def /myday exch def
- startday myday 1 sub add dup 7 mod daywidth mul
- myday 10 lt {25} {40} ifelse add % gives column
- exch 7 idiv negdayheight mul 27 add % gives row
- dup /ypos exch def moveto
- /LM currentpoint pop def /RM LM myday 10 lt {75} {60} ifelse add def
- /day myday def
- do-moon-p { /RM RM 16 sub def } if
- mytext { dup (.p) eq { crlf pop} {prstr ( ) show} ifelse } forall
- } def
-
-
- /notetext {
- dayfont findfont 12 scalefont setfont
- 4 daywidth mul 5 add % title column
- 5 negdayheight mul 24 add % title row
- moveto
- (Notes) show
- notesfont findfont notesfontsize scalefont setfont
- /mytext exch def
- 4 daywidth mul 5 add % gives column
- 5 negdayheight mul 16 add % gives row
- dup /ypos exch def moveto
- /LM currentpoint pop def /RM LM 95 add def
- mytext { dup (.p) eq { crlf pop} {prstr ( ) show} ifelse } forall
- } def
-
- /crlf {
- ypos notesfontsize sub /ypos exch def LM ypos moveto
- } def
-
- /prstr {
- dup stringwidth pop currentpoint pop
- add RM gt {crlf ( ) show} if show
- } def
-
- /printmonth {
- landscape-p
- { 90 rotate 50 -120 translate }
- { 0.75 0.75 scale 50 500 translate }
- ifelse
- /submonth 0 def
- calendar
- month 1 sub 0 eq
- {
- /lmonth 12 def
- /lyear year 1 sub def
- }
- {
- /lmonth month 1 sub def
- /lyear year def
- } ifelse
- month 1 add 13 eq
- {
- /nmonth 1 def
- /nyear year 1 add def
- }
- {
- /nmonth month 1 add def
- /nyear year def
- } ifelse
- /savemonth month def
- /saveyear year def
- /submonth 1 def
- /savedatefontsize datefontsize def
- /year lyear def
- /month lmonth def
- /datefontsize 48 def
- gsave
- 500 -365 translate
- gsave
- .138 .138 scale
- 10 -120 translate
- calendar
- grestore
- /submonth 1 def
- /year nyear def
- /month nmonth def
- 100 0 translate
- gsave
- .138 .138 scale
- 10 -120 translate
- calendar
- grestore
- /month savemonth def
- /year saveyear def
- /submonth 0 def
- /datefontsize savedatefontsize def
- grestore
- } def
-
- % Moons...
-
- /doy { % year month day doy -> returns the number of the day
- /theday exch def % of the year
- /themonth exch def
- /theyear exch def
- /dayofyear 0 def
- themonth 1 ne {
- 1 1 themonth .5 sub {
- /mo exch cvi def
- /dayofyear theyear mo
- ndays_2
- dayofyear add
- def
- } for
- } if
- dayofyear theday add
- } def % doy
-
-
- /findphase { % find the difference between any day and the reference
- /thisday exch def % day of the full moon
- /thismonth exch def % will probably be one off if the reference is leap yr.
- /thisyear exch def
- /daysdiff thisyear thismonth thisday doy
- fullyear fullmonth fullday doy sub
- longer mul def % try to be accurate about it
- /yearsdiff thisyear fullyear sub def
- yearsdiff 0 ne {
- /daysdiff daysdiff yearsdiff daysperyear mul
- yearsdiff 100 idiv yearsdiff 400 idiv sub sub add def
- } if
- daysdiff % return difference in days
- } def % findphase
-
- /shrink { 2 sqrt div } def
-
- /transmogrify { 10000 mul cvi % take a real number and 'mod it down'
- period 10000 mul cvi % so it is in the range 0->period
- mod % or -period->0
- 10000 div } def % the 10000's preserve the accuracy
-
-
- /domoon { % draw the moon at the current phase
- /phase exch def
-
- 0 0 radius % might as well push these on now
- 0 0 radius
- phase halfperiod lt
- { 270 90 arc stroke % line on right, fill on left
- 0 radius neg moveto
- 270 90 arcn
- }
- { 90 270 arc stroke % line on left, fill on right
- 0 radius neg moveto
- 270 90 arc
- /phase phase halfperiod sub def % get rid of top halfperiod
- }
- ifelse
-
- /phase phase quartperiod sub % scale it down to -r(root2) -> r(root2)
- rect mul
- def
-
- phase % x1
- phase abs shrink % y1 need abs!
- phase % x2
- phase abs shrink neg % y2 need abs!
- 0 % x3
- radius neg % y3
- curveto
- fill
- } def % domoon
-
- /do-moon-p {
- draw-moons true eq
- { true }
- { draw-moons 4 eq
- { /p startphase day longer mul add
- % AWR: tweaked to more accurately select date of new/half/full moons
- % transmogrify neg period add
- 0.5 sub transmogrify neg period add
- def
- p 0.00 gt p 1.00 lt and
- p 7.38 gt p 8.38 lt and or
- p 14.76 gt p 15.76 lt and
- p 22.15 gt p 23.15 lt and or
- or }
- { false }
- ifelse
- }
- ifelse
- } def
-
-
- /shiftdo {
- do-moon-p
- { /p startphase day longer mul add
- transmogrify neg period add
- def
- p domoon }
- if
- } def
-
-
- /drawmoons {
- /fullyear 1990 def % these are the dates of a full moon,
- /fullmonth 2 def % any date should work if it is that
- /fullday 9 def % of a full moon, but I haven't tried many
- % I wouldn't make this reference date fall in a leap year, wierdness
- % will probably happen in findphase. You will probably gain or lose a day
- % somewhere. MBH
- /period 29.5306 def
- /daysperyear 365.2422 def
- /longer daysperyear 365 div def
- /halfperiod period 2 div def
- /quartperiod period 4 div def
- /radius 6 def
- /rect radius 2 sqrt mul quartperiod div def
- /startphase year month 0 findphase transmogrify
- dup 0 lt { period add } if def
- /start startday def
- /days year month ndays_2 def
-
- gsave
- 0.1 setlinewidth
- newpath
- daywidth radius sub 3 sub 30 radius 3 add sub translate
- start daywidth mul 0 translate
- 1 1 days {
- /day exch def
- shiftdo
- day start add 1 sub 7 mod 6 eq
- { daywidth 6 mul neg dayheight neg translate }
- { daywidth 0 translate }
- ifelse
- } for
- grestore
- } def % drawmoons
-
- SHAR_EOF
- fi
- exit 0
- # End of shell archive
-