--- title: "Appointment Calendar" id: 56662 type: "computer_media" slug: "appointment-calendar" url: "http://localhost/computer_media/appointment-calendar/" markdown_url: "http://localhost/computer_media/appointment-calendar.md" published_at: "2024-09-22T23:31:36+00:00" modified_at: "2026-04-03T07:59:02+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/CALENDAR.png" excerpt: "A complete month-at-a-glance appointment calendar storing up to eight entries per day, with tape save and printer output built right in." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "Heath Computer Services" slug: "heath-computer-services" taxonomy: "post_tag" url: "http://localhost/tag/heath-computer-services/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Home" slug: "home" taxonomy: "genre" url: "http://localhost/type/home/" media_type: "Cassette" download_url: "https://archive.org/download/timex-sinclair-software-archive/Appointment%20Calendar%281982%29%28Heath%20CS%29%28TS1000%29%28US%29%28Program%29.zip" mediadate: "1982" producer_company: - id: 10929 title: "Heath Computer Services" type: "company" url: "http://localhost/company/heath-computer-services/" images: - url: "http://localhost/wp-content/uploads/2024/09/CALENDAR.png" - url: "http://localhost/wp-content/uploads/2024/09/CA_INS1-scaled.jpg" - url: "http://localhost/wp-content/uploads/2024/09/CAL_INS2-scaled.jpg" - url: "http://localhost/wp-content/uploads/2024/09/CALENDAR.jpg" related_products: - id: 11780 title: "Appointment Calendar" type: "product" url: "http://localhost/product/appointment-calendar/" media_type_tags: "Home" --- # Appointment Calendar This program implements a monthly appointment calendar allowing up to eight appointments per day across 31 days. It stores appointments in eight parallel string arrays (A$ through H$), each dimensioned 31×32, using a 32-character blank string as a sentinel value to detect empty slots. The program supports entering, viewing, editing, and deleting appointments interactively, as well as saving the entire calendar to tape and printing individual days or the full month via LPRINT. Navigation uses INKEY$ polling for menu selection and INPUT for text entry, with option 9 in the day-view triggering immediate printer output. *** ## Program Analysis ### Program Structure The program is organized into several distinct functional regions: 1. **Lines 10–100:** Variable and array initialization — numeric array `X(31)` (unused after setup), blank string `U$`, and eight 31×32 string arrays. 2. **Lines 110–380:** Title/splash screen, month input, and main menu with INKEY$ dispatch. 3. **Lines 390–900:** Day selection and appointment entry loop (slots A$–H$). 4. **Lines 910–1010:** Tape save routine. 5. **Lines 1020–1500:** Day viewer with inline edit/delete and optional LPRINT output. 6. **Lines 1510–1570:** Entry prompt subroutine and blank-entry guard. 7. **Lines 1580–1700:** Full-month print loop. 8. **Lines 1710–2020:** Eight individual LPRINT subroutines, one per appointment slot. 9. **Lines 2500–2510:** Auto-save and restart block. ### Data Storage Design Appointments are held in eight parallel string arrays `A$()` through `H$()`, each dimensioned `(31,32)`, giving 32 characters per appointment slot per day. The 32-character string `U$` (32 spaces) serves as a sentinel: a slot equal to `U$` is considered empty. This is a straightforward but memory-hungry approach — eight arrays of 31×32 characters consume approximately 7,936 bytes of string storage alone, which is a significant portion of the 16 KB RAM available on an unexpanded machine. The numeric array `X(31)` declared at line 10 is never actually used for data storage; the day number is instead held in the numeric variable `X` entered by the user. The array allocation is therefore wasted memory. ### Menu and Navigation The main menu at lines 220–380 uses an INKEY$ polling loop (lines 320–330) rather than INPUT, avoiding the need for the user to press ENTER. Invalid key presses fall through to `GOTO 0220`, re-drawing the menu. The leading zeros in `GOTO 0320`, `GOTO 0390`, etc. are cosmetic — BASIC ignores them — but they were a common stylistic convention to pad line number references to a consistent width. ### Appointment Entry Flow Lines 460–850 implement a sequential slot-filling loop. Each of the eight slots is checked in order: if the slot is not blank (i.e., already contains an appointment), it is skipped; if it is blank, the entry subroutine (line 1510) is called and user input is stored. The guard subroutine at line 1560 checks whether the entered string `I$` is empty, and if so jumps back to the day-selection prompt at line 390, effectively allowing the user to stop entering appointments early by pressing ENTER with no text. If all eight slots fill up, line 870 prints a “IS FULL” message. ### Day View, Edit, and Print The day viewer at lines 1020–1500 displays all eight slots with numeric labels and waits for an INKEY$ keypress. Pressing `9` reprints the screen while simultaneously sending each non-blank slot to the printer via LPRINT. Pressing `0` returns to the menu. Pressing digits 1–8 prompts for a replacement string at lines 1390–1410; pressing ENTER with an empty input effectively deletes the appointment because an empty INPUT on a string variable returns a zero-length string, which will no longer equal `U$` — meaning the slot will display as blank but will still not be treated as empty by the sentinel check. This is a subtle bug: deleted entries are replaced with an empty string `""` rather than `U$`, so the “slot full” logic and the print-all loop will incorrectly treat them as occupied. ### Print-All Subroutine Redundancy Lines 1710–2020 consist of eight near-identical LPRINT subroutines, each printing the month name, day number, one appointment string, and a blank line. This block could have been collapsed into a single parameterized subroutine, but the ZX81 BASIC dialect makes passing parameters to subroutines awkward, so the repetition is understandable given the constraints. Together these subroutines account for over 300 lines of essentially duplicated code. ### Notable Techniques and Idioms - INKEY$ polling loop (`IF M$="" THEN GOTO 0320`) used for single-keypress menu selection without requiring ENTER. - Blank string sentinel (`U$` = 32 spaces) for detecting empty array slots, a common ZX81 idiom since arrays are pre-filled with spaces. - Option `M$="2"` (Look at a date) shares the same day-entry input block (line 390) as option 1, with the branch to the viewer at line 450 — the code path diverges only after the day number is entered. - The variable `I$` is reused for multiple purposes: appointment text during entry, a print-trigger flag (`"9"`) in the viewer, and a dummy INPUT variable at line 890 for a “press ENTER to continue” pause. - `SAVE T$` at line 1000 saves the entire program and variable space (including all calendar data) under the name entered by the user, providing simple persistence. ### Bugs and Anomalies | Location | Issue | | --- | --- | | Lines 460–850 (skip logic) | Slots already containing data are skipped rather than appended after, meaning re-entering a day skips to the first empty slot but also skips editing existing entries in the entry path. | | Lines 1420–1490 (delete) | Replacing an appointment with an empty INPUT sets the slot to `""`, not `U$`. The sentinel check (`<>U$`) will then treat the slot as occupied, causing it to appear in print-all output as a blank line. | | Line 10 | `DIM X(31)` allocates a numeric array that is never used, wasting approximately 128 bytes of RAM. | | Line 1040 | On first entry to the viewer, `I$` may hold stale content from a previous interaction, potentially triggering unexpected LPRINT output. | ## Source Code ``` 10 DIM X(31) 20 LET U$=" " 30 DIM A$(31,32) 40 DIM B$(31,32) 50 DIM C$(31,32) 60 DIM D$(31,32) 70 DIM E$(31,32) 80 DIM F$(31,32) 90 DIM G$(31,32) 100 DIM H$(31,32) 110 CLS 120 PRINT AT 2,8; "ZX81/TIMEX 1000" 130 PRINT AT 3,6;"APPOINTMENT CALENDAR" 140 PRINT AT 4,14;"BY" 150 PRINT AT 5,4;"HEATH COMPUTER SERVICES" 160 PRINT AT 6,7;"950 EAST 52 SOUTH" 170 PRINT AT 7,9;"GREENTOWN IN." 180 PRINT AT 8,12;"46936" 190 PRINT AT 10,8;"COPYRIGHT 1982" 200 PRINT AT 18,8;"(ENTER MONTH)" 210 INPUT S$ 220 CLS 230 PRINT "********************************" 240 PRINT AT 2,10;S$ 250 PRINT AT 6,6;"DO YOU WANT TO--" 260 PRINT AT 10,3;"(1)ENTER APPOINTMENTS" 270 PRINT AT 11,3;"(2)LOOK AT A DATE" 280 PRINT AT 12,3;"(3)SAVE CALENDAR ON TAPE" 290 PRINT AT 13,3;"(4)PRINT CALENDAR" 300 PRINT AT 16,6;"PRESS NO. 1-4" 310 PRINT AT 20,0;"********************************" 320 LET M$=INKEY$ 330 IF M$="" THEN GOTO 0320 340 IF M$="1" THEN GOTO 0390 350 IF M$="2" THEN GOTO 0390 360 IF M$="3" THEN GOTO 0910 370 IF M$="4" THEN GOTO 1580 380 GOTO 0220 390 CLS 400 PRINT AT 8,8;"ENTER THE DAY" 410 PRINT AT 18,6;"ENTER (0) FOR MENU" 420 INPUT X 430 IF X=0 THEN GOTO 0220 440 IF X>31 THEN GOTO 0390 450 IF M$="2" THEN GOTO 1020 460 IF A$(X)<>U$ THEN GOTO 0510 470 GOSUB 1510 480 INPUT I$ 490 GOSUB 1560 500 LET A$(X)=I$ 510 IF B$(X)<>U$ THEN GOTO 0560 520 GOSUB 1510 530 INPUT I$ 540 GOSUB 1560 550 LET B$(X)=I$ 560 IF C$(X)<>U$ THEN GOTO 0610 570 GOSUB 1510 580 INPUT I$ 590 GOSUB 1560 600 LET C$(X)=I$ 610 IF D$(X)<>U$ THEN GOTO 0660 620 GOSUB 1510 630 INPUT I$ 640 GOSUB 1560 650 LET D$(X)=I$ 660 IF E$(X)<>U$ THEN GOTO 0710 670 GOSUB 1510 680 INPUT I$ 690 GOSUB 1560 700 LET E$(X)=I$ 710 IF F$(X)<>U$ THEN GOTO 0760 720 GOSUB 1510 730 INPUT I$ 740 GOSUB 1560 750 LET F$(X)=I$ 760 IF G$(X)<>U$ THEN GOTO 0810 770 GOSUB 1510 780 INPUT I$ 790 GOSUB 1560 800 LET G$(X)=I$ 810 IF H$(X)<>U$ THEN GOTO 0860 820 GOSUB 1510 830 INPUT I$ 840 GOSUB 1560 850 LET H$(X)=I$ 860 CLS 870 PRINT AT 10,5;S$;" ";X;" IS FULL" 880 PRINT AT 20,2;" PRESS TO CONTINUE" 890 INPUT I$ 900 GOTO 0390 910 CLS 920 PRINT "POSITION TAPE" 930 PRINT 940 PRINT "TYPE (MONTH)" 950 PRINT 960 PRINT "PRESS PLAY AND RECORD ON RECORDER" 970 PRINT 980 PRINT "PRESS WHEN READY" 990 INPUT T$ 1000 SAVE T$ 1010 GOTO 0110 1020 CLS 1030 PRINT AT 1,8;S$;" ";X; 1040 IF I$="9" THEN LPRINT S$;" ";X 1050 PRINT 1060 IF I$="9" THEN LPRINT 1070 PRINT "1" 1080 PRINT A$(X) 1090 IF I$="9" AND A$(X)<>U$ THEN LPRINT A$(X) 1100 PRINT "2" 1110 PRINT B$(X) 1120 IF I$="9" AND B$(X)<>U$ THEN LPRINT B$(X) 1130 PRINT "3" 1140 PRINT C$(X) 1150 IF I$="9" AND C$(X)<>U$ THEN LPRINT C$(X) 1160 PRINT "4" 1170 PRINT D$(X) 1180 IF I$="9" AND D$(X)<>U$ THEN LPRINT D$(X) 1190 PRINT "5" 1200 PRINT E$(X) 1210 IF I$="9" AND E$(X)<>U$ THEN LPRINT E$(X) 1220 PRINT "6" 1230 PRINT F$(X) 1240 IF I$="9" AND F$(X)<>U$ THEN LPRINT F$(X) 1250 PRINT "7" 1260 PRINT G$(X) 1270 IF I$="9" AND G$(X)<>U$ THEN LPRINT G$(X) 1280 PRINT "8" 1290 PRINT H$(X) 1300 IF I$="9" AND H$(X)<>U$ THEN LPRINT H$(X) 1310 PRINT 1320 IF I$="9" THEN LPRINT 1330 PRINT "PRESS (0)FOR MENU (9)TO PRINT" 1340 PRINT "PRESS CORRESPONDING NUMBER TO CHANGE OR DELETE" 1350 LET I$=INKEY$ 1360 IF I$="" THEN GOTO 1350 1370 IF I$="9" THEN GOTO 1020 1380 IF I$="0" THEN GOTO 0220 1390 PRINT AT 19,0;"PRESS TO DELETE " 1400 PRINT "ENTER NEW APPOINTMENT " 1410 INPUT J$ 1420 IF I$="1" THEN LET A$(X)=J$ 1430 IF I$="2" THEN LET B$(X)=J$ 1440 IF I$="3" THEN LET C$(X)=J$ 1450 IF I$="4" THEN LET D$(X)=J$ 1460 IF I$="5" THEN LET E$(X)=J$ 1470 IF I$="6" THEN LET F$(X)=J$ 1480 IF I$="7" THEN LET G$(X)=J$ 1490 IF I$="8" THEN LET H$(X)=J$ 1500 GOTO 1020 1510 CLS 1520 PRINT AT 2,6;S$;" ";X 1530 PRINT AT 4,0;"ENTER NEXT APPOINTMENT" 1540 PRINT AT 6,0;"PRESS WHEN FINISHED." 1550 RETURN 1560 IF I$="" THEN GOTO 0390 1570 RETURN 1580 CLS 1590 PRINT AT 9,9;"PRINTING" 1600 FOR X=1 TO 31 1610 IF A$(X)<>U$ THEN GOSUB 1710 1620 IF B$(X)<>U$ THEN GOSUB 1750 1630 IF C$(X)<>U$ THEN GOSUB 1790 1640 IF D$(X)<>U$ THEN GOSUB 1830 1650 IF E$(X)<>U$ THEN GOSUB 1870 1660 IF F$(X)<>U$ THEN GOSUB 1910 1670 IF G$(X)<>U$ THEN GOSUB 1950 1680 IF H$(X)<>U$ THEN GOSUB 1990 1690 NEXT X 1700 GOTO 0220 1710 LPRINT S$;" ";X 1720 LPRINT A$(X) 1730 LPRINT 1740 RETURN 1750 LPRINT S$;" ";X 1760 LPRINT B$(X) 1770 LPRINT 1780 RETURN 1790 LPRINT S$;" ";X 1800 LPRINT C$(X) 1810 LPRINT 1820 RETURN 1830 LPRINT S$;" ";X 1840 LPRINT D$(X) 1850 LPRINT 1860 RETURN 1870 LPRINT S$;" ";X 1880 LPRINT E$(X) 1890 LPRINT 1900 RETURN 1910 LPRINT S$;" ";X 1920 LPRINT F$(X) 1930 LPRINT 1940 RETURN 1950 LPRINT S$;" ";X 1960 LPRINT G$(X) 1970 LPRINT 1980 RETURN 1990 LPRINT S$;" ";X 2000 LPRINT H$(X) 2010 LPRINT 2020 RETURN 2500 SAVE "CALENDA%R" 2510 GOTO 0010 ```