/*
 * pcal.c: PostScript/C monthly calendar, with items from the user's
 *		calendar file placed accordingly.
 *
 * Revision History:
 *
 *		kk: Ken Keirnan of Pacific Bell
 *		pw: Patrick Wood of Pipeline Associates
 *		bv: Bill Vogel of AT&T.
 *		jpl: Joe Larson of Dayton-Hudson
 *
 *		?-87	pw		PostScript code written.
 *		?-??	bv		Calendar file inclusion code written.
 *		?-89	kk		Collected together and posted to Usenet.
 *		1-90	jpl.	Fixed bug in postscript code.  Added a full-year
 *						mode.  Posted to Usenet.
 *		1-90	jpl.	Implemented optional rotation, fonts, etc as per
 *						suggestions (and even some "diffs") from the net.
 *						Split prolog into external file.
 *						Fixed the "-m month" option so it really works.
 *						Got rid of some questionable C practices due to
 *						reports of syntax errors with some compilers.
 */

#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>

#ifndef	PROLOG_FILE			/* Define this file accordingly. */
#define	PROLOG_FILE	"/mit/calendar/lib/newpcal.ps"
#endif

char	*words[100],		/* maximum number of words on a line */
		lbuf[512];			/* maximum line size */

char months[12][4] =		/* used to match alpha months */
{
	"jan", "feb", "mar", "apr", "may", "jun",
	"jul", "aug", "sep", "oct", "nov", "dec"
};


FILE	*cfp = NULL;		/* Calendar input file */
int		year,
		cyear;

extern int		errno;
void exit();
char *getenv();

main(argc, argv)
int argc;
char **argv;
{
	extern char		*optarg;
	struct tm		*lt;
	FILE			*ifile;				/* Prolog input file		*/

	char			cbuf[80],			/* String buffer			*/
					*cfile,				/* Name of calendar file	*/
					*cp,				/* Used in the getenv stuff	*/
 					*titlefont,
					*dayfont;

	long			t, time();
 	short			rotate,
					nocal,
					m,
					month;

	char			doyear,
					doprolog;


/*
 * Initialize variables.
 */
	cfile = NULL;
	titlefont = "Times-Bold";
	dayfont = "Times-Bold";
	rotate = 90;
	nocal = month = 0;
	doyear = 0;
	doprolog = 1;

/*
 * Handle the arglist.
 */
 	while ((m = getopt(argc, argv, "ef:pr:m:y:t:d:")) != EOF)
		switch (m)
		{
			case 'p':	doprolog = 0; break;
			case 'e':	nocal++; cfile = NULL; break;

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

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

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

			case 'r':	rotate = 0; break;
			case 't':	titlefont = optarg; break;
			case 'd':	dayfont = optarg; break;

			case '?':	fprintf(stderr, "\
Usage: %s [ -r ] [ -e | -f <cal> ] [ -m month] [ -y <year> ]\n\
        [ -t <title font> ] [ -d <day font> ]\n", argv[0]);
						exit(1);
		}


/*
 * Get all the month/year info needed.
 */
	t = time((long *)0);
	lt = localtime(&t);

	if (!month && !doyear)
		month = lt->tm_mon + 1;
	if (!year)
		year = lt->tm_year + 1900;
	cyear = year;		/* If no year in calendar file, assume current. */

/*
 * Open a supplied calendar file (if any)
 */
	if (cfile != NULL)
	{
		if ((cfp = fopen(cfile, "r")) == NULL)
		{
			fprintf(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
 */
	if (doprolog)
	{
		if ((ifile = fopen(PROLOG_FILE, "r")) == NULL)
		{
			perror(PROLOG_FILE);
			exit(errno);
		}
		printf("%%!\n");

		while (fgets(cbuf, 80, ifile) != NULL)
			printf("%s", cbuf);
		fclose(ifile);
	}

	printf("/titlefont /%s def\n/dayfont /%s def\n", titlefont, dayfont);
 	printf("%d rotate\n", rotate);
 	if (rotate)
 		printf("50 -120 translate\n");
 	else
 		printf("0.75 0.75 scale\n50 460 translate\n");

/*
 * Now go do the monthly calendar(s).
 */
	printf("/year %d def\n", year);
	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;
	register day;
	time_t t;
	char *dp;

	oldday = -1;
	/*
	 * Do the calendar
	 */
	printf("/month %d def\n", m);

	t = time(0);
	dp = ctime(&t);
	dp[strlen(dp)-1] = '\0';	/* strip trailing newline */
	printf("/dateprinted (printed:  %s) def\n", dp);

	printf("printmonth\n");

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

	} while (day = getday(m));
	printf("] daytext\n");
	printf("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);
	while (1)
	{
		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)
			break;
	}

	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; i < 12; 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++);
	return(i);
}
