Calendar - for "REAL" programmers

You are encouraged to You are encouraged to solve this task according to the task description, using any language you may know.

Task

Provide an algorithm as per the Calendar task, except the entire code for the algorithm must be presented entirely without lowercase.

Also - as per many 1969 era line printers - format the calendar to nicely fill a page that is 132 characters wide.

(Hint: manually convert the code from the Calendar task to all UPPERCASE)

This task also is inspired by Real Programmers Don't Use PASCAL by 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."

Moreover this task is further inspired by the long lost corollary article titled:

"Real programmers think in UPPERCASE"!

Note: Whereas today we only need to worry about ASCII, UTF-8, UTF-16, UTF-32, UTF-7 and UTF-EBCDIC encodings, in the 1960s having code in UPPERCASE was often mandatory as characters were often stuffed into 36-bit words as 6 lots of 6-bit characters. More extreme words sizes include 60-bit words of the CDC 6000 series computers. The Soviets even had a national character set that was inclusive of all 4-bit, 5-bit, 6-bit & 7-bit depending on how the file was opened... And one rogue Soviet university went further and built a 1.5-bit based computer.

Of course... as us Boomers have turned into Geezers we have become HARD OF HEARING, and suffer from chronic Presbyopia, hence programming in UPPERCASE is less to do with computer architecture and more to do with practically. :-)

For economy of size, do not actually include Snoopy generation in either the code or the output, instead just output a place-holder.

FYI: a nice ASCII art file of Snoopy can be found at textfiles.com. Save with a .txt extension.

Trivia: The terms uppercase and lowercase date back to the early days of the mechanical printing press. Individual metal alloy casts of each needed letter, or punctuation symbol, were meticulously added to a press block, by hand, before rolling out copies of a page. These metal casts were stored and organized in wooden cases. The more often needed minuscule letters were placed closer to hand, in the lower cases of the work bench. The less often needed, capitalized, majuscule letters, ended up in the harder to reach upper cases.





This is for real programmers who code only in assembler :). The code could have been run in april 1964, punched on 80-column cards, read on a card reader, and printed with a 132-column line printer on fan-folded paper with perforated edges.

* CALENDAR FOR REAL PROGRAMMERS 05/03/2017

CALENDAR CSECT

USING CALENDAR,R13 BASE REGISTER

B 72(R15) SKIP MY SAVEAREA

DC 17F'0' MY SAVEAREA

STM R14,R12,12(R13) SAVE CALLER'S REGISTERS

ST R13,4(R15) LINK BACKWARD

ST R15,8(R13) LINK FORWARD

LR R13,R15 SET ADDRESSABILITY

L R4,YEAR YEAR

SRDA R4,32 .

D R4,=F'4' YEAR//4

LTR R4,R4 IF YEAR//4=0

BNZ LYNOT

L R4,YEAR YEAR

SRDA R4,32 .

D R4,=F'100' YEAR//100

LTR R4,R4 IF YEAR//100=0

BNZ LY

L R4,YEAR YEAR

SRDA R4,32 .

D R4,=F'400' IF YEAR//400

LTR R4,R4 IF YEAR//400=0

BNZ LYNOT

LY MVC ML+2,=H'29' ML(2)=29 LEAPYEAR

LYNOT SR R10,R10 LTD1=0

LA R6,1 I=1

LOOPI1 C R6,=F'31' DO I=1 TO 31

BH ELOOPI1

XDECO R6,XDEC EDIT I

LA R14,TD1 TD1

AR R14,R10 TD1+LTD1

MVC 0(3,R14),XDEC+9 SUB(TD1,LTD1+1,3)=PIC(I,3)

LA R10,3(R10) LTD1+3

LA R6,1(R6) I=I+1

B LOOPI1

ELOOPI1 LA R6,1 I=1

LOOPI2 C R6,=F'12' DO I=1 TO 12

BH ELOOPI2

ST R6,M M=I

MVC D,=F'1' D=1

MVC YY,YEAR YY=YEAR

L R4,M M

C R4,=F'3' IF M<3

BNL GE3

L R2,M M

LA R2,12(R2) M+12

ST R2,M M=M+12

L R2,YY YY

BCTR R2,0 YY-1

ST R2,YY YY=YY-1

GE3 L R2,YY YY

LR R1,R2 YY

SRA R1,2 YY/4

AR R2,R1 YY+(YY/4)

L R4,YY YY

SRDA R4,32 .

D R4,=F'100' YY/100

SR R2,R5 YY+(YY/4)-(YY/100)

L R4,YY YY

SRDA R4,32 .

D R4,=F'400' YY/400

AR R2,R5 YY+(YY/4)-(YY/100)+(YY/400)

A R2,D R2=YY+(YY/4)-(YY/100)+(YY/400)+D

LA R5,153 153

M R4,M 153*M

LA R5,8(R5) 153*M+8

D R4,=F'5' (153*M+8)/5

AR R5,R2 ((153*M+8)/5+R2

LA R4,0 .

D R4,=F'7' R4=MOD(R5,7) 0=SUN 1=MON ... 6=SAT

LTR R4,R4 IF J=0

BNZ JNE0

LA R4,7 J=7

JNE0 BCTR R4,0 J-1

MH R4,=H'3' J*3

LR R10,R4 J1=J*3

LR R1,R6 I

SLA R1,1 *2

LH R11,ML-2(R1) ML(I)

MH R11,=H'3' J2=ML(I)*3

MVC TD2,BLANK TD2=' '

LA R4,TD1 @TD1

LR R5,R11 J2

LA R2,TD2 @TD2

AR R2,R10 @TD2+J1

LR R3,R5 J2

MVCL R2,R4 SUB(TD2,J1+1,J2)=SUB(TD1,1,J2)

LR R1,R6 I

MH R1,=H'144' *144

LA R14,DA-144(R1) @DA(I)

MVC 0(144,R14),TD2 DA(I)=TD2

LA R6,1(R6) I=I+1

B LOOPI2

ELOOPI2 XPRNT SNOOPY,132 PRINT SNOOPY

L R1,YEAR YEAR

XDECO R1,PG+56 EDIT YEAR

XPRNT PG,L'PG PRINT YEAR

MVC WDLINE,BLANK WDLINE=' '

LA R10,1 LWDLINE=1

LA R8,1 K=1

LOOPK3 C R8,=F'6' DO K=1 TO 6

BH ELOOPK3

LA R4,WDLINE @WDLINE

AR R4,R10 +LWDLINE

MVC 0(20,R4),WDNA SUB(WDLINE,LWDLINE+1,20)=WDNA

LA R10,20(R10) LWDLINE=LWDLINE+20

C R8,=F'6' IF K<6

BNL ITERK3

LA R10,2(R10) LWDLINE=LWDLINE+2

ITERK3 LA R8,1(R8) K=K+1

B LOOPK3

ELOOPK3 LA R6,1 I=1

LOOPI4 C R6,=F'12' DO I=1 TO 12 BY 6

BH ELOOPI4

MVC MOLINE,BLANK MOLINE=' '

LA R10,6 LMOLINE=6

LR R8,R6 K=I

LOOPK4 LA R2,5(R6) I+5

CR R8,R2 DO K=I TO I+5

BH ELOOPK4

LR R1,R8 K

MH R1,=H'10' *10

LA R3,MO-10(R1) MO(K)

LA R4,MOLINE @MOLINE

AR R4,R10 +LMOLINE

MVC 0(10,R4),0(R3) SUB(MOLINE,LMOLINE+1,10)=MO(K)

LA R10,22(R10) LMOLINE=LMOLINE+22

LA R8,1(R8) K=K+1

B LOOPK4

ELOOPK4 XPRNT MOLINE,L'MOLINE PRINT MONTHS

XPRNT WDLINE,L'WDLINE PRINT DAYS OF WEEK

LA R7,1 J=1

LOOPJ4 C R7,=F'106' DO J=1 TO 106 BY 21

BH ELOOPJ4

MVC PG,BLANK CLEAR BUFFER

LA R9,PG PGI=0

LR R8,R6 K=I

LOOPK5 LA R2,5(R6) I+5

CR R8,R2 DO K=I TO I+5

BH ELOOPK5

LR R1,R8 K

MH R1,=H'144' *144

LA R4,DA-144(R1) DA(K)

BCTR R4,0 -1

AR R4,R7 +J

MVC 0(21,R9),0(R4) SUBSTR(DA(K),J,21)

LA R9,22(R9) PGI=PGI+22

LA R8,1(R8) K=K+1

B LOOPK5

ELOOPK5 XPRNT PG,L'PG PRINT BUFFER

LA R7,21(R7) J=J+21

B LOOPJ4

ELOOPJ4 LA R6,6(R6) I=I+6

B LOOPI4

ELOOPI4 L R13,4(0,R13) RESTORE PREVIOUS SAVEAREA POINTER

LM R14,R12,12(R13) RESTORE CALLER'S REGISTERS

XR R15,R15 SET RETURN CODE TO 0

BR R14 RETURN TO CALLER

SNOOPY DC CL57' ',CL18'INSERT SNOOPY HERE',CL57' '

YEAR DC F'1969' <== 1969

MO DC CL10' JANUARY ',CL10' FEBRUARY ',CL10' MARCH '

DC CL10' APRIL ',CL10' MAY ',CL10' JUNE '

DC CL10' JULY ',CL10' AUGUST ',CL10'SEPTEMBER '

DC CL10' OCTOBER ',CL10' NOVEMBER ',CL10' DECEMBER '

ML DC H'31',H'28',H'31',H'30',H'31',H'30'

DC H'31',H'31',H'30',H'31',H'30',H'31'

WDNA DC CL20'MO TU WE TH FR SA SU'

M DS F

D DS F

YY DS F

TD1 DS CL93

TD2 DS CL144

MOLINE DS CL132

WDLINE DS CL132

PG DC CL132' ' BUFFER FOR THE LINE PRINTER

XDEC DS CL12

BLANK DC CL144' '

DA DS 12CL144

YREGS

END CALENDAR

Output:

INSERT SNOOPY HERE 1969 JANUARY FEBRUARY MARCH APRIL MAY JUNE MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 1 2 1 2 1 2 3 4 5 6 1 2 3 4 1 6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 31 30 JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 1 2 1 2 3 4 5 6 7 7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14 14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21 21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28 28 29 30 31 25 26 27 28 29 30 31 29 30 27 28 29 30 31 24 25 26 27 28 29 30 29 30 31

In Ada, the task is really easy, because Ada is case insensitive. I.e., one could simply replicate the code from Ada solution of the calendar task and convert every lowercase character to uppercase. Instead of doing that, the implementation below reuses the package "PRINTABLE_CALENDAR" (same as "Printable_Calendar" or "printable_calendar") from the calendar task:

WITH PRINTABLE_CALENDAR;



PROCEDURE REAL_CAL IS



C: PRINTABLE_CALENDAR. CALENDAR := PRINTABLE_CALENDAR. INIT_132

( ( WEEKDAY_REP =>

"MO TU WE TH FR SA SO" ,

MONTH_REP =>

( " JANUARY " , " FEBRUARY " ,

" MARCH " , " APRIL " ,

" MAY " , " JUNE " ,

" JULY " , " AUGUST " ,

" SEPTEMBER " , " OCTOBER " ,

" NOVEMBER " , " DECEMBER " )

) ) ;



BEGIN

C. PRINT_LINE_CENTERED ( "[SNOOPY]" ) ;

C. NEW_LINE ;

C. PRINT ( 1969 , "NINETEEN-SIXTY-NINE" ) ;

END REAL_CAL;

Output:

[SNOOPY] NINETEEN-SIXTY-NINE JANUARY FEBRUARY MARCH APRIL MAY JUNE MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO 1 2 3 4 5 1 2 1 2 1 2 3 4 5 6 1 2 3 4 1 6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 31 30 JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO 1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 1 2 1 2 3 4 5 6 7 7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14 14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21 21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28 28 29 30 31 25 26 27 28 29 30 31 29 30 27 28 29 30 31 24 25 26 27 28 29 30 29 30 31

To change the output to 80-character devices, replace "INIT_132" by "INIT_80".

Works with: ALGOL 68 version Revision 1 - no extensions to language used

This code uses 'quote stropping' to mark reserved words, it is a very early form of wikitext and makes syntax highlighting of source code for publication relatively easy.

Note: to run this code with ALGOL 68G you need to use the --quote-stropping option.

' PR' QUOTE 'PR '



' PROC ' PRINT CALENDAR = ( ' INT ' YEAR , PAGE WIDTH ) ' VOID ' : ' BEGIN '



( ) ' 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 ' : ' BEGIN '

# '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 ' MODAB ' 100 ;

( D - 1 + ( ( M + 1 ) * 26 ) ' OVER ' 10 + Y + Y ' OVER ' 4 + C ' OVER ' 4 - 2 * C ) ' MOD ' 7

' END ' ;



' MODE ' 'SIMPLEOUT' = ' UNION ' ( ' STRING ' , ( ) ' STRING ' , ' INT ' ) ;



' PROC ' CPUTF = ( ' REF ' ( ) ' CHAR ' OUT , ' FORMAT ' FMT , 'SIMPLEOUT' ARGV ) ' VOID ' : ' BEGIN '

' FILE ' F ; ' STRING ' S ; ASSOCIATE ( F , S ) ;

PUTF ( F , ( FMT , ARGV ) ) ;

OUT ( : ' UPB ' S ) := S ;

CLOSE ( F )

' END ' ;



' PROC ' MONTH REPR = ( ' INT ' YEAR , MONTH ) 'MONTHBOX' : ' BEGIN '

'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

' END ' ;



' PROC ' YEAR REPR = ( ' INT ' YEAR ) 'YEARBOX' : ' BEGIN '

'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

' END ' ;



' 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 )

) )

' END ' ;



MAIN : ' BEGIN '

'CO' INSPIRED BY HTTP :// WWW.EE.RYERSON.CA /~ ELF / hack / realmen.html

REAL PROGRAMMERS DONT USE PASCAL - ED POST

DATAMATION , VOLUME 29 NUMBER 7 , JULY 1983

THE REAL PROGRAMMERS 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 = 132 ; # AS AT 1969! #

PRINT CALENDAR ( MANKIND STEPPED ON THE MOON , LINE PRINTER WIDTH )

' END '

Output:

(INSERT SNOOPY HERE) 1969 JANUARY FEBRUARY MARCH APRIL MAY JUNE SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 1 1 1 2 3 4 5 1 2 3 1 2 3 4 5 6 7 5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14 12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21 19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28 26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31 29 30 30 31 JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 5 1 2 1 2 3 4 5 6 1 2 3 4 1 1 2 3 4 5 6 6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13 13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20 20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27 27 28 29 30 31 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31 31 30

