[alt.sources] Pcal: postscript/c calendar printer

joe@dayton.UUCP (Joseph P. Larson) (01/12/90)

(This is an enhanced and repaired version of a program by the same name
posted by Ken Keirnan last summer or so.)

This is "pcal", a program that lets you print a monthly calendar complete with
text taken from a calendar file.  See the two ReadMe files and the man page
for more information.  -Joe

#! /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
#	pcal.c
#	pcal.man
# This archive created: Thu Jan 11 16:22:36 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'
#
# Normally the day numbers for Saturday and Sunday are printed in gray
# instead of black.  If you want only Sundays in gray, uncomment the
# following line.
#
# COPTS = -DSATBLK
MANDIR=/usr1/jad/man

pcal:	pcal.c
	$(CC) $(CFLAGS) $(LDFLAGS) $(COPTS) -o pcal pcal.c

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'
This is pcal as posted some time ago.  However, the "for" loops didn't always
use their arguments.  I found this when I tried to allow a full-year to be
dumped at once.  I'd get through 3 months and *wham*: stack overflow.
Surprise!

Anyways, I put in a couple of pop's, modified the command line a little
and hopefully, the man page enough, and here it is.  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.

Note: if I had the time, I'd pull the PostScript code back out of the
program and include a PS prolog file; as is, this is ugly and a little
more difficult to modify.  Ah well.  It may be easier sometimes to include
log prolog inside the C program, but it's an awful lot easier to modify
the prolog when it's a separate file.  Whatever.

-Joe
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 'pcal.c'
then
	echo shar: "will not over-write existing file 'pcal.c'"
else
cat << \SHAR_EOF > 'pcal.c'
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <string.h>

#define PRT	(void)printf
#define FPR	(void)fprintf

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,
};

/*
 * pheader - provides the PostScript routines
 */
char *pheader[] = {
  "%!",
  "/titlefont /Times-Bold def",
  "/dayfont /Helvetica-Bold def",
  "/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\tdup dup 100 mul 40 moveto",
  "\t\t[ (Sunday) (Monday) (Tuesday) (Wednesday) (Thursday) (Friday) (Saturday) ] exch get",
  "\t\t100 center",
  "\t\t100 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",
  "\tstart 100 mul 5 add 10 rmoveto",
  "\t1 1 days {",
  "\t\t/day exch def",
  "\t\tgsave",
#ifndef SATBLK
  "\t\tday start add 7 mod 0 eq",
  "\t\t{",
  "\t\t\tsubmonth 0 eq",
  "\t\t\t{",
  "\t\t\t\t.8 setgray",
  "\t\t\t} if",
  "\t\t} if",
#endif
  "\t\tday start add 7 mod 1 eq",
  "\t\t{",
  "\t\t\tsubmonth 0 eq",
  "\t\t\t{",
  "\t\t\t\t.8 setgray",
  "\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 1000 mod 0 eq or and\t% unless it's a millenia",
  "} 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 1000 idiv add\t% number of millenia",
  "\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 {",
  "\t90 rotate",
  "\t50 -120 translate",
  "\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 m;
	int month;
	char doyear = 0;

	while ((m = getopt(argc, argv, "ef:m:y:")) != EOF)

		switch (m) {

		case 'e':
			nocal++;
			cfile = NULL;
			break;

		case 'f':
			cfile = optarg;
			nocal = 0;
			break;

		case 'm':
			month = atoi(month);
			if (!month) doyear = 1;
			break;

		case 'y':
			year = atoi(optarg);
			if (year < 1900) year = year % 100 + 1900;
			break;

		case '?':
			errflg = 1;
			break;
		}
	if (errflg) {
		FPR(stderr,
			"Usage: pcal [ -e | -f <cal> ] [ -m month] [ -y <year> ]\n");
		exit(1);
	}
	t = time((long *)0);
	lt = localtime(&t);

	if (!month && !doyear)
		m = 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
	 */
	for (ap = pheader; *ap; ap++)
		PRT("%s\n", *ap);

	if (month)
		pmonth(month);
	else
		for (month = 1; month <= 12; month++)
			pmonth(month);

	return(0);
}

/*
 * pmonth - do calendar for month "m"
 */
pmonth(m)
int m;
{
	register char **s;
	register oldday = -1;
	register day;

	/*
	 * Do the calendar
	 */
	PRT("/year %d def\n", year);
	PRT("/month %d def\n", m);
	PRT("printmonth\n");

	/*
	 * Browse through the calendar file looking for day info
	 */
	if ((day = getday(m)) == 0) {	/* no info */
		PRT("showpage\n");
		return;
	}
	do {
		if (day != oldday) {
			if (oldday == -1)
				PRT("%d [ \n", day);
			else
				PRT(" ] daytext %d [  \n", day);
			oldday = day;
		} else
			PRT("(.p)\n");
		for (s = words; *s; s++)
			PRT("(%s)\n", *s);

	} while (day = getday(m));
	PRT("] daytext\n");
	PRT("showpage\n");
}

