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