CALENDAR ( YR ) {

LASTDAY := [ ] , DAY := [ ]

TITLES =

( LTRIM

______JANUARY_________________FEBRUARY_________________MARCH_______

_______APRIL____________________MAY____________________JUNE________

________JULY___________________AUGUST_________________SEPTEMBER_____

______OCTOBER_________________NOVEMBER________________DECEMBER______

)

STRINGSPLIT , TITLE , TITLES , % CHR ( 10 )

RES := "________________________________" YR CHR ( 13 ) CHR ( 10 )



LOOP 4 { ; 4 VERTICAL SECTIONS

DAY [ 1 ] := YR SUBSTR ( "0" A_INDEX * 3 - 2 , - 1 ) 01

DAY [ 2 ] := YR SUBSTR ( "0" A_INDEX * 3 - 1 , - 1 ) 01

DAY [ 3 ] := YR SUBSTR ( "0" A_INDEX * 3 , - 1 ) 01

RES .= CHR ( 13 ) CHR ( 10 ) TITLE %A_INDEX% CHR ( 13 ) CHR ( 10 ) "SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA"

LOOP , 6 { ; 6 WEEKS MAX PER MONTH

WEEK := A_INDEX , RES .= CHR ( 13 ) CHR ( 10 )

LOOP , 21 { ; 3 WEEKS TIMES 7 DAYS

MON := CEIL ( A_INDEX / 7 ) , THISWD := MOD ( A_INDEX - 1 , 7 ) + 1

FORMATTIME , WD , % DAY [ MON ] , WDAY

;~ MSGBOX % WD

FORMATTIME , DD , % DAY [ MON ] , % CHR ( 100 ) CHR ( 100 )

IF ( WD > THISWD ) {

RES .= "__ "

CONTINUE

}

DD := ( ( WEEK > 3 ) && DD < 10 ) ? "__" : DD , RES .= DD " " , LASTDAY [ MON ] := DAY [ MON ] , DAY [ MON ] += 1 , D

RES .= ( ( WD = 7 ) && A_INDEX < 21 ) ? "___" : ""

FORMATTIME , DD , % DAY [ MON ] , % CHR ( 100 ) CHR ( 100 )

}

}

RES .= CHR ( 13 ) CHR ( 10 )

}

STRINGREPLACE , RES , RES , _ , %A_SPACE% , ALL

STRINGREPLACE , RES , RES , %A_SPACE% 0 , %A_SPACE% %A_SPACE% , ALL

RETURN RES

}

EXAMPLES:

GUI , FONT , S8 , COURIER

GUI , ADD , EDIT , VYR W40 R1 LIMIT4 NUMBER , 1969

GUI , ADD , EDIT , VEDIT2 W580 R38

GUI , ADD , BUTTON , DEFAULT HIDDEN GSUBMIT

GUI , SHOW



SUBMIT :

GUI , SUBMIT , NOHIDE

GUICONTROL ,, EDIT2 , % CALENDAR ( YR )

RETURN



GUIESCAPE :

GUICLOSE :

EXITAPP

RETURN

Output:

1969 JANUARY FEBRUARY MARCH SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 1 1 05 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 30 31 APRIL MAY JUNE SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 5 1 2 3 1 2 3 4 5 6 7 06 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14 13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21 20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28 27 28 29 30 25 26 27 28 29 30 31 29 30 JULY AUGUST SEPTEMBER SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 5 1 2 1 2 3 4 5 6 06 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13 13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20 20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27 27 28 29 30 31 24 25 26 27 28 29 30 28 29 30 31 OCTOBER NOVEMBER DECEMBER SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 1 1 2 3 4 5 6 05 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31 30

Examples:

Choosing 132 character output. Same as the "Calendar" from the calendar task but using all capitals:

DECLARE MON$ [ ] = { "JANUARY" , "FEBRUARY" , "MARCH" , "APRIL" , "MAY" , "JUNE" , "JULY" , "AUGUST" , "SEPTEMBER" , "OCTOBER" , "NOVEMBER" , "DECEMBER" }

DECLARE MON [ ] = { 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 }

Y$ = "1969"

' Leap year

INCR MON [ 1 ] , IIF ( MOD ( VAL ( Y$ ) , 4 ) = 0 OR MOD ( VAL ( Y$ ) , 100 ) = 0 AND MOD ( VAL ( Y$ ) , 400 ) <> 0 , 1 , 0 )

PRINT ALIGN$ ( "[SNOOPY HERE]" , 132 , 2 )

PRINT ALIGN$ ( Y$, 132 , 2 )

FOR NR = 0 TO 11

ROW = 3

GOTOXY 1 + ( NR %6 ) * 22 , ROW+ ( NR/ 6 ) * 9

PRINT ALIGN$ ( MON$ [ NR ] , 21 , 2 ) ;

INCR ROW

GOTOXY 1 + ( NR %6 ) * 22 , ROW+ ( NR/ 6 ) * 9

PRINT ALIGN$ ( "MO TU WE TH FR SA SU" , 21 , 2 ) ;

INCR ROW

' Each day

FOR D = 1 TO MON [ NR ]

' Zeller

J = VAL ( LEFT $ ( Y$, 2 ) )

K = VAL ( MID $ ( Y$, 3 , 2 ) )

M = NR+ 1

IF NR < 2 THEN

INCR M, 12

DECR K

END IF

H = ( D + ( ( M+ 1 ) * 26 ) / 10 + K + ( K/ 4 ) + ( J/ 4 ) + 5 *J )

DAYNR = MOD ( H, 7 ) - 2

IF DAYNR < 0 THEN INCR DAYNR, 7

IF DAYNR = 0 AND D > 1 THEN INCR ROW

GOTOXY 1 + ( NR %6 ) * 22 +DAYNR* 3 , ROW+ ( NR/ 6 ) * 9

PRINT D;

NEXT

NEXT

Output:

[SNOOPY HERE] 1969 JANUARY FEBRUARY MARCH APRIL MAY JUNE MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 1 2 1 2 1 2 3 4 5 6 1 2 3 4 1 6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 31 30 JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 1 2 1 2 3 4 5 6 7 7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14 14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21 21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28 28 29 30 31 25 26 27 28 29 30 31 29 30 27 28 29 30 31 24 25 26 27 28 29 30 29 30 31

Works with: BBC BASIC for Windows

VDU 23,22,1056;336;8,16,16,128



YEAR = 1969

PRINT TAB(62) "[SNOOPY]" TAB(64); YEAR

DIM DOM(5), MJD(5), DM(5), MONTH$(11)

DAYS$ = "SU MO TU WE TH FR SA"

MONTH$() = "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", \

\ "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"



FOR MONTH = 1 TO 7 STEP 6

PRINT

FOR COL = 0 TO 5

MJD(COL) = FNMJD(1, MONTH + COL, YEAR)

MONTH$ = MONTH$(MONTH + COL - 1)

PRINT TAB(COL*22 + 11 - LEN(MONTH$)/2) MONTH$;

NEXT

FOR COL = 0 TO 5

PRINT TAB(COL*22 + 1) DAYS$;

DM(COL) = FNDIM(MONTH + COL, YEAR)

NEXT

DOM() = 1

COL = 0

REPEAT

DOW = FNDOW(MJD(COL))

IF DOM(COL)<=DM(COL) THEN

PRINT TAB(COL*22 + DOW*3 + 1); DOM(COL);

DOM(COL) += 1

MJD(COL) += 1

ENDIF

IF DOW=6 OR DOM(COL)>DM(COL) COL = (COL + 1) MOD 6

UNTIL DOM(0)>DM(0) AND DOM(1)>DM(1) AND DOM(2)>DM(2) AND \

\ DOM(3)>DM(3) AND DOM(4)>DM(4) AND DOM(5)>DM(5)

PRINT

NEXT

END



DEF FNMJD(D%,M%,Y%) : M% -= 3 : IF M% < 0 M% += 12 : Y% -= 1

= D% + (153*M%+2)DIV5 + Y%*365 + Y%DIV4 - Y%DIV100 + Y%DIV400 - 678882



DEF FNDOW(J%) = (J%+2400002) MOD 7



DEF FNDIM(M%,Y%)

CASE M% OF

WHEN 2: = 28 - (Y%MOD4=0) + (Y%MOD100=0) - (Y%MOD400=0)

WHEN 4,6,9,11: = 30

OTHERWISE = 31

ENDCASE

Output:

[SNOOPY] 1969 JANUARY FEBRUARY MARCH APRIL MAY JUNE SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 1 1 1 2 3 4 5 1 2 3 1 2 3 4 5 6 7 5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14 12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21 19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28 26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31 29 30 30 31 JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 5 1 2 1 2 3 4 5 6 1 2 3 4 1 1 2 3 4 5 6 6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13 13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20 20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27 27 28 29 30 31 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31 31 30





Note: Historically, some UNIX systems were connected to upper-case only terminals, and users of those systems needed to write C programs. One could configure the terminal using the "stty" command, setting the olcuc and iuclc options to translate uppercase to lowercase on input, and convert lowercase to uppercase on output (although typically the setting was applied by the "getty" program so that logging in would be possible).

So the text that was actually saved in the C source code would be lowercase, but it would appear on the terminal as uppercase.

This would also apply to any other language source or document.



Modern versions of Linux and MacOS have preserved this feature.



However, the following is an actual upper-case only version of the C Calendar task. It relies on the ability of most C compilers to allow #defines to be specified on the command line and also declares the putchar function to avoid needing any #includes (neither #define nor #include could be specified in upper-case without a non-standard pre-processor).

The program can be compiled with the following (substitute the name of your compiler for tcc):

tcc -DSTRUCT=struct -DCONST=const -DINT=int -DCHAR=char -DVOID=void -DMAIN=main -DIF=if -DELSE=else -DWHILE=while -DFOR=for -DDO=do -DBREAK=break -DRETURN=return -DPUTCHAR=putchar UCCALENDAR.c

/* UPPER CASE ONLY VERSION OF THE ORIGINAL CALENDAR.C, CHANGES MOSTLY TO AVOID NEEDING #INCLUDES */

/* ERROR MESSAGES GO TO STDOUT TO SLIGHTLY SIMPLIFY THE I/O HANDLING */

/* WHEN COMPILING THIS, THE COMMAND LINE SHOULD SPECIFY -D OPTIONS FOR THE FOLLOWING WORDS: */

/* STRUCT, VOID, INT, CHAR, CONST, MAIN, IF, ELSE, WHILE, FOR, DO, BREAK, RETURN, PUTCHAR */

/* THE VALUE OF EACH MACRO SHOULD BE THE WORD IN LOWER-CASE */



INT PUTCHAR ( INT ) ;



INT WIDTH = 80 , YEAR = 1969 ;

INT COLS , LEAD , GAP ;



CONST CHAR * WDAYS [ ] = { "SU" , "MO" , "TU" , "WE" , "TH" , "FR" , "SA" } ;

STRUCT MONTHS {

CONST CHAR * NAME ;

INT DAYS , START_WDAY , AT ;

} MONTHS [ 12 ] = {

{ "JANUARY" , 31 , 0 , 0 } ,

{ "FEBRUARY" , 28 , 0 , 0 } ,

{ "MARCH" , 31 , 0 , 0 } ,

{ "APRIL" , 30 , 0 , 0 } ,

{ "MAY" , 31 , 0 , 0 } ,

{ "JUNE" , 30 , 0 , 0 } ,

{ "JULY" , 31 , 0 , 0 } ,

{ "AUGUST" , 31 , 0 , 0 } ,

{ "SEPTEMBER" , 30 , 0 , 0 } ,

{ "OCTOBER" , 31 , 0 , 0 } ,

{ "NOVEMBER" , 30 , 0 , 0 } ,

{ "DECEMBER" , 31 , 0 , 0 }

} ;



VOID SPACE ( INT N ) { WHILE ( N -- > 0 ) PUTCHAR ( ' ' ) ; }

VOID PRINT ( CONST CHAR * S ) { WHILE ( * S != ' \0 ' ) { PUTCHAR ( * S ++ ) ; } }

INT STRLEN ( CONST CHAR * S )

{

INT L = 0 ;

WHILE ( * S ++ != ' \0 ' ) { L ++; } ;

RETURN L ;

}

INT ATOI ( CONST CHAR * S )

{

INT I = 0 ;

INT SIGN = 1 ;

CHAR C ;

WHILE ( ( C = * S ++ ) != ' \0 ' ) {

IF ( C == '-' )

SIGN *= - 1 ;

ELSE {

I *= 10 ;

I += ( C - '0' ) ;

}

}

RETURN I * SIGN ;

}



VOID INIT_MONTHS ( VOID )

{

INT I ;



IF ( ( ! ( YEAR % 4 ) && ( YEAR % 100 ) ) || ! ( YEAR % 400 ) )

MONTHS [ 1 ] . DAYS = 29 ;



YEAR --;

MONTHS [ 0 ] . START_WDAY

= ( YEAR * 365 + YEAR / 4 - YEAR / 100 + YEAR / 400 + 1 ) % 7 ;



FOR ( I = 1 ; I < 12 ; I ++ )

MONTHS [ I ] . START_WDAY =

( MONTHS [ I - 1 ] . START_WDAY + MONTHS [ I - 1 ] . DAYS ) % 7 ;



COLS = ( WIDTH + 2 ) / 22 ;

WHILE ( 12 % COLS ) COLS --;

GAP = COLS - 1 ? ( WIDTH - 20 * COLS ) / ( COLS - 1 ) : 0 ;

IF ( GAP > 4 ) GAP = 4 ;

LEAD = ( WIDTH - ( 20 + GAP ) * COLS + GAP + 1 ) / 2 ;

YEAR ++;

}



VOID PRINT_ROW ( INT ROW )

{

INT C , I , FROM = ROW * COLS , TO = FROM + COLS ;

SPACE ( LEAD ) ;

FOR ( C = FROM ; C < TO ; C ++ ) {

I = STRLEN ( MONTHS [ C ] . NAME ) ;

SPACE ( ( 20 - I ) / 2 ) ;

PRINT ( MONTHS [ C ] . NAME ) ;

SPACE ( 20 - I - ( 20 - I ) / 2 + ( ( C == TO - 1 ) ? 0 : GAP ) ) ;

}

PUTCHAR ( ' \012 ' ) ;



SPACE ( LEAD ) ;

FOR ( C = FROM ; C < TO ; C ++ ) {

FOR ( I = 0 ; I < 7 ; I ++ ) {

PRINT ( WDAYS [ I ] ) ;

PRINT ( I == 6 ? "" : " " ) ;

}

IF ( C < TO - 1 ) SPACE ( GAP ) ;

ELSE PUTCHAR ( ' \012 ' ) ;

}



WHILE ( 1 ) {

FOR ( C = FROM ; C < TO ; C ++ )

IF ( MONTHS [ C ] . AT < MONTHS [ C ] . DAYS ) BREAK ;

IF ( C == TO ) BREAK ;



SPACE ( LEAD ) ;

FOR ( C = FROM ; C < TO ; C ++ ) {

FOR ( I = 0 ; I < MONTHS [ C ] . START_WDAY ; I ++ ) SPACE ( 3 ) ;

WHILE ( I ++ < 7 && MONTHS [ C ] . AT < MONTHS [ C ] . DAYS ) {

INT MM = ++ MONTHS [ C ] . AT ;

PUTCHAR ( ( MM < 10 ) ? ' ' : '0' + ( MM / 10 ) ) ;

PUTCHAR ( '0' + ( MM % 10 ) ) ;

IF ( I < 7 || C < TO - 1 ) PUTCHAR ( ' ' ) ;

}

WHILE ( I ++ <= 7 && C < TO - 1 ) SPACE ( 3 ) ;

IF ( C < TO - 1 ) SPACE ( GAP - 1 ) ;

MONTHS [ C ] . START_WDAY = 0 ;

}

PUTCHAR ( ' \012 ' ) ;

}

PUTCHAR ( ' \012 ' ) ;

}