/*
 * getday - find next day entry for desired month in the calendar file
 */
getday(m)
register m;
{
	static mon = 0;
	static eof = 0;
	register char *cp;
	register c;

	if (cfp == NULL)	/* whoops, no calendar file */
		return(0);

	if (m != mon) {		/* new month, rewind */
		rewind(cfp);
		eof = 0;
		mon = m;
	}
	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;

	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);
				if (loadwords())
					return(i);
				return(0);
			}
		return(0);
	}
	/*
	 * Not alpha month, try numeric
	 */
	if ((i = atoi(cp)) != m)
		return(0);
	while (isdigit(*cp))
		cp++;
	while (*cp && !isdigit(*cp))
		cp++;

	/* now get day */

	if ((i = atoi(cp)) < 1 || i > 31)
		return(0);

	 /* Numeric dates may have a year */

	while (isdigit(*cp))
		cp++;
	while (*cp && !isdigit(*cp))
		cp++;
	if ((m = atoi(cp)) > 0) {
		if (m < 100)
			m += 1900;
		cyear = m;
	}

	if (cyear != year)
		return(0);

	if (loadwords())
		return(i);
	return(0);
}

/*
 * loadwords - tokenize line buffer into word array
 */
loadwords()
{
	register char **ap = words, *c;
	register i;

	for (i = 0; *ap = strtok((char *)0, " \t") ; ap++, i++);
/*	{
		if ((*ap = strtok((char *)0, " \t")) == NULL)
			break;
		while ((c = strpbrk(*ap, "()")) != NULL)
		{
			if (c != *ap) ap++;
			if (*c == '(')
				*ap = "\\(";
			else
				*ap = "\\)";
			*c = 0;
			c++;
			if (*c)
				*(++ap) = c;
		}
	} */
	return(i);
}
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>
] [
.B \-m <month>
[
.B \-y <year>
]]
.SH DESCRIPTION
.I Pcal
generates PostScript to produce landscape calendars for any month and year.
The arguments
.B <month>
and
.BR <year> ,
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.
The defaults for month and year are the current month and year.
If month is provided, but zero, the entire year is printed.
.P
If a file named
.I calendar
resides in the callers home directory, 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.  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.
.P
.I Pcal has two options:
.P
.TP
.B \-e
Print an empty calendar.  Do not print entries from a calendar file.
.TP
.BR \-f <cal>
Directs
.I pcal
to use the file name <cal> as the input file in place of the default
calendar file in the callers home directory.
.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.  Patricks original PostScript was modified and enhanced several
times by others whos names have regrettably been lost.  I am responsible
for assembling this "C" version, but the lion's share of the work was
done by others.
.sp
Ken Keirnan
.br
Pacific Bell
.br
San Ramon, CA.
SHAR_EOF
fi
exit 0
#	End of shell archive
-- 
UUCP: rutgers!dayton!joe   (Picts 1-16 are   DHDSC - Joe Larson/MIS 1060
ATT : (612) 375-3537       now ready.)       700 on the Mall, Mpls, Mn. 55402

rogers@sud509.ed.ray.com (Andrew Rogers) (06/04/90)

OK, I have a few of my own contributions to add to this program...

	1) New -s flag to print Saturdays in black instead of gray

	2) Holidays print in gray if the date is followed by '*' in the
	   calendar file (e.g. "7/4* Independence Day")

	3) The illegible weekday names on the small calendars are suppressed

	4) The code has been revised throughout for tightness and clarity.

The version below also incorporates the recent patch posted by Ed Hand as well
as the revised man page posted by Matthieu Herrb.  Enjoy!

