This program implements a monthly calendar manager that allows users to set up a calendar for any named month, view it on screen, enter and search appointments, and save data to cassette or Micro Wafer. The calendar grid is stored in a 42-element array C() mapping week positions to day numbers, with up to 155 appointments held in parallel arrays P() (day numbers) and E$() (25-character event strings). Navigation throughout the program uses a cursor-highlight idiom driven by INKEY$ polling rather than INPUT, with inverse-video characters marking the selected menu option. Special holidays are hard-coded: July 4th and December 25th are displayed in inverse video on the calendar grid. A machine-code routine is invoked via RAND USR 13082 to handle Micro Wafer saves.
Program Analysis
Program Structure
The program is organised into clearly labelled subroutines, each beginning at a round line number. The flow starts at line 100 (main menu), which dispatches to one of four major modules via the computed GOSUB (L*100)+100 at line 490. The modules are:
- Lines 500–595 — Month setup: collects month name, first day of week, and number of days.
- Lines 600–650 — Calendar array builder.
- Lines 700–770 — Calendar display.
- Lines 900–970 — Appointment entry.
- Lines 1100–1160 — Save to cassette or Micro Wafer.
- Lines 2000–2880 — Calendar view/navigation hub with sub-menus.
- Lines 3000–3510 — First-letter event search.
- Lines 4000–5070 — Day item display and item editing.
- Lines 6000–6810 — On-screen cursor navigation to select a calendar day.
- Lines 7000–7020 — Save-and-restart routine.
Lines 25–50 contain array dimension statements that are jumped over by GOTO 100 at line 20; they are executed only when called as a subroutine (via GOSUB 25 at line 501), re-dimensioning arrays before a new month is set up. The RETURN at line 50 closes that subroutine.
Data Structures
| Variable | Type | Purpose |
|---|---|---|
C(42) | Numeric array | Calendar grid: 42 cells (6 weeks × 7 days), each holds the day-of-month number or 0 for empty cells |
P(155) | Numeric array | Day number for each appointment |
E$(155,25) | String array | Event text, up to 25 characters per appointment |
M$(3) | String array | 3-character month abbreviation (e.g. “JAN”) |
S$(1) | String | Single-character search key for first-letter event lookup |
ANUM | Scalar | Next free appointment slot index (1-based) |
F | Scalar | First day of month (1=Sun … 7=Sat) |
END | Scalar | Computed last cell index in C() for the month |
Calendar Array Construction
Lines 600–650 fill the C() array. Cells 1 to F-1 are set to 0 (days before the 1st of the month), cells F to END receive ascending day numbers starting at 1, and any remaining cells up to 42 are zeroed. The variable END is adjusted at line 555: LET END=END+F-1 converts the raw number-of-days into a final array index that accounts for the starting offset.
INKEY$-Based Menu Navigation
All menus use a polling loop rather than INPUT, reading INKEY$ repeatedly. Keys “5” (up) and “8” (down) move a highlight cursor; CHR$ 118 (ENTER/NEWLINE) confirms the selection. The current selection position is tracked in variables L, LL, or LX depending on the menu. The main menu (lines 455–475) moves a two-character inverse-video marker (%=%>) up and down in steps of 2 screen rows, clamped between rows 4 and 10, and dispatches via the computed GOSUB (L*100)+100.
On-Screen Day Selector (Lines 6000–6810)
A block-graphic cursor (\''\'`, a 2×2 block) is moved over the printed calendar grid using the four cursor keys (5/6/7/8). Columns are spaced 4 apart (matching the STEP 4 in the calendar printer at line 720) and rows 2 apart (STEP 2 at line 715). On ENTER, the subroutine at line 6050 performs a reverse-mapping: it iterates through the same nested loop structure as the calendar printer, counting positions until the cursor coordinates match, yielding an index into C() from which the actual day number is recovered. If the cursor is on an empty cell the subroutine returns DAY=0.
Special Holiday Highlighting
Lines 726–727 hard-code two holidays with inverse-video display: July 4th (M$="JUL" and C(X)=4) and December 25th (M$="DEC" and C(X)=25). These checks occur inside the calendar printing loop immediately after the normal day number is printed, overwriting the cell with an inverse-video version.
Machine Code for Micro Wafer
Line 1150 invokes RAND USR 13082 to save data to a Timex Micro Wafer unit. Address 13082 is a known entry point in the Micro Wafer Interface ROM. The standard SAVE M$ at line 1155 handles cassette storage, using the month abbreviation as the tape filename.
Event Search
The search routine (lines 3000–3260) accepts a single character via S$ and iterates through all ANUM appointments comparing E$(X,1) against it. Matching entries are printed with their day number and event text. When the display reaches row 21, subroutine 3200 pauses and clears the screen to handle overflow, then continues from the same loop position — though note the FAST/SLOW calls and the CLS inside the overflow handler at line 3235 mean the outer loop at line 3055 continues printing from the top of the new page without resetting X, which is correct behaviour.
Item Editing (Lines 5000–5070)
The change-item routine prompts for an index number (INDEX) and directly overwrites P(INDEX) and E$(INDEX) with new INPUT values. There is no bounds check on INDEX against ANUM, so entering an out-of-range value would silently corrupt unrelated array cells or produce an error.
Notable Anomalies
- Line 2050 (
GOTO 700) is unreachable — execution can never fall through from line 2040’s unconditionalGOTO 2020to line 2050. It appears to be a leftover stub. - The variable name
ENDis used as a plain numeric variable (lines 545–555). While not a reserved word in this dialect, it is an unusual choice that could cause confusion. - Lines 2030 and 2035 check
INKEY$=CHR$ 118and dispatch toLL*1000. WithLLranging 3–5, this resolves to lines 3000, 4000, or 5000 — but line 5000 is the change-item subroutine, seemingly not intended as a direct destination from this menu path. - The cursor erase in the main menu prints two spaces at
AT L-2,0andAT L+2,0before drawing atAT L,0, meaning the previous cursor position is only erased if it is exactly two rows away; rapid key presses could leave ghost characters. GOSUB 25at line 501 re-dimensions all arrays, which resets appointment data. This is intentional for setting up a new month, but any previously entered appointments are silently discarded.
Content
Source Code
1 REM CALENDAR PROGRAMME
2 REM COPYRIGHT 30-OCT-86
3 REM VERS 1.6, £ A101
4 REM BY: M. FELERSKI
5 LET ANUM=1
7 LET MENU=100
10 DIM M$(3)
20 GOTO 100
25 DIM W(7,5)
30 DIM C(42)
35 DIM P(155)
40 DIM E$(155,25)
45 DIM S$(1)
50 RETURN
100 LET L=4
400 REM MAIN MENU
405 CLS
407 SLOW
410 PRINT "%C%A%L%E%N%D%A%R% %F%O%R% %M%O%N%T%H%:"
415 PRINT AT 0,21;M$
420 REM MAIN MENU CHOICES
430 PRINT
435 PRINT AT 4,2;" SET UP NEW MONTH"
440 PRINT AT 6,2;" VIEW MONTH/ITEMS"
445 PRINT AT 8,2;" ENTER NEW ITEMS"
450 PRINT AT 10,2;" SAVE MONTH TO TAPE/WAFER"
455 PRINT AT L-2,0;" "
457 PRINT AT L+2,0;" "
460 PRINT AT L,0;"%=%>"
465 IF INKEY$="6" THEN LET L=L+2
467 IF INKEY$="7" THEN LET L=L-2
469 IF INKEY$=CHR$ 118 THEN GOTO 490
470 IF L>10 THEN LET L=10
473 IF L<4 THEN LET L=4
475 GOTO 455
490 GOSUB (L*100)+100
495 GOTO 405
500 REM SETUP QUESTIONS
501 GOSUB 25
503 CLS
504 PRINT AT 0,1;"%C%L%E%A%R% %A%N%D% %S%E%T% %U%P% %A% %N%E%W% %M%O%N%T%H"
505 PRINT AT 6,0;"ENTER 3 CHAR. MONTH NAME:"
507 LET ANUM=1
510 INPUT M$
515 PRINT AT 6,27;M$
520 PRINT AT 8,2;"ENTER FIRST DAY OF MONTH:"
525 PRINT AT 10,0;"%I%.%E%. SUN=1, MON=2, TUE=3, ETC,"
530 INPUT F
535 PRINT AT 8,28;F
540 PRINT AT 12,0;"ENTER NUMBER OF DAYS IN MONTH:"
545 INPUT END
555 LET END=END+F-1
560 GOSUB 600
595 RETURN
600 REM SET UP CALENDAR, F=DAY1
603 FAST
605 FOR I=1 TO F-1
610 LET C(I)=0
615 NEXT I
617 LET J=1
620 FOR I=F TO END
625 LET C(I)=J
630 LET J=J+1
635 NEXT I
640 FOR I=(END+1) TO 42
645 LET C(I)=0
647 NEXT I
650 RETURN
700 REM PRINT CALENDER
703 CLS
705 FAST
707 PRINT AT 0,12;"% % ";M$;"% % "
710 PRINT AT 2,2;"SUN MON TUE WED THR FRI SAT"
712 LET X=1
715 FOR I=4 TO 14 STEP 2
720 FOR J=3 TO 27 STEP 4
725 IF C(X)<>0 THEN PRINT AT I,J;C(X)
726 IF (M$="JUL") AND (C(X)=4) THEN PRINT AT I,J;"%4"
727 IF (M$="DEC") AND (C(X)=25) THEN PRINT AT I,J;"%2%5"
730 IF C(X)=0 THEN PRINT AT I,J;" "
735 LET X=X+1
740 NEXT J
745 NEXT I
747 SLOW
750 GOTO 2000
760 REM RETURN TO MAIN MENU
770 RETURN
900 REM ENTER NEW ITEMS
905 CLS
910 PRINT "%E%N%T%E%R% %N%E%W% %A%P%P%O%I%N%T%M%E%N%T%S%:";M$
911 PRINT AT 19,0;"%T%Y%P%E 0 %F%O%R% %D%A%Y% %T%O% %E%X%I%T"
912 LET D=2
915 IF ANUM>155 THEN GOTO 960
920 PRINT AT 21,0;"%E%N%T%E%R% %D%A%Y% %O%F% %T%H%E% %M%O%N%T%H"
925 INPUT P(ANUM)
927 IF P(ANUM)=0 THEN RETURN
930 PRINT AT 21,0;"ENTER EVENT (25 CHAR) "
935 INPUT E$(ANUM)
940 LET D=D+1
945 PRINT AT D,0;P(ANUM);AT D,3;E$(ANUM,1 TO 25)
947 LET ANUM=ANUM+1
948 IF ANUM>155 THEN GOTO 960
950 IF D=18 THEN GOTO 905
955 GOTO 915
960 PRINT AT 21,0;"PROGRAM IS FULL--SORRY "
965 PAUSE 220
970 RETURN
1100 REM SAVE ROUTINE
1105 CLS
1107 LET L=6
1110 PRINT AT 0,0;"%D%A%T%A% %S%T%O%R%A%G%E% %M%E%N%U"
1115 PRINT AT 6,2;" SAVE TO CASSETTE"
1120 PRINT AT 8,2;" SAVE TO MICRO WAFER"
1123 PRINT AT L,0;"%=%>"
1125 IF INKEY$="6" THEN LET L=8
1130 IF INKEY$="7" THEN LET L=6
1135 IF INKEY$=CHR$ 118 THEN GOTO 1150
1137 IF L=8 THEN PRINT AT 6,0;" "
1139 IF L=6 THEN PRINT AT 8,0;" "
1140 GOTO 1123
1150 IF L=8 THEN RAND USR 13082
1155 IF L=6 THEN SAVE M$
1160 RETURN
2000 REM CHOOSE YOUR VIEWING
2003 LET LL=4
2005 GOSUB 2600
2020 IF INKEY$="5" THEN GOSUB 2500
2025 IF INKEY$="8" THEN GOSUB 2800
2030 IF (INKEY$=CHR$ 118) AND (LL<>5) THEN GOTO LL*1000
2035 IF (INKEY$=CHR$ 118) AND (LL=5) THEN GOTO 760
2040 GOTO 2020
2050 GOTO 700
2500 IF LL>3 THEN LET LL=LL-1
2505 IF LL=3 THEN GOSUB 2550
2510 IF LL=4 THEN GOSUB 2600
2520 RETURN
2550 PRINT AT 21,0;"%F%I%N%D% %E%V%E%N%T"
2560 PRINT AT 21,12;"VIEW DAY"
2570 PRINT AT 21,22;"MAIN MENU"
2580 RETURN
2600 PRINT AT 21,0;"FIND EVENT"
2610 PRINT AT 21,12;"%V%I%E%W% %D%A%Y"
2620 PRINT AT 21,22;"MAIN MENU"
2630 RETURN
2800 IF LL<5 THEN LET LL=LL+1
2805 IF LL=4 THEN GOSUB 2600
2810 IF LL=5 THEN GOSUB 2850
2820 RETURN
2850 PRINT AT 21,0;"FIND EVENT"
2860 PRINT AT 21,12;"VIEW DAY"
2870 PRINT AT 21,22;"%M%A%I%N% %M%E%N%U"
2880 RETURN
3000 REM FIND ITEM
3005 CLS
3010 PRINT AT 0,0;"%F%I%N%D% %E%V%E%N%T% %F%O%R%: ";M$
3015 PRINT AT 2,0;"ENTER THE FIRST LETTER"
3020 PRINT "OF THE EVENT YOU ARE"
3025 PRINT "SEARCHING FOR. THERE"
3030 PRINT "WILL BE A SHORT PAUSE"
3035 PRINT "DURING THE SEARCH....."
3040 INPUT S$
3045 FAST
3047 CLS
3050 PRINT AT 0,0;"%D%A%Y%/%E%V%E%N%T%S% %F%O%U%N%D% % % %I%N%: ";M$
3052 LET Y=2
3055 FOR X=1 TO ANUM
3060 IF E$(X,1)=S$ THEN PRINT AT Y,0;P(X);AT Y,5;E$(X)
3065 IF E$(X,1)=S$ THEN LET Y=Y+1
3070 IF Y>21 THEN GOSUB 3200
3075 NEXT X
3080 SLOW
3095 GOTO 3300
3200 PRINT AT 21,0;"%T%Y%P%E% %E%N%T%E%R% %T%O% %C%O%N%T%I%N%U%E"
3205 SLOW
3210 IF INKEY$=CHR$ 118 THEN GOTO 3230
3220 GOTO 3210
3230 FAST
3235 CLS
3240 LET Y=2
3255 PRINT AT 0,0;"%F%I%N%D% %E%V%E%N%T% %F%O%R%: ";M$
3260 RETURN
3300 REM SEARCH CHOICES
3310 LET LX=1
3315 GOSUB 3400
3320 IF INKEY$="5" THEN GOSUB 3500
3325 IF INKEY$="8" THEN GOSUB 3400
3330 IF INKEY$=CHR$ 118 THEN GOTO 3350
3340 GOTO 3320
3350 IF LX=2 THEN GOTO 2050
3355 IF LX=1 THEN GOTO 3000
3400 PRINT AT 21,3;"REPEAT";AT 21,17;"%C%A%L%E%N%D%A%R"
3405 LET LX=2
3410 RETURN
3500 PRINT AT 21,3;"%R%E%P%E%A%T";AT 21,17;"CALENDAR"
3505 LET LX=1
3510 RETURN
4000 REM ITEM DISPLAY
4002 GOSUB 6000
4003 IF DAY=0 THEN GOTO 2050
4004 CLS
4005 FAST
4007 PRINT AT 0,0;"%I%N%D%E%X%/%E%V%E%N%T%S% %F%O%R% %D%A%Y ";DAY;" %O%F ";M$
4010 LET TOT=1
4020 FOR X=1 TO ANUM
4030 IF P(X)=DAY THEN GOSUB 4200
4040 IF TOT=6 THEN GOTO 4060
4050 NEXT X
4060 SLOW
4070 LET LX=3
4080 GOSUB 4500
4100 IF INKEY$="5" THEN GOSUB 4600
4110 IF INKEY$="8" THEN GOSUB 4700
4120 IF (INKEY$=CHR$ 118) AND (LX=1) THEN GOSUB 5000
4125 IF (INKEY$=CHR$ 118) AND (LX=2) THEN COPY
4130 IF (INKEY$=CHR$ 118) AND (LX=3) THEN GOTO 2050
4140 GOTO 4100
4200 REM DISPLAY
4210 PRINT AT TOT*2,0;X;")"
4215 PRINT AT TOT*2,5;E$(X,1 TO 25)
4220 LET TOT=TOT+1
4230 RETURN
4300 PRINT AT 21,0;"%C%H%A%N%G%E% %I%T%E%M";AT 21,14;"COPY";AT 21,21;"CALENDAR"
4320 RETURN
4400 PRINT AT 21,0;"CHANGE ITEM";AT 21,14;"%C%O%P%Y";AT 21,21;"CALENDAR"
4420 RETURN
4500 PRINT AT 21,0;"CHANGE ITEM";AT 21,14;"COPY";AT 21,21;"%C%A%L%E%N%D%A%R"
4520 RETURN
4600 IF LX>1 THEN LET LX=LX-1
4610 IF LX=1 THEN GOSUB 4300
4620 IF LX=2 THEN GOSUB 4400
4630 RETURN
4700 IF LX<3 THEN LET LX=LX+1
4710 IF LX=2 THEN GOSUB 4400
4720 IF LX=3 THEN GOSUB 4500
4730 RETURN
5000 REM CHANGE ITEM
5005 PRINT AT 21,0;"ENTER EVENT %I%N%D%E%X NUMBER: "
5010 INPUT INDEX
5015 PRINT AT 21,0;"< CHANGE ON EVENT ABOVE >"
5020 PRINT AT 19,3;E$(INDEX,1 TO 25)
5025 PAUSE 160
5030 PRINT AT 21,0;"< ENTER NEW EVENT DATA: >"
5035 PAUSE 160
5040 PRINT AT 21,0;"< ENTER DAY > "
5045 INPUT P(INDEX)
5050 PRINT AT 21,0;"< ENTER EVENT (25 CHAR) >"
5052 INPUT E$(INDEX)
5055 PRINT AT 14,0;INDEX;")";"DAY: ";P(INDEX)
5060 PRINT AT 15,3;E$(INDEX)
5061 PRINT AT 19,3;" "
5062 PRINT AT 21,0;" "
5065 GOSUB 4300
5070 RETURN
6000 REM CHOOSE DAY
6005 LET A=5
6007 LET B=3
6010 PRINT AT A,B;"''''"
6015 IF INKEY$="5" THEN GOSUB 6500
6020 IF INKEY$="6" THEN GOSUB 6600
6025 IF INKEY$="7" THEN GOSUB 6700
6030 IF INKEY$="8" THEN GOSUB 6800
6035 IF INKEY$=CHR$ 118 THEN GOTO 6050
6040 GOTO 6010
6050 REM GET DAY
6052 PRINT AT 21,0;" DAY CHOSEN "
6053 PAUSE 20
6055 LET X=1
6060 FOR I=4 TO 14 STEP 2
6065 FOR J=3 TO 27 STEP 4
6070 IF ((A-1)=I) AND (B=J) THEN GOTO 6100
6072 LET X=X+1
6075 NEXT J
6080 NEXT I
6085 PRINT AT 18,0;"BAD INPUT"
6087 PAUSE 30
6089 PRINT AT 18,0;" "
6090 LET DAY=0
6095 RETURN
6100 LET Y=1
6101 IF C(Y)<>0 THEN GOTO 6104
6102 LET Y=Y+1
6103 GOTO 6101
6104 LET DAY=X-Y+1
6105 IF DAY<1 THEN GOTO 6110
6106 IF (X>0) AND (X<(END+1)) THEN RETURN
6110 PRINT AT 18,0;"BAD INPUT, TRY AGAIN"
6115 PAUSE 120
6120 PRINT AT 18,0;" "
6122 PRINT AT 21,0;" "
6125 IF INKEY$=CHR$ 118 THEN GOTO 6135
6130 GOTO 6010
6135 LET DAY=0
6140 RETURN
6500 IF B=3 THEN GOTO 6510
6502 PRINT AT A,B;" "
6505 LET B=B-4
6510 RETURN
6600 IF A>=14 THEN GOTO 6610
6602 PRINT AT A,B;" "
6605 LET A=A+2
6610 RETURN
6700 IF A<=5 THEN GOTO 6710
6702 PRINT AT A,B;" "
6705 LET A=A-2
6710 RETURN
6800 IF B=27 THEN GOTO 6810
6802 PRINT AT A,B;" "
6805 LET B=B+4
6810 RETURN
7000 REM SAVE AND BEGIN ROUTINE
7010 SAVE "CALENDE%R"
7020 GOTO 2
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.