VOID PRINT_YEAR ( VOID )

{

INT Y = YEAR ;

INT ROW ;

CHAR BUF [ 32 ] ;

CHAR * B = & ( BUF [ 31 ] ) ;

* B -- = ' \0 ' ;

DO {

* B -- = '0' + ( Y % 10 ) ;

Y /= 10 ;

} WHILE ( Y > 0 ) ;

B ++;

SPACE ( ( WIDTH - STRLEN ( B ) ) / 2 ) ;

PRINT ( B ) ; PUTCHAR ( ' \012 ' ) ; PUTCHAR ( ' \012 ' ) ;

FOR ( ROW = 0 ; ROW * COLS < 12 ; ROW ++ )

PRINT_ROW ( ROW ) ;

}



INT MAIN ( INT C , CHAR ** V )

{

INT I , YEAR_SET = 0 , RESULT = 0 ;

FOR ( I = 1 ; I < C && RESULT == 0 ; I ++ ) {

IF ( V [ I ] [ 0 ] == '-' && V [ I ] [ 1 ] == 'W' && V [ I ] [ 2 ] == ' \0 ' ) {

IF ( ++ I == C || ( WIDTH = ATOI ( V [ I ] ) ) < 20 )

RESULT = 1 ;

} ELSE IF ( ! YEAR_SET ) {

YEAR = ATOI ( V [ I ] ) ;

IF ( YEAR <= 0 )

YEAR = 1969 ;

YEAR_SET = 1 ;

} ELSE

RESULT = 1 ;

}



IF ( RESULT == 0 ) {

INIT_MONTHS ( ) ;

PRINT_YEAR ( ) ;

} ELSE {

PRINT ( "BAD ARGS \012 USAGE: " ) ;

PRINT ( V [ 0 ] ) ;

PRINT ( " YEAR [-W WIDTH (>= 20)] \012 " ) ;

}

RETURN RESULT ;

}

Although it seems to be missing the pinup of Snoopy, see COBOL Calendar task entry where the code, and output, is already an example of a "REAL programmer" calendar; even down to the 6 character, all uppercase, program name CALEND.

( QL : QUICKLOAD ' ( DATE-CALC ) )



( DEFPARAMETER *DAY-ROW* "SU MO TU WE TH FR SA" )

( DEFPARAMETER *CALENDAR-MARGIN* 3 )



( DEFUN MONTH-TO-WORD ( MONTH )

"TRANSLATE A MONTH FROM 1 TO 12 INTO ITS WORD REPRESENTATION."

( SVREF # ( "JANUARY" "FEBRUARY" "MARCH" "APRIL"

"MAY" "JUNE" "JULY" "AUGUST"

"SEPTEMBER" "OCTOBER" "NOVEMBER" "DECEMBER" )

( 1 - MONTH ) ) )



