[comp.lang.postscript] pscal

smann@june.cs.washington.edu (Stephen Mann) (05/12/89)

Here's a version of Pscal that has holidays hacked in.  The program
is a Unix C-shell script that sends PostScript directly to a printer.
Documentation appears in the header comments of the script.

Steve
--------
#!/bin/csh -f
#+
#
# 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 4
#	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.
#
# OPTIONS:
#	Any argument whose first character is '-' is passed on to lpr.
#
# 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 
#
# 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).
#

set printer="-Pps"	# set default printer
set flags

top:
if ($#argv > 0) then
	switch ("$argv[1]")
		case -P*:
			set printer="$argv[1]"
			shift argv
			goto top
		case -*:
			set flags = ($flags $argv[1])
			shift argv
			goto top
		case *:
			if ($?month) then
				set year="$argv[1]"
			else if ($?year) then
				echo "usage: $0 [-Pprinter] month year"
				exit 1
			else
				set month="$argv[1]"
			endif
			shift argv
			goto top
	endsw
endif

if ($?year) then
else 
	echo "usage: $0 [-Pprinter] [-flag1 -flag2 ...] month year"
	exit 1
endif

if ( -e $home/.holiday ) then
    set noglob
    set holidays = \
       (  \[ `grep  ^$month\: $home/.holiday | awk -F: '{print $2,"(",$3,")" }'` ] )
else
    set noglob
    set holidays = (\[ ] )
endif

lpr $printer $flags <<END-OF-CALENDAR
%!
% PostScript program to draw calendar
% Copyright (C) 1987 by Pipeline Associates, Inc.
% Permission is granted to modify and distribute this free of charge.

% /month should be set to a number from 1 to 12
% /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
% won't produce valid calendars before 1800 (weird stuff happened
% in September of 1752)

/month $month def
/year $year def
/titlefont /Times-Bold def
/dayfont /Helvetica-Bold def
/eventfont /Times-Roman def

/holidays $holidays def

/month_names [ (January) (February) (March) (April) (May) (June) (July)
		(August) (September) (October) (November) (December) ] def

/prtnum { 3 string cvs show} def

/drawgrid {		% draw calendar boxes
	dayfont findfont 10 scalefont setfont
	0 1 6 {
		dup dup 100 mul 40 moveto
		[ (Sunday) (Monday) (Tuesday) (Wednesday) (Thursday) (Friday) (Saturday) ] exch get
		100 center
		100 mul 35 moveto
		1.0 setlinewidth
		0 1 5 {
			gsave
			100 0 rlineto 
			0 -80 rlineto
			-100 0 rlineto
			closepath stroke
			grestore
			0 -80 rmoveto
		} for
	} for
} def

/drawnums {		% place day numbers on calendar
	dayfont findfont 30 scalefont setfont
	/start startday def
	/days ndays def
	start 100 mul 5 add 10 rmoveto
	1 1 days {
		/day exch def
		gsave
		day start add 7 mod 0 eq
		{
			submonth 0 eq
			{
				.8 setgray
			} if
		} if
		day start add 7 mod 1 eq
		{
			submonth 0 eq
			{
				.8 setgray
			} if
		} if
		day prtnum
		grestore
		day start add 7 mod 0 eq
		{
			currentpoint exch pop 80 sub 5 exch moveto
		}
		{
			100 0 rmoveto
		} ifelse
	} for
} def

/drawfill {		% place fill squares on calendar
	/start startday def
	/days ndays def
	0 35 rmoveto
	1.0 setlinewidth
	0 1 start 1 sub {
		gsave
		.9 setgray
		100 0 rlineto 
		0 -80 rlineto
		-100 0 rlineto
		closepath fill
		grestore
		100 0 rmoveto
	} for
	submonth 1 eq
	{
		/lastday 42 def
		600 -365 moveto
	}
	{
		/lastday 40 def
		400 -365 moveto
	} ifelse
	lastday -1 ndays start 1 add add
	{
		/day exch def
		gsave
		.9 setgray
		100 0 rlineto 
		0 -80 rlineto
		-100 0 rlineto
		closepath fill
		grestore
		day 7 mod 1 eq
		{
			600 -365 80 add moveto
		}
		{
			-100 0 rmoveto
		} ifelse
	} for
} 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

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

/ndays {		% number of days in this month
	days_month month 1 sub get
	month 2 eq	% Feb
	isleap and
	{
		1 add
	} if
} 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 7 mod 7 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 7 mod		% 0--Sunday, 1--monday, etc.
} def

/prtevent {		% event-string day prtevent
			%  print out an event
	    /day 2 1 roll def
	    day start add 1 sub 7 mod 100 mul
	    day start add 1 sub 7 div truncate -80 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

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

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

	0 0 moveto
	drawnums

	0 0 moveto
	drawfill

	eventflag {
		0 0 moveto
		drawevents
	} if

	0 0 moveto
	drawgrid
} def

