#!/usr/local/bin/a68g --script # PROC print calendar = (INT year, page width)VOID: ( []STRING month names = ( "January","February","March","April","May","June", "July","August","September","October","November","December"), weekday names = ("Su","Mo","Tu","We","Th","Fr","Sa"); FORMAT weekday fmt = $g,n(UPB weekday names - LWB weekday names)(" "g)$; # Juggle the calendar format to fit the printer/screen width # INT day width = UPB weekday names[1], day gap=1; INT month width = (day width+day gap) * UPB weekday names-1; INT month heading lines = 2; INT month lines = (31 OVER UPB weekday names+month heading lines+2); # +2 for head/tail weeks # INT year cols = (page width+1) OVER (month width+1); INT year rows = (UPB month names-1)OVER year cols + 1; INT month gap = (page width - year cols*month width + 1)OVER year cols; INT year width = year cols*(month width+month gap)-month gap; INT year lines = year rows*month lines; MODE MONTHBOX = [month lines, month width]CHAR; MODE YEARBOX = [year lines, year width]CHAR; INT week start = 1; # Sunday # PROC days in month = (INT year, month)INT: CASE month IN 31, IF year MOD 4 EQ 0 AND year MOD 100 NE 0 OR year MOD 400 EQ 0 THEN 29 ELSE 28 FI, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ESAC; PROC day of week = (INT year, month, day)INT: ( # Day of the week by Zeller’s Congruence algorithm from 1887 # INT y := year, m := month, d := day, c; IF m <= 2 THEN m +:= 12; y -:= 1 FI; c := y OVER 100; y %*:= 100; (d - 1 + ((m + 1) * 26) OVER 10 + y + y OVER 4 + c OVER 4 - 2 * c) MOD 7 ); MODE SIMPLEOUT = UNION(STRING, []STRING, INT); PROC cputf = (REF[]CHAR out, FORMAT fmt, SIMPLEOUT argv)VOID:( FILE f; STRING s; associate(f,s); putf(f, (fmt, argv)); out[:UPB s]:=s; close(f) ); PROC month repr = (INT year, month)MONTHBOX:( MONTHBOX month box; FOR line TO UPB month box DO month box[line,]:=" "* 2 UPB month box OD; STRING month name = month names[month]; # center the title # cputf(month box[1,(month width - UPB month name ) OVER 2+1:], $g$, month name); cputf(month box[2,], weekday fmt, weekday names); INT first day := day of week(year, month, 1); FOR day TO days in month(year, month) DO INT line = (day+first day-week start) OVER UPB weekday names + month heading lines + 1; INT char =((day+first day-week start) MOD UPB weekday names)*(day width+day gap) + 1; cputf(month box[line,char:char+day width-1],$g(-day width)$, day) OD; month box ); PROC year repr = (INT year)YEARBOX:( YEARBOX year box; FOR line TO UPB year box DO year box[line,]:=" "* 2 UPB year box OD; FOR month row FROM 0 TO year rows-1 DO FOR month col FROM 0 TO year cols-1 DO INT month = month row * year cols + month col + 1; IF month > UPB month names THEN done ELSE INT month col width = month width+month gap; year box[ month row*month lines+1 : (month row+1)*month lines, month col*month col width+1 : (month col+1)*month col width-month gap ] := month repr(year, month) FI OD OD; done: year box ); INT center = (year cols*(month width+month gap) - month gap - 1) OVER 2; INT indent = (page width - year width) OVER 2; printf(( $n(indent + center - 9)k g l$, "[Insert Snoopy here]", $n(indent + center - 1)k 4d l$, year, $l$, $n(indent)k n(year width)(g) l$, year repr(year) )) ); main: ( CO inspired by http://www.ee.ryerson.ca/~elf/hack/realmen.html Real Programmers Don't Use PASCAL - Ed Post Datamation, volume 29 number 7, July 1983 THE REAL PROGRAMMER'S NATURAL HABITAT "Taped to the wall is a line-printer Snoopy calender for the year 1969." CO INT mankind stepped on the moon = 1969, line printer width = 80; # as at 1969! # print calendar(mankind stepped on the moon, line printer width) )