( DEFUN MONTH-STRINGS ( YEAR MONTH )

"COLLECT ALL OF THE STRINGS THAT MAKE UP A CALENDAR FOR A GIVEN

MONTH AND YEAR."

` ( , ( DATE-CALC : CENTER ( MONTH-TO-WORD MONTH ) ( LENGTH *DAY-ROW* ) )

, *DAY-ROW*

;; WE CAN ASSUME THAT A MONTH CALENDAR WILL ALWAYS FIT INTO A 7 BY 6 BLOCK

;; OF VALUES. THIS MAKES IT EASY TO FORMAT THE RESULTING STRINGS.

, @ ( LET ( ( DAYS ( MAKE- ARRAY ( * 7 6 ) : INITIAL-ELEMENT NIL ) ) )

( LOOP : FOR I : FROM ( DATE-CALC : DAY-OF-WEEK YEAR MONTH 1 )

: FOR DAY : FROM 1 : TO ( DATE-CALC : DAYS-IN-MONTH YEAR MONTH )

: DO ( SETF ( AREF DAYS I ) DAY ) )

( LOOP : FOR I : FROM 0 : TO 5

: COLLECT

( FORMAT NIL "~{~:[ ~;~2,D~]~^ ~}"

( LOOP : FOR DAY : ACROSS ( SUBSEQ DAYS ( * I 7 ) ( + 7 ( * I 7 ) ) )

: APPEND ( IF DAY ( LIST DAY DAY ) ( LIST DAY ) ) ) ) ) ) ) )



( DEFUN CALC-COLUMNS ( CHARACTERS MARGIN-SIZE )

"CALCULATE THE NUMBER OF COLUMNS GIVEN THE NUMBER OF CHARACTERS PER

COLUMN AND THE MARGIN-SIZE BETWEEN THEM."

( MULTIPLE-VALUE-BIND ( COLS EXCESS )

( TRUNCATE CHARACTERS ( + MARGIN-SIZE ( LENGTH *DAY-ROW* ) ) )

( INCF EXCESS MARGIN-SIZE )

( IF ( >= EXCESS ( LENGTH *DAY-ROW* ) )

( 1 + COLS )

COLS ) ) )



( DEFUN TAKE ( N LIST )

"TAKE THE FIRST N ELEMENTS OF A LIST."

( LOOP : REPEAT N : FOR X : IN LIST : COLLECT X ) )



( DEFUN DROP ( N LIST )

"DROP THE FIRST N ELEMENTS OF A LIST."

( COND ( ( OR ( <= N 0 ) ( NULL LIST ) ) LIST )

( T ( DROP ( 1 - N ) ( CDR LIST ) ) ) ) )



( DEFUN CHUNKS-OF ( N LIST )

"SPLIT THE LIST INTO CHUNKS OF SIZE N."

( ASSERT ( > N 0 ) )

( LOOP : FOR X := LIST : THEN ( DROP N X )

: WHILE X

: COLLECT ( TAKE N X ) ) )



( DEFUN PRINT-CALENDAR ( YEAR & KEY ( CHARACTERS 80 ) ( MARGIN-SIZE 3 ) )

"PRINT OUT THE CALENDAR FOR A GIVEN YEAR, OPTIONALLY SPECIFYING

A WIDTH LIMIT IN CHARACTERS AND MARGIN-SIZE BETWEEN MONTHS."

( ASSERT ( >= CHARACTERS ( LENGTH *DAY-ROW* ) ) )

( ASSERT ( >= MARGIN-SIZE 0 ) )

( LET * ( ( CALENDARS ( LOOP : FOR MONTH : FROM 1 : TO 12

: COLLECT ( MONTH-STRINGS YEAR MONTH ) ) )

( COLUMN-COUNT ( CALC-COLUMNS CHARACTERS MARGIN-SIZE ) )

( TOTAL-SIZE ( + ( * COLUMN-COUNT ( LENGTH *DAY-ROW* ) )

( * ( 1 - COLUMN-COUNT ) MARGIN-SIZE ) ) )

( FORMAT-STRING ( CONCATENATE 'STRING

"~{~A~^~" ( WRITE-TO-STRING MARGIN-SIZE ) ", [email protected] ~}~%" ) ) )

( FORMAT T "~A~%~A~%~%"

( DATE-CALC : CENTER "[SNOOPY]" TOTAL-SIZE )

( DATE-CALC : CENTER ( WRITE-TO-STRING YEAR ) TOTAL-SIZE ) )

( LOOP : FOR ROW : IN ( CHUNKS-OF COLUMN-COUNT CALENDARS )

: DO ( APPLY ' MAPCAR

( LAMBDA ( & REST HEADS )

( FORMAT T FORMAT-STRING HEADS ) )

ROW ) ) ) )

Output:

CL-USER> (PRINT-CALENDAR 1969) [SNOOPY] 1969 JANUARY FEBRUARY MARCH SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 1 1 5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 30 31 APRIL MAY JUNE SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 5 1 2 3 6 7 8 9 10 11 12 4 5 6 7 8 9 10 1 2 3 4 5 6 7 13 14 15 16 17 18 19 11 12 13 14 15 16 17 8 9 10 11 12 13 14 20 21 22 23 24 25 26 18 19 20 21 22 23 24 15 16 17 18 19 20 21 27 28 29 30 25 26 27 28 29 30 31 22 23 24 25 26 27 28 29 30 JULY AUGUST SEPTEMBER SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 5 1 2 1 2 3 4 5 6 6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13 13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20 20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27 27 28 29 30 31 24 25 26 27 28 29 30 28 29 30 31 OCTOBER NOVEMBER DECEMBER SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 1 1 2 3 4 5 6 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31 30 NIL

D keywords are lower case, so this silly solution uses the whole Calendar Task code, with small changes and all in upper case, in a text file named "CALENDAR":

IMPORT STD.STDIO, STD.DATETIME, STD.STRING, STD.CONV, STD.ALGORITHM, STD.ARRAY; VOID PRINT_CALENDAR(IN UINT YEAR, IN UINT COLS) IN { ASSERT(COLS > 0 && COLS <= 12); } BODY { STATIC ENUM CAMEL_CASE = (STRING[] PARTS) PURE => PARTS[0] ~ PARTS[1 .. $].MAP!CAPITALIZE.JOIN; IMMUTABLE ROWS = 12 / COLS + (12 % COLS != 0); MIXIN("AUTO DATE = " ~ "DATE(YEAR, 1, 1);".CAPITALIZE); ENUM STRING S1 = CAMEL_CASE("DAY OF WEEK".SPLIT); MIXIN(FORMAT("AUTO OFFS = CAST(INT)DATE.%S;", S1)); CONST MONTHS = "JANUARY FEBRUARY MARCH APRIL MAY JUNE JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER" .SPLIT.MAP!CAPITALIZE.ARRAY; STRING[8][12] MONS; FOREACH (IMMUTABLE M; 0 .. 12) { MONS[M][0] = MONTHS[M].CENTER(21); MONS[M][1] = " " ~ "SU MO TU WE TH FR SA" .SPLIT.MAP!CAPITALIZE.JOIN(" "); ENUM STRING S2 = CAMEL_CASE("DAYS IN MONTH".SPLIT); MIXIN(FORMAT("IMMUTABLE DIM = DATE.%S;", S2)); FOREACH (IMMUTABLE D; 1 .. 43) { IMMUTABLE DAY = D > OFFS && D <= OFFS + DIM; IMMUTABLE STR = DAY ? FORMAT(" %2S", D-OFFS) : " "; MONS[M][2 + (D - 1) / 7] ~= STR; } OFFS = (OFFS + DIM) % 7; DATE.ADD!"MONTHS"(1); } FORMAT("[%S %S]", "SNOOPY".CAPITALIZE, "PICTURE".CAPITALIZE) .CENTER(COLS * 24 + 4).WRITELN; WRITELN(YEAR.TEXT.CENTER(COLS * 24 + 4), "\N"); FOREACH (IMMUTABLE R; 0 .. ROWS) { STRING[8] S; FOREACH (IMMUTABLE C; 0 .. COLS) { IF (R * COLS + C > 11) BREAK; FOREACH (IMMUTABLE I, LINE; MONS[R * COLS + C]) S[I] ~= FORMAT(" %S", LINE); } WRITEFLN("%-(%S\N%)\N", S); } } STATIC THIS() { PRINT_CALENDAR(1969, 3); }

Then in another source code file there is a little loader, that imports it and mixes-in it (for safety this program must be compiled with -Jsomepath ):

import std. string ; mixin ( import ( "CALENDAR" ) . toLower ) ; void main ( ) { }

Output:

[Snoopy Picture] 1969 January February March Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 1 2 3 4 1 1 5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 30 31 April May June Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 1 2 3 4 5 1 2 3 1 2 3 4 5 6 7 6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14 13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21 20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28 27 28 29 30 25 26 27 28 29 30 31 29 30 July August September Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 1 2 3 4 5 1 2 1 2 3 4 5 6 6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13 13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20 20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27 27 28 29 30 31 24 25 26 27 28 29 30 28 29 30 31 October November December Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 1 2 3 4 1 1 2 3 4 5 6 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31 30

ELENA 5.0 :

import system'text;

import system'routines;

import system'calendar;

import extensions;

import extensions'routines;



const MonthNames = new string[]{"JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE","JULY","AUGUST","SEPTEMBER","OCTOBER",

"NOVEMBER","DECEMBER"};

const DayNames = new string[]{"MO", "TU", "WE", "TH", "FR", "SA", "SU"};



class CalendarMonthPrinter

{

Date theDate;

TextBuilder theLine;

int theMonth;

int theYear;

ref<int> theRow;



constructor(year, month)

{

theMonth := month;

theYear := year;

theLine := new TextBuilder();

theRow := 0;

}



writeTitle()

{

theRow.Value := 0;

theDate := Date.new(theYear, theMonth, 1);

DayNames.forEach:(name)

{ theLine.print(" ",name) }

}



writeLine()

{

theLine.clear();



if (theDate.Month == theMonth)

{

var dw := theDate.DayOfWeek;



theLine.writeCopies(" ",theDate.DayOfWeek == 0 ? 6 : (theDate.DayOfWeek - 1));



do

{

theLine.writePaddingLeft(theDate.Day.toPrintable(), $32, 3);



theDate := theDate.addDays:1

}

until(theDate.Month != theMonth || theDate.DayOfWeek == 1)

};



int length := theLine.Length;

if (length < 21)

{ theLine.writeCopies(" ", 21 - length) };



theRow.append(1)

}



indexer() = new Indexer

{

bool Available = theRow < 7;



int Index

{

get() = theRow.Value;



set(int index)

{

if (index <= theRow)

{ self.writeTitle() };



while (index > theRow)

{ self.writeLine() }

}

}



appendIndex(int index)

{

this self.Index := theRow.Value + index

}



get int Length() { ^ 7 }



get() = self;



set(o) { NotSupportedException.raise() }

};



printTitleTo(output)

{

output.writePadding(MonthNames[theMonth - 1], $32, 21)

}



printTo(output)

{

output.write(theLine.Value)

}

}



class Calendar

{

int theYear;

int theRowLength;



constructor new(int year)

{

theYear := year;

theRowLength := 3

}



printTo(output)

{

output.writePadding("[SNOOPY]", $32, theRowLength * 25);

output.writeLine();

output.writePadding(theYear.toPrintable(), $32, theRowLength * 25);

output.writeLine().writeLine();



var rowCount := 12 / theRowLength;

var months := Array.allocate(rowCount).populate:(i =>

Array.allocate(theRowLength)

.populate:(j =>

new CalendarMonthPrinter(theYear, i * theRowLength + j + 1)));



months.forEach:(row)

{

var r := row;



row.forEach:(month)

{

month.printTitleTo:output;



output.write:" "

};



output.writeLine();



ParallelEnumerator.new(row).forEach:(line)

{

line.forEach:(printer)

{

printer.printTo:output;



output.write:" "

};



output.writeLine()

}

}

}

}



public program()

{

var calender := Calendar.new(console.write:"ENTER THE YEAR:".readLine().toInt());



calender.printTo:console;



console.readChar()

}

Output:

ENTER THE YEAR:1969 [SNOOPY] 1969 JANUARY FEBRUARY MARCH MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 1 2 1 2 6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9 13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16 20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23 27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30 31 APRIL MAY JUNE MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 6 1 2 3 4 1 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 30 JULY AUGUST SEPTEMBER MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7 7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14 14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21 21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28 28 29 30 31 25 26 27 28 29 30 31 29 30 OCTOBER NOVEMBER DECEMBER MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 1 2 1 2 3 4 5 6 7 6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14 13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21 20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28 27 28 29 30 31 24 25 26 27 28 29 30 29 30 31

Alas, the header "FORTRAN" is not recognised - REAL programmers were absent that day? Even upon the apperance of lower case, I have preferred to use shouting for programme source, and normal upper/lower case for commentary. Aside from petty details such as 1 and l being nowhere as distinct as 1 and L, this allows the two sorts of blather to be identifiably different without ratiocination as the hours drag past. Further, the names of variables can easily be distinguished from the same word in discussion, as in ... the text in TEXT will be printed as the subtitle to the text in TITLE ... Anyway, in the spirit of old, herewith the source without tedious commentary:



MODULE DATEGNASH



TYPE DATEBAG

INTEGER DAY,MONTH,YEAR

END TYPE DATEBAG



CHARACTER * 9 MONTHNAME ( 12 ) ,DAYNAME ( 0 : 6 )

PARAMETER ( MONTHNAME = ( / "JANUARY" , "FEBRUARY" , "MARCH" , "APRIL" ,

1 "MAY" , "JUNE" , "JULY" , "AUGUST" , "SEPTEMBER" , "OCTOBER" , "NOVEMBER" ,

2 "DECEMBER" / ) )

PARAMETER ( DAYNAME = ( / "SUNDAY" , "MONDAY" , "TUESDAY" , "WEDNESDAY" ,

1 "THURSDAY" , "FRIDAY" , "SATURDAY" / ) )



INTEGER * 4 JDAYSHIFT

PARAMETER ( JDAYSHIFT = 2415020 )

CONTAINS

INTEGER FUNCTION LSTNB ( TEXT )

CHARACTER * ( * ) , INTENT ( IN ) :: TEXT

INTEGER L

L = LEN ( TEXT )

1 IF ( L. LE .0 ) GO TO 2

IF ( ICHAR ( TEXT ( L : L ) ) . GT . ICHAR ( " " ) ) GO TO 2

L = L - 1

GO TO 1

2 LSTNB = L

RETURN

END FUNCTION LSTNB

CHARACTER * 2 FUNCTION I2FMT ( N )

INTEGER * 4 N

IF ( N. LT .0 ) THEN

IF ( N. LT . - 9 ) THEN

I2FMT = "-!"

ELSE

I2FMT = "-" // CHAR ( ICHAR ( "0" ) - N )

END IF

ELSE IF ( N. LT .10 ) THEN

I2FMT = " " // CHAR ( ICHAR ( "0" ) + N )

ELSE IF ( N. LT .100 ) THEN

I2FMT = CHAR ( N / 10 + ICHAR ( "0" ) )

1 // CHAR ( MOD ( N, 10 ) + ICHAR ( "0" ) )

ELSE

I2FMT = "+!"

END IF

END FUNCTION I2FMT

CHARACTER * 8 FUNCTION I8FMT ( N )

INTEGER * 4 N

CHARACTER * 8 HIC

WRITE ( HIC, 1 ) N

1 FORMAT ( I8 )

I8FMT = HIC

END FUNCTION I8FMT



SUBROUTINE SAY ( OUT ,TEXT )

INTEGER OUT

CHARACTER * ( * ) TEXT

WRITE ( 6 , 1 ) TEXT ( 1 : LSTNB ( TEXT ) )

1 FORMAT ( A )

END SUBROUTINE SAY



INTEGER * 4 FUNCTION DAYNUM ( YY,M,D )

INTEGER * 4 JDAYN

INTEGER YY,Y,M,MM,D

Y = YY

IF ( Y. LT .1 ) Y = Y + 1

MM = ( M - 14 ) / 12

JDAYN = D - 32075

A + 1461 * ( Y + 4800 + MM ) / 4

B + 367 * ( M - 2 - MM * 12 ) / 12

C - 3 * ( ( Y + 4900 + MM ) / 100 ) / 4

DAYNUM = JDAYN - JDAYSHIFT

END FUNCTION DAYNUM



TYPE ( DATEBAG ) FUNCTION MUNYAD ( DAYNUM )

INTEGER * 4 DAYNUM,JDAYN

INTEGER Y,M,D,L,N

JDAYN = DAYNUM + JDAYSHIFT

L = JDAYN + 68569

N = 4 * L / 146097

L = L - ( 146097 * N + 3 ) / 4

Y = 4000 * ( L + 1 ) / 1461001

L = L - 1461 * Y / 4 + 31

M = 80 * L / 2447

D = L - 2447 * M / 80

L = M / 11

M = M + 2 - 12 * L

Y = 100 * ( N - 49 ) + Y + L

IF ( Y. LT .1 ) Y = Y - 1

MUNYAD % YEAR = Y

MUNYAD % MONTH = M

MUNYAD % DAY = D

END FUNCTION MUNYAD



INTEGER FUNCTION PMOD ( N,M )

INTEGER N,M

PMOD = MOD ( MOD ( N,M ) + M,M )

END FUNCTION PMOD



SUBROUTINE CALENDAR ( Y1,Y2,COLUMNS )



INTEGER Y1,Y2,YEAR

INTEGER M,M1,M2,MONTH

INTEGER * 4 DN1,DN2,DN,D

INTEGER W,G

INTEGER L,LINE

INTEGER COL,COLUMNS,COLWIDTH

CHARACTER * 200 STRIPE ( 6 ) ,SPECIAL ( 6 ) ,MLINE,DLINE

W = 3

G = 1

COLWIDTH = 7 * W + G

Y : DO YEAR = Y1,Y2

CALL SAY ( MSG, "" )

IF ( YEAR. EQ .0 ) THEN

CALL SAY ( MSG, "THERE IS NO YEAR ZERO." )

CYCLE Y

END IF

MLINE = ""

L = ( COLUMNS * COLWIDTH - G - 8 ) / 2

IF ( YEAR. GT .0 ) THEN

MLINE ( L : ) = I8FMT ( YEAR )

ELSE

MLINE ( L - 1 : ) = I8FMT ( - YEAR ) // "BC"

END IF

CALL SAY ( MSG,MLINE )

DO MONTH = 1 , 12 ,COLUMNS

M1 = MONTH

M2 = MIN ( 12 ,M1 + COLUMNS - 1 )

MLINE = ""

DLINE = ""

STRIPE = ""

SPECIAL = ""

L0 = 1

DO M = M1,M2

L = ( COLWIDTH - G - LSTNB ( MONTHNAME ( M ) ) ) / 2 - 1

MLINE ( L0 + L : ) = MONTHNAME ( M )

DO D = 0 , 6

L = L0 + ( 3 - W ) + D * W

DLINE ( L : L + 2 ) = DAYNAME ( D ) ( 1 : W - 1 )

END DO

DN1 = DAYNUM ( YEAR,M, 1 )

DN2 = DAYNUM ( YEAR,M + 1 , 0 )

COL = MOD ( PMOD ( DN1, 7 ) + 7 , 7 )

LINE = 1

D = 1

DO DN = DN1,DN2

L = L0 + COL * W

STRIPE ( LINE ) ( L : L + 1 ) = I2FMT ( D )

D = D + 1

COL = COL + 1

IF ( COL. GT .6 ) THEN

LINE = LINE + 1

COL = 0

END IF

END DO

L0 = L0 + 7 * W + G

END DO

CALL SAY ( MSG,MLINE )

CALL SAY ( MSG,DLINE )

DO LINE = 1 , 6

IF ( STRIPE ( LINE ) . NE . "" ) THEN

CALL SAY ( MSG,STRIPE ( LINE ) )

END IF

END DO

END DO

END DO Y

CALL SAY ( MSG, "" )

END SUBROUTINE CALENDAR

END MODULE DATEGNASH



PROGRAM SHOW1968

USE DATEGNASH

INTEGER NCOL

DO NCOL = 1 , 6

CALL CALENDAR ( 1969 , 1969 ,NCOL )

END DO

END



And for output, the wide form:

1969 JANUARY FEBRUARY MARCH APRIL MAY JUNE SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 1 1 1 2 3 4 5 1 2 3 1 2 3 4 5 6 7 5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14 12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21 19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28 26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31 29 30 30 31 JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 5 1 2 1 2 3 4 5 6 1 2 3 4 1 1 2 3 4 5 6 6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13 13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20 20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27 27 28 29 30 31 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31 31 30

Actual lineprinters offer the opportunity of overprinting lines so double (or triple) printing of the same text gave a bold effect if with some blurring due to wobble. Further decoration was possible: via underlines (and for overlines, an underline on the previous line) the appearance can be improved. Vertical bars can also be used, and more advanced lineprinters (IBM1403 etc. using the "TN" chain) or dot-matrix printers also supplied "corner" glyphs so that boxes would not have leaks.

' VERSION 16-03-2016

' COMPILE WITH: FBC -S CONSOLE



' TRUE/FALSE ARE BUILT-IN CONSTANTS SINCE FREEBASIC 1.04

' BUT WE HAVE TO DEFINE THEM FOR OLDER VERSIONS.

#IFNDEF TRUE

#DEFINE FALSE 0

#DEFINE TRUE NOT FALSE

#ENDIF



FUNCTION WD ( M AS INTEGER , D AS INTEGER , Y AS INTEGER ) AS INTEGER

' ZELLERISH

' 0 = SUNDAY, 1 = MONDAY, 2 = TUESDAY, 3 = WEDNESDAY

' 4 = THURSDAY, 5 = FRIDAY, 6 = SATURDAY



IF M < 3 THEN ' IF M = 1 OR M = 2 THEN

M += 12

Y -= 1

END IF

RETURN ( Y + ( Y \ 4 ) - ( Y \ 100 ) + ( Y \ 400 ) + D + ( ( 153 * M + 8 ) \ 5 ) ) MOD 7

END FUNCTION



FUNCTION LEAPYEAR ( Y AS INTEGER ) AS INTEGER



IF ( Y MOD 4 ) <> 0 THEN RETURN FALSE

IF ( Y MOD 100 ) = 0 ANDALSO ( Y MOD 400 ) <> 0 THEN RETURN FALSE

RETURN TRUE

END FUNCTION



' ------=< MAIN >=------

' HARD CODED FOR 132 CHARACTERS PER LINE



DIM AS STRING WDN = "MO TU WE TH FR SA SU" ' WEEKDAY NAMES

DIM AS STRING MO ( 1 TO 12 ) => { "JANUARY" , "FEBRUARY" , "MARCH" , "APRIL" , _

"MAY" , "JUNE" , "JULY" , "AUGUST" , "SEPTEMBER" , _

"OCTOBER" , "NOVEMBER" , "DECEMBER" }

DIM AS STRING TMP1, TMP2, D ( 1 TO 12 )



DIM AS UINTEGER ML ( 1 TO 12 ) => { 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 }

DIM AS UINTEGER I, I1, J, K, Y = 1969



'SCREENRES 1080,600,8



IF LEAPYEAR ( Y ) = TRUE THEN ML ( 2 ) = 29



TMP1 = ""

FOR I = 1 TO 31

TMP1 = TMP1 + RIGHT ( ( " " + STR ( I ) ) , 3 )

NEXT I





FOR I = 1 TO 12

TMP2 = ""

J = WD ( I, 1 , Y )

IF J = 0 THEN J = 7

J = J - 1

TMP2 = SPACE ( J * 3 ) + LEFT ( TMP1, ML ( I ) * 3 ) + SPACE ( 21 )

D ( I ) = TMP2

NEXT I



PRINT

TMP1 = "INSERT YOUR SNOOPY PICTURE HERE"

PRINT SPACE ( ( 132 - LEN ( TMP1 ) ) \ 2 ) ; TMP1

PRINT

TMP1 = STR ( Y )

PRINT SPACE ( ( 132 - LEN ( TMP1 ) ) \ 2 ) ; TMP1

PRINT



' 6 MONTH ON A ROW

TMP2 = " "

FOR I = 1 TO 6

TMP2 = TMP2 + WDN

IF I < 6 THEN TMP2 = TMP2 + " "

NEXT I



FOR I = 1 TO 12 STEP 6

TMP1 = ""

FOR J = I TO I + 4

TMP1 = TMP1 + LEFT ( SPACE ( ( 22 - LEN ( MO ( J ) ) ) \ 2 ) + MO ( J ) + SPACE ( 11 ) , 22 )

NEXT J

TMP1 = TMP1 + SPACE ( ( 22 - LEN ( MO ( I + 5 ) ) ) \ 2 ) + MO ( I + 5 )

PRINT TMP1

PRINT TMP2

FOR J = 1 TO 85 STEP 21

FOR K = I TO I + 4

PRINT MID ( D ( K ) , J , 21 ) ; " " ;

NEXT K

PRINT MID ( D ( I + 5 ) , J , 21 )

NEXT J

PRINT

NEXT I



' EMPTY KEYBOARD BUFFER

WHILE INKEY <> "" : WEND

PRINT : PRINT "HIT ANY KEY TO END PROGRAM"

SLEEP

END

Output:

INSERT YOUR SNOOPY PICTURE HERE 1969 JANUARY FEBRUARY MARCH APRIL MAY JUNE MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 1 2 1 2 1 2 3 4 5 6 1 2 3 4 1 6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 1 2 1 2 3 4 5 6 7 7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14 14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21 21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28 28 29 30 31 25 26 27 28 29 30 31 29 30 27 28 29 30 31 24 25 26 27 28 29 30 29 30 31

Go is case-sensitive: all its keywords and certain other identifiers/verbs are lower case and imported functions etc. are title case. Consequently, it is impossible to run an upper case version of the Calendar task program as it stands. So what I've done instead is to follow the approach of the Kotlin entry:

1. Saved the Calendar program, after conversion to upper case to a text file called realcal_UC.txt.

2. Written another program called realcal.go which takes realcalc_UC.txt as input, outputs a runnable program called realcal_NC.go to disk, runs it and prints the output to the terminal (Ubuntu 16.04 being used). This program only makes the minimum changes to realcal_UC.txt to enable it to run. Everything else is left as upper case even though this is at odds with the usual Go naming conventions.

This is realcal_UC.txt:

PACKAGE MAIN



IMPORT (

"FMT"

"TIME"

)



CONST PAGEWIDTH = 80



FUNC MAIN () {

PRINTCAL ( 1969 )

}



FUNC PRINTCAL ( YEAR INT ) {

THISDATE := TIME . DATE ( YEAR , 1 , 1 , 1 , 1 , 1 , 1 , TIME . UTC )

VAR (

DAYARR [ 12 ][ 7 ][ 6 ] INT // MONTH, WEEKDAY, WEEK

MONTH , LASTMONTH TIME . MONTH

WEEKINMONTH , DAYINMONTH INT

)

FOR THISDATE . YEAR () == YEAR {

IF MONTH = THISDATE . MONTH (); MONTH != LASTMONTH {

WEEKINMONTH = 0

DAYINMONTH = 1

}

WEEKDAY := THISDATE . WEEKDAY ()

IF WEEKDAY == 0 && DAYINMONTH > 1 {

WEEKINMONTH ++

}

DAYARR [ INT ( MONTH ) - 1 ][ WEEKDAY ][ WEEKINMONTH ] = THISDATE . DAY ()

LASTMONTH = MONTH

DAYINMONTH ++

THISDATE = THISDATE . ADD ( TIME . HOUR * 24 )

}

CENTRE := FMT . SPRINTF ( "%D" , PAGEWIDTH / 2 )

FMT . PRINTF ( "%" + CENTRE + "S\N\N" , "[SNOOPY]" )

CENTRE = FMT . SPRINTF ( "%D" , PAGEWIDTH / 2 - 2 )

FMT . PRINTF ( "%" + CENTRE + "D\N\N" , YEAR )

MONTHS := [ 12 ] STRING {

" JANUARY " , " FEBRUARY" , " MARCH " , " APRIL " ,

" MAY " , " JUNE " , " JULY " , " AUGUST " ,

"SEPTEMBER" , " OCTOBER " , " NOVEMBER" , " DECEMBER" }

DAYS := [ 7 ] STRING { "SU" , "MO" , "TU" , "WE" , "TH" , "FR" , "SA" }

FOR QTR := 0 ; QTR < 4 ; QTR ++ {

FOR MONTHINQTR := 0 ; MONTHINQTR < 3 ; MONTHINQTR ++ { // MONTH NAMES

FMT . PRINTF ( " %S " , MONTHS [ QTR * 3 + MONTHINQTR ])

}

FMT . PRINTLN ()

FOR MONTHINQTR := 0 ; MONTHINQTR < 3 ; MONTHINQTR ++ { // DAY NAMES

FOR DAY := 0 ; DAY < 7 ; DAY ++ {

FMT . PRINTF ( " %S" , DAYS [ DAY ])

}

FMT . PRINTF ( " " )

}

FMT . PRINTLN ()

FOR WEEKINMONTH = 0 ; WEEKINMONTH < 6 ; WEEKINMONTH ++ {

FOR MONTHINQTR := 0 ; MONTHINQTR < 3 ; MONTHINQTR ++ {

FOR DAY := 0 ; DAY < 7 ; DAY ++ {

IF DAYARR [ QTR * 3 + MONTHINQTR ][ DAY ][ WEEKINMONTH ] == 0 {

FMT . PRINTF ( " " )

} ELSE {

FMT . PRINTF ( "%3D" , DAYARR [ QTR * 3 + MONTHINQTR ][ DAY ][ WEEKINMONTH ])

}

}

FMT . PRINTF ( " " )

}

FMT . PRINTLN ()

}

FMT . PRINTLN ()

}

}

and this is realcal.go:

package main



import (

"io/ioutil"

"log"

"os"

"os/exec"

"strings"

)



func check ( err error ) {

if err != nil {

log . Fatal ( err )

}

}



func main () {

lower := [] string {

"const " , "else " , "for " , "func " , "if " , "import " , "int " , "package " , "string " , "var " ,

" int" , "int(" , "string{" , " main" , "main(" , "fmt" , "time" , "%d" , "%s" , "%3d" , `d



` , `s



` ,

}

title := [] string {

".add" , ".date" , ".day" , ".hour" , ".month" , ".printf" , ".println" , ".sprintf" , ".weekday" , ".year" ,

}

code , err := ioutil . ReadFile ( "realcal_UC.txt" )

check ( err )

text := string ( code )

for _ , lwr := range lower {

text = strings . Replace ( text , strings . ToUpper ( lwr ), lwr , - 1 )

}

for _ , ttl := range title {

text = strings . Replace ( text , strings . ToUpper ( ttl ), "." + strings . Title ( ttl [ 1 :]), - 1 )

}

err = ioutil . WriteFile ( "realcal_NC.go" , [] byte ( text ), 0666 )

check ( err )

cmd := exec . Command ( "go" , "run" , "realcal_NC.go" )

cmd . Stdout = os . Stdout

cmd . Stderr = os . Stderr

check ( cmd . Run ())

}

which produces (as expected) this output:

[SNOOPY] 1969 JANUARY FEBRUARY MARCH SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 1 1 5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 30 31 APRIL MAY JUNE SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 5 1 2 3 1 2 3 4 5 6 7 6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14 13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21 20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28 27 28 29 30 25 26 27 28 29 30 31 29 30 JULY AUGUST SEPTEMBER SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 5 1 2 1 2 3 4 5 6 6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13 13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20 20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27 27 28 29 30 31 24 25 26 27 28 29 30 28 29 30 31 OCTOBER NOVEMBER DECEMBER SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 1 1 2 3 4 5 6 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31 30

In Graphical User Interface Support Script, we utilize applications that are already written. So for this task, we shall just display the calendar that sets the system clock.

RIGHTCLICK:CLOCK,ADJUST DATE AND TIME,BUTTON:CANCEL

Icon and Unicon don't lend themselves to REAL programming in the sense of this task easily. And initially this task was marked omit because the primary declarations, reserved words, and the name of the main procedure are all in lowercase. However, getting in the spirit of the task real programmers do not give up and a number of solutions are possible:

A real programmer could write a preprocessor to eliminate lower case or insert before translation the one unreal line needed to realize this solution

An uber-real programmer would rewrite the entire translator

Or, a real programmer could do what's presented below on a coffee break with the preprocessor

In the example,

we must concede lowercase letters for the preprocessor directive $include (although as noted a preprocessor could handle this)

(although as noted a preprocessor could handle this) we temporarily concede the lowercase letters needed to realize the IPL procedures IsLeapYear and julian ; however, a real programmer could easily rewrite these in a more real format (or an uber-real programmer would just rewrite the IPL

and ; however, a real programmer could easily rewrite these in a more real format (or an uber-real programmer would just rewrite the IPL the character set usage has been reduced from 69 unique characters to 51 (within 6 bit character representations) by the following tactics: elimination of # and all comments as real programmers don't need them use of preprocessor definitions to eliminate the need for {[]} use of char (excuse me CHAR) to generate characters such as "

" elimination of tabs for blanks



Now clearly all of these measures will make the storage, interpretation, and comprehension of this program more real and efficient for real programmers like us.

Oh, dear. It seems I have written documentation to explain what I have done. Tisk. Tisk. Someone come take my real programmer epaulettes away. And, you! Since you've read this you must surrender your stripes too.

Also it makes me go all nostalgic for my old WATFIVE compiler. And an IBM 129 keypunch. And 5 hole paper tape.

$ include "REALIZE.ICN"



LINK DATETIME

$ define ISLEAPYEAR IsLeapYear

$ define JULIAN julian



PROCEDURE MAIN ( A )

PRINTCALENDAR ( \ A $< 1 $>| 1969 )

END



PROCEDURE PRINTCALENDAR ( YEAR )

COLS := 3

MONS := $<$>

"JANUARY FEBRUARY MARCH APRIL MAY JUNE " ||

"JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER " ?

WHILE PUT ( MONS , TAB ( FIND ( " " ) ) ) DO MOVE ( 1 )



WRITE ( CENTER ( "$<SNOOPY PICTURE$>" , COLS * 24 + 4 ) )

WRITE ( CENTER ( YEAR , COLS * 24 + 4 ) , CHAR ( 10 ) )



M := LIST ( COLS )

EVERY MON := 0 TO 9 BY COLS DO $ (

WRITES ( " " )

EVERY I := 1 TO COLS DO {

WRITES ( CENTER ( MONS $< MON + I $>, 24 ) )

M $< I $> := CREATE CALENDARFORMATWEEK ( YEAR , MON + I )

$ )

WRITE ( )

EVERY 1 TO 7 DO $ (

EVERY C := 1 TO COLS DO $ (

WRITES ( " " )

EVERY 1 TO 7 DO WRITES ( RIGHT ( @ M $< C $>, 3 ) )

$ )

WRITE ( )

$ )

$ )

RETURN

END



PROCEDURE CALENDARFORMATWEEK ( YEAR , M )

STATIC D

INITIAL D := $< 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 $>



EVERY SUSPEND "SU" | "MO" | "TU" | "WE" | "TH" | "FR" | "SA"

EVERY 1 TO ( DAY := ( JULIAN ( M , 1 , YEAR ) + 1 ) % 7 ) DO SUSPEND ""

EVERY SUSPEND 1 TO D $< M $> DO DAY +:= 1

IF M = 2 & ISLEAPYEAR ( YEAR ) THEN SUSPEND ( DAY +:= 1 , 29 )

EVERY DAY TO ( 6 * 7 ) DO SUSPEND ""

END

Where REALIZE.ICN would be something like this (this example is incomplete but sufficient for this program):

$ define PROCEDURE procedure

$ define END end

$ define WRITE write

$ define WRITES writes

$ define SUSPEND suspend

$ define DO do

$ define TO to

$ define EVERY every

$ define LIST list

$ define WHILE while

$ define MAIN main

$ define PUT put

$ define TAB tab

$ define MOVE move

$ define CHAR move

$ define CENTER center

$ define RIGHT right

$ define FIND find

$ define STATIC static

$ define INITIAL initial

$ define CREATE create

$ define LINK link

$ define IF if

$ define THEN then

$ define BY by

$ define DATETIME datetime

$ define RETURN return

DATETIME.ICN provides IsLeapYear and julian

For added "real"ness, we also only use 1 character names:

B: given a year returns a number which when added to numeric values indexing days that year, mod 7, index the proper day names within a week. (In other words 7 | 0 + B 1969 gives the day of week index for the first day of 1969.)

M: given a year return a list of 12 numbers representing the number of days in each month

R: given a year, return 12 rows of 42 numbers, each row representing days of the month framed in a six week period which will be used to display that month (0 for days that are not part of that month)

H: text that will be the header for each month's block of days

C: A calendar of 12 months (in a flat list, each month is organized text but the months are not yet arranged).

D: given a number of characters (at least 20) and a year, gives the calendar arranged in rows that will best fill that character width without exceeding it.

L: given a textual table (fixed width character columns), left justify it

E: given a textual table and a width, center the text within that width (assuming it fits)

F: width F year gives us our formatted calendar. We do a little extra work here to make sure that a 20 character wide calendar can be displayed. (In that case, we trim off the left and right borders. We use the same trimming code in all cases, but typically we trim empty space added specially for this purpose. That said, the 20 character wide thing seems to be gone from the task description so this definition should be simplified...)

Here's an example calendar (the first line 132 F 1969 being the command that build this calendar):

132 F 1969

[INSERT SNOOPY HERE]

1969

┌────────────────────┬────────────────────┬────────────────────┬────────────────────┬────────────────────┬────────────────────┐

│ JAN │ FEB │ MAR │ APR │ MAY │ JUN │

│SU MO TU WE TH FR SA│SU MO TU WE TH FR SA│SU MO TU WE TH FR SA│SU MO TU WE TH FR SA│SU MO TU WE TH FR SA│SU MO TU WE TH FR SA│

│ 1 2 3 4│ 1│ 1│ 1 2 3 4 5│ 1 2 3│ 1 2 3 4 5 6 7│

│ 5 6 7 8 9 10 11│ 2 3 4 5 6 7 8│ 2 3 4 5 6 7 8│ 6 7 8 9 10 11 12│ 4 5 6 7 8 9 10│ 8 9 10 11 12 13 14│

│12 13 14 15 16 17 18│ 9 10 11 12 13 14 15│ 9 10 11 12 13 14 15│13 14 15 16 17 18 19│11 12 13 14 15 16 17│15 16 17 18 19 20 21│

│19 20 21 22 23 24 25│16 17 18 19 20 21 22│16 17 18 19 20 21 22│20 21 22 23 24 25 26│18 19 20 21 22 23 24│22 23 24 25 26 27 28│

│26 27 28 29 30 31 │23 24 25 26 27 28 │23 24 25 26 27 28 29│27 28 29 30 │25 26 27 28 29 30 31│29 30 │

│ │ │30 31 │ │ │ │

├────────────────────┼────────────────────┼────────────────────┼────────────────────┼────────────────────┼────────────────────┤

│ JUL │ AUG │ SEP │ OCT │ NOV │ DEC │

│SU MO TU WE TH FR SA│SU MO TU WE TH FR SA│SU MO TU WE TH FR SA│SU MO TU WE TH FR SA│SU MO TU WE TH FR SA│SU MO TU WE TH FR SA│

│ 1 2 3 4 5│ 1 2│ 1 2 3 4 5 6│ 1 2 3 4│ 1│ 1 2 3 4 5 6│

│ 6 7 8 9 10 11 12│ 3 4 5 6 7 8 9│ 7 8 9 10 11 12 13│ 5 6 7 8 9 10 11│ 2 3 4 5 6 7 8│ 7 8 9 10 11 12 13│

│13 14 15 16 17 18 19│10 11 12 13 14 15 16│14 15 16 17 18 19 20│12 13 14 15 16 17 18│ 9 10 11 12 13 14 15│14 15 16 17 18 19 20│

│20 21 22 23 24 25 26│17 18 19 20 21 22 23│21 22 23 24 25 26 27│19 20 21 22 23 24 25│16 17 18 19 20 21 22│21 22 23 24 25 26 27│

│27 28 29 30 31 │24 25 26 27 28 29 30│28 29 30 │26 27 28 29 30 31 │23 24 25 26 27 28 29│28 29 30 31 │

│ │31 │ │ │30 │ │

└────────────────────┴────────────────────┴────────────────────┴────────────────────┴────────────────────┴────────────────────┘



Note that this version of F will work fine with a left argument of 20 (why anyone felt that this was important to mention is perhaps best thought of as an issue lost in history).

Julia code is a valid data type in Julia. Executable code can be created from a String with Meta.parse() and run with eval. This example does require a small function with Julia's lowercase keywords, perhaps loaded on startup from a separate file.



# IF THIS SMALL FUNCTION IS PLACED IN THE STARTUP.JL

# FILE, IT WILL BE LOADED ON STARTUP. THE REST OF

# THIS EXAMPLE IS IN ALL UPPERCASE.

function RUNUPPERCASECODE(CO)

COD = replace(lowercase(CO), "date" => "Date")

for E in Meta.parse(COD, 1) eval(E) end

end





CODE = """BEGIN



USING DATES;

CENTEROBJECT(X, N) = BEGIN S = UPPERCASE(STRING(X)); RPAD(LPAD(S, DIV(N + LENGTH(S), 2)), N) END;

FUNCTION FORMATMONTH(YR, MO)

DT = DATE(\"\$YR-\$MO-01\");

DAYOFWEEKFIRST = DAYOFWEEK(DT);

NUMWEEKLINES = 1;

STR = UPPERCASE(CENTEROBJECT(MONTHNAME(DT), 20) * \"\\NMO TU WE TH FR SA SU\\N\");

STR *= \" \" ^ (3 * (DAYOFWEEKFIRST - 1)) * LPAD(STRING(1), 2);

FOR I = 2:DAYSINMONTH(DT)

IF (I + DAYOFWEEKFIRST + 5) % 7 == 0

STR *= \"\\N\" * LPAD(I, 2);

NUMWEEKLINES += 1;

ELSE

STR *= LPAD(STRING(I), 3);

END;

END;

STR *= NUMWEEKLINES < 6 ? \"\\N\\N\\N\" : \"\\N\\N\";

ARR = [];

FOR S IN SPLIT(STR, \"\\N\")

PUSH!(ARR, RPAD(S, 20)[1:20])

END;

JOIN(ARR, \"\\N\");

END;



FUNCTION FORMATYEAR(DISPLAYYEAR)

CALMONTHS = [FORMATMONTH(DISPLAYYEAR, MO) FOR MO IN 1:12];

MONTHSPERLINE = 6;

JOINSPACES = 2;

STR = \"\\N\" * CENTEROBJECT(DISPLAYYEAR, 132) * \"\\N\";

MONTHCAL = [SPLIT(FORMATMONTH(DISPLAYYEAR, I), \"\\N\") FOR I IN 1:12];

FOR I IN 1:MONTHSPERLINE:LENGTH(CALMONTHS) - 1

FOR J IN 1:LENGTH(MONTHCAL[1])

MONTHLINES = MAP(X->MONTHCAL[X][J], I:I + MONTHSPERLINE - 1);

STR *= RPAD(JOIN(MONTHLINES, \" \" ^ JOINSPACES), 132) * \"\\N\";

END;

STR *= \"\\N\";

END;

STR;

END;



PRINTLN(FORMATYEAR(1969));



END;

"""



RUNUPPERCASECODE(CODE)



Output:

1969 JANUARY FEBRUARY MARCH APRIL MAY JUNE MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 1 2 1 2 1 2 3 4 5 6 1 2 3 4 1 6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 31 30

JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 1 2 1 2 3 4 5 6 7 7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14 14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21 21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28 28 29 30 31 25 26 27 28 29 30 31 29 30 27 28 29 30 31 24 25 26 27 28 29 30 29 30 31

Kotlin is case-sensitive: all its keywords and packages are lower case, all its library classes are mixed case and its library functions are either lower case or mixed case. Consequently, it is impossible to run an upper case version of the Calendar task program as it stands. So what I've done instead (and similar to what several other languages in the same boat have done) is:

1. Saved the Calendar program, after conversion to upper case and a small marked alteration to give upper case output, to a text file called calendar_UC.txt.

2. Written another program called real_calendar.kt which takes calendar_UC.txt as input, outputs a runnable program called calendar_NC.kt to disk, compiles it to a .jar file, runs it, captures the output and prints it to the terminal (Ubuntu 14.04 being used). This program only makes the minimum changes to calendar_UC.txt to enable it to run. Everything else is left as upper case even though almost certainly no Kotlin programmer ("REAL" or not) would write such a program in practice.

This is calendar_UC.txt:

IMPORT JAVA. TEXT . *

IMPORT JAVA. UTIL . *

IMPORT JAVA. IO . PRINTSTREAM



INTERNAL FUN PRINTSTREAM. PRINTCALENDAR ( YEAR : INT, NCOLS : BYTE, LOCALE : LOCALE ? ) {

IF ( NCOLS < 1 || NCOLS > 12 )

THROW ILLEGALARGUMENTEXCEPTION ( "ILLEGAL COLUMN WIDTH." )

VAL W = NCOLS * 24

VAL NROWS = MATH. CEIL ( 12.0 / NCOLS ) . TOINT ( )



VAL DATE = GREGORIANCALENDAR ( YEAR, 0 , 1 )

VAR OFFS = DATE. GET ( CALENDAR. DAY_OF_WEEK ) - 1



VAL DAYS = DATEFORMATSYMBOLS ( LOCALE ) . SHORTWEEKDAYS . SLICE ( 1 .. 7 ) . MAP { IT. SLICE ( 0 .. 1 ) } . JOINTOSTRING ( " " , " " )

VAL MONS = ARRAY ( 12 ) { ARRAY ( 8 ) { "" } }

DATEFORMATSYMBOLS ( LOCALE ) . MONTHS . SLICE ( 0 .. 11 ) . FOREACHINDEXED { M, NAME - >

VAL LEN = 11 + NAME. LENGTH / 2

VAL FORMAT = MESSAGEFORMAT. FORMAT ( "%{0}S%{1}S" , LEN, 21 - LEN )

MONS [ M ] [ 0 ] = STRING. FORMAT ( FORMAT, NAME, "" )

MONS [ M ] [ 1 ] = DAYS

VAL DIM = DATE. GETACTUALMAXIMUM ( CALENDAR. DAY_OF_MONTH )

FOR ( D IN 1 .. 42 ) {

VAL ISDAY = D > OFFS && D <= OFFS + DIM

VAL ENTRY = IF ( ISDAY ) STRING. FORMAT ( " %2S" , D - OFFS ) ELSE " "

IF ( D % 7 == 1 )

MONS [ M ] [ 2 + ( D - 1 ) / 7 ] = ENTRY

ELSE

MONS [ M ] [ 2 + ( D - 1 ) / 7 ] + = ENTRY

}

OFFS = ( OFFS + DIM ) % 7

DATE. ADD ( CALENDAR. MONTH , 1 )

}



PRINTF ( "%" + ( W / 2 + 10 ) + "S%N" , "[SNOOPY PICTURE]" )

PRINTF ( "%" + ( W / 2 + 4 ) + "S%N%N" , YEAR )



FOR ( R IN 0 .. NROWS - 1 ) {

FOR ( I IN 0 .. 7 ) {

VAR C = R * NCOLS

WHILE ( C < ( R + 1 ) * NCOLS && C < 12 ) {

PRINTF ( " %S" , MONS [ C ] [ I ] . TOUPPERCASE ( ) ) // ORIGINAL CHANGED TO PRINT IN UPPER CASE

C++

}

PRINTLN ( )

}

PRINTLN ( )

}

}



FUN MAIN ( ARGS : ARRAY < STRING > ) {

SYSTEM. OUT . PRINTCALENDAR ( 1969 , 3 , LOCALE. US )

}

and this is real_calendar.kt:

// version 1.1.3



import java. io . File

import java. io . BufferedReader

import java. io . InputStreamReader



fun main ( args : Array < String > ) {

val keywords = listOf (

"import" , "internal" , "fun" , "if" , "throw" , "val" , "var" , "for" , "in" , "while"

)



val singleCase = listOf (

"java.text" ,

"java.util" ,

"java.io" ,

"else" , // really a keyword but doesn't have a following space here

"ceil" ,

"it" , // really a keyword but doesn't have a following space here

"get(" , // also included in GETACTUALMAXIMUM

"slice" ,

"map" ,

"months" ,

"length" ,

".format" , // also variable called FORMAT

"add" ,

"printf" ,

"println" ,

"out" ,

"main" ,

"args" ,

"s%{1}s" ,

"%2s" ,

"s%n%n" ,

"s%n" ,

"%s"

)



val mixedCase = listOf (

"PRINTSTREAM" to "PrintStream" ,

"INT," to "Int," , // also included in PRINTCALENDAR

"BYTE" to "Byte" ,

"LOCALE?" to "Locale?" , // also variable called LOCALE

"LOCALE." to "Locale." ,

"ILLEGALARGUMENTEXCEPTION" to "IllegalArgumentException" ,

"MATH" to "Math" ,

"GREGORIANCALENDAR" to "GregorianCalendar" ,

"DATEFORMATSYMBOLS" to "DateFormatSymbols" ,

"ARRAY" to "Array" ,

"MESSAGEFORMAT" to "MessageFormat" ,

"JOINTOSTRING" to "joinToString" ,

"STRING" to "String" ,

"CALENDAR." to "Calendar." , // also included in PRINTCALENDAR

"SYSTEM" to "System" ,

"TOINT" to "toInt" ,

"SHORTWEEKDAYS" to "shortWeekdays" ,

"FOREACHINDEXED" to "forEachIndexed" ,

"GETACTUALMAXIMUM" to "getActualMaximum" ,

"TOUPPERCASE" to "toUpperCase"

)



var text = File ( "calendar_UC.txt" ) . readText ( )

for ( k in keywords ) text = text. replace ( "${k.toUpperCase()} " , "$k " ) // add a following space to be on safe side

for ( s in singleCase ) text = text. replace ( s. toUpperCase ( ) , s )

for ( m in mixedCase ) text = text. replace ( m. first , m. second )

File ( "calendar_NC.kt" ) . writeText ( text )

val commands = listOf ( "kotlinc" , "calendar_NC.kt" , "-include-runtime" , "-d" , "calendar_X.jar" )

val pb = ProcessBuilder ( commands )

pb. redirectErrorStream ( true )

val process = pb. start ( )

process. waitFor ( )

val commands2 = listOf ( "java" , "-jar" , "calendar_NC.jar" )

val pb2 = ProcessBuilder ( commands2 )

pb2. redirectErrorStream ( true )

val process2 = pb2. start ( )

val out = StringBuilder ( )

val br = BufferedReader ( InputStreamReader ( process2. inputStream ) )

while ( true ) {

val line = br. readLine ( )

if ( line == null ) break

out. append ( line ) . append ( '

' )

}

br. close ( )

println ( out. toString ( ) )

}

which generates (on disk) calendar_NC.kt:

import java. text . *

import java. util . *

import java. io . PrintStream



internal fun PrintStream. PRINTCALENDAR ( YEAR : Int, NCOLS : Byte, LOCALE : Locale ? ) {

if ( NCOLS < 1 || NCOLS > 12 )

throw IllegalArgumentException ( "ILLEGAL COLUMN WIDTH." )

val W = NCOLS * 24

val NROWS = Math. ceil ( 12.0 / NCOLS ) . toInt ( )



val DATE = GregorianCalendar ( YEAR, 0 , 1 )

var OFFS = DATE. get ( Calendar. DAY_OF_WEEK ) - 1



val DAYS = DateFormatSymbols ( LOCALE ) . shortWeekdays . slice ( 1 .. 7 ) . map { it. slice ( 0 .. 1 ) } . joinToString ( " " , " " )

val MONS = Array ( 12 ) { Array ( 8 ) { "" } }

DateFormatSymbols ( LOCALE ) . months . slice ( 0 .. 11 ) . forEachIndexed { M, NAME - >

val LEN = 11 + NAME. length / 2

val FORMAT = MessageFormat. format ( "%{0}s%{1}s" , LEN, 21 - LEN )

MONS [ M ] [ 0 ] = String. format ( FORMAT, NAME, "" )

MONS [ M ] [ 1 ] = DAYS

val DIM = DATE. getActualMaximum ( Calendar. DAY_OF_MONTH )

for ( D in 1 .. 42 ) {

val ISDAY = D > OFFS && D <= OFFS + DIM

val ENTRY = if ( ISDAY ) String. format ( " %2s" , D - OFFS ) else " "

if ( D % 7 == 1 )

MONS [ M ] [ 2 + ( D - 1 ) / 7 ] = ENTRY

else

MONS [ M ] [ 2 + ( D - 1 ) / 7 ] + = ENTRY

}

OFFS = ( OFFS + DIM ) % 7

DATE. add ( Calendar. MONTH , 1 )

}



printf ( "%" + ( W / 2 + 10 ) + "s%n" , "[SNOOPY PICTURE]" )

printf ( "%" + ( W / 2 + 4 ) + "s%n%n" , YEAR )



for ( R in 0 .. NROWS - 1 ) {

for ( I in 0 .. 7 ) {

var C = R * NCOLS

while ( C < ( R + 1 ) * NCOLS && C < 12 ) {

printf ( " %s" , MONS [ C ] [ I ] . toUpperCase ( ) ) // ORIGINAL CHANGED TO PRINT in UPPER CASE

C++

}

println ( )

}

println ( )

}

}



fun main ( args : Array < String > ) {

System. out . PRINTCALENDAR ( 1969 , 3 , Locale. US )

}

which when compiled and run produces output of:

[SNOOPY PICTURE] 1969 JANUARY FEBRUARY MARCH SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 1 1 5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8 12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15 19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22 26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29 30 31 APRIL MAY JUNE SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 5 1 2 3 1 2 3 4 5 6 7 6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14 13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21 20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28 27 28 29 30 25 26 27 28 29 30 31 29 30 JULY AUGUST SEPTEMBER SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 5 1 2 1 2 3 4 5 6 6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13 13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20 20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27 27 28 29 30 31 24 25 26 27 28 29 30 28 29 30 31 OCTOBER NOVEMBER DECEMBER SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA 1 2 3 4 1 1 2 3 4 5 6 5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13 12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20 19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27 26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31 30

Tested with Lua 5.3.2

Lua is case sensitive and all the keywords and library routines are in lower case. As with the D sample, we use a simple pre-processor to execute the (slightly modified) upper-cased source of the Lua solution for the standard Calendar task.

The upper case Lua source - stored in a file called UCCALENDAR.LUU:



FUNCTION PRINT_CAL ( YEAR )

LOCAL MONTHS = { "JANUARY" , "FEBRUARY" , "MARCH" , "APRIL" , "MAY" , "JUNE" ,

"JULY" , "AUGUST" , "SEPTEMBER" , "OCTOBER" , "NOVEMBER" , "DECEMBER" }

LOCAL DAYSTITLE = "MO TU WE TH FR SA SU"

LOCAL DAYSPERMONTH = { 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 }

LOCAL STARTDAY = ( ( YEAR - 1 ) * 365 + MATH . FLOOR ( ( YEAR - 1 ) / 4 ) - MATH . FLOOR ( ( YEAR - 1 ) / 100 ) + MATH . FLOOR ( ( YEAR - 1 ) / 400 ) ) % 7

IF YEAR % 4 == 0 AND YEAR % 100 ~= 0 OR YEAR % 400 == 0 THEN

DAYSPERMONTH [ 2 ] = 29

END

LOCAL SEP = 5

LOCAL MONTHWIDTH = DAYSTITLE : LEN ( )

LOCAL CALWIDTH = 3 * MONTHWIDTH + 2 * SEP



FUNCTION CENTER ( STR , WIDTH )

LOCAL FILL1 = MATH . FLOOR ( ( WIDTH - STR : LEN ( ) ) / 2 )

LOCAL FILL2 = WIDTH - STR : LEN ( ) - FILL1

RETURN STRING . REP ( " " , FILL1 ) .. STR .. STRING . REP ( " " , FILL2 )

END



FUNCTION MAKEMONTH ( NAME , SKIP , DAYS )

LOCAL CAL = {

CENTER ( NAME , MONTHWIDTH ) ,

DAYSTITLE

}

LOCAL CURDAY = 1 - SKIP

WHILE # CAL < 9 DO

LINE = { }

FOR I = 1 , 7 DO

IF CURDAY < 1 OR CURDAY > DAYS THEN

LINE [ I ] = " "

ELSE

LINE [ I ] = STRING . FORMAT ( "%2D" , CURDAY )

END

CURDAY = CURDAY + 1

END

CAL [ # CAL + 1 ] = TABLE . CONCAT ( LINE , " " )

END

RETURN CAL

END



LOCAL CALENDAR = { }

FOR I , MONTH IN IPAIRS ( MONTHS ) DO

LOCAL DPM = DAYSPERMONTH [ I ]

CALENDAR [ I ] = MAKEMONTH ( MONTH , STARTDAY , DPM )

STARTDAY = ( STARTDAY + DPM ) % 7

END





PRINT ( CENTER ( "[SNOOPY]" , CALWIDTH ) : UPPER ( ) , " \N " )

PRINT ( CENTER ( "--- " .. YEAR .. " ---" , CALWIDTH ) : UPPER ( ) , " \N " )



FOR Q = 0 , 3 DO

FOR L = 1 , 9 DO

LINE = { }

FOR M = 1 , 3 DO

LINE [ M ] = CALENDAR [ Q * 3 + M ] [ L ]

END

PRINT ( TABLE . CONCAT ( LINE , STRING . REP ( " " , SEP ) ) : UPPER ( ) )

END

END

END



PRINT_CAL ( 1969 )



The following "one-liner" standard Lua source will down-case and run the program in the source file specified as it's parameter (file luu.lua):

do io.input ( arg [ 1 ] ) ; local s = io.read ( "*a" ) : lower ( ) ; io.close ( ) ; assert ( load ( s ) ) ( ) end



The following command will execute the UCCALENDAR.LUU source (replace lua532 with the appropriate command for your system):



lua532 luu.lua UCCALENDAR.LUU



Output:

[SNOOPY] --- 1969 --- JANUARY FEBRUARY MARCH MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 1 2 1 2 6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9 13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16 20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23 27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30 31 APRIL MAY JUNE MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 6 1 2 3 4 1 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29 30 JULY AUGUST SEPTEMBER MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7 7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14 14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21 21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28 28 29 30 31 25 26 27 28 29 30 31 29 30 OCTOBER NOVEMBER DECEMBER MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU 1 2 3 4 5 1 2 1 2 3 4 5 6 7 6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14 13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21 20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28 27 28 29 30 31 24 25 26 27 28 29 30 29 30 31

Console 132 characters by 43 lines. Six columns for months.





GLOBAL CONST PRINT_IT AS BOOLEAN=FALSE

MODULE GLOBAL SNOOPY {

IF NOT PRINT_IT THEN CURSOR 0,ROW ELSE IF ROW>0 THEN PAGE 1

PRINT $(,8)

PRINT #-2, {

XXXX

X XX

X *** X XXXXX

X ***** X XXX XX

XXXX ******* XXX XXXX XX

XX X ****** XXXXXXXXX [email protected] XX XXX

XX X **** X X** X

X XX XX X X***X

X //XXXX X XXXX

X // X XX

X // X XXXXXXXXXXXXXXXXXX/

X XXX// X X

X X X X X

X X X X X

X X X X X XX

X X X X X XXX XX

X XXX X X X X X X

X X X XX X XXXX

X X XXXXXXXX\ XX XX X

XX XX X X @X XX

XX XXXX XXXXXX/ X XXXX

XXX XX*** X X

XXXXXXXXXXXXX * * X X

*---* X X X

*-* * XXX X X

*- * XXX X

*- *X XXX

*- *X X XXX

*- *X X XX

*- *XX X X

* *X* X X X

* *X * X X X

* * X** X XXXX X

* * X** XX X X

* ** X** X XX X

* ** X* XXX X X

* ** XX XXXX XXX

* * * XXXX X X

* * * X X X

=======******* * * X X XXXXXXXX\

* * * /XXXXX XXXXXXXX\ )

=====********** * X ) \ )

====* * X \ \ )XXXXX

=========********** XXXXXXXXXXXXXXXXXXXXXX



}

}

MODULE CALENDAR (YEAR, LOCALEID) {

FUNCTION GETMAX(YEAR, MONTH) {

A=DATE(STR$(YEAR)+"-"+STR$(MONTH)+"-1")

MAX=32

DO {

MAX--

M=VAL(STR$(CDATE(A,0,0,MAX), "M"))

} UNTIL M=MONTH

=MAX+1

}

FUNCTION SKIPMO(YEAR, MONTH) {

A=DATE(STR$(YEAR)+"-"+STR$(MONTH)+"-1")

=(VAL(STR$(A, "W"))-8) MOD 7 +7

}

FUNCTION TITLE$(A$) {

=UCASE$(LEFT$(A$,1))+LCASE$(MID$(A$, 2))

}

LOCALE LOCALEID

IF NOT PRINT_IT THEN CURSOR 0,HEIGHT-1 ' LAST LINE, SO EACH NEW LINE SCROLL ALL LINES UP

SNOOPY



PRINT UNDER ' PRINT UNDERLINE

PRINT OVER $(2), YEAR

PRINT

FOR J=0 TO 1 {

PRINT

FOR I=1 TO 6 {

MONTH=I+J*6

PRINT PART @((I-1)*22), $(2,21), UCASE$(LOCALE$(55+MONTH))

}

PRINT

DIM SKIP(1 TO 6), COUNT(1 TO 6), D(1 TO 6)=1

FOR I=1 TO 6 {

MONTH=I+J*6

IF I>1 THEN PRINT " ";

FOR K=42 TO 48 :PRINT " ";UCASE$(LEFT$(LOCALE$(K),2));:NEXT K

SKIP(I)=SKIPMO(YEAR, MONTH)

COUNT(I)=GETMAX(YEAR, MONTH)

}

PRINT

FOR I=1 TO 6 {

IF I>1 THEN PRINT " ";

FOR K=1 TO 7 {

SKIP(I)--

IF SKIP(I)>0 THEN PRINT " "; :CONTINUE

COUNT(I)--

PRINT FORMAT$(" {0::-2}", D(I));

D(I)++

}

}

PRINT

PRINT @(0)

FOR M=1 TO 5 {

FOR I=1 TO 6 {

IF I>1 THEN PRINT " ";

FOR K=1 TO 7 {

COUNT(I)--

IF COUNT(I)<0 THEN PRINT " "; : CONTINUE

PRINT FORMAT$(" {0::-2}", D(I));

D(I)++

}

}

PRINT

}

}

}

WHILE INKEY$<>"" : END WHILE

IF PRINT_IT THEN PRINTING ON

FONT "COURIER NEW"

PEN 0

CLS 15, 0

FORM 132,68

CALENDAR 1966, 1032 ' GREEK

GOSUB WAITKEY_OR_MOUSE

FOR I=2019 TO 2025

CALENDAR I, 1033 ' ENGLISH

GOSUB WAITKEY_OR_MOUSE

NEXT I

IF PRINT_IT THEN PRINTING OFF

CLEAR ' CLEAR VARIABLES FROM THIS MODULE

KEYBOARD "INFO"+CHR$(13)

END

WAITKEY_OR_MOUSE:

IF PRINT_IT THEN RETURN

WHILE INKEY$="" AND MOUSE=0

END WHILE

RETURN







Since we can't use eval or print (or any other keywords) at the top level, we need to abuse backticks in order to print anything, as in the infamous JAPH with no letters or numbers. Consequently, the calendar is printed to standard error instead of standard output.

$PROGRAM = ' \'



MY @START_DOW = (3, 6, 6, 2, 4, 0,

2, 5, 1, 3, 6, 1);

MY @DAYS = (31, 28, 31, 30, 31, 30,

31, 31, 30, 31, 30, 31);



MY @MONTHS;

FOREACH MY $M (0 .. 11) {

FOREACH MY $R (0 .. 5) {

$MONTHS[$M][$R] = JOIN " ",

MAP { $_ < 1 || $_ > $DAYS[$M] ? " " : SPRINTF "%2D", $_ }

MAP { $_ - $START_DOW[$M] + 1 }

$R * 7 .. $R * 7 + 6;

}

}



SUB P { WARN $_[0], " \\ N" }

P UC " [INSERT SNOOPY HERE]";

P " 1969";

P "";

FOREACH (UC(" JANUARY FEBRUARY MARCH APRIL MAY JUNE"),

UC(" JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER")) {

P $_;

MY @MS = SPLICE @MONTHS, 0, 6;

P JOIN " ", ((UC "SU MO TU WE TH FR SA") X 6);

P JOIN " ", MAP { SHIFT @$_ } @MS FOREACH 0 .. 5;

}



\' ' ;



# LOWERCASE LETTERS

$E = '%' | '@' ;

$C = '#' | '@' ;

$H = '(' | '@' ;

$O = '/' | '@' ;

$T = '4' | '@' ;

$R = '2' | '@' ;

$A = '!' | '@' ;

$Z = ':' | '@' ;

$P = '0' | '@' ;

$L = ',' | '@' ;



`${E}${C}${H}${O} $PROGRAM | ${T}${R} A-Z ${A}-${Z} | ${P}${E}${R}${L}` ;

$_ = $ARGV [ 0 ] // 1969 ; ` \1 43 \1 41 \1 54 $_ >&2`

Although, if we are abusing the backticks and other innocent programs, why not just:

OK, I'm not going to take this too seriously but this is as good an opportunity as I'll ever get to showcase how trivial it is to make some rather fundamental changes to the compiler.

So, the first task is to take a copy of Calendar and make it output uppercase. Change the line

return repeat(' ',left)&s&repeat(' ',right)

in routine centre to:

return repeat(' ',left)&upper(s)&repeat(' ',right)

(That's that done.) Now, Phix is case-sensitive, and many of the keywords and builtins are in lower case, which presents a bit of a challenge - but we can cope.

It is too tedious and not particularly helpful to present a completed solution, instead I shall outline the (relatively simple) steps this would require. I have limited my tests to INCLUDE and INTEGER.

In psym.e you can find the line

initialSymEntry("integer", S_Type,"TI",opInt, E_none) -- #01 / 0b0001 integer

Immediately after that (it should now be there commented out) add:

Alias("INTEGER",symlimit)

Add similar lines for length, floor, repeat, upper, day_of_week, sequence, string, sprintf, append, printf, join, at the appropriate places.

Keywords are handled slightly differently: In pttree.e we need a new alias routine (you should find this one commented out, from when I was testing all this):

procedure tt_stringA(sequence text, integer alias)

tt_string(text,-2)

tt[pcurr] = alias

end procedure

and you can find the line

global constant T_include = 596 tt_stringF("include",T_include)

Sometime after that, in fact after the very last use of tt_stringF, add (likewise you should find this one commented out):

tt_stringA("INCLUDE",T_include)

Add similar lines for function, end, iff, for, to, do, if, or, then, else, return, procedure, but this time all some ways away from the originals. Quickly run "p p" and make sure you get a normal prompt, without any "T_include should be 624(not 596)" or suchlike.

Currently ptok.e recognises

but not \N . Search for all references to escchar (there should be one definition and two references) and make sure the character being checked is mapped to lower case, ie change (twice)

Ch = find(Ch,escchar)

to

Ch = find(lower(Ch),escchar)

Lastly, the calendar example includes builtins\timedate.e, which contains some lower-case definitions. So copy it to (say) TIMEDATEUPPER.E and change adjust_timedate, timedelta, days (the 2nd param to timedelta), and format_timedate to their uppercase equivalents, and of course change that include to INCLUDE BUILTINS\TIMEDATEUPPER.E .

There is probably some change in ptok.e/pttree.e even simpler than the steps outlined above that makes everything case insensitive, but locating that is left as an exercise for the reader.

You don't actually have to repackage to test this, just run p p test.exw - percentagewise it might be ten times slower (as p.exw is much bigger than test.exw), but it'll still only be a fraction of a second.

Finally, you can take that copy of Calendar and make it all uppercase. In Edita (shipped with Phix) that is just <Ctrl A><Alt U>.

While PHP functions are case-sensitive (aside of _() ), this isn't the case for language constructs.

<?PHP

ECHO <<<REALPROGRAMMERSTHINKINUPPERCASEANDCHEATBYUSINGPRINT

JANUARY FEBRUARY MARCH APRIL MAY JUNE

MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO

1 2 3 4 5 1 2 1 2 1 2 3 4 5 6 1 2 3 4 1

6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 2 3 4 5 6 7 8

13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 9 10 11 12 13 14 15

20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 16 17 18 19 20 21 22

27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 23 24 25 26 27 28 29

31 30



JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER

MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO MO TU WE TH FR SA SO

1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 1 2 1 2 3 4 5 6 7

7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9 8 9 10 11 12 13 14

14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16 15 16 17 18 19 20 21

21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23 22 23 24 25 26 27 28

28 29 30 31 25 26 27 28 29 30 31 29 30 27 28 29 30 31 24 25 26 27 28 29 30 29 30 31

REALPROGRAMMERSTHINKINUPPERCASEANDCHEATBYUSINGPRINT

; // MAGICAL SEMICOLON

The "CALENDAR.L" source file:

(DE CAL (YEAR)

(PRINL "====== " YEAR " ======")

(FOR DAT (RANGE (DATE YEAR 1 1) (DATE YEAR 12 31))

(LET D (DATE DAT)

(TAB (3 3 4 8)

(WHEN (= 1 (CADDR D))

(GET `(INTERN (PACK (MAPCAR CHAR (42 77 111 110)))) (CADR D)) )

