home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
usenet
/
altsrcs
/
1
/
1412
/
pcal.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-28
|
14KB
|
650 lines
/*
* 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);
}