#!/bin/sh
#+
#
# NAME:
#	pscal
#
# SYNOPSIS:
#	pscal [-Pprinter] [other printer flags] month year
#
# DESCRIPTION:
#	`Pscal' is a PostScript program to print calendars.
#
#	The file $HOME/.holiday is read and used to print short messages
#	on specified days.  The .holiday file should consist of lines of
#	the form 
#		month:day:message string
#	Messages should be 20 characters or less, with no more than 6
#	messages per day.  No spaces should appear from the beginning
#	of a line until after the second colon.
#	Month and day should be numbers in the obvious ranges.
#	12/89 - The holiday checking has been loosened up in that the
#	following takes place:
#		1. The Shell Variable EFILE is used preferentially
#		2. Then the file Events in the current directory is used
#		3. Finally the $HOME/.holiday file is used.
#	The whole process can be turned off by setting EFILE=/dev/null.
#
# OPTIONS:
#	Any argument whose first character is '-' is passed on to lpr.
#	The shell variables BANNER, LFOOT, CFOOT, and RFOOT become a
#	top centered banner, and left, centered, or right justified
#	footers respectively.  As in:
#
#		BANNER="Schedule 1" CFOOT=Preliminary pscal 4 90
#
# AUTHOR:
#	Patrick Wood
#	Copyright (C) 1987 by Pipeline Associates, Inc.
#	Permission is granted to modify and distribute this free of charge.
# 
# HISTORY:
#	@Original From: patwood@unirot.UUCP (Patrick Wood)
#	@Shell stuff added 3/9/87 by King Ables
#	@Made pretty by tjt 1988
#	@Holiday and printer flag passing hacks added Dec 1988 
#	@ by smann@june.cs.washington.edu 
#	@Used the better looking version with 5 rows of days rather than 6
#	@ hacked together with holiday and banner/footnotes added
#	@ by Joe (No Relation) Wood, 12/89, jlw@lzga.ATT.COM
#	@Fixed "-R" (didn't work at all; now it at least works on 8.5x11)
#	@Also fixed handling of unrecognized arguments
#	@ by Jeff Mogul, 1/90, mogul@decwrl.dec.com
#
# BUGS:
#	`Pscal' doesn't work for months before 1753 (weird stuff happened
#	in September, 1752).
#
#	A better format for the dates of holidays would be nice.
#	An escape to allow holiday messages to be raw PostScript would
#	also be nice.
#	The holiday messages should be handled more intelligently (ie,
#	the messages should be clipped to the day).
#

# 
# PostScript program to print calendars.
# Doesn't deal well with September 1752 or before.
# 

USAGE="Usage: pscal [ -Rrt ] [ -F hfont ] [ -f font ] [ month [ year ] ]"

#TFONT=Times-Bold
#DFONT=Helvetica-Bold
#EFONT=Times-Roman
TFONT=Times-Bold-Gothic
DFONT=Helvetica-Gothic
EFONT=Times-Roman-Ryumin

Calendar=$HOME/Calendar

ROTATE=90
SCALE="1.0 1.0"
#	Was 50 -120 - changed to 71 -120 for A4 Use
TRANSLATE="71 -120"

CAT="cat"
#CAT=" nkf -e -u"	# if you use ja_JP.* but ja_JP.ujis

LPR="lpr"

while test $# != 0
do
    case $1 in
	-P) test $# -lt 2 && { echo "$USAGE" 1>&2; exit 1; }
	    eval ENVAR="$1$2"; shift 2;;
	-P*) eval ENVAR=$1; shift 1;;
	-F) test $# -lt 2 && { echo "$USAGE" 1>&2; exit 1; }
	    TFONT="$2"; shift 2;;
	-F*) TFONT=`echo $1 | sed -n 1s/-.//p`; shift 1;;
	-f) test $# -lt 2 && { echo "$USAGE" 1>&2; exit 1; }
	    DFONT="$2"; shift 2;;
	-f*) DFONT=`echo $1 | sed -n 1s/-.//p`; shift 1;;
	-t) LPR=cat; shift 1;;
	-r) ROTATE=90; shift 1;;
	-R) ROTATE=0; SCALE="0.75 0.75"; TRANSLATE="50 900"; shift 1;;
	--|-) break;;
	-*) eval ENVAR=\"$ENVAR $1\"; shift 1;;
	*) break
    esac
