--- title: "MenuE" id: 55087 type: "computer_media" slug: "menue" url: "http://localhost/computer_media/menue/" markdown_url: "http://localhost/computer_media/menue.md" published_at: "2024-06-14T10:55:37+00:00" modified_at: "2026-03-31T18:26:20+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A single-keypress disk-directory manager stores up to 24 labeled boxes of 20 entries each, with add, delete, and move operations in a packed string array." 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: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Bob Swoger (K9WVY)" slug: "bob-swoger" taxonomy: "indiv" url: "http://localhost/indiv/bob-swoger/" genre: - name: "Database" slug: "database" taxonomy: "genre" url: "http://localhost/type/database/" media_type: "Program" programmers: - name: "Bob Swoger (K9WVY)" slug: "bob-swoger" taxonomy: "indiv" url: "http://localhost/indiv/bob-swoger/" download_url: "https://archive.org/download/timex-sinclair-software-archive/MenuE%20%28198x%29%28Swoger%2C%20Bob%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" media_type_tags: "Database" --- MenuE is a disk-directory manager that Bob Swoger wrote to organize his 24 boxes of disks. Each box held 20 named slots stored in a large string array, allowing Bob to add, delete, and move entries between boxes via single-keypress commands. The program uses a packed string storage scheme where each box occupies 260 characters in the master string G$, with each slot consuming 13 characters, accessed through arithmetic index expressions. Two user-defined graphics are defined at startup — UDG “a” with an alternating checkerboard pattern via BIN literals and UDG “b” as a stylized diagonal shape — used to fill the background billboard display. Screen layout relies on POKE 23659 to suppress the lower editing area during prompts, and POKE 23562/23609/23658 to configure display behavior at startup. The SAVE section includes a VERIFY pass with audible BEEP cues to confirm tape integrity. *** ## Program Analysis ### Program Structure The program is organized into clearly labeled subroutine blocks, each prefixed with a REM line. The main flow begins at line 8000 (initialization), proceeds to the billboard display at line 9010, then enters an input loop at line 9120. Navigation between sections is driven entirely by single-keypress detection. | Line Range | Section | | --- | --- | | 710–720 | Entry point and paper setup | | 810–820 | PROMPT subroutine | | 910–930 | DISPLAY subroutine | | 1010–1050 | ADD section | | 2010–2030 | ERASE/DELETE section | | 3010–3140 | MOVE section | | 4010–4090 | LPRINT section | | 8010–8280 | Initialization and UDG definition | | 9010–9360 | Billboard display and main key loop | | 9991–9999 | SAVE/VERIFY section | ### Data Storage Scheme All directory entries are stored in a single large string `G$` (dimensioned externally as `DIM G$(6241)`, commented out at line 8020). The layout packs 24 boxes × 260 characters each. Within each box, 20 slots of 13 characters each occupy the first 260 characters. The index formula used throughout is: - Slot start: `((I*260)-258)+((J*13)-13)` - Slot end: `((I*260)-259)+(J*13)` Where `I` is the box number (1–24) and `J` is the slot number (1–20). The display section also reads a second column of entries offset by `(J+B)*13`, suggesting each box stores two parallel columns of 10 entries. ### Variable Roles | Variable | Role | | --- | --- | | `A` | Constant 0 (reused as zero) | | `B` | Constant 10 (slots per column) | | `C` | Constant 20 (total slots per box) | | `D` | Constant 1 (lower bound / step) | | `E` | Constant 2 (row multiplier) | | `I` | Current box number (1–13 active range, 24 max) | | `J` | Current slot number | | `G$` | Master directory string (packed storage) | | `S$` | Temporary slot title string (12 chars) | ### Key BASIC Idioms The program makes extensive use of `VAL "number"` in place of numeric literals for constants assigned to variables at initialization (line 8030). This is a recognized memory-saving technique, as string tokens consume less tokenized storage than numeric literals in certain contexts. The main input loop at line 9130 uses `INKEY$` in a tight polling loop rather than `INPUT`, providing immediate single-keypress response without requiring Enter. Multiple keys are mapped to the same action (e.g., `"7"`, `"D"`, `"0"`, `"-"` all invoke DELETE), accommodating different keyboard layouts or preferences. `POKE 23659` is used to control the lower screen area: setting it to `A` (0) suppresses the prompt line, and setting it to `E` (2) restores it, bracketing PRINT statements that write to line 22. ### UDG Definitions Two UDGs are defined at startup. UDG `"a"` is built with alternating `BIN 10101010` and `BIN 01010101` rows in a loop (lines 8110–8140), producing a checkerboard texture. Note that the loop runs `H=0 TO 7` but writes to both `USR "a"+H` and `USR "a"+(H+1)`, meaning the 8th row is overwritten and the pattern cycles correctly across 8 bytes. UDG `"b"` is defined with hand-coded BIN values (lines 8210–8280) producing a diagonal or stylized glyph. The billboard fill at line 9040 prints 32 copies of UDG `\a` per row across 22 rows, creating a textured background. The border is then drawn over this with PLOT/DRAW calls forming a double-rectangle frame (line 9060). ### Navigation Logic Box navigation wraps around: pressing the “next” key (mapped to `"8"` and `"N"`) increments `I` and wraps at 13 back to 1 (line 9110). The “previous” key (mapped to `"5"`) decrements and wraps at 1 back to 13 (line 9350). The active browse range is thus boxes 1–13 rather than the full 1–24, with the upper boxes only reachable via the MOVE operation’s direct INPUT. ### LPRINT Section Lines 4010–4090 iterate over all 13 browsable boxes and use `LPRINT` with `AT` positioning to produce a formatted printed directory listing. This mirrors the screen display logic from the DISPLAY subroutine but outputs to a printer rather than the screen. ### Bugs and Anomalies - Line 9160 maps `"D"` to `GO TO 2000` (DELETE), but `"D"` more intuitively suggests “Down” or another navigation action; the prompt at line 820 labels the option as “Delete,” so this is intentional though mnemonic-ambiguous. - The `DIM S$(12)` at line 8020 allocates 12 characters for the title, but the slot storage formula writes 13 characters (`J*13` span). The extra character may serve as a delimiter or padding byte, but the off-by-one between DIM and the index range could cause string-length mismatches on assignment. - Line 3110 validates `J` and jumps to `3170` on failure, but line 3170 does not exist in the listing — this would cause a runtime error on an out-of-range slot entry in MOVE mode. - `GO TO VAL "9000"` at line 9999 targets line 9000, which does not exist in the listing; execution would fall through to the next available line (9010), which is the billboard redraw — this is likely intentional. ## Source Code ``` 710 REM MENUE 720 PAPER VAL "7": GO TO 8000 810 REM PROMPT Section 820 POKE 23659,A: PRINT AT 22,A; INK A; PAPER VAL "4";'" Add Delete Move Next Save": POKE 23659,E: RETURN 910 REM DISPLAY Section 920 PRINT AT A,13; FLASH D;"BOX ";AT A,17+(IC THEN GO TO 1020 1030 INPUT " TITLE?";S$ 1040 IF S$(D)=" " THEN GO TO 1030 1050 LET G$(((I*260)-258)+((J*13)-13) TO ((I*260)-259)+(J*13))=S$: GO TO 3130 2010 REM ERASE Section 2020 INPUT " DELETE MODE - SLOT(1 - 20)?";J: IF JC THEN GO TO 2020 2030 LET G$(((I*260)-258)+((J*13)-13) TO ((I*260)-259)+(J*13))="": GO TO 3130 3010 REM MOVE Section 3020 INPUT " MOVE FROM SLOT(1 - 20)?";J: IF JC THEN GO TO 3020 3030 LET S$=G$(((I*260)-258)+((J*13)-13) TO ((I*260)-259)+(J*13)) 3040 INPUT " DELETE FROM OLD SLOT?";Y$ 3050 IF Y$(1)="Y" THEN LET G$(((I*260)-258)+((J*13)-13) TO ((I*260)-259)+(J*13))="" 3080 INPUT " MOVE TO BOX(1 - 24)?";I 3090 GO SUB 900 3110 INPUT " MOVE INTO SLOT(1 - 20)?";J: IF JC THEN GO TO 3170 3120 LET G$(((I*260)-258)+((J*13)-13) TO ((I*260)-259)+(J*13))=S$ 3130 GO SUB 820 3140 GO TO 9120 4010 REM LPRINT Section 4020 FOR I=D TO 13 4040 LPRINT AT A,13;"BOX ";AT A,17+(I13 THEN LET I=D 9120 GO SUB 900 9130 LET I$=INKEY$: IF I$="" THEN GO TO 9130 9140 IF I$="A" THEN GO TO 1000 9150 IF I$="7" THEN GO TO 2000 9160 IF I$="D" THEN GO TO 2000 9170 IF I$="M" THEN GO TO 3000 9180 IF I$="Z" THEN COPY 9190 IF I$="P" THEN COPY 9210 IF I$="K" THEN GO TO 4000 9220 IF I$="L" THEN GO TO 4000 9230 IF I$="S" THEN GO TO 9990 9240 IF I$="0" THEN GO TO 2000 9250 IF I$="6" THEN GO TO 3000 9260 IF I$="-" THEN GO TO 2000 9270 IF I$="+" THEN GO TO 1000 9280 IF I$="5" THEN GO TO 9350 9290 IF I$="8" THEN GO TO 9110 9310 IF I$="C" THEN GO TO 4000 9320 IF I$="V" THEN GO TO 4000 9330 IF I$<>"N" THEN GO TO 9130 9340 GO TO 9110 9350 LET I=I-D: IF I<1 THEN LET I=13 9360 GO TO 9120 9991 REM SAVE Section 9992 BEEP .15,5 9993 SAVE "MENUE" LINE 8000 9994 BEEP .042,50: PAUSE 2.8: BEEP .042,50 9995 POKE 23659,A: PRINT PAPER 4;''" Rewind & Play tape to VERIFY ": POKE 23659,E: PRINT AT A,A; 9996 VERIFY "MENUE" 9997 BEEP .042,50: PAUSE 2.8: BEEP .042,50 9999 GO TO VAL "9000" ```