/eventflag true def
90 rotate
50 -120 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
/submonth 1 def
/year lyear def
/month lmonth def
500 -365 translate
gsave
.138 .138 scale
10 -120 translate
calendar
grestore
/submonth 1 def
/year nyear def
/month nmonth def
100 0 translate
gsave
.138 .138 scale
10 -120 translate
calendar
grestore

showpage

END-OF-CALENDAR

smann@cs.washington.edu (Stephen Mann) (11/14/90)

I modified a version of pscal to put the day of the year at the top
center of each day.  If you'd like a copy, send me email (if enough
people request it, I'll go ahead and post it).  Note the following,
however:

	1) This is a csh version of pscal
	2) It uses the 6 weeks per month format (and not the 5 weeks/month)

Steve

schuster@cup.portal.com (Michael Alan Schuster) (11/15/90)

Here is a calendar program I just found on GEnie:

%!PS-Adobe-2.0      
%% Title:         CALENDAR.PS
%% Creator:       C.FOSSETT
%% CreationDate:  November 10, 1990

%------------------------------ CALENDAR.PS ----------------------------------

% Copyright (c) 1990                                                         
% Chad Fossett               Commercial use is absolutely prohibited.       
% 8026 Nightingale Way       Personal use is permitted as long as this      
% San Diego, CA  92123       copyright notice remains present and intact.   
% All Rights Reserved.                                                       

% CALENDAR.PS produces a wall-style monthly calendar for December, 1990.
% It can be easily modified to print any month.  It can also be tailored
% to individual tastes by adjusting the calendar size and aspect-ratio,
% and by adding personalized special events to any date.

%----------------------------------------------------------------------------
%
%      The calendar is laid out as follows:
%
%                         columns on the x-axis
%              0     1     2     3     4     5     6
%            0                                               Each cell is
%                0 0   1 0   2 0   3 0                       designated as   
%            1                                               the intersection
%                0 1                                         of the two lines
%    rows    2                                               at its upper
%   on the       0 2                           5 2           left corner
%   y-axis   3                                               (see the x,y
%                            2 3                             notation in
%            4                                               the cells to
%                                  3 4                       the left for
%                                                            examples).
%
%-----------------------------------------------------------------------------

% As it is set up below, it prints in landscape orientation on an 8 x11 page.
% The aspect ratio can be changed by adjusting CH and CW below, or by
% xy scaling the whole calendar at print time.
% If the size and aspect ratio are OK, then the only things needing
% attention are the top three definitions (month, startday, and numdays),
% and any special events, holidays, etc. (enumerated near the end).


%------------------------------- PROLOGUE ------------------------------------

/month (DECEMBER  1990) def         % This gets centered at the top

/startday 6 def     % day of the week the month starts on 0=sun, 1=mon etc.
/numdays 31 def     % number of days in the month

/monthsize 36 def                   % Point size for month (JANUARY  1990),
/datesize 30 def                    % date (1 2 3 4 etc.),
/daysize 14 def                     % and day (SUNDAY, MONDAY etc.).

/monthfont {/AvantGarde-Demi findfont monthsize scalefont setfont} def
/datefont {/AvantGarde-Demi findfont datesize scalefont setfont} def
/dayfont {/AvantGarde-Book findfont daysize scalefont setfont} def

/CH -82 def                         % Cell Height (y-axis value of 1)
/CW 105 def                         % Cell Width  (x-axis value of 1)

/cellcoord {CH mul exch CW mul exch} def          % scaling for 1x1 cells

/monthshow {monthfont                             % set the font
            month dup stringwidth pop CW 7 mul    % and print the month
            exch sub 2 div                        % centered
            70 monthsize sub rmoveto show} def    % above the line

/daynames {[(SUNDAY) (MONDAY)                     % 7-element array
            (TUESDAY) (WEDNESDAY)                 % of the names of
            (THURSDAY) (FRIDAY)                   % the days of
            (SATURDAY)]} def                      % the week

/dayshow { dayfont                                % display the daynames
  0 1 6                                           % start the loop (0-6)
   {dup 0 cellcoord moveto                        % move to a cell 0
    daynames exch get                             % get the array element
    dup stringwidth pop CW exch sub 2 div         % center it left-right
    26 daysize sub 2 div                          % and up-down
    gsave rmoveto show grestore                   % show it
    0 25 rlineto CW 0 rlineto                     % and draw a line
    0 -25 rlineto stroke                          % around it (on 3 sides)
   } for                                          % end of the loop
 } def