done

test $# -gt 2 && { echo "$USAGE" 1>&2; exit 1; }

case $# in
    0)	set `date`; YEAR=$6; MONTH=$2;;
    1)	MONTH=$1; set `date`; YEAR=$6;;
    2)	MONTH=$1 YEAR=$2;;
esac

MONTH=`case $MONTH in Jan|jan) echo 1;;Feb|feb) echo 2;;Mar|mar) echo 3;;Apr|apr) echo 4;;
	May|may) echo 5;;Jun|jun) echo 6;;Jul|jul) echo 7;;Aug|aug) echo 8;;
	Sep|sep) echo 9;;Oct|oct) echo 10;;Nov|nov) echo 11;;Dec|dec) echo 12;;
	1|2|3|4|5|6|7|8|9|10|11|12) echo $MONTH;;esac`

test $YEAR -lt 100 && YEAR=`expr $YEAR + 1900`

if [ -n "$EFILE" -a -r "$EFILE" ]
then
	Files=$EFILE
	monthday=yes
elif [ -r Events ]
then
	Files=Events
	monthday=yes
elif [ -r $HOME/.holiday ]
then
	Files=$HOME/.holiday
	monthday=yes
elif [ -d $Calendar ]
then
	cd $Calendar
	if [ -d xy$YEAR ]
	then
		cd xy$YEAR
	fi
	set 'dummy' 'Jan' 'Feb' 'Mar' 'Apr' 'May' 'Jun' 'Jul' 'Aug' 'Sep' 'Oct' 'Nov' 'Dec'
	shift $MONTH
	list=`echo xc*$1$YEAR`
	case "$list" in
	xc\*$1$YEAR)
			;;
	*)
		for file in $list
		do
			day=`expr $file : 'xc\([0-9]*\)'`
			($CAT $file; echo) | sed '/^$/d
					s/^/./' |
					# fmt -22 |
					awk '{
					N = 22
					len = length($0)
					kanji1 = 0
					lp = 0
					for(sp = 0; sp<len; sp++) {
					  c = substr($0, sp+1, 1)
					  if (kanji1) {
					    if (lp+2 > N) {
						printf "\n"
						lp = 0
					    }
					    printf "%s%s", c1, c
					    lp += 2
					    kanji1 = 0
					  }
					  else {
					    if (c ~ /[-~]/) {
					      if (lp+1 > N) {
						printf "\n"
						lp = 0
					      }
					      printf "%s", c
					      lp++
					    }
					    else {
					      kanji1 = 1
					      c1 = c
					    }
					  }
				        }
					printf "\n"
				        }' |
					 sed -n "7q
					s/^\.//
					s/^/$day ( /
					s/\$/ )/
					p"
		done > /tmp/pscal$$
		holidays=`cat /tmp/pscal$$`
		rm -f /tmp/pscal$$	
	esac
fi

case "$monthday" in
yes)
	holidays=`cat $Files | grep \^$MONTH: | awk -F: '{printf("%s ( %s",$2,$3);\
		for(i = 4; i <= NF; i++) printf(":%s", $i);printf(")\n"); }'`
esac


$LPR $ENVAR <<END-OF-CALENDAR
%!
%%BeginProcSet: cmpfont.ps 1 2
% composite fonts for ASCII-EUC mixed string
% Version 1.2 1/31/1990
% Author Ken'ichi HANDA (handa@etl.go.jp)
% Anyone can freely copy, modify, distribute this program.
/copyfont {	% font-dic extra-entry-count  copyfont  font-dic
	1 index maxlength add dict begin
	{	1 index /FID ne 2 index /UniqueID ne and
		{def} {pop pop} ifelse
	} forall
	currentdict
	end
} bind def

/compositefont {	% ASCIIFontName EUCFontName  compositefont  font'
    findfont dup /FontType get 0 eq {
	12 dict begin
	    1 copyfont dup begin
		/Encoding Encoding
		FMapType dup 2 eq {
		    pop 128 128
		}{
		    5 eq {
			256 256
		    }{
			/compositefont errordict /invalidfont get exec
		    } ifelse
		} ifelse
		getinterval def
	    end
	    /eucfont exch definefont
	    exch
	    findfont 1 copyfont dup begin
		/FontMatrix FontMatrix [1 0 0 1 0 0.05] matrix concatmatrix def
	    end
	    /asciifont exch definefont
	    exch
	    /FDepVector [ 4 2 roll ] def
	    /FontType 0 def
	    /WMode 0 def
	    /FMapType 4 def
	    /FontMatrix matrix def
	    /Encoding [0 1] def
	    /FontBBox {0 0 0 0} def
	    currentdict
	end
    }{
	pop findfont 0 copyfont
    } ifelse
} def	