(CADDR D)

(DAY DAT `(INTERN (PACK (MAPCAR CHAR (42 68 97 121)))))

(WHEN (=0 (% (INC DAT) 7))

(PACK (CHAR 87) "EEk " (WEEK DAT)) ) ) ) ) )



(CAL 1969)

(BYE)

Then it can be executed with this command line:

$ pil -'load (list "awk" "{print tolower($0)}" "CALENDAR.L")'

Output:

====== 1969 ====== Jan 1 Wed 2 Thu 3 Fri 4 Sat 5 Sun 6 Mon Week 2 7 Tue .... 28 Sat 29 Sun 30 Mon Week 27 Jul 1 Tue 2 Wed 3 Thu 4 Fri .... 25 Thu 26 Fri 27 Sat 28 Sun 29 Mon Week 53 30 Tue 31 Wed

(SUBRG, SIZE, FOFL):

CALENDAR: PROCEDURE (YEAR) OPTIONS (MAIN);

DECLARE YEAR CHARACTER (4) VARYING;

DECLARE (A, B, C) (0:5,0:6) CHARACTER (3);

DECLARE NAME_MONTH(12) STATIC CHARACTER (9) VARYING INITIAL (

'JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE',

'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER');

DECLARE I FIXED;

DECLARE (MM, MMP1, MMP2) PIC '99';



PUT EDIT (CENTER('CALENDAR FOR ' || YEAR, 67)) (A);

PUT SKIP (2);



DO MM = 1 TO 12 BY 3;

MMP1 = MM + 1; MMP2 = MM + 2;

CALL PREPARE_MONTH('01' || MM || YEAR, A);

CALL PREPARE_MONTH('01' || MMP1 || YEAR, B);

CALL PREPARE_MONTH('01' || MMP2 || YEAR, C);



PUT SKIP EDIT (CENTER(NAME_MONTH(MM), 23),

CENTER(NAME_MONTH(MMP1), 23),

CENTER(NAME_MONTH(MMP2), 23) ) (A);

PUT SKIP EDIT ((3)' M T W T F S S ') (A);

DO I = 0 TO 5;

PUT SKIP EDIT (A(I,*), B(I,*), C(I,*)) (7 A, X(2));

END;

END;



PREPARE_MONTH: PROCEDURE (START, MONTH);

DECLARE MONTH(0:5,0:6) CHARACTER (3);

DECLARE START CHARACTER (8);

DECLARE I PIC 'ZZ9';

DECLARE OFFSET FIXED;

DECLARE (J, DAY) FIXED BINARY (31);

DECLARE (THIS_MONTH, NEXT_MONTH, K) FIXED BINARY;



DAY = DAYS(START, 'DDMMYYYY');

OFFSET = WEEKDAY(DAY) - 1;

IF OFFSET = 0 THEN OFFSET = 7;

MONTH = '';

DO J = DAY BY 1;

THIS_MONTH = SUBSTR(DAYSTODATE(J, 'DDMMYYYY'), 3, 2);

NEXT_MONTH = SUBSTR(DAYSTODATE(J+1, 'DDMMYYYY'), 3, 2);

IF THIS_MONTH^= NEXT_MONTH THEN LEAVE;

END;

I = 1;

DO K = OFFSET-1 TO OFFSET+J-DAY-1;

MONTH(K/7, MOD(K,7)) = I; I = I + 1;

END;

END PREPARE_MONTH;



END CALENDAR;

See CALENDAR for result.



#CI(MODULE NAME-OF-THIS-FILE RACKET

(REQUIRE RACKET/DATE)

(DEFINE (CALENDAR YR)

(DEFINE (NSPLIT N L) (IF (NULL? L) L (CONS (TAKE L N) (NSPLIT N (DROP L N)))))

(DEFINE MONTHS

(FOR/LIST ([MN (IN-NATURALS 1)]

[MNAME '(JANUARY FEBRUARY MARCH APRIL MAY JUNE JULY

AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER)])

(DEFINE S (FIND-SECONDS 0 0 12 1 MN YR))

(DEFINE PFX (DATE-WEEK-DAY (SECONDS->DATE S)))

(DEFINE DAYS

(LET ([? (IF (= MN 12) (Λ(X Y) Y) (Λ(X Y) X))])

(ROUND (/ (- (FIND-SECONDS 0 0 12 1 (? (+ 1 MN) 1) (? YR (+ 1 YR))) S)

60 60 24))))

(LIST* (~A MNAME #:WIDTH 20 #:ALIGN 'CENTER) "SU MO TU WE TH FR SA"

(MAP STRING-JOIN

(NSPLIT 7 `(,@(MAKE-LIST PFX " ")

,@(FOR/LIST ([D DAYS])

(~A (+ D 1) #:WIDTH 2 #:ALIGN 'RIGHT))

,@(MAKE-LIST (- 42 PFX DAYS) " ")))))))