Andrew W. Rogers
(PS: send Email if you'd like a VMS version of this...)

---------------------------- 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
#	pcal.c
#	pcal.man
# This archive created: Mon Jun  4 12:10:04 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
	$(CC) $(CFLAGS) $(LDFLAGS) $(COPTS) -o pcal pcal.c

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'
This is pcal as posted some time ago.  However, the "for" loops didn't always
use their arguments.  I found this when I tried to allow a full-year to be
dumped at once.  I'd get through 3 months and *wham*: stack overflow.
Surprise!

Anyways, I put in a couple of pop's, modified the command line a little
and hopefully, the man page enough, and here it is.  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.

Note: if I had the time, I'd pull the PostScript code back out of the
program and include a PS prolog file; as is, this is ugly and a little
more difficult to modify.  Ah well.  It may be easier sometimes to include
log prolog inside the C program, but it's an awful lot easier to modify
the prolog when it's a separate file.  Whatever.

-Joe

Additional note: This version incorporates several new command-line options
and related features implemented by Ed Hand and myself.  Read the 'man' page
for further details.

-Andrew
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 '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/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);
}

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>
] [
.B \-m <month>
[
.B \-y <year>
]] [
.B -r
] [
.B -s
] [
.B -t <titlefont name>
] [
.B -d <dayfont name>
]
.SH DESCRIPTION
.I Pcal
generates PostScript to produce landscape or portrait calendars for any 
month and year.  The arguments
.B <month>
and
.BR <year> ,
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.
The defaults for month and year are the current month and year.
If month is provided, but zero, the entire year is printed.
.P
If a file named
.I calendar
resides in the caller's home directory, 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.  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.
.P
.I Pcal has many options:
.P
.TP
.B \-e
Print an empty calendar.  Do not print entries from a calendar file.
.TP
.BR \-f <cal>
Directs
.I pcal
to use the file name <cal> as the input file in place of the default
calendar file in the callers home directory.
.TP
.B \-r
This will cause the output to come out in portrait
mode instead of landscape.
.TP
.B \-s
This will cause Saturdays to be printed in black instead of gray.
.TP
.BR \-t <titlefont name>
This option can be used to change the font the title
is printed in. (ie. pcal -t Times-Roman).
.TP
.BR  -d <dayfont name>
This option is the same as -t except that the font used
to print the day numbers is changed.
.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, and Andrew W. Rogers.
SHAR_EOF
fi
exit 0
#	End of shell archive

rogers@sud509.ed.ray.com (Andrew Rogers) (06/05/90)

In article <1340@sud509.ed.ray.com> rogers@sud509.RAY.COM I wrote:
>(PS: send Email if you'd like a VMS version of this...)

Well, I guess I underestimated how many requests I'd get for this... so I'm
posting the VMS version (actually the changes required to adapt the version
I posted earlier to VMS) below.  The changes visible to the user are:

	1) Default calendar file is SYS$LOGIN:CALENDAR.DAT

	2) Automatically writes to an output file, CALENDAR.PS; added -o
	   option to override the default file name

The changes visible only to the programmer are:

	3) Eliminated use of getopt() to parse command line.  There may be
	   some minor variations in functionality introduced by this.

The following code replaces main() in the Unix version previously posted:

Andrew W. Rogers

--------------------------- cut here ----------------------------
/*
 * VMS version of pcal.c main module
 *
 * Adapted by Andrew W. Rogers
 */

main(argc, argv)
int argc;
char **argv;
{

#define EXIT_SUCCESS 1
#define EXIT_FAILURE 3

#define GETARG(arg) if ((parg = *++opt ? opt : \
			(*(argv+1) && **(argv+1) != '-' ? *++argv : NULL) ) \
			!= NULL) arg = parg; else

#define DOHEADER(phdr) for(ap = phdr; *ap; ap++) PRT("%s\n", *ap);

	register struct tm *lt;
	register char **ap;
	register char *cp;
	char *cfile = NULL;
	char *opt, *pnum, *parg;
	char cbuf[80];
	long t;
	int errflg = 0;
	int nocal = 0;
	int sat = 0;
 	char *titlefont = "Times-Bold";
 	char *dayfont = "Times-Bold";
	char *outfile = "CALENDAR.PS";
 	int rotate = 90;
 	int month = 0;
	char doyear = 0;
	char *trnlog();

 	while (!errflg && *++argv) {

		if (**argv != '-') {
			errflg = 1;
			break;
			}

		opt = (*argv) + 1;
		switch (*opt) {

 		case 'd':		/* Alternate day name/number font */
 			GETARG(dayfont);
 			break;

		case 'e':		/* Empty calendar */
			nocal++;
			cfile = NULL;
			break;

		case 'f':		/* Alternate calendar file name */
			GETARG(cfile);
			nocal = 0;
			break;

		case 'm':		/* Month */
			pnum = NULL;
			GETARG(pnum);
			month = pnum ? atoi(pnum) : 0;
			if (!month) doyear = 1;
			break;

		case 'o':		/* Alternate output file name */
			GETARG(outfile);
			break;

 		case 'r':		/* Portrait */
 			rotate = 0;
 			break;
 
		case 's':		/* Saturdays in black */
			sat++;
			break;

 		case 't':		/* Alternate title font */
 			GETARG(titlefont);
 			break;
 
		case 'y':		/* Year */
			pnum = NULL;
			GETARG(pnum);
			year = pnum ? atoi(pnum) : 0;
			if (year != 0 && year < 1900) year = year % 100 + 1900;
			break;

		default:
			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> ] [-o <output file>]\n");
		exit(EXIT_FAILURE);
	}
	t = time((long *)0);
	lt = localtime(&t);

	if (!month && !doyear)
		month = lt->tm_mon + 1;
	if (!year)
		year = lt->tm_year + 1900;

	if (outfile && freopen(outfile, "w", stdout) == (FILE *) NULL) {
		FPR(stderr, "pcal: can't open file: %s\n", outfile);
		exit(EXIT_FAILURE);
		}

	/*
	 * 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(EXIT_FAILURE);
		}
	}
	/*
	 * Else see if a calendar file exists in the home directory
	 */
	else if (nocal == 0 && (cp = trnlog("SYS$LOGIN")) != NULL) {
		(void)strcpy(cbuf, cp);
		(void)strcat(cbuf, "CALENDAR.DAT");
		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)
		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);

	FPR(stderr, "Output is in file %s\n", outfile);
	exit(EXIT_SUCCESS);
}

