This is psCalendar.c in view mode; [Download] [Up]
/* * psCalendar.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, Andrew W. Rogers and Michael * Friendly. */ #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 psCalendar.c */ /* modified by MLF to put out proper PostScript header declarations */ char *header_0[] = { "%!PS-Adobe-3.0", "%%Pages: (atend)", "%%Creator: psCalendar", "%%EndComments", (char *)0 }; /* 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: psCalendar [ -r ] [ -s ] [ -e | -f <cal> ] [ -m month|0] [ -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, "psCalendar: 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 */ DOHEADER(header_0); 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) { PRT("%%%%Page: 1\n"); pmonth(month); PRT("%%%%Trailer:\n"); PRT("%%%%Pages: 1\n"); } else { for (month = 1; month <= 12; month++) { PRT("%%%%Page: %d\n", month); pmonth(month); } PRT("%%%%Trailer:\n"); PRT("%%%%Pages: 12\n"); } 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); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.