(LET* ([S '(" 11,-~4-._3. 41-4! 10/ ()=(2) 3\\ 40~A! 9( 3( 80 39-4! 10\\._\\"

", ,-4'! 5#[email protected]! 12/ 2-3'~2;! 11/ 4/~2|-! 9=( 3~4 2|! 3/~42\\! "

"2/_23\\! /_25\\!/_27\\! 3|_20|! 3|_20|! 3|_20|! 3| 20|!!")]

[S (REGEXP-REPLACE* "!" (STRING-APPEND* S) "~%")]

[S (REGEXP-REPLACE* "@" S (STRING-FOLDCASE "X"))]

[S (REGEXP-REPLACE* ".(?:[1-7][0-9]*|[1-9])" S

(Λ(M) (MAKE-STRING (STRING->NUMBER (SUBSTRING M 1))

(STRING-REF M 0))))])

(PRINTF S YR))

(FOR-EACH (COMPOSE1 DISPLAYLN STRING-TITLECASE)

(DROPF-RIGHT (FOR*/LIST ([3MS (NSPLIT 3 MONTHS)] [S (APPLY MAP LIST 3MS)])

(REGEXP-REPLACE " +$" (STRING-JOIN S " ") ""))

(Λ(S) (EQUAL? "" S)))))



(CALENDAR 1969))