/slantfont {	% FontName slant-degree  slantfont  font'
    exch findfont 1 copyfont begin
    [ 1 0 4 -1 roll 1 0 0 ] FontMatrix exch matrix concatmatrix
    /FontMatrix exch def
    currentdict
    end
} def
%%EndProcSet
% reencodeISO was modified to deal with a composite font correctly.
% Modifier: Shigeru Chiba (chiba@is.s.u-tokyo.ac.jp)
%           Kazuhiro Kazama (kazama@expert-sun.ntt.jp)
/reencodeISOa {		% CompFontName font reencodeISOb font' 
dup length dict begin
{ 1 index /FID ne { def }{ pop pop } ifelse } forall
/Encoding ISOLatin1Encoding def
currentdict end definefont
} def

/reencodeISO {		% FontName reencodeISO font
    dup dup findfont dup /FontType get 0 ne {
    reencodeISOa
}{
    dup length dict begin {
    1 index dup /FID eq {
	pop pop pop
    }{ /FDepVector eq {
	dup length array copy
	dup dup 0 get 4 index exch reencodeISOa	0 exch put def
    }{
	def
    } ifelse } ifelse } forall
    currentdict end definefont
} ifelse } def

/ISOLatin1Encoding [
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright
/parenleft/parenright/asterisk/plus/comma/minus/period/slash
/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon
/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N
/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright
/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m
/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve
/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut
/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar
/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot
/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior
/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine
/guillemotright/onequarter/onehalf/threequarters/questiondown
/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla
/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex
/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute
/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis
/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave
/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex
/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis
/yacute/thorn/ydieresis
] def

/Helvetica-Gothic
    /Helvetica /GothicBBB-Medium-EUC-H compositefont definefont pop
/Helvetica-Gothic reencodeISO def

/Times-Bold-Gothic
    /Times-Bold /GothicBBB-Medium-EUC-H compositefont definefont pop
/Times-Bold-Gothic reencodeISO def

/Times-Roman-Ryumin
    /Times-Roman /Ryumin-Light-EUC-H compositefont definefont pop
/Times-Roman-Ryumin reencodeISO def

% PostScript program to draw calendar
% Copyright (C) 1987 by Pipeline Associates, Inc.
% Permission is granted to modify and distribute this free of charge.

% The number after /month should be set to a number from 1 to 12.
% The number after /year should be set to the year you want.
% You can change the title and date fonts, if you want.
% We figure out the rest.
% This program won't produce valid calendars before 1800 due to the switch
% from Julian to Gregorian calendars in September of 1752 wherever English
% was spoken.

/month $MONTH def
/year $YEAR def
/titlefont /$TFONT def
/dayfont /$DFONT def
/eventfont /$EFONT def
/holidays [ $holidays ] def
/Bannerstring ($BANNER) def
/Lfootstring ($LFOOT) def
/Rfootstring ($RFOOT) def
/Cfootstring ($CFOOT) def

% calendar names - change these if you don't speak english
% "August", "April" and "February" could stand to be kerned even if you do

/month_names
[ () () () () () () ()
() () () () () ]
def

/day_names
[ () () () () () () () ]
def

% layout parameters - you can change these, but things may not look nice

/daywidth 100 def
/dayheight 95 def

/titlefontsize 48 def
%/weekdayfontsize 10 def
/weekdayfontsize 12 def
/datefontsize 30 def
/footfontsize 20 def

/topgridmarg 35 def
/leftmarg 35 def
/daytopmarg 10 def
/dayleftmarg 5 def

% layout constants - don't change these, things probably won't work

/rows 5 def
/subrows 6 def

% calendar constants - change these if you want a French revolutionary calendar

/days_week 7 def

/days_month [ 31 28 31 30 31 30 31 31 30 31 30 31 ] def