/bestgray {106 45                                 % the Guru's
          {dup mul exch dup                       % (Don Lancaster's)
           mul add 1.0 exch sub}                  % best gray half-tone
           setscreen} def                         % setscreen

/box {1 setlinewidth gsave                        % draw a box
      CW 0 rlineto 0 CH rlineto                   % CH high by
      CW neg 0 rlineto closepath                  % CW wide
      stroke grestore
     } def

/datecalc {7 mul add startday sub 1 add} def      % calculate date (- OK)

/gtcheck {dup 0 gt                                % if greater than 0,
          {lecheck}                               % do lecheck
          {pop pop pop} ifelse} def               % if not, pop off

/lecheck {dup numdays le                          % if   numdays,
          {row5check}                             % do row5check
          {pop pop pop} ifelse} def               % if not, pop off

/row5check {2 copy pop 5 eq                       % if row equals 5,
            {xsundaycheck}                        % do x(tra)sundatecheck
            {sundaycheck} ifelse} def             % if not, sundaycheck

/xsundaycheck {3 copy pop pop 0 eq                % if col equals 0,
               {xsundateshow pop pop}             % do x(tra)sundateshow
               {xdateshow pop pop} ifelse} def    % if not, x(tra)dateshow

/sundaycheck {3 copy pop pop 0 eq                 % if col equals 0,
               {sundateshow pop pop}              % do sundateshow
               {dateshow pop pop} ifelse} def     % if not, dateshow

/dateshow {datefont
           2 string cvs dup stringwidth           % prints date towards 
           pop CW 4 sub exch sub 0 datesize       % the upper-right
           .9 mul sub rmoveto                     % corner of the cell
           show } def

/sundateshow {datefont
           2 string cvs dup stringwidth           % same as dateshow
           pop CW 4 sub exch sub 0 datesize       % but
           .9 mul sub rmoveto 0 setlinewidth
           true charpath gsave                    % instead of black,
           bestgray .96 setgray fill              % filled with gray
           grestore stroke } def                  % and outlined

/xdateshow {0 CH -2 div rmoveto gsave             % moves *up* a half
           CW 0 rlineto                           % cell, and prints
           1 setlinewidth stroke grestore         % a line across;
           dateshow} def                          % then dateshow

/xsundateshow {0 CH -2 div rmoveto gsave          % moves *up* a half
              CW 0 rlineto                        % cell, and prints
              1 setlinewidth stroke grestore      % a line across;
              sundateshow} def                    % then sundateshow

/docell {dup 5 lt {box} if          % print a box if lt row 5
         2 copy                     % col row col row on stack
         datecalc                   % col row datenum after datecalc
         gtcheck                    % start a series of checks for
        } def                       %     a printable number

/calendar {gsave                    % start calendar definition

1 setlinewidth                      % set stroke line width to 1

0 0 cellcoord moveto monthshow      % show the month

dayshow                             % show the days

0 1 5 { dup                         % do dates; loop for rows (nb *6* rows)
   0 1 6 {                          % nested loop for columns (7)
      exch 2 copy                   % col row col row on stack
      cellcoord moveto docell dup   % go to the cell and do it
         } for pop pop              % end of nested loop
      } for                         % end of outer loop

grestore} def                       % end calendar definition


/littlecal {cellcoord gsave translate             % prints a small calendar.
            4.5 -20 translate                     % 0 0, then fudge a bit
            .13 .13 scale                         % reduce the size
            calendar grestore} def                % and do calendar

/specialfont {/AvantGarde-Book findfont 8 scalefont setfont} def

/specialevent {specialfont                        % prints special events
              cellcoord moveto gsave              % towards the bottom right
              dup stringwidth pop CW 4 sub        % of a cell
              exch sub CH 4 add rmoveto
              show grestore} def                    

/holiday {specialevent                            % print specialevent,
          sundateshow} def                        % then gray date


%-------------------------------- SCRIPT -------------------------------------


-90 rotate                  % landscape mode
-763.5 472.5 translate      % 0 0 at the UL corner of UL cell

calendar                    % and print it - this is the basic calendar


% Then print any special days & events, holidays, small calendars, etc.
% This is done manually to facilitate month-to-month changes, and
% to avoid the "clunky stuff" that shows up if they're displayed in
% the small calendars (at least at 300 dpi on my H-P LaserJet II).


(Pearl Harbor Day, 1941) 5 1 specialevent   % a special day in cell 5 1
(Winter begins) 6 3 specialevent            % onset of winter in 6 3
(full moon) 0 1 specialevent                % full moon in 0 1
(Chanukah) 3 2 specialevent                 % a religious celebration in 3 2
(Grandma's Birthday) 1 3.5 specialevent     % a birthday reminder in cell 1 3.5
                                            % (the upper "half" cell above 1 4)
(New Year's Eve) 1 4 specialevent           % New Year's Eve in cell 1 4
(25) (Christmas) 2 4 holiday                % make the 25th (Christmas)
                                            % look like a holiday in 2 4
                                            % (note *2* strings for holidays)

/month (NOVEMBER 1990) def       % print the previous month's calendar
/startday 4 def                  % which starts on Thursday (4)
/numdays 30 def                  % and has 30 days
1 0 littlecal                    % as a small calendar in 1 0

/month (JANUARY 1991) def        % print the next month's calendar
/startday 2 def                  % which starts on Tuesday (2)
/numdays 30 def                  % and has 30 days
5 0 littlecal                    % as a small calendar in 5 0

showpage                         % and finally, show what's there

quit                             % and quit

%---------------------------- END CALENDAR.PS --------------------------------