(formerly Perl 6) Uppercase is no challenge, who needs letters at all? [Requires the year to be supplied as a command-line argument, and Unixish cal command.]

$_ = " \0 " .. "~" ;<

115 97 121 32 34 91 73 78 83 69 82 84 32 83 78 79 79 80 89 32 72 69 82 69 93 34

59 114 117 110 32 60 99 97 108 62 44 64 42 65 82 71 83 91 48 93 47 47 49 57 54 57

>. "$_[99]$_[104]$_[114]$_[115]" ( ) . "$_[69]$_[86]$_[65]$_[76]" ( )

This is essentially the same REXX program as for the CALENDAR task, but written entirely in uppercase. Indeed,

it could be written without any Latin (or any language) letters of any kind for the REXX program's variables.

From the task's description, I took it to mean the program was to be in all uppercase, but the output was

still supposed to look pretty (that is, partly in lowercase). Even so, on the (line) printers that were used

long ago, the printers (if not supporting lowercase), would print lowercase as uppercase (with the FOLD option).

The other REXX program made use of lowercase letters for determining the minimum length of any of the options

(from the command line), and a few simple tricks were used to accomplish this.

[Note: the command line may also be all uppercase.]

This version automatically will use the depth and width of the terminal screen to determine which layout fits best.

However, the depth and width can be overridden with the depth and width keywords.