/isleap {				% is this a leap year?
	year 4 mod 0 eq			% multiple of 4
	year 100 mod 0 ne 		% not century
	year 1000 mod 0 eq or and	% unless it's a millenia
} def

/ndays {				% number of days in this month
	days_month month 1 sub get
	month 2 eq			% February
	isleap and
	{
		1 add
	} if
} def

/weekday {				% weekday (range 0-6) for integer date
	days_week mod
} def

/startday {				% starting day-of-week for this month
	/off year 2000 sub def		% offset from start of "epoch"
	off
	off 4 idiv add			% number of leap years
	off 100 idiv sub		% number of centuries
	off 1000 idiv add		% number of millenia
	6 add weekday days_week add 	% offset from Jan 1 2000
	/off exch def
	1 1 month 1 sub {
		/idx exch def
		days_month idx 1 sub get
		idx 2 eq
		isleap and
		{
			1 add
		} if
		/off exch off add def
	} for
	off weekday			% 0--Sunday, 1--monday, etc.
} def

/prtevent {		% event-string day prtevent
			%  print out an event
	/start startday def
	/day 2 1 roll def
	day start add 1 sub 7 mod daywidth mul
	day start add 1 sub 7 div truncate dayheight neg mul 
	-5 
	numevents day start add get -10 mul add
	numevents
	day start add 
	numevents day start add get 1 add
	put
	add moveto
	show
} def

/drawevents {		% read in a file full of events; print
			%  the events for this month
	/numevents
	[0 0 0 0 0 0 0
	 0 0 0 0 0 0 0
	 0 0 0 0 0 0 0
	 0 0 0 0 0 0 0
	 0 0 0 0 0 0 0
	 0 0 0 0 0 0 0] def 
	 eventfont findfont 9 scalefont setfont
	 0 2 holidays length 2 sub {
		dup
		1 add holidays 2 1 roll get
		2 1 roll holidays 2 1 roll get
		prtevent
	} for
		
} def

% ------------------------------------------------------------------------

/prtnum { 3 string cvs show } def

/center {				% center string in given width
	/width exch def
	/str exch def width str 
	stringwidth pop sub 2 div 0 rmoveto str show
} def

/centernum { exch 3 string cvs exch center } def

/drawgrid {				% draw calendar boxes
	titlefont findfont weekdayfontsize scalefont setfont
	currentpoint /y0 exch def /x0 exch def
	0 1 days_week 1 sub {
		submonth 0 eq
		{
			x0 y0 moveto
			dup dup daywidth mul 40 rmoveto
			day_names exch get
			daywidth center
		} if
		x0 y0 moveto
		daywidth mul topgridmarg rmoveto
		1.0 setlinewidth
		submonth 0 eq
		{
			/rowsused rows 1 sub def
		}
		{
			/rowsused rows def
		}
		ifelse
		0 1 rowsused {
			gsave
			daywidth 0 rlineto 
			0 dayheight neg rlineto
			daywidth neg 0 rlineto
			closepath stroke
			grestore
			0 dayheight neg rmoveto
		} for
	} for
} def

/drawnums {				% place day numbers on calendar
	dayfont findfont datefontsize
	submonth 0 ne
	{
		2.5 mul
	} if scalefont setfont
	/start startday def
	/days ndays def
	start daywidth mul dayleftmarg add daytopmarg rmoveto
	submonth 0 ne
	{
		dayleftmarg neg dayheight -2 div rmoveto
	} if
	1 1 days {
		/day exch def
		gsave
		day start add weekday 0 eq
		{
			submonth 0 eq
			{
				.7 setgray
			} if
		} if
		day start add weekday 1 eq
		{
			submonth 0 eq
			{
				.7 setgray
			} if
		} if
		submonth 0 eq
		{
			isdouble
			{
				day prtdouble
			}
			{
				day prtnum
			} ifelse
		}
		{
			day daywidth centernum
		} ifelse
		grestore
		day start add weekday 0 eq
		{
			currentpoint exch pop dayheight sub 0 exch moveto
			submonth 0 eq
			{
				dayleftmarg 0 rmoveto
			} if
		}
		{
			daywidth 0 rmoveto
		} ifelse
	} for
} def
/isdouble {				% overlay today with next/last week?
	days start add rows days_week mul gt
	{
		day start add rows days_week mul gt
		{
			true true
		}
		{
			day start add rows 1 sub days_week mul gt
			day days_week add days le and
			{
				false true
			}
			{
				false
			} ifelse
		} ifelse
	}
	{
		false
	} ifelse
} def

