home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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 (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 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).
- *
- * 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:
- *
- * -d <FONT> specify alternate font for day names
- * (default: Times-Bold)
- *
- * -e generate empty calendar (ignore date file)
- *
- * -f <FILE> specify alternate date file (default:
- * ~/calendar on Unix, SYS$LOGIN:CALENDAR.DAT
- * on VMS)
- *
- * -o <FILE> specify alternate output file (default:
- * stdout on Unix, CALENDAR.PS on VMS)
- *
- * -r generate portrait-style calendars
- * (default: landscape)
- *
- * -s print Saturdays in black
- * -S print Saturdays and Sundays in black
- * (default: print Saturdays and Sundays in gray)
- *
- * -t <FONT> specify alternate font for titles
- * (default: Times-Bold)
- *
- * Parameters and flags may be mixed on the command line.
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <time.h>
- #include <string.h>
-
- #ifdef VMS
- #define INFILE "SYS$LOGIN:CALENDAR.DAT"
- #define OUTFILE "CALENDAR.PS"
- #define S_OPT "\"S\""
- #define END_PATH ']'
- #define EXIT_SUCCESS 1
- #define EXIT_FAILURE 3
- #else
- #define INFILE "~/calendar"
- #define OUTFILE ((char *)0)
- #define S_OPT "S"
- #define END_PATH '/'
- #define EXIT_SUCCESS 0
- #define EXIT_FAILURE 1
- #endif
-
- #define DAYFONT "Times-Bold"
- #define TITLEFONT "Times-Bold"
-
- #define FALSE 0
- #define TRUE 1
-
- #define PRT (void)printf
- #define FPR (void)fprintf
-
- #define MIN_YR 1900
- #define MAX_YR 9999
-
- #define MAXARGS 3
- #define HOLIDAY (1 << 6) /* bit set to flag day as holiday */
-
- char *words[100]; /* maximum number of words on a line */
- char lbuf[512]; /* maximum line size */
-
- char *months[] = { /* used to match alpha months */
- "jan", "feb", "mar", "apr", "may", "jun",
- "jul", "aug", "sep", "oct", "nov", "dec",
- (char *)0,
- };
-
- #include "pcalinit.h" /* PostScript boilerplate */
-
- FILE *cfp = NULL;
- int curr_year;
-
-
- main(argc, argv)
- int argc;
- char **argv;
- {
-
- /* Look for the argument following a flag - may be separated by spaces or
- * not. If no argument appears, leave "arg" alone
- */
- #define GETARG(arg) if ((parg = *++opt ? opt : \
- (*(argv+1) && **(argv+1) != '-' ? *++argv : NULL) ) \
- != NULL) arg = parg; else
-
- /* Loop through one of the header sections in pcalinit.h */
- #define DOHEADER(phdr) for (ap = phdr; *ap; ap++) PRT("%s\n", *ap)
-
- char *progname = **argv ? *argv : "pcal";
- struct tm *p_tm;
- register char **ap;
- register char *cp;
- char *date_file = NULL;
- char *opt, *pnum, *parg, *p;
- long tmp;
- int nocal = FALSE;
- int sat_gray = TRUE;
- int sun_gray = TRUE;
- char *titlefont = TITLEFONT;
- char *dayfont = DAYFONT;
- char *outfile = OUTFILE;
- int rotate = 90;
- int month, year, nmonths;
- int badopt = FALSE; /* flag set if bad option */
- int badpar = FALSE; /* flag set if bad param */
- int nargs = 0; /* count of non-flag args */
- int numargs[MAXARGS]; /* non-flag (numeric) args */
-
- /* isolate root program name (for use in error messages) */
-
- if ((p = strrchr(progname, END_PATH)) != NULL)
- progname = ++p;
- if ((p = strchr(progname, '.')) != NULL)
- *p = '\0';
-
- /* walk through command-line arguments */
-
- while (*++argv) {
-
- if (**argv != '-') { /* assume numeric argument */
- if (nargs < MAXARGS)
- numargs[nargs++] = atoi(*argv);
- continue;
- }
-
- opt = (*argv) + 1;
- switch (*opt) {
-
- case 'd': /* specify alternate day font */
- GETARG(dayfont);
- break;
-
- case 'e': /* generate empty calendar */
- nocal = TRUE;
- date_file = NULL;
- break;
-
- case 'f': /* specify alternate calendar file */
- GETARG(date_file);
- nocal = FALSE;
- break;
-
- case 'o': /* specify alternate output file */
- GETARG(outfile);
- break;
-
- case 'r': /* generate portrait calendar */
- rotate = 0;
- break;
-
- case 'S': /* Saturdays and Sundays in black */
- sun_gray = FALSE;
- case 's': /* Saturdays in black */
- sat_gray = FALSE;
- break;
-
- case 't': /* specify alternate title font */
- GETARG(titlefont);
- break;
-
- default:
- FPR(stderr, "%s: illegal option -%s\n", progname, opt);
- badopt = TRUE;
- break;
- }
- }
-
- /* Get and validate non-flag (numeric) parameters */
-
- switch (nargs) {
- case 0: /* no arguments - print current month/year */
- time(&tmp);
- p_tm = localtime(&tmp);
- month = p_tm->tm_mon + 1;
- year = p_tm->tm_year;
- nmonths = 1;
- break;
- case 1: /* one argument - print entire year */
- month = 1;
- year = numargs[0];
- nmonths = 12;
- break;
- default: /* two or three arguments - print one or more months */
- month = numargs[0];
- year = numargs[1];
- nmonths = nargs > 2 ? numargs[2] : 1;
- break;
- }
-
- if (year > 0 && year < 100) /* treat nn as 19nn */
- year += 1900;
-
- if (nmonths < 1) /* ensure at least one month */
- nmonths = 1;
-
- if (month < 1 || month > 12) { /* check range of month and year */
- FPR(stderr, "%s: month %d not in range 1 .. 12\n", progname,
- month);
- badpar = TRUE;
- }
-
- if (year < MIN_YR || year > MAX_YR) {
- FPR(stderr, "%s year %d not in range %d .. %d\n", progname,
- year, MIN_YR, MAX_YR);
- badpar = TRUE;
- }
-
- /* command-line errors? generate usage message and quit */
-
- if (badpar || badopt) {
- usage(progname);
- exit(EXIT_FAILURE);
- }
-
- /* flag and numeric parameters OK - now try to open the files */
-
- if (outfile && freopen(outfile, "w", stdout) == (FILE *) NULL) {
- FPR(stderr, "%s: can't open file %s\n", progname, outfile);
- exit(EXIT_FAILURE);
- }
-
- /*
- * In case we don't encounter any year data in the
- * calendar file, assume the current year.
- */
- curr_year = year;
-
- /*
- * Attempt to open user-specified calendar file first
- */
- if (date_file != NULL) {
- if ((cfp = fopen(date_file, "r")) == NULL) {
- FPR(stderr, "%s: can't open file %s\n", progname,
- date_file);
- exit(EXIT_FAILURE);
- }
- }
-
- /*
- * Else see if the default calendar file exists (no error if
- * nonexistent; program will just print empty calendar)
- */
- else if (nocal == FALSE)
- cfp = fopen(INFILE, "r");
-
- /*
- * Write out PostScript prolog
- */
- PRT("%%!\n");
- PRT("/titlefont /%s def\n/dayfont /%s def\n", titlefont, dayfont);
-
- DOHEADER(header_1);
- if (sun_gray) {
- PRT("\t\t\tday start add 7 mod 1 %s {\n",
- sat_gray ? "le" : "eq" );
- PRT("\t\t\t\t.8 setgray\n");
- PRT("\t\t\t} if\n");
- }
- DOHEADER(header_2);
-
- PRT("\t%d rotate\n", rotate);
- if (rotate)
- PRT("\t50 -120 translate\n");
- else
- PRT("\t0.75 0.75 scale\n\t50 460 translate\n");
-
- DOHEADER(header_3);
-
- while (nmonths--) {
- pmonth(month, year);
- if (++month > 12) {
- month = 1;
- year++;
- }
- }
-
- if (outfile)
- FPR(stderr, "Output is in file %s\n", outfile);
-
- exit(EXIT_SUCCESS);
- }
-
-
- /*
- * Print message explaining correct usage of the command-line
- * arguments and flags
- */
- usage(prog)
- char *prog;
- {
- FPR(stderr, "\nUsage:\n\n");
- FPR(stderr, "\t%s [-d FONT] [-e | -f FILE] [-o FILE] [-r] [-s | -%s] [-t FONT]\n",
- prog, S_OPT);
- FPR(stderr, "\t\t[ [ [mm] yy ] | [mm yy n] ]\n\n");
- FPR(stderr, "\t\t-d FONT\t\tspecify alternate font for day names\n");
- FPR(stderr, "\t\t\t\t(default: %s)\n", DAYFONT);
- FPR(stderr, "\n");
- FPR(stderr, "\t\t-e\t\tgenerate empty calendar (ignore date file)\n");
- FPR(stderr, "\n");
- FPR(stderr, "\t\t-f FILE\t\tspecify alternate date file\n");
- FPR(stderr, "\t\t\t\t(default: %s)\n", INFILE);
- FPR(stderr, "\n");
- FPR(stderr, "\t\t-o FILE\t\tspecify alternate output file\n");
- FPR(stderr, "\t\t\t\t(default: %s)\n", OUTFILE ? OUTFILE : "stdout");
- FPR(stderr, "\n");
- FPR(stderr, "\t\t-r\t\tgenerate portrait-style calendars\n");
- FPR(stderr, "\t\t\t\t(default: landscape)\n");
- FPR(stderr, "\n");
- FPR(stderr, "\t\t-s\t\tprint Saturdays in black\n");
- FPR(stderr, "\t\t-%s\t\tprint Saturdays and Sundays in black\n", S_OPT);
- FPR(stderr, "\t\t\t\t(default: print Saturdays and Sundays in gray)\n");
- FPR(stderr, "\n");
- FPR(stderr, "\t\t-t FONT\t\tspecify alternate font for titles\n");
- FPR(stderr, "\t\t\t\t(default: %s)\n", TITLEFONT);
- FPR(stderr, "\n");
- FPR(stderr, "\t%s [opts]\t\tgenerate calendar for current month/year\n",
- prog);
- FPR(stderr, "\n");
- FPR(stderr, "\t%s [opts] yy\t\tgenerate calendar for entire year yy\n",
- prog);
- FPR(stderr, "\n");
- FPR(stderr, "\t%s [opts] mm yy\tgenerate calendar for month mm\n", prog);
- FPR(stderr, "\t\t\t\t(Jan = 1), year yy (19yy if yy < 100)\n");
- FPR(stderr, "\n");
- FPR(stderr, "\t%s [opts] mm yy n\tas above, for n consecutive months\n",
- prog);
- FPR(stderr, "\n");
- }
-
-
- /*
- * Browse through the calendar file looking for day info in current month
- */
- find_daytext(m, y)
- int m, y;
- {
- register char **s;
- register int oldday = -1;
- register int day;
-
- for (day = getday(m, y, TRUE); day != 0; day = getday(m, y, FALSE))
- if (*words) {
- day &= ~HOLIDAY;
- if (day != oldday) {
- if (oldday == -1)
- PRT("%d [ \n", day);
- else
- PRT("] daytext\n%d [ \n", day);
- oldday = day;
- } else
- PRT("(.p)\n");
- for (s = words; *s; s++)
- PRT("(%s)\n", *s);
- }
-
- if (oldday != -1) /* terminate call to daytext */
- PRT("] daytext\n");
- }
-
-
- /*
- * Browse through the calendar file looking for holidays in current month
- */
- find_holidays(m, y)
- int m, y;
- {
- register int day;
- unsigned long holidays = 0;
-
- /* sort holidays by setting bits in flag word */
- for (day = getday(m, y, TRUE); day != 0; day = getday(m, y, FALSE))
- if (day & HOLIDAY)
- holidays |= 1 << (day & ~HOLIDAY);
-
- PRT("/holidays ["); /* start definition of list */
- for (day = 1; day <= 31; day++)
- if (holidays & (1 << day))
- PRT(" %d", day);
- PRT(" 99 ] def\n"); /* terminate with dummy entry */
- }
-
-
- /*
- * pmonth - do calendar for month "m"
- */
- pmonth(m, y)
- int m, y;
- {
-
- PRT("/year %d def\n", y); /* set up year and month */
- PRT("/month %d def\n", m);
- find_holidays(m, y); /* first pass - make list of holidays */
- PRT("printmonth\n");
- find_daytext(m, y); /* second pass - add text to boxes */
- PRT("showpage\n");
- }
-
-
- /*
- * getday - find next day entry for desired month in the calendar file
- */
- int getday(m, y, reset)
- register int m, y;
- int reset;
- {
- static eof = 0;
- register char *cp;
- register c;
- int in_comment; /* comments: from '#' to end-of-line */
-
- if (cfp == NULL) /* whoops, no calendar file */
- return(0);
-
- if (reset) { /* new month, rewind */
- rewind(cfp);
- eof = 0;
- }
- if (eof)
- return(0);
-
- do {
- cp = lbuf;
- do {
- in_comment = FALSE;
- while ((c = getc(cfp)) != '\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) {
- eof = 1;
- return(0);
- }
- } while (cp == lbuf); /* ignore empty lines */
- *cp = 0;
-
- /* examine the line, see if its one we want */
- } while ( (c = parse(m, y)) == 0);
-
- return(c);
- }
-
- /*
- * parse - check calendar entry for desired month, break line into fields
- */
- parse(m, y)
- register int m, y;
- {
- register char *cp;
- register i;
- int is_holiday = 0; /* '*' after date flags it as holiday */
- int valid = 1;
-
- cp = strtok(lbuf, " \t"); /* get first field */
-
- while (*cp) {
- if (isupper(*cp))
- *cp = tolower(*cp);
- cp++;
- }
- cp = lbuf;
-
- /*
- * Check for "year" line
- */
- if (strcmp(cp, "year") == 0) {
- cp = strtok((char *)0, " \t");
- if ((i = atoi(cp)) > 0) {
- if (i < 100)
- i += 1900;
- curr_year = i;
- }
- return(0);
- }
-
- /*
- * If field begins with alpha, try to decode month name
- */
- if (isalpha(*cp)) {
- if (curr_year != y)
- return(0);
-
- for (i = 0; months[i]; i++)
- if (strncmp(cp, months[i], 3) == 0) {
- if (++i != m)
- return(0);
-
- /* month found, get day */
-
- if ((cp = strtok((char *)0, " \t")) == NULL)
- return(0);
- if ((i = atoi(cp)) < 1 || i > 31)
- return(0);
- while (isdigit(*cp)) /* skip over day field */
- cp++;
- if (*cp == '*') /* holiday? */
- is_holiday = 1;
- if (loadwords() || is_holiday)
- return(i | is_holiday * HOLIDAY);
- return(0);
- }
- return(0);
- }
- /*
- * Not alpha month, try numeric (parse full date to see if year OK)
- */
- if ((i = atoi(cp)) != m)
- valid = 0;
- while (isdigit(*cp))
- cp++;
- while (*cp && !isdigit(*cp))
- cp++;
-
- /* now get day */
-
- if ((i = atoi(cp)) < 1 || i > 31)
- valid = 0;
-
- /* Numeric dates may have a year */
-
- while (isdigit(*cp)) /* skip over day field */
- cp++;
- if (*cp == '*') /* holiday? */
- is_holiday = 1;
- while (*cp && !isdigit(*cp))
- cp++;
- if ((m = atoi(cp)) > 0) {
- if (m < 100)
- m += 1900;
- curr_year = m;
- while (isdigit(*cp)) /* skip over year field */
- cp++;
- if (*cp == '*') /* holiday? */
- is_holiday = 1;
- }
-
- if (!valid || curr_year != y) /* date not applicable - return 0 */
- return(0);
-
- if (loadwords() || is_holiday) /* date of some significance */
- return(i | is_holiday * HOLIDAY);
- return(0);
- }
-
-
- /*
- * loadwords - tokenize line buffer into word array, return word count
- */
- loadwords()
- {
- register char **ap = words;
- register i;
-
- for (i = 0; *ap = strtok((char *)0, " \t") ; ap++, i++) ;
- return(i);
- }
-
-