jim@syteke.be (Jim Sanchez) (11/15/90)
Since my earlier posting for a version of the postscript calendar program that prints week numbers, I have gotten a bunch of requests for the original program. Since it seems to have been missed by a bunch of people, I am posting it here. Sorry if you already have it but it seems to be a popular request. I still don't have a version that does week numbers - hope you postscript hackers are out there working on it :-). Anyway, here she comes .... #!/bin/sh # # NAME: # pscal # # SYNOPSIS: # pscal [-Pprinter] [other option 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 # @Moon routines added; 1000 changed to 400 in isleap and startday; # @ fixed bug involving printing events on isdouble 30,31 days. # @ by Mark Hanson, 2/90, cs62a12@wind.ucsd.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). # USAGE="Usage: pscal [ -Rrtm ] [ -F hfont ] [ -f font ] [ month [ year ] ]" TFONT=Times-Bold DFONT=Helvetica-Bold EFONT=NewCenturySchlbk-BoldItalic ROTATE=90 SCALE="1.0 1.0" TRANSLATE="50 -120" MOON="false" LPR="lp" # here you should put whatever you need to direct the output to # a laser printer; or you can replace it with "cat" or use the # -t option if you want the the code to go to standard output. while test $# != 0 do case $1 in -m) MOON="true"; shift;; -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=`case $2 in Jan) echo 1;;Feb) echo 2;;Mar) echo 3;;Apr) echo 4;; May) echo 5;;Jun) echo 6;;Jul) echo 7;;Aug) echo 8;; Sep) echo 9;;Oct) echo 10;;Nov) echo 11;;Dec) echo 12;;esac`;; 1) MONTH=$1; set `date`; YEAR=$6;; 2) MONTH=$1 YEAR=$2;; esac if [ -n "$EFILE" -a -r "$EFILE" ] then Files=$EFILE elif [ -r Events ] then Files=Events elif [ -r $HOME/.holiday ] then Files=$HOME/.holiday else Files=/dev/null fi holidays=`cat $Files | grep \^$MONTH: | awk -F: '{printf("%s ( %s",$2,$3);\ for(i = 4; i <= NF; i++) printf(":%s", $i);printf(")\n"); }'` test $YEAR -lt 100 && YEAR=`expr $YEAR + 1900` $LPR $ENVAR <<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. % % 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 [ (January) (February) (March) (April) (May) (June) (July) (August) (September) (October) (November) (December) ] def /day_names [ (Sunday) (Monday) (Tuesday) (Wednesday) (Thursday) (Friday) (Saturday) ] def % layout parameters - you can change these, but things may not look nice /daywidth 100 def /dayheight 95 def /titlefontsize 48 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? /theyear exch def theyear 4 mod 0 eq % multiple of 4 theyear 100 mod 0 ne % not century theyear 400 mod 0 eq or and % unless it's divisible by 400 } def /ndays { % number of days in this month /themonth exch def /theyear exch def days_month themonth 1 sub get month 2 eq % February theyear 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 400 idiv add % number of extra weird days 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 year 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 % offset numevents day start add get -10 mul add numevents day start add numevents day start add get 1 add put add moveto % move DOWN appropriate amount isdouble { % go UP some if it's double and 30 or 31 { 0 dayheight numevents day 7 sub start add get 10 mul sub rmoveto ( /*) show } { ( */) show } % give a hint as to what day the event is on ifelse } if 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 % loads string 2 1 roll holidays 2 1 roll get % loads day 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 year month 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 year month 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 year month 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 year month 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 /doy { % year month day doy -> returns the number of the day /theday exch def % of the year /themonth exch def /theyear exch def /dayofyear 0 def themonth 1 ne { 1 1 themonth .5 sub { /mo exch cvi def /dayofyear theyear mo ndays dayofyear add def } for } if dayofyear theday add } def % doy /findphase { % find the difference between any day and the reference /thisday exch def % day of the full moon /thismonth exch def % will probably be one off if the reference is leap yr. /thisyear exch def /daysdiff thisyear thismonth thisday doy fullyear fullmonth fullday doy sub longer mul def % try to be accurate about it /yearsdiff thisyear fullyear sub def yearsdiff 0 ne { /daysdiff daysdiff yearsdiff daysperyear mul yearsdiff 100 idiv yearsdiff 400 idiv sub sub add def } if daysdiff % return difference in days } def % findphase /shrink { 2 sqrt div } def /transmogrify { 10000 mul cvi % take a real number and 'mod it down' period 10000 mul cvi % so it is in the range 0->period mod % or -period->0 10000 div } def % the 10000's preserve the accuracy /domoon { % draw the moon at the current phase /phase exch def 0 0 radius % might as well push these on now 0 0 radius phase halfperiod lt { 270 90 arc stroke % line on right, fill on left 0 radius neg moveto 270 90 arcn } { 90 270 arc stroke % line on left, fill on right 0 radius neg moveto 270 90 arc /phase phase halfperiod sub def % get rid of top halfperiod } ifelse /phase phase quartperiod sub % scale it down to -r(root2) -> r(root2) rect mul def phase % x1 phase abs shrink % y1 need abs! phase % x2 phase abs shrink neg % y2 need abs! 0 % x3 radius neg % y3 curveto fill } def % domoon /shiftdo { startphase day longer mul add transmogrify neg period add domoon } def /drawmoons { { /fullyear 1990 def % these are the dates of a full moon, /fullmonth 2 def % any date should work if it is that /fullday 9 def % of a full moon, but I haven't tried many % I wouldn't make this reference date fall in a leap year, wierdness % will probably happen in findphase. You will probably gain or lose a day % somewhere. MBH /period 29.5306 def /daysperyear 365.2422 def /longer daysperyear 365 div def /halfperiod period 2 div def /quartperiod period 4 div def /radius 13 def /rect radius 2 sqrt mul quartperiod div def /startphase year month 0 findphase transmogrify dup 0 lt { period add } if def /start startday def /days year month ndays def gsave 0.1 setlinewidth newpath daywidth radius sub 3 sub 15 translate start daywidth mul 0 translate 1 1 days { /day exch def isdouble { % true if 30,31 - false if 23,24 (left on the stack after isdouble) { gsave radius 2 div dayheight radius 2 div sub translate 0.5 0.5 scale shiftdo grestore } { gsave radius 2 div neg radius 2 div translate 0.5 0.5 scale shiftdo grestore } ifelse } { shiftdo } ifelse day start add 1 sub weekday 6 eq { daywidth 6 mul neg dayheight neg translate } { daywidth 0 translate } ifelse } for grestore } if % don't do anything if the argument is false } def % drawmoons % % Main Program % /eventflag true def $SCALE scale $ROTATE rotate $TRANSLATE translate /submonth 0 def calendar $MOON drawmoons /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 -- Jim Sanchez | jim@syteke.be (PREFERRED) Hughes LAN Systems | OR uunet!mcsun!ub4b!syteke!jim Brussels Belgium | OR {sun,hplabs}!sytek!syteke!jim
jwz@lucid.com (Jamie Zawinski) (11/16/90)
There was a much better version of this calendar program posted to alt.sources a while back; instead of being a shell script that produces PostScript, it is a C program. This gives it better command line processing, and MUCH better date file processing. This version is called "pcal" and is up to version 1.5 (last I heard.) So go scout out your local alt.sources archive, it's really a *lot* better. I believe Joe Brownlee <jbr@cblph.att.com> is its current keeper, though many hands have modified it. -- Jamie
minor@motcid.UUCP (Kevin E. Minor (+1 708 632 7043)) (11/16/90)
jwz@lucid.com (Jamie Zawinski) writes: |>There was a much better version of this calendar program posted to alt.sources |>a while back; instead of being a shell script that produces PostScript, it is |>a C program. This gives it better command line processing, and MUCH better |>date file processing. This version is called "pcal" and is up to version 1.5 |>(last I heard.) So go scout out your local alt.sources archive, it's really |>a *lot* better. I believe Joe Brownlee <jbr@cblph.att.com> is its current |>keeper, though many hands have modified it. Does anyone have the latest copy of this (pcal) that they could send me ? Or is at a mail server somewhere ? (I don't have access to alt.sources or ftp :-(.....) Thanks in advance, Kevin -- /-------------------------------------------------------\ | Kevin Minor ...uunet!motcid!minor | \-------------------------------------------------------/
smorton@uxh.cso.uiuc.edu (11/17/90)
> Written 4:30 pm Nov 15, 1990 by jwz@lucid.com > There was a much better version of this calendar program posted to alt.sources > a while back; instead of being a shell script that produces PostScript, it is > a C program. This gives it better command line processing, and MUCH better > date file processing. This version is called "pcal" and is up to version 1.5 > (last I heard.) I found the 2.1 version of pcal on an anonymous ftp server with the Internet address of hydra.helsinki.fi. It is in the directory pub/archives/alt.sources. Scott Morton (smorton@ncsa.uiuc.edu) PS. I found this source by using an extremely useful archive server called "ARCHIE: The McGill School of Computer Science Archive Server." To access it, telnet to quiche.cs.mcgill.ca and sign-on as archie. Note: no password is required. There is a brief on-line help which will get you started.