--- title: "Mail List" id: 64540 type: "computer_media" slug: "mail-list" url: "http://localhost/computer_media/mail-list/" markdown_url: "http://localhost/computer_media/mail-list.md" published_at: "2026-03-02T02:14:42+00:00" modified_at: "2026-03-30T21:43:34+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/03/SCR-20260301-sjuu.png" excerpt: "A complete tape-based mailing-list manager for a T/S user group, with member records, label printing, and a machine-code printer patch all bundled together." 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/" genre: - name: "Database" slug: "database" taxonomy: "genre" url: "http://localhost/type/database/" media_contents: - id: 60550 title: "Fort Worth TS2068 Club Library Tape" type: "computer_media" url: "http://localhost/computer_media/fort-worth-ts2068-club-library-tape/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Fort%20Worth%20US%20Maillist%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/03/SCR-20260301-sjuu.png" related_content: - id: 24819 title: "Timex/Sinclair Users Group Of Fort Worth" type: "usergroup" url: "http://localhost/usergroup/timex-sinclair-users-group-of-fort-worth/" media_type_tags: "Database" --- # Mail List This program is a mailing-list manager for a [Timex/Sinclair User Group (T/SUG) based in Fort Worth, Texas](http://localhost/usergroup/timex-sinclair-users-group-of-fort-worth/), storing up to 50 member records of 90 characters each and up to 20 T/SUG records of 120 characters each in two fixed-length string arrays. An eight-option menu dispatches to subroutines via the idiom `GO SUB c*1000`, where the user’s numeric choice directly computes the target line number. The program loads a companion machine-code file at startup (line 1) and POKEs two bytes at addresses 26703–26704, likely to redirect or patch the LPRINT routine for a specific printer interface. Data is persisted to tape as named DATA files (`SAVE “Members” DATA m$()` / `SAVE “T/S U.G.” DATA g$()`), and the program itself plus the printer machine-code block (`SAVE “pr” CODE 64256,1111`) can also be saved from within the menu. *** ## Program Structure The program is organized around a central menu loop occupying lines 1–80, with eight subroutine blocks each anchored at a multiple of 1000: | Lines | Purpose | | --- | --- | | 1–2 | Load machine-code file, POKE printer patch bytes | | 3–8 | Variable documentation (REM), string constants, DIM arrays | | 9–80 | Main menu display and dispatch loop | | 1000–1060 | Compile membership list (keyboard input) | | 2000–2580 | Print/view membership list | | 3000–3080 | Compile T/SUG address list | | 4000–4590 | Print/view T/SUG list | | 5000–5080 | Print return address labels | | 6000–6160 | Load both DATA files from tape | | 7000–7060 | Save both DATA files to tape | | 8000–8060 | Save program and printer machine-code block | ## Key BASIC Idioms **Computed GO SUB:** Line 60 uses `GO SUB c*1000`, where `c` is the user’s menu choice (1–8). This elegantly maps each integer directly to its subroutine entry point without a chain of `IF` statements, and is validated by the range check at line 50. **Fixed-length string array slicing:** Both arrays use fixed 30-character field widths packed into a single string row. For example, `m$(n, TO 30)` is the name field, `m$(n,31 TO 60)` is the address, and `m$(n,61 TO )` is the city/state/ZIP. This is a classic database-in-a-DIM technique that avoids the overhead of separate arrays. **Record-count recovery after LOAD:** Because the DATA file always fills all 50 (or 20) rows, lines 6030–6070 iterate through the array after loading and count non-blank first characters to reconstruct the active record count into `m` (and similarly `g`). This compensates for the fact that a simple `LOAD DATA` restores raw bytes with no embedded length metadata. ## Machine Code Usage Line 1 loads an unnamed CODE block from tape immediately on startup. Lines 2 POKEs addresses `26703` and `26704` with values `5` and `251` respectively. Address 26703 (0x684F) falls in the upper RAM / system variable region and the two-byte value `0xFB05` is consistent with patching a jump or pointer — most likely redirecting the LPRINT channel to a specific printer interface port, a common requirement for third-party TS2068 printer add-ons. Line 8050 saves the machine-code block back to tape: `SAVE "pr" CODE 64256,1111`. The start address 64256 (0xFB00) is in the high RAM / ROM shadow area, further confirming this is a small printer driver residing near the top of RAM. ## Data Storage Design - `DIM m$(50,90)` — 50 members × 90 characters = 4,500 bytes for the membership array. - `DIM g$(20,120)` — 20 T/SUG entries × 120 characters = 2,400 bytes; each entry has four 30-character address lines. - Arrays are saved and loaded by name: `SAVE "Members" DATA m$()` and `SAVE "T/S U.G." DATA g$()`, matching the string constants in `a$` and `b$`. - The program itself is saved with `SAVE "mail list" LINE 1`, causing auto-run from line 1 on reload. ## Return Label Printing Subroutine 5000 computes `z=m+g` (line 5000) to determine how many return address labels are needed — one for each member and one for each T/SUG entry — then LPRINTs the same hard-coded “T/SUG of Fort Worth, Texas / David Baulch / 4424 Geddes Ave. / Fort Worth, TX 76107” block `z` times. This is a simple but effective mailshot technique. ## View/Print Toggle Logic Both the membership (lines 2000–2580) and T/SUG (lines 4000–4590) output sections share an identical pattern: the user first chooses View or Print; View mode displays records on screen then offers a prompt that can loop back to redisplay (`N`), proceed to print (`Y`), or return to the menu (`M`). The `GO TO 2020` / `GO TO 4020` jumps re-enter the LPRINT loop after a screen-view session, avoiding code duplication for the print path. ## Source Code ``` 1 CLS : PRINT AT 10,6; FLASH 1;"DO NOT STOP THE TAPE"; FLASH 0: LOAD ""CODE 2 POKE 26703,5: POKE 26704,251 3 REM Variables used- n,i,l,r=used for loops; b,d=used for counters; c=used for gosub to reach sub- routines; z=m+g for return labels; m=number of members; g=number of T/SUG's 4 LET t$="Mail List" 5 LET a$="Members" 6 LET b$="T/S U.G." 7 DIM m$(50,90) 8 DIM g$(20,120) 9 CLS 10 PRINT INVERSE 1;AT 2,(32-LEN t$)/2;t$ 20 PRINT AT 4,4;"1) Compile Membership List";AT 6,4;"2) Print Membership List";AT 8,4;"3) Compile T/S U.G. List";AT 10,4;"4) Print T/S U.G. List";AT 12,4;"5) Print Return Labels";AT 14,4;"6) Load Data Files";AT 16,4;"7) Save Data Files";AT 18,4;"8) Save Program Logic" 30 PRINT FLASH 1;AT 20,6;" Your Choice." 40 INPUT c 50 IF c<1 OR c>8 THEN GO TO 40 60 CLS : GO SUB c*1000 70 GO TO 9 80 STOP 1000 PRINT "How many people are on the"'"membership list? ": INPUT m 1010 CLS : FOR n=1 TO m 1020 INPUT "Name: ";m$(n, TO 30): PRINT n;".";m$(n, TO 30) 1030 INPUT "Address: ";m$(n,31 TO 60): PRINT m$(n,31 TO 60) 1040 INPUT "City, State, ZIP Code: ";m$(n,61 TO ): PRINT m$(n,61 TO ) 1050 PRINT : NEXT n 1060 RETURN 2000 PRINT "Would you like to (V)iew the","list or (P)rint the list? (V/P)": INPUT q$ 2010 IF q$="V" OR q$="v" THEN GO TO 2500 2020 FOR n=1 TO m 2030 LPRINT m$(n, TO 30) 2040 LPRINT m$(n,31 TO 60) 2050 LPRINT m$(n,61 TO ) 2060 LPRINT : LPRINT : LPRINT 2070 NEXT n 2080 RETURN 2500 CLS : FOR n=1 TO m 2510 PRINT m$(n, TO 30) 2520 PRINT m$(n,31 TO 60) 2530 PRINT m$(n,61 TO ) 2540 PRINT 2550 NEXT n 2560 INPUT "PRINT? (Y/N) OR M FOR MENU ";q$ 2570 IF q$="N" OR q$="n" THEN GO TO 2500 2575 IF q$="M" OR q$="m" THEN RETURN 2580 GO TO 2020 3000 PRINT "How many people are on the"'"T/S U.G. list? ": INPUT g 3010 CLS : FOR i=1 TO g 3020 INPUT "Address Line 1: ";g$(i, TO 30): PRINT i;".";g$(i, TO 30) 3030 INPUT "Address Line 2: ";g$(i,31 TO 60): PRINT g$(i,31 TO 60) 3040 INPUT "Address Line 3: ";g$(i,61 TO 90): PRINT g$(i,61 TO 90) 3050 INPUT "Address Line 4: ";g$(i,91 TO ): PRINT g$(i,91 TO ) 3060 PRINT 3070 NEXT i 3080 RETURN 4000 PRINT "Would you like to (V)iew the"'"list or (P)rint the list? (V/P)": INPUT q$ 4010 IF q$="V" OR q$="v" THEN GO TO 4500 4020 FOR i=1 TO g 4030 LPRINT g$(i, TO 30) 4040 LPRINT g$(i,31 TO 60) 4050 LPRINT g$(i,61 TO 90) 4060 LPRINT g$(i,91 TO ) 4070 LPRINT : LPRINT 4080 NEXT i 4090 RETURN 4500 CLS : FOR i=1 TO g 4510 PRINT g$(i, TO 30) 4520 PRINT g$(i,31 TO 60) 4530 PRINT g$(i,61 TO 90) 4540 PRINT g$(i,91 TO ) 4550 PRINT 4560 NEXT i 4570 INPUT "PRINT? (Y/N) OR M FOR MENU ";q$ 4580 IF q$="N" OR q$="n" THEN GO TO 4500 4585 IF q$="M" OR q$="m" THEN RETURN 4590 GO TO 4020 5000 LET z=m+g 5010 FOR r=1 TO z 5020 LPRINT "T/SUG of Fort Worth, Texas" 5030 LPRINT "David Baulch" 5040 LPRINT "4424 Geddes Ave." 5050 LPRINT "Fort Worth, TX 76107" 5060 LPRINT : LPRINT 5070 NEXT r 5080 RETURN 6000 PRINT "Press to ""LOAD"" the"'"membership list.": INPUT d$ 6010 LOAD a$ DATA m$() 6020 LET b=0 6030 FOR l=1 TO 50 6040 IF m$(l,1)=" " THEN GO TO 6060 6050 LET b=b+1 6060 NEXT l 6070 LET m=b 6080 CLS : PRINT "Press to ""LOAD"" the"'"T/S U.G. list.": INPUT d$ 6090 LOAD b$ DATA g$() 6100 LET d=0 6110 FOR l=1 TO 20 6120 IF g$(l,1)=" " THEN GO TO 6140 6130 LET d=d+1 6140 NEXT l 6150 LET g=d 6160 RETURN 7000 PRINT "Set recorder up for a ""SAVE""."''"Put a new tape in the recorder." 7010 PRINT : PRINT "You will be saving two data"''"files. The first is the member-"''"ship list, and the second is the"''"T/S U.G. list." 7020 INPUT "Press to ""SAVE"" file 1";d$ 7030 SAVE a$ DATA m$() 7040 INPUT "Press to ""SAVE"" file 2";d$ 7050 SAVE b$ DATA g$() 7060 RETURN 8000 PRINT "Set recorder up for a ""SAVE""."''"Put a new tape in the recorder." 8010 PRINT : PRINT "You will be saving two parts of"''"the program. The first is the"''"program it self and the second"''"is the ""printer"" code." 8020 INPUT "Press to ""SAVE"" program ";d$ 8030 SAVE "mail list" LINE 1 8040 INPUT "Press to ""SAVE"" ""pr"" CODE";d$ 8050 SAVE "pr"CODE 64256,1111 8060 RETURN ```