In any case, both versions of the programs' output are identical (but the second REXX version sure as heck looks

like it was beat with a big ole ugly stick ─── and pardon the strong language).

/*REXX PROGRAM TO SHOW ANY YEAR'S (MONTHLY) CALENDAR (WITH/WITHOUT GRID)*/

@ABC=

PARSE VALUE SCRSIZE ( ) WITH SD SW .

DO J= 0 TO 255 ;_= D2C ( J ) ; IF DATATYPE ( _, 'L' ) THEN @[email protected] || _; END

@[email protected]; UPPER @ABCU

DAYS_= 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY'

MONTHS_= 'JANUARY FEBRUARY MARCH APRIL MAY JUNE JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER'

DAYS=; MONTHS=

DO J= 1 FOR 7

_= LOWER ( WORD ( DAYS_,J ) )

DAYS=DAYS TRANSLATE ( LEFT ( _, 1 ) ) SUBSTR ( _, 2 )

END

DO J= 1 FOR 12

_= LOWER ( WORD ( MONTHS_,J ) )

MONTHS=MONTHS TRANSLATE ( LEFT ( _, 1 ) ) SUBSTR ( _, 2 )

END

CALFILL= ' ' ; MC= 12 ; _= '1 3 1234567890' "FB" X

PARSE VAR _ GRID CALSPACES # CHK . CV_ DAYS . 1 DAYS . 2 DAYS . 3 DAYSN

_= 0 ; PARSE VAR _ COLS 1 JD 1 LOWERCASE 1 MAXKALPUTS 1 NARROW 1 ,

NARROWER 1 NARROWEST 1 SHORT 1 SHORTER 1 SHORTEST 1 ,

SMALL 1 SMALLER 1 SMALLEST 1 UPPERCASE

PARSE ARG MM '/' DD "/" YYYY _ '(' OPS; UOPS=OPS

IF _ \ == '' | \ IS# ( MM ) | \ IS# ( DD ) | \ IS# ( YYYY ) THEN CALL ERX 86



@CALMONTHS = 'CALMON' || LOWER ( 'THS' )

@CALSPACES = 'CALSP' || LOWER ( 'ACES' )

@DEPTH = 'DEP' || LOWER ( 'TH' )

@GRIDS = 'GRID' || LOWER ( 'S' )

@LOWERCASE = 'LOW' || LOWER ( 'ERCASE' )

@NARROW = 'NAR' || LOWER ( 'ROW' )

@NARROWER = 'NARROWER'

@NARROWEST = 'NARROWES' || LOWER ( 'T' )

@SHORT = 'SHOR' || LOWER ( 'T' )

@SHORTER = 'SHORTER'

@SHORTEST = 'SHORTES' || LOWER ( 'T' )

@UPPERCASE = 'UPP' || LOWER ( 'ERCASE' )

@WIDTH = 'WID' || LOWER ( 'TH' )

DO WHILE OPS \ == '' ; OPS= STRIP ( OPS, 'L' ) ; PARSE VAR OPS _1 2 1 _ . 1 _O OPS

UPPER _

SELECT

WHEN ABB ( @CALMONTHS ) THEN MC=NAI ( )

WHEN ABB ( @CALSPACES ) THEN CALSPACES=NAI ( )

WHEN ABB ( @DEPTH ) THEN SD=NAI ( )

WHEN ABBN ( @GRIDS ) THEN GRID=NO ( )

WHEN ABBN ( @LOWERCASE ) THEN LOWERCASE=NO ( )

WHEN ABBN ( @NARROW ) THEN NARROW=NO ( )

WHEN ABBN ( @NARROWER ) THEN NARROWER=NO ( )

WHEN ABBN ( @NARROWEST ) THEN NARROWEST=NO ( )

WHEN ABBN ( @SHORT ) THEN SHORT=NO ( )

WHEN ABBN ( @SHORTER ) THEN SHORTER=NO ( )

WHEN ABBN ( @SHORTEST ) THEN SHORTEST=NO ( )

WHEN ABBN ( @SMALL ) THEN SMALL=NO ( )

WHEN ABBN ( @SMALLER ) THEN SMALLER=NO ( )

WHEN ABBN ( @SMALLEST ) THEN SMALLEST=NO ( )

WHEN ABBN ( @UPPERCASE ) THEN UPPERCASE=NO ( )

WHEN ABB ( @WIDTH ) THEN SW=NAI ( )

OTHERWISE NOP

END /*SELECT*/

END /*DO WHILE OPTS\== ...*/



IF SD== 0 THEN SD= 43 ; SD= SD- 3

IF SW== 0 THEN SW= 80 ; SW= SW- 1

MC=INT ( MC, 'MONTHSCALENDER' ) ; IF MC > 0 THEN CAL= 1

DAYS= ' ' DAYS; MONTHS= ' ' MONTHS

CYYYY= RIGHT ( DATE ( ) , 4 ) ; HYY= LEFT ( CYYYY, 2 ) ; LYY= RIGHT ( CYYYY, 2 )

DY . = 31 ; _= 30 ; PARSE VAR _ DY . 4 1 DY . 6 1 DY . 9 1 DY . 11; DY . 2= 28 +LY ( YYYY )

YY= RIGHT ( YYYY, 2 ) ; CW= 10 ; CINDENT= 1 ; CALWIDTH= 76

IF SMALL THEN DO ; NARROW= 1 ; SHORT= 1 ; END

IF SMALLER THEN DO ; NARROWER= 1 ; SHORTER= 1 ; END

IF SMALLEST THEN DO ; NARROWEST= 1 ; SHORTEST= 1 ; END

IF SHORTEST THEN SHORTER= 1

IF SHORTER THEN SHORT = 1

IF NARROW THEN DO ; CW= 9 ; CINDENT= 3 ; CALWIDTH= 69 ; END

IF NARROWER THEN DO ; CW= 4 ; CINDENT= 1 ; CALWIDTH= 34 ; END

IF NARROWEST THEN DO ; CW= 2 ; CINDENT= 1 ; CALWIDTH= 20 ; END

CV_=CALWIDTH+CALSPACES+ 2

CALFILL= LEFT ( COPIES ( CALFILL,CW ) ,CW )

DO J= 1 FOR 7 ; _= WORD ( DAYS,J )

DO JW= 1 FOR 3 ; _D= STRIP ( SUBSTR ( _,CW * JW-CW+ 1 ,CW ) )

IF JW= 1 THEN _D= CENTRE ( _D,CW+ 1 )

ELSE _D= LEFT ( _D,CW+ 1 )

DAYS . JW=DAYS . JW || _D

END /*JW*/

__=DAYSN

IF NARROWER THEN DAYSN=__ || CENTRE ( LEFT ( _, 3 ) , 5 )

IF NARROWEST THEN DAYSN=__ || CENTER ( LEFT ( _, 2 ) , 3 )

END /*J*/

_YYYY=YYYY; CALPUTS= 0 ; CV= 1 ; _MM=MM+ 0 ; MONTH= WORD ( MONTHS,MM )

DY . 2= 28 +LY ( _YYYY ) ; DIM=DY . _MM; _DD=01; DOW=DOW ( _MM,_DD,_YYYY ) ; $DD=DD+ 0



/*─────────────────────────────NOW: THE BUSINESS OF THE BUILDING THE CAL*/

CALL CALGEN

DO _J= 2 TO MC

IF CV_ \ == '' THEN DO

CV=CV+CV_