smann@cs.washington.edu (Stephen Mann) (01/09/90)
Well, as long as everyone else is posting their version of pscal, I may as well post my latest version. It's still a csh script. Although I like the look of the 5 row format, the 6 row format avoids the doubling of days (and holidays for those days). Changes others made didn't make it into my version. Changes from the last version I posted include: - PostScript will appear on standard output instead of sending it directly it to a printer. The user now must redirect the output to a printer. - The command line semantics were changed as follows: - with no arguments, print the calendar for the current month; - with one argument (a year) print the calendar for the entire year; - with two arguments (month and year) print the calendar for that month and year. If month is 0, then print it for the entire year; - If the lone arguement of '-man' is given, print the man page; - Months can now be specified as a string of 3 characters (first three characters of the month, first letter capitalized) - Corrections to 'isleap' and 'startday' mentioned earlier were incorporated - A crummy facility for showing full and new moons was added (basically, you list them in a file). Maybe someday I'll get around to allowing arbitrary PostScript in the holiday file, clipping of holidays to the day box, and writing a better holiday processor. Maybe. Steve ----------------- #!/bin/csh -f #+ # # NAME: # pscal # # SYNOPSIS: # pscal [[month] year] # # DESCRIPTION: # `Pscal' is a PostScript program to generate calendars. # There are multiple ways of invoking the program. # If no arguments are given, then the calendar for the # current month/year is generated. # If one argument is given, then it is assumed to be a year, # and the calendar for the entire year is printed. # If two arguments are given, then the first is taken to # be the month, and the second the year. # # The month may be in one of two formats: first, it can be # a number from 0 to 12. The numbers correspond to the # obvious month; '0' is special, and will indicates that # the calendar for the entire year should be generated. # The second format for the month is as a string of three # characters. The format is the same one that the Unix 'date' # program uses: first three letters of the month, first # letter capitolized. # # 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. # # Also, you may have a ~/.holiday.moon.<year> file. # This is a real ugly hack to put pictures of the full # and new moon on the calendar. Form of the lines # should be # month day full # (or new, if it is a new moon). If there are two full (new) # moons in a month, an entry should be made for each. # Like I said, a real ugly hack. # # If invoked with the single argument '-man', pscal will # print this man page. # # NOTES: # This version differs from previous versions! The calendar # is printed on standard output. It is up to the user # to redirect the output to a printer. # # 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 # @Command line processing changed; character string months # @ added; printing of entire year added; phase of moon # @ hacked in; corrections to isleap and startday (noted # @ elsewhere) made; added -man switch; # @ by smann@june.cs.washington.edu Jan 1990 # # 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). # # END-OF-MAN set dmon = (Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) set flags set date = (`date`) switch ($#argv) case 0: set month = $date[2] set i = 1 foreach m ($dmon) if ( $m == $month ) then set month = $i break endif @ i++ end set year = $date[6] breaksw case 1: switch ($1) case -man: cat $0 | awk '{if ($2 == "END-OF-MAN") exit;else print}' | more exit case -*: echo "usage: $0 [[month] year]" exit 1 endsw set month = 0 set year = $argv[1] breaksw case 2: set month = $argv[1] set i = 1 foreach m ($dmon) if ( $m == $month ) then set month = $i break endif @ i++ end set year = $argv[2] breaksw default: echo "usage: $0 [[month] year]" exit 1 breaksw endsw if ( $month != 0 ) then set monthlist = ($month) else set monthlist = (12 11 10 9 8 7 6 5 4 3 2 1) endif cat <<END-OF-HEADER %! % 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) /titlefont /Times-Bold def /dayfont /Helvetica-Bold def /eventfont /Times-Roman 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 400 mod 0 eq or and % unless its a century divisible by 400 } 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 400 idiv add % Gregorian correction 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 /prtmoon { % phase day prtmoon - dup 0 ne { gsave .1 setlinewidth 0 setgray /day 2 1 roll def day start add 1 sub 7 mod 100 mul 85 add day start add 1 sub 7 div truncate -80 mul 20 add newpath 10 0 360 arc 0 ne {stroke} {fill} ifelse grestore } { pop pop } ifelse } 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 0 newmoon1 prtmoon 1 fullmoon1 prtmoon 0 newmoon2 prtmoon 1 fullmoon2 prtmoon } 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 %% EndProlog END-OF-HEADER foreach month ($monthlist) if ( -e $home/.holiday ) then set noglob set holidays = \ ( `grep ^$month\: $home/.holiday | awk -F: '{print $2,"(",$3,")" }'` ) else set noglob set holidays endif if ( -e $home/.holiday.$year ) then set noglob set holidays = ( \[ "$holidays" `grep ^$month\: $home/.holiday.$year | awk -F: '{print $2,"(",$3,")" }'` ] ) else set noglob set holidays = ( \[ "$holidays" ] ) endif if ( -e $home/.holiday.moon.$year ) then set fullmoon = `grep ^$month $home/.holiday.moon.$year | grep full | awk '{print $2}'` set newmoon = `grep ^$month $home/.holiday.moon.$year | grep new | awk '{print $2}'` else set fullmoon = (0 0) set newmoon = (0 0) endif if ( "$fullmoon" == "" ) set fullmoon = (0 0) if ( "$newmoon" == "" ) set newmoon = (0 0) if ( $#fullmoon == 1 ) set fullmoon = ($fullmoon 0) if ( $#newmoon == 1 ) set newmoon = ($newmoon 0) cat <<END-OF-CALENDAR /month $month def /year $year def /holidays $holidays def /fullmoon1 $fullmoon[1] def /newmoon1 $newmoon[1] def /fullmoon2 $fullmoon[2] def /newmoon2 $newmoon[2] 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 end