Yet another Pcal revision

Andrew Rogers rogers at sud509.ed.ray.com
Fri Jul 20 05:30:45 AEST 1990


This is a new, improved release of pcal.  Among the numerous revisions
(since the last version I posted) are:

	1) month and year are now centered at top of calendar

	2) revised command-line parameters: confusing "-m" and "-y" flags
	   dropped entirely, and several new options added (see man page)

	3) holidays need not appear in order

	4) PostScript boilerplate moved to new file, pcalinit.h

	5) source is compatible with VMS and Unix

	6) comprehensive usage message

	7) comments ('#' through end-of-line) supported in calendar file

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.

Andrew W. Rogers

Additional note: This distribution includes a VMS HELP file written by
Richard Dyson.  The "strcat" utility was borrowed from Jef Poskanzer's
ID Toolkit.  Countless other people worked on it long before me; see the
ReadMe.orig file and topline comments in pcal.c.

------------------------------- 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
#	 calendar
#	 pcal.c
#	 pcal.hlp
#	 pcal.man
#	 pcalinit.h
# This archive created: Thu Jul 19 15:26:36 EDT 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			

pcal:	pcal.c pcalinit.h
	$(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 a new, improved release of pcal.  Among the numerous revisions
(since the last version I posted) are:

	1) month and year are now centered at top of calendar

	2) revised command-line parameters: confusing "-m" and "-y" flags
	   dropped entirely, and several new options added (see man page)

	3) holidays need not appear in order

	4) PostScript boilerplate moved to new file, pcalinit.h

	5) source is compatible with VMS and Unix

	6) comprehensive usage message

	7) comments ('#' through end-of-line) supported in calendar file

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.

Andrew W. Rogers

Additional note: This distribution includes a VMS HELP file written by
Richard Dyson.  The "strcat" utility was borrowed from Jef Poskanzer's
ID Toolkit.  Countless other people worked on it long before me; see the
ReadMe.orig file and topline comments in pcal.c.

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 'calendar'
then
	echo shar: will not over-write existing file 'calendar'
else
cat << \SHAR_EOF > 'calendar'
# Sample calendar file for pcal
#
# This should be ~/calendar on Unix, SYS$LOGIN:CALENDAR.DAT on VMS

year 1990				# set year explicitly

5/28* Memorial Day (observed)		# '*' prints holiday in gray
5/31 Memorial Day

7/4/90* Independence Day		# full date format

Sep 3* Labor Day			# month written out

10/8* Columbus Day (observed)
10/12 Columbus Day

11/22* Thanksgiving
11/23*					# holiday without text

12/24* Christmas
12/25*

1/1/91* New Year's Day			# set new year implicitly
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 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);
}

SHAR_EOF
fi
if test -f 'pcal.hlp'
then
	echo shar: will not over-write existing file 'pcal.hlp'
else
cat << \SHAR_EOF > 'pcal.hlp'
1 PCAL
        Pcal  generates  PostScript  to produce landscape or  portrait
    orientated calendars for  any  month  and  year.  The defaults for
    month and year are the current month and year.

        VMS Version
        Execution format:
    
            pcal [options]m yy] [n]

        If a file named calendar.dat  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 calendar.dat 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 calendar.dat 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.  Comments ('#' through end-
    of-line) are permitted.

2 parameters
  mm yy n
        "mm" and "yy"  are numeric values of the month (1-12) and year
    (0-99) (i.e., July 1990  would  be 7 90).  If you just include the
    "yy" option, an entire 12  months  of calendars will be generated.
    A specific month can be produced  by including the "mm" parameter.
    The  "n"  parameter will produce the "n"  consectutive  months  of
    calendars starting with the requested month.

2 -e
        Print an  empty  calendar.    Do  not  print  entries  from  a
    calendar.dat file.

2 -f <FILE>
        Directs pcal to use the  file name [1m<FILE>[m as the input file in
    place  of the  default  calendar.dat  file  in  the  callers  home
    directory.
2 -o <FILE>
        Directs pcal to write the PostScript calendar into [1mFILE[m.
2 -r
        This will cause  the  output  to  come  out  in  portrait mode
    instead of landscape mode.
2 -s
        This will  cause  Saturdays  to be printed in black instead of
    gray.
2 -"S"
        This will cause  Saturdays  and Sundays to be printed in black
    instead of gray.
2 -t <FONT>
        This option can be used  to  change  the  font  the  title  is
    printed  with  (ie.    pcal  -tTimes-Roman).      The  default  is
    Times-Bold.
2 -d <FONT>
        This option is the same as  -t  except  that  the font used to
    print the day numbers is changed.
2 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.dat  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.  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.  This  VMS  HELP
    file was written by Richard Dyson.
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>
]
[
.BR \-o <file>
]
[
.B -r
] [
.B -s
|
.B -S
] [
.B -t <titlefont name>
] [
.B -d <dayfont name>
]
[
.B month
] [
.B year
] [
.B nmonths
]
.SH DESCRIPTION
.I Pcal
generates PostScript to produce landscape or portrait calendars for any 
month and year.  The arguments
.BR month ,
.BR year ,
and
.BR nmonths ,
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.
.P
If no numeric arguments are provided, the current month and year will be
generated.
.P
If one numeric argument is provided, it is interpreted as the year; the
entire year will be generated.  Otherwise, 
.I nmonth
months, starting with
.I month
and
.I year,
will be generated.
.PP
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.  Comments ('#' through end-of-line)
are supported.
.PP
.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 \-o <file>
Directs
.I pcal
to write the output to <file> instead of to stdout.
.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
.B \-S
This will cause Saturdays and Sundays 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
if test -f 'pcalinit.h'
then
	echo shar: will not over-write existing file 'pcalinit.h'
else
cat << \SHAR_EOF > 'pcalinit.h'
/*
 * pcalinit.h - provides 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 to calculate leap years correctly, print holidays in gray,
   and to center month and year together */

char *header_2[] = {
  "\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",
  "/strcat {\t\t% concatenate two strings",
  "\t2 copy",
  "\tlength exch length",
  "\tdup 3 -1 roll add",
  "\tstring",
  "\tdup 0 6 -1 roll putinterval",
  "\tdup 3 -1 roll 4 -1 roll putinterval",
  "} def",
  "/calendar",
  "{",
  "\ttitlefont findfont 48 scalefont setfont",
  "\t/month_name month_names month 1 sub get def",
  "\t/yearstring year 10 string cvs def",
  "\t0 60 moveto",
  "\tmonth_name (  ) strcat yearstring strcat 700 center",
  "\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_3[] = {
  "\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,
};

SHAR_EOF
fi
exit 0
#	End of shell archive



More information about the Alt.sources mailing list