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.




        .MODEL  TINY
        .CODE
        .486
        ORG     100H            ;.COM FILES START HERE
YEAR    EQU     1969            ;DISPLAY CALENDAR FOR SPECIFIED YEAR
START:  MOV     CX, 61          ;SPACE(61);  TEXT(0, "[SNOOPY]");  CRLF(0)
        CALL    SPACE
        MOV     DX, OFFSET SNOOPY
        CALL    TEXT
        MOV     CL, 63          ;SPACE(63);  INTOUT(0, YEAR);  CRLF(0);  CRLF(0)
        CALL    SPACE
        MOV     AX, YEAR
        CALL    INTOUT
        CALL    CRLF
        CALL    CRLF
 
        MOV     DI, 1           ;FOR MONTH:= 1 TO 12 DO         DI=MONTH
L22:    XOR     SI, SI          ; FOR COL:= 0 TO 6-1 DO         SI=COL
L23:    MOV     CL, 5           ;  SPACE(5)
        CALL    SPACE
        MOV     DX, DI          ;  TEXT(0, MONAME(MONTH+COL-1));  SPACE(7);
        DEC     DX              ;  DX:= (MONTH+COL-1)*10+MONAME
        ADD     DX, SI
        IMUL    DX, 10
        ADD     DX, OFFSET MONAME
        CALL    TEXT
        MOV     CL, 7
        CALL    SPACE
        CMP     SI, 5           ;  IF COL<5 THEN SPACE(1);
        JGE     L24
         MOV    CL, 1
         CALL   SPACE
         INC    SI
         JMP    L23
L24:    CALL    CRLF
 
        MOV     SI, 6           ; FOR COL:= 0 TO 6-1 DO
L25:    MOV     DX, OFFSET SUMO ;  TEXT(0, "SU MO TU WE TH FR SA");
        CALL    TEXT
        DEC     SI              ;   IF COL<5 THEN SPACE(2);
        JE      L27
         MOV    CL, 2
         CALL   SPACE
         JMP    L25
L27:    CALL    CRLF
 
        XOR     SI, SI          ;FOR COL:= 0 TO 6-1 DO
L28:    MOV     BX, DI          ;DAY OF FIRST SUNDAY OF MONTH (CAN BE NEGATIVE)
        ADD     BX, SI          ;DAY(COL):= 1 - WEEKDAY(YEAR, MONTH+COL, 1);
        MOV     BP, YEAR
 
;DAY OF WEEK FOR FIRST DAY OF THE MONTH (0=SUN 1=MON..6=SAT)
        CMP     BL, 2           ;IF MONTH<=2 THEN
        JG      L3
         ADD    BL, 12          ; MONTH:= MONTH+12;
         DEC    BP              ; YEAR:= YEAR-1;
L3:
;REM((1-1 + (MONTH+1)*26/10 + YEAR + YEAR/4 + YEAR/100*6 + YEAR/400)/7)
        INC     BX              ;MONTH
        IMUL    AX, BX, 26
        MOV     CL, 10
        CWD
        IDIV    CX
        MOV     BX, AX
        MOV     AX, BP          ;YEAR
        ADD     BX, AX
        SHR     AX, 2
        ADD     BX, AX
        MOV     CL, 25
        CWD
        IDIV    CX
        IMUL    DX, AX, 6       ;YEAR/100*6
        ADD     BX, DX
        SHR     AX, 2           ;YEAR/400
        ADD     AX, BX
        MOV     CL, 7
        CWD
        IDIV    CX
        NEG     DX
        INC     DX
        MOV     [SI+DAY], DL    ;COL+DAY
        INC     SI
        CMP     SI, 5
        JLE     L28
 
        MOV     BP, 6           ;FOR LINE:= 0 TO 6-1 DO         BP=LINE
L29:    XOR     SI, SI          ; FOR COL:= 0 TO 6-1 DO         SI=COL
L30:    MOV     BX, DI          ;  DAYMAX:= DAYS(MONTH+COL);
        MOV     BL, [BX+SI+DAYS]
 
;IF MONTH+COL=2 & (REM(YEAR/4)=0 & REM(YEAR/100)#0 ! REM(YEAR/400)=0) THEN
        MOV     AX, DI          ;MONTH
        ADD     AX, SI
        CMP     AL, 2
        JNE     L32
        MOV     AX, YEAR
        TEST    AL, 03H
        JNE     L32
        MOV     CL,100
        CWD
        IDIV    CX
        TEST    DX, DX
        JNE     L31
        TEST    AL, 03H
        JNE     L32
L31:     INC    BX              ;IF FEBRUARY AND LEAP YEAR THEN ADD A DAY
L32:
        MOV     DX, 7           ;FOR WEEKDAY:= 0 TO 7-1 DO
L33:    MOVZX   AX, [SI+DAY]    ; IF DAY(COL)>=1 & DAY(COL)<=DAYMAX THEN
        CMP     AL, 1
        JL      L34
        CMP     AL, BL
        JG      L34
        CALL    INTOUT          ; INTOUT(0, DAY(COL));
        CMP     AL, 10          ; IF DAY(COL)<10 THEN SPACE(1); LEFT JUSTIFY
        JGE     L36
         MOV    CL, 1
         CALL   SPACE
        JMP     L36
L34:    MOV     CL, 2           ; ELSE SPACE(2);
        CALL    SPACE           ; SUPPRESS OUT OF RANGE DAYS
L36:    MOV     CL, 1           ; SPACE(1);
        CALL    SPACE
        INC     BYTE PTR [SI+DAY] ; DAY(COL):= DAY(COL)+1;
        DEC     DX              ;NEXT WEEKDAY
        JNE     L33
 
        CMP     SI, 5           ;IF COL<5 THEN SPACE(1);
        JGE     L37
         MOV    CL, 1
         CALL   SPACE
         INC    SI
         JMP    L30
L37:    CALL    CRLF
 
        DEC     BP              ;NEXT LINE DOWN
        JNE     L29
        CALL    CRLF
 
        ADD     DI, 6           ;NEXT 6 MONTHS
        CMP     DI, 12
        JLE     L22
        RET
 
;DISPLAY POSITIVE INTEGER IN AX
INTOUT: PUSHA
        MOV     BX, 10
        XOR     CX, CX
NO10:   CWD
        IDIV    BX
        PUSH    DX
        INC     CX
        TEST    AX, AX
        JNE     NO10
NO20:   MOV     AH, 02H
        POP     DX
        ADD     DL, '0'
        INT     21H
        LOOP    NO20
        POPA
        RET
 
;DISPLAY CX SPACE CHARACTERS
SPACE:  PUSHA
SP10:   MOV     AH, 02H
        MOV     DL, 20H
        INT     21H
        LOOP    SP10
        POPA
        RET
 
;START A NEW LINE
CRLF:   MOV     DX, OFFSET LCRLF
 
;DISPLAY STRING AT DX
TEXT:   MOV     AH, 09H
        INT     21H
        RET
 
SNOOPY  DB      "[SNOOPY]"
LCRLF   DB      0DH, 0AH, '$'
MONAME  DB      " JANUARY $ FEBRUARY$  MARCH  $  APRIL  $   MAY   $   JUNE  $"
        DB      "   JULY  $  AUGUST $SEPTEMBER$  OCTOBER$ NOVEMBER$ DECEMBER$"
SUMO    DB      "SU MO TU WE TH FR SA$"
DAYS    DB      0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
DAY     DB      ?, ?, ?, ?, ?, ?
        END     START