/prtdouble {
	gsave
	  dayfont findfont datefontsize 2 mul 3 div scalefont setfont
	  exch
	  {
		(23/) stringwidth pop dayheight rmoveto
		prtnum
	  }
	  {
		0 datefontsize 5 div rmoveto
		prtnum
		0 datefontsize -5 div rmoveto
		gsave
		  dayfont findfont datefontsize scalefont setfont
		  (/) show
		grestore
	  } ifelse
	grestore
} def

/drawfill {				% place fill squares on calendar
	/start startday def
	/days ndays def
	currentpoint /y0 exch def /x0 exch def
	submonth 0 eq
	{
		usefirst
		{
			/fillstart 2 def
		}
		{
			/fillstart 0 def
		}
		ifelse
	}
	{
		/fillstart 0 def
	}
	ifelse
	fillstart daywidth mul topgridmarg rmoveto
	1.0 setlinewidth
	fillstart 1 start 1 sub {
		gsave
		.9 setgray
		daywidth 0 rlineto 
		0 dayheight neg rlineto
		daywidth neg 0 rlineto
		closepath fill
		grestore
		daywidth 0 rmoveto
	} for
	x0 y0 moveto
	submonth 0 ne
	{
		/lastday rows 1 add days_week mul def
		days_week 1 sub daywidth mul -440 rmoveto
	}
	{
		/lastday rows days_week mul 2 sub fillstart add def
		days_week 3 sub fillstart add daywidth mul
		-440 dayheight add rmoveto
	} ifelse
	lastday -1 ndays start 1 add add
	{
		/day exch def
		gsave
		.9 setgray
		daywidth 0 rlineto 
		0 dayheight neg rlineto
		daywidth neg 0 rlineto
		closepath fill
		grestore
		day weekday 1 eq
		{
			x0 y0 moveto
			days_week 1 sub daywidth mul -440 dayheight add rmoveto
		}
		{
			daywidth neg 0 rmoveto
		} ifelse
	} for
} def

/usefirst {				% are last two boxes used by days?
	start ndays add rows days_week mul 3 sub gt
	start 2 ge and
	
} def

/calendar
{
	titlefont findfont titlefontsize scalefont setfont
	0 60 moveto
	/month_name month_names month 1 sub get def
	month_name show
	/yearstring year 10 string cvs def
	daywidth days_week mul yearstring stringwidth pop sub 60 moveto
	yearstring show

	eventflag {
		% Show a centered Banner if any at the Top
		daywidth days_week mul 2 div
		Bannerstring stringwidth pop 2 div sub
		60 moveto
		Bannerstring show
		% Show footnotes left-center-right
		eventfont findfont footfontsize scalefont setfont
		/bottomrow { dayheight rows mul 5 sub neg } def
		0 bottomrow moveto
		Lfootstring show
		daywidth days_week mul Rfootstring stringwidth pop sub
		bottomrow moveto
		Rfootstring show
		daywidth days_week mul Cfootstring stringwidth pop sub 2 div
		bottomrow moveto
		Cfootstring show
		
	} if

	0 -5 moveto
	drawnums

	0 -5 moveto
	drawfill

	eventflag {
		0 0 moveto
		drawevents
	} if

	0 -5 moveto
	drawgrid
} def

/eventflag true def

$SCALE scale
$ROTATE rotate
$TRANSLATE translate
/submonth 0 def
calendar
/eventflag false def
month 1 sub 0 eq
{
	/lmonth 12 def
	/lyear year 1 sub def
}
{
	/lmonth month 1 sub def
	/lyear year def
} ifelse
month 1 add 13 eq
{
	/nmonth 1 def
	/nyear year 1 add def
} 
{
	/nmonth month 1 add def
	/nyear year def
} ifelse
usefirst
{
	0 30 translate
}
{
	days_week 2 sub daywidth mul -350 translate
}
ifelse
/submonth 1 def
/year lyear def
/month lmonth def
gsave
.138 .138 scale
12 -120 translate
calendar
grestore
/submonth 1 def
/year nyear def
/month nmonth def
daywidth 0 translate
gsave
.138 .138 scale
12 -120 translate
calendar
grestore

showpage

END-OF-CALENDAR

