Mail List

Date: 198x
Type: Program
Platform(s): TS 2068

This program is a mailing-list manager for a Timex/Sinclair User Group (T/SUG) based in Fort Worth, Texas, 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:

LinesPurpose
1–2Load machine-code file, POKE printer patch bytes
3–8Variable documentation (REM), string constants, DIM arrays
9–80Main menu display and dispatch loop
1000–1060Compile membership list (keyboard input)
2000–2580Print/view membership list
3000–3080Compile T/SUG address list
4000–4590Print/view T/SUG list
5000–5080Print return address labels
6000–6160Load both DATA files from tape
7000–7060Save both DATA files to tape
8000–8060Save 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.

Content

Appears On

This tape is a compilation of programs from user group members (Robert Burton, David Baulch, Frank Bouldin, Chuck Dawson, Ryan

Related Products

Related Articles

Related Content

Image Gallery

Mail List

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;"<ENTER> 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 <ENTER> 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 <ENTER> 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 <ENTER> to ""SAVE"" file 1";d$
 7030 SAVE a$ DATA m$()
 7040 INPUT "Press <ENTER> 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 <ENTER> to ""SAVE"" program ";d$
 8030 SAVE "mail list" LINE 1
 8040 INPUT "Press <ENTER> to ""SAVE"" ""pr"" CODE";d$
 8050 SAVE "pr"CODE 64256,1111
 8060 RETURN 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top