#include <ssdef.h>
#include <descrip.h>

char *trnlog(logname)	/* look up logical name */
    char *logname;
{
static char trnbuf[81];

$DESCRIPTOR(src, logname);
$DESCRIPTOR(dst, trnbuf);
short len;
int ret;

src.dsc$w_length  = strlen(logname);
ret = LIB$SYS_TRNLOG(&src, &len, &dst);
if (ret != SS$_NORMAL)
	len = 0;
trnbuf[len] = '\0';
return trnbuf;
}

vail@tegra.COM (Johnathan Vail) (06/08/90)

Here is a small hack I made for use with the pcal program recently
posted.  It will filter a file from the Casio BOSS (the little
calculator sized memory/phone-list/schedule gizmos) and produce lines
for schedule items for the pcal program.

Shar and Enjoy, jv

"Frisbeetarianism is the belief that when you die, your soul goes up on
the roof and gets stuck." -- button
 _____
|     | Johnathan Vail | n1dxg@tegra.com
|Tegra| (508) 663-7435 | N1DXG@448.625-(WorldNet)
 -----  jv@n1dxg.ampr.org {...sun!sunne ..uunet}!tegra!vail

--------------------------->8 cut here 8<----------------------------
/*
**	boss2cal - Convert Casio BOSS file dates to calender files.
**
**	Written  6 Jun 1990, Johnathan Vail, N1DXG  vail@tegra.com
**
**    This program will filter a file from a Casio BOSS into a file
** suitable for use with the pcal program to generate postscript
** calenders.
**
*/



#include <stdio.h>



void boss_convert_date(char *in_line, char *out_line)
{
    char *start_time, *end_time, *date, *year;
    char *lp, *event;
    char time_buf[50];

    for(lp=in_line; *lp; lp++)
	if (*lp=='\t' || *lp=='\r')
	    *lp='\0';

    if (strncmp(in_line,":0300",5)==0) {
	in_line[9]='\0';
	year=in_line+5;
	date=in_line+10;

	start_time=end_time=in_line+16;

	while(*end_time++);

	event=end_time;
	while (*event++);
	while (*event++);	/* skip over alarm time		*/

	for(lp=event; *lp; lp++)
	    if (*lp=='\\' && *(lp+1)=='0') {
		*lp=' ';
		*++lp=' ';
		*++lp=' ';
	    }

	sprintf(time_buf,"%s%s%s",
		start_time,
		(*end_time?" to ":""),
		end_time);

	sprintf(out_line,"%s-%s %s %s",
		date,
		year,
		time_buf,
		event);
    }
    else {
	*out_line='\0';
    }
}



main()
{
    char in_line[380], out_line[380];

    while(gets(in_line)) {
	if (!*in_line) break;
	boss_convert_date(in_line, out_line);
	if (*out_line)
	    printf("%s\n",out_line);
    }
    exit(0);
}
    

rogers@sud509.ed.ray.com (Andrew Rogers) (06/12/90)

Some follow-up observations about the version(s) of Pcal I posted recently:

	1) In order for the "holidays in gray" feature to work correctly, the
	   holidays must appear in order in the 'calendar' file.  The following
	   version of find_holidays() removes that restriction:

find_holidays(m)
int m;
{
	register int day;
	unsigned long holidays = 0;

	/* sort holidays by setting bits in flag word */
	for (day = getday(m, TRUE); day != 0; day = getday(m, 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 */
}

	2) The VMS patch I posted is unnecessarily complex; the function
	   trnlog() is not necessary.  The VMS file system will succesfully
	   translate "SYS$LOGIN:" for you.

Andrew W. Rogers