home *** CD-ROM | disk | FTP | other *** search
- /*
- * pcal.c - generate PostScript file to print calendar for any month/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 W. Rogers.
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <time.h>
- #include <string.h>
-
- #define PRT (void)printf
- #define FPR (void)fprintf
-
- #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,
- };
-
- /*
- * the PostScript routines for pcal.c
- */
-
- /* modified by AWR to skip printing days of week on small calendars */
-
- char *header_1[] = {
- "/month_names [ (January) (February) (March) (April) (May) (June) (July)",
- "\t\t(August) (September) (October) (November) (December) ] def",
- "/prtnum { 3 string cvs show} def",
- "/drawgrid {\t\t% draw calendar boxes",
- "\tdayfont findfont 10 scalefont setfont",
- "\t0 1 6 {",
- "\t\t/i exch def",
- "\t\tsubmonth 0 eq {",
- "\t\t\ti 100 mul 40 moveto",
- "\t\t\t[ (Sunday) (Monday) (Tuesday) (Wednesday) (Thursday) (Friday) (Saturday) ] i get",
- "\t\t\t100 center",
- "\t\t} if",
- "\t\ti 100 mul 35 moveto",
- "\t\t1.0 setlinewidth",
- "\t\t0 1 5 {",
- "\t\t\tgsave",
- "\t\t\t100 0 rlineto ",
- "\t\t\t0 -80 rlineto",
- "\t\t\t-100 0 rlineto",
- "\t\t\tclosepath stroke",
- "\t\t\tgrestore",
- "\t\t\t0 -80 rmoveto",
- "\t\t pop } for",
- "\t} for",
- "} def",
- "/drawnums {\t\t% place day numbers on calendar",
- "\tdayfont findfont 30 scalefont setfont",
- "\t/start startday def",
- "\t/days ndays def",
- "\t/n 0 def",
- "\tstart 100 mul 5 add 10 rmoveto",
- "\t1 1 days {",
- "\t\t/day exch def",
- "\t\tgsave",
- "\t\tsubmonth 0 eq {",
- (char *)0
- };
-
- /* modified by AWR: choice of black or gray Saturdays now command-line option */
-
- char *header_2[] = { /* set Saturdays to gray */
- "\t\t\tday start add 7 mod 0 eq {",
- "\t\t\t\t.8 setgray",
- "\t\t\t} if",
- (char *)0
- };
-
- /* modified by AWR: calculate leap years correctly, print holidays in gray */
-
- char *header_3[] = {
- "\t\t\tday start add 7 mod 1 eq {",
- "\t\t\t\t.8 setgray",
- "\t\t\t} if",
- "\t\t\tday holidays n get eq {",
- "\t\t\t\t.8 setgray",
- "\t\t\t\t/n n 1 add def",
- "\t\t\t} if",
- "\t\t} if",
- "\t\tday prtnum",
- "\t\tgrestore",
- "\t\tday start add 7 mod 0 eq",
- "\t\t{",
- "\t\t\tcurrentpoint exch pop 80 sub 5 exch moveto",
- "\t\t}",
- "\t\t{",
- "\t\t\t100 0 rmoveto",
- "\t\t} ifelse",
- "\t} for",
- "} def",
- "/drawfill {\t\t% place fill squares on calendar",
- "\t/start startday def",
- "\t/days ndays def",
- "\t0 35 rmoveto",
- "\t1.0 setlinewidth",
- "\t0 1 start 1 sub {",
- "\t\tgsave",
- "\t\t.9 setgray",
- "\t\t100 0 rlineto ",
- "\t\t0 -80 rlineto",
- "\t\t-100 0 rlineto",
- "\t\tclosepath fill",
- "\t\tgrestore",
- "\t\t100 0 rmoveto",
- "\tpop } for",
- "\tsubmonth 1 eq",
- "\t{",
- "\t\t/lastday 42 def",
- "\t\t600 -365 moveto",
- "\t}",
- "\t{",
- "\t\t/lastday 40 def",
- "\t\t400 -365 moveto",
- "\t} ifelse",
- "\tlastday -1 ndays start 1 add add",
- "\t{",
- "\t\t/day exch def",
- "\t\tgsave",
- "\t\t.9 setgray",
- "\t\t100 0 rlineto ",
- "\t\t0 -80 rlineto",
- "\t\t-100 0 rlineto",
- "\t\tclosepath fill",
- "\t\tgrestore",
- "\t\tday 7 mod 1 eq",
- "\t\t{",
- "\t\t\t600 -365 80 add moveto",
- "\t\t}",
- "\t\t{",
- "\t\t\t-100 0 rmoveto",
- "\t\t} ifelse",
- "\t} for",
- "} def",
- "/isleap {\t\t% is this a leap year?",
- "\tyear 4 mod 0 eq\t\t% multiple of 4",
- "\tyear 100 mod 0 ne \t% not century",
- "\tyear 400 mod 0 eq or and\t% or divisible by 400",
- "} def",
- "/days_month [ 31 28 31 30 31 30 31 31 30 31 30 31 ] def",
- "/ndays {\t\t% number of days in this month",
- "\tdays_month month 1 sub get",
- "\tmonth 2 eq\t% Feb",
- "\tisleap and",
- "\t{",
- "\t\t1 add",
- "\t} if",
- "} def",
- "/startday {\t\t% starting day-of-week for this month",
- "\t/off year 2000 sub def\t% offset from start of epoch",
- "\toff",
- "\toff 4 idiv add\t\t% number of leap years",
- "\toff 100 idiv sub\t% number of centuries",
- "\toff 400 idiv add\t% number of years divisible by 400",
- "\t6 add 7 mod 7 add \t% offset from Jan 1 2000",
- "\t/off exch def",
- "\t1 1 month 1 sub {",
- "\t\t/idx exch def",
- "\t\tdays_month idx 1 sub get",
- "\t\tidx 2 eq",
- "\t\tisleap and",
- "\t\t{",
- "\t\t\t1 add",
- "\t\t} if",
- "\t\t/off exch off add def",
- "\t} for",
- "\toff 7 mod\t\t% 0--Sunday, 1--monday, etc.",
- "} def",
- "/center {\t\t% center string in given width",
- "\t/width exch def",
- "\t/str exch def width str ",
- "\tstringwidth pop sub 2 div 0 rmoveto str show",
- "} def",
- "/calendar",
- "{",
- "\ttitlefont findfont 48 scalefont setfont",
- "\t0 60 moveto",
- "\t/month_name month_names month 1 sub get def",
- "\tmonth_name show",
- "\t/yearstring year 10 string cvs def",
- "\t700 yearstring stringwidth pop sub 60 moveto",
- "\tyearstring show",
- "\t0 0 moveto",
- "\tdrawnums",
- "\t0 0 moveto",
- "\tdrawfill",
- "\t0 0 moveto",
- "\tdrawgrid",
- "} def",
- "/daytext {",
- "\t/Helvetica-Narrow findfont 6 scalefont setfont",
- "\t/mytext\texch def /myday exch def",
- "\tstartday myday 1 sub add dup 7 mod 100 mul 5 add % gives column",
- "\texch 7 idiv -80 mul % gives row",
- "\tdup /ypos exch def moveto",
- "\t/LM currentpoint pop def /RM LM 95 add def",
- " mytext { dup (.p) eq { crlf pop} {prstr ( ) show} ifelse } forall",
- "} def",
- "/crlf {",
- " ypos 8 sub /ypos exch def LM ypos moveto",
- "} def",
- "/prstr {",
- " dup stringwidth pop currentpoint pop",
- " add RM gt {crlf} if show",
- "} def",
- "/printmonth {",
- (char *)0,
- };
-
- char *header_4[] = {
- "\t/submonth 0 def",
- "\tcalendar",
- "\tmonth 1 sub 0 eq",
- "\t{",
- "\t\t/lmonth 12 def",
- "\t\t/lyear year 1 sub def",
- "\t}",
- "\t{",
- "\t\t/lmonth month 1 sub def",
- "\t\t/lyear year def",
- "\t} ifelse",
- "\tmonth 1 add 13 eq",
- "\t{",
- "\t\t/nmonth 1 def",
- "\t\t/nyear year 1 add def",
- "\t} ",
- "\t{",
- "\t\t/nmonth month 1 add def",
- "\t\t/nyear year def",
- "\t} ifelse",
- "\t/savemonth month def",
- "\t/saveyear year def",
- "\t/submonth 1 def",
- "\t/year lyear def",
- "\t/month lmonth def",
- "\tgsave",
- "\t500 -365 translate",
- "\tgsave",
- "\t.138 .138 scale",
- "\t10 -120 translate",
- "\tcalendar",
- "\tgrestore",
- "\t/submonth 1 def",
- "\t/year nyear def",
- "\t/month nmonth def",
- "\t100 0 translate",
- "\tgsave",
- "\t.138 .138 scale",
- "\t10 -120 translate",
- "\tcalendar",
- "\tgrestore",
- "\t/month savemonth def",
- "\t/year saveyear def",
- "\t/submonth 0 def",
- "\tgrestore",
- "} def",
- (char *)0,
- };
-
- FILE *cfp = NULL;
- int year;
- int cyear;
-
- void exit();
- char *getenv();
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- extern char *optarg;
- extern int optind;
- register struct tm *lt;
- register char **ap;
- register char *cp;
- char *cfile = NULL;
- char cbuf[80];
- long t, time();
- int errflg = 0;
- int nocal = 0;
- int sat = 0;
- char *titlefont = "Times-Bold";
- char *dayfont = "Times-Bold";
- int rotate = 90;
- int month = 0;
- int m;
- char doyear = 0;
-
- #define DOHEADER(phdr) for(ap = phdr; *ap; ap++) PRT("%s\n", *ap);
-
- while ((m = getopt(argc, argv, "d:ef:m:rst:y:")) != EOF)
-
- switch (m) {
-
- case 'd': /* select font for day names/numbers */
- dayfont = optarg;
- break;
-
- case 'e': /* print empty calendar */
- nocal++;
- cfile = NULL;
- break;
-
- case 'f': /* use alternate calendar file */
- cfile = optarg;
- nocal = 0;
- break;
-
- case 'm': /* select month */
- month = atoi(optarg);
- if (!month) doyear = 1;
- break;
-
- case 'r': /* generate portrait calendar */
- rotate = 0;
- break;
-
- case 's': /* print Saturdays in black */
- sat++;
- break;
-
- case 't': /* select font for month/year */
- titlefont = optarg;
- break;
-
- case 'y': /* select year */
- year = atoi(optarg);
- if (year && year < 1900) year = year % 100 + 1900;
- break;
-
- case '?':
- errflg = 1;
- break;
- }
-
- if (errflg) {
- FPR(stderr,
- "Usage: pcal [ -r ] [ -s ] [ -e | -f <cal> ] [ -m month] [ -y <year> ]\n");
- FPR(stderr,
- "\t\t[ -t <title font> ] [ -d <day font> ]\n");
- exit(1);
- }
- t = time((long *)0);
- lt = localtime(&t);
-
- if (!month && !doyear)
- month = lt->tm_mon + 1;
- if (!year)
- year = lt->tm_year + 1900;
-
- /*
- * In case we don't encounter any year data in the
- * calendar file, assume the current year.
- */
- cyear = year;
-
- /*
- * Open a supplied calendar file (if any)
- */
- if (cfile != NULL) {
- if ((cfp = fopen(cfile, "r")) == NULL) {
- FPR(stderr, "pcal: can't open file: %s\n", cfile);
- exit(1);
- }
- }
- /*
- * Else see if a calendar file exists in the home directory
- */
- else if (nocal == 0 && (cp = getenv("HOME")) != NULL) {
- (void)strcpy(cbuf, cp);
- (void)strcat(cbuf, "/calendar");
- cfp = fopen(cbuf, "r");
- }
-
- /*
- * Write out PostScript prolog
- */
- PRT("%%!\n");
- PRT("/titlefont /%s def\n/dayfont /%s def\n", titlefont, dayfont);
-
- DOHEADER(header_1);
- if (sat == 0)
- DOHEADER(header_2);
- DOHEADER(header_3);
-
- 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_4);
-
- if (month)
- pmonth(month);
- else
- for (month = 1; month <= 12; month++)
- pmonth(month);
-
- exit(0);
- }
-
- /*
- * Browse through the calendar file looking for day info in current month
- */
- find_daytext(m)
- int m;
- {
- register char **s;
- register int oldday = -1;
- register int day;
- int reset;
-
- for (reset = 1; (day = getday(m, reset)) != 0; reset = 0)
- 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)
- int m;
- {
- register int oldday = -1;
- register int day;
- int reset;
-
- PRT("/holidays ["); /* start definition of list */
-
- for (reset = 1; (day = getday(m, reset)) != 0; reset = 0)
- if (day & HOLIDAY) {
- day &= ~HOLIDAY;
- if (day != oldday) {
- PRT(" %d", day);
- oldday = day;
- }
- }
-
- PRT(" 99 ] def\n"); /* terminate with dummy entry */
- }
-
-
- /*
- * pmonth - do calendar for month "m"
- */
- pmonth(m)
- int m;
- {
-
- PRT("/year %d def\n", year); /* set up year and month */
- PRT("/month %d def\n", m);
- find_holidays(m); /* first pass - make list of holidays */
- PRT("printmonth\n");
- find_daytext(m); /* second pass - add text to boxes */
- PRT("showpage\n");
- }
-
-
- /*
- * getday - find next day entry for desired month in the calendar file
- */
- int getday(m, reset)
- register int m;
- int reset;
- {
- static eof = 0;
- register char *cp;
- register c;
-
- if (cfp == NULL) /* whoops, no calendar file */
- return(0);
-
- if (reset) { /* new month, rewind */
- rewind(cfp);
- eof = 0;
- }
- if (eof)
- return(0);
- nextline:
- cp = lbuf;
- do {
- while ((c = getc(cfp)) != '\n' && c != EOF) {
- /* ignore leading white space */
- if (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 */
- if ((c = parse(m)) == 0)
- goto nextline;
-
- return(c);
- }
-
- /*
- * parse - check calendar entry for desired month, break line into fields
- */
- parse(m)
- register m;
- {
- 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;
- cyear = i;
- }
- return(0);
- }
-
- /*
- * If field begins with alpha, try to decode month name
- */
- if (isalpha(*cp)) {
- if (cyear != year)
- 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 has changed)
- */
- 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;
- cyear = m;
- while (isdigit(*cp)) /* skip over year field */
- cp++;
- if (*cp == '*') /* holiday? */
- is_holiday = 1;
- }
-
- if (!valid || cyear != year) /* 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);
- }
-
-