This program manages membership records and finances for a computer users club, specifically the SINclair Computer Users Society based in Johnson City, NY. It uses a three-dimensional string array B$(35,6,32) to store up to 35 member records, each consisting of six 32-character fields covering membership type, name, address, city/state/zip, telephone, computer type, and dues paid. The program loads and saves two machine code blocks from cassette — one at address 57786 (30 bytes) and one at 65368 (168 bytes) — called via RANDOMIZE USR 57786 during receipt printing, likely for printer initialization or control. A prorated dues calculator reads month names from DATA statements and computes the fractional annual dues owed from the member’s join month through July. Menu navigation uses computed GO SUB targets (e.g., GO SUB (VAL Z$*100)+1000) to dispatch to numbered subroutine blocks for new, renewal, update, and review member operations.
Program Analysis
Program Structure
The program is organized into subroutine blocks aligned to hundred-boundaries, with the main initialization starting at line 901. Navigation variables such as Main=200, member=250, money=300, print=350, NAME=80, HEAD=90, and DATA=100 are assigned numeric line-number values so they can be used with GO SUB as readable named labels. The overall flow from line 938 onwards drives a multi-level menu system.
| Line Range | Purpose |
|---|---|
| 80–99 | Header display subroutines (NAME and HEAD) |
| 101–197 | Member data entry (DATA subroutine) |
| 205–399 | Menu display subroutines: Main, Members, Money, Printout |
| 405–460 | Financial review display (subroutine 400) |
| 500–530 | Total dues calculation subroutine |
| 901–950 | Initialization and main dispatch loop |
| 1010–1510 | Members submenu and handlers (New, Renewal, Update, Review) |
| 2005–2510 | Money submenu and handlers (Balance, Incomes, Expenses, Review) |
| 3010–3299 | Printout submenu (print members, print money report) |
| 4005–4999 | Receipt printing via LPRINT |
| 5000–5070 | Record correction subroutine |
| 8005–8100 | Startup information screen |
| 8035–8699 | Month entry and prorated dues calculation |
| 9000–9999 | Cleanup and SAVE routines |
Data Storage
Member records are stored in the three-dimensional string array B$(35,6,32), declared at line 903. This allows up to 35 members, each with 6 fields of 32 characters. The fields per record are packed as follows:
- Record header: membership type + header label + member name + year (line
110) - Full name
- Street address
- City, state, and ZIP
- Telephone number with dues paid amount appended at position 20
- Computer type and payment method (cash or check)
The dues paid amount is embedded in field 5 starting at character position 20 using a slice assignment: LET B$(M,K,20 TO )="$"+C$. It is later extracted at line 515 with VAL B$(G,5,21 TO ), skipping the leading $ sign.
Computed GO SUB Dispatch
Both the Members and Money submenus use computed GO SUB targets to avoid long chains of IF statements. At line 1040, the expression GO SUB (VAL Z$*100)+1000 maps menu choices 1–4 to subroutines at lines 1100, 1200, 1300, and 1400 respectively. Similarly, line 2030 maps money submenu choices to lines 2100–2400 with GO SUB (VAL Z$*100)+2000. This is a compact and efficient dispatch technique for BASIC menu systems.
Machine Code Usage
Two machine code blocks are loaded from cassette at line 901: 30 bytes at address 57786 and 168 bytes at address 65368. They are invoked with RANDOMIZE USR 57786 inside the receipt printing subroutine (lines 4015, 4029, 4100) interspersed with POKE 23607,60 calls. Address 23607 is the system variable PRTCC (printer column counter), so the POKE resets the printer’s column position to 60. The machine code at 57786 likely performs printer-specific formatting or control functions such as sending escape codes.
Prorated Dues Calculation
The subroutine at line 8500 reads month names and offsets from DATA statements. Months are assigned values representing the number of months remaining until July (the club’s fiscal year start), with July itself assigned 12 to handle a full year. Line 8605 calculates prorated dues as INT(8/12*N*100+.05)/100, which multiplies the $8 annual dues by the fractional months remaining, rounds to two decimal places using the standard multiply-by-100/add-epsilon/truncate idiom.
Menu Navigation and Variable Aliasing
Subroutine line numbers are stored in numeric variables (Main, member, money, print, NAME, HEAD, DATA) at line 902–903, allowing calls like GO SUB Main and GO SUB HEAD. This is a well-known BASIC technique for making code more readable while also slightly compressing token storage compared to repeated literal line numbers.
Notable Bugs and Anomalies
- Line
101initializesk=1(lowercase), but line110incrementsK=K+1(uppercase). On this platform, variable names are case-sensitive in stored token form, sokandKare distinct variables. The slice index used in subsequentB$assignments usesK, so the first slice at line110correctly usesk(value 1) but then incrementsK— which is uninitialized (defaults to 0), makingKbecome 1. Subsequent slices useK, so fields 2 onward are written to rows 1–4, leaving field 6 at row 5. This mixed-case variable usage is likely unintentional. - Line
138usesLET B$(M,K, TO LEN C$+4)=C$— assigning a string of lengthLEN C$to a slice of lengthLEN C$+4may cause a mismatch error unless the system silently right-pads. - Line
2350in the expenses routine hasGO TO 2210on “N” answer, which jumps back into the incomes section rather than the expenses re-entry point at2310. This appears to be a copy-paste error from the incomes routine. - Line
944pollsINKEY$in a tight loop to check for keys “1”–”4″, but lines946–950re-checkINKEY$independently. Since the key may no longer be held by the time those checks run, selection “1” (Members) can only proceed by falling through when none of 2, 3, or 4 match — which works correctly in practice but is fragile. - Line
8035usesGO SUB 8030inside the subroutine block starting at8035(called from line936asGO SUB 8030), targeting a non-existent line — execution will fall through to line8035, which is the intended behavior.
UDG Usage
The program uses UDG characters \a through \g (chars 144–150) throughout display strings and LPRINT statements to render a club logo or decorative characters. The UDG shape data is stored in the machine code block loaded at address 65368 (168 bytes = enough for 21 UDGs at 8 bytes each), which is loaded from the “file” CODE block at line 901. Address 65368 is within the standard UDG area for this platform (USR "A" = 65368).
Content
Image Gallery
Source Code
1 REM \a\b\c\d\e\f\g FILE PROGRAM \*by Paul Hill,April 8, 1985
80 PAPER 6: INK 9: PRINT AT 0,4;S$;AT 1,13;YEAR
85 RETURN
90 PAPER 6: INK 9: PRINT AT 0,4;S$
95 PAPER 6: INK 9: PRINT AT 1,(16-(LEN N$+5)/2);N$;" ";YEAR
99 RETURN
101 LET k=1:
102 PRINT AT 2,0;H$'"DUES-$8","PRORATED-$";PRODUES
103 PRINT AT 18,0;;">";"C-Corresponding or R-Regular": PRINT
105 INPUT c$: IF c$<>"C" AND c$<>"R" THEN GO TO 105
110 LET b$(m,k,1 TO 32)=STR$ M+"-"+C$+" "+H$+" "+n$+" "+STR$ YEAR: LET K=K+1
115 PRINT AT 18,1;"ENTER Name- ": PRINT
118 INPUT c$: PRINT AT 4,0;c$: INPUT ;"OK? Y/N";Q$: IF Q$="N" THEN GO TO 115
120 LET B$(M,K, TO LEN C$)=C$: LET K=K+1
122 PRINT AT 18,1;"ADDRESS(STREET)- ": PRINT
124 INPUT C$: PRINT AT 5,0;C$: INPUT "OK? Y/N";Q$: IF Q$="N" THEN GO TO 122
126 LET B$(M,K, TO LEN C$)=C$: LET K=K+1
128 PRINT AT 18,1;"CITY,ST.,ZIP ": PRINT
130 INPUT C$: PRINT AT 6,0;C$: INPUT "OK ? Y/N";Q$: IF Q$="N" THEN GO TO 128
132 LET B$(M,K, TO LEN C$)=C$: LET K=K+1
134 PRINT AT 18,1;"TELEPHONE # ": PRINT
136 INPUT C$: PRINT AT 7,0;C$: INPUT "OK ? Y/N";Q$: IF Q$="N" THEN GO TO 134
138 LET B$(M,K, TO LEN C$+4)=C$
140 PRINT AT 18,1;"DUES PAID ?": PRINT
142 INPUT "AMOUNT-0 IF NO PAY";C$: PRINT AT 7,16;"DUES PAID $";C$: INPUT "OK ? Y/N";Q$: IF Q$="N" THEN GO TO 140
144 LET B$(M,K,20 TO )="$"+C$: LET K=K+1
145 INPUT "CASH or CHECK ?";x$: IF x$="" THEN GO TO 145
146 PRINT AT 18,1;"TYPE OF COMPUTER ": PRINT
148 INPUT C$: PRINT AT 8,0;C$: INPUT "OK ? Y/N";Q$: IF Q$="N" THEN GO TO 146
150 LET B$(M,K, TO 32)=C$+" "+X$
160 INPUT "RECEIPT ? Y/N";Q$: IF Q$="Y" THEN GO SUB 4000
197 RETURN
205 CLS : INK 0: PAPER 7: PRINT AT 3,0;"\:'\''MAIN MENU\''\':";
206 PRINT AT 4,0;"\: \ :"'"\: 1. Members \ :"'"\: 2. Money \ :"'"\: 3. Printout\ :"'"\:.\..\..\..\..\..\..\..\..\..\..\..\.:"
249 RETURN
255 PAPER 6: INK 1: PRINT AT 10,0;"\:'\''\''"; INVERSE 1;"MEMBERS"; INK 1;; INVERSE 0;"\''\''\''\':"'"\: \ :"'"\: 1. New \ :"'"\: 2. Renewal \ :"'"\: 3. Update \ :"'"\: 4. Review \ :"'"\: 5. Main Menu\ :"'"\:.\..\..\..\..\..\..\..\..\..\..\..\..\.:"
299 RETURN
305 PAPER 2: INK 9: PRINT AT 3,17;"\:'\''\''\''MONEY\''\''\''\''\':";AT 4,17;"\: \ :";AT 5,17;"\: 1. Bank Bal \ :";AT 6,17;"\: 2. Incomes \ :";AT 7,17;"\: 3. Outgoes \ :";AT 8,17;"\: 4. Review \ :";AT 9,17;"\: 5. Main Menu\ :";AT 10,17;"\:.\..\..\..\..\..\..\..\..\..\..\..\..\.:"
349 RETURN
355 PAPER 5: INK 9: PRINT AT 13,17;"\:'\''\''PRINTOUT\''\''\':";AT 14,17;"\: \ :";AT 15,17;"\: 1. Members \ :";AT 16,17;"\: 2. Money \ :";AT 17,17;"\: 3. Main Menu\ :";AT 18,17;"\:.\..\..\..\..\..\..\..\..\..\..\..\..\.:"
399 RETURN
405 CLS : GO SUB HEAD
407 PRINT ; INVERSE 1;'"BALANCE"; INVERSE 0;TAB (30-LEN M$);"$";BALANCE
410 PRINT INVERSE 1;'"INCOMES"
412 FOR K=1 TO INC
414 PRINT I$(K);"$";I(K)
416 NEXT K
418 PRINT "DUES $";: GO SUB 500: PRINT TODUE
420 PRINT "---- ----"
422 PRINT N$;"'S INCOME ";TAB 24;"$";TI+TODUE
424 PRINT INVERSE 1;"EXPENSES"
426 FOR K=1 TO EXP
428 PRINT E$(K);"$";E(K)
430 NEXT K
431 PRINT "---- ----"
432 PRINT "EXPENSES PAID";TAB 24;"$";TE
434 LET NET=(TI+TODUE)-TE
435 IF (TI+TODUE)>TE THEN PRINT '"NET GAIN = $";NET
436 IF TE>(TI+TODUE) THEN PRINT '"NET LOSS = $";NET
438 PRINT ; INVERSE 1;'"BALANCE"; INVERSE 0;TAB (29-LEN M$);"$";BALANCE+NET
450 PAUSE 0
460 RETURN
499 STOP
505 LET TODUE=0
510 FOR G=1 TO M
515 LET TODUE=TODUE+VAL B$(G,5,21 TO )
520 NEXT G
530 RETURN
901 LOAD "FILE"CODE 57786,30: LOAD "file"CODE 65368,168
902 LET EXP=0: LET TE=EXP: LET TI=TE: LET INC=EXP: LET TODUE=0: LET money=300: LET print=350: LET Main=200: LET member=250: LET year=1986
903 LET NAME=80: LET HEAD=90: DIM B$(35,6,32): LET DATA=100: LET m=0
905 CLS : PAPER 7: INK 0
915 LET s$="\a\b\c\d\e\f\g Filing Program"
922 GO SUB Main
924 GO SUB member
926 GO SUB money
928 GO SUB print
929 GO SUB NAME
930 PRINT #1;TAB 7;"ANY";" Key to Start"
932 PAUSE 0
934 GO SUB 8000
936 GO SUB 8030
938 GO SUB MAIN
939 GO SUB MEMBER: GO SUB MONEY: GO SUB PRINT
940 GO SUB HEAD
942 PRINT #1;"SELECT";" SUB MENU"
944 IF INKEY$<>"4" AND INKEY$<>"1" AND INKEY$<>"2" AND INKEY$<>"3" THEN GO TO 944
946 IF INKEY$="2" THEN GO TO 2000
948 IF INKEY$="3" THEN GO TO 3000
950 IF INKEY$="4" THEN STOP
1010 CLS : PAPER 7: GO SUB HEAD: GO SUB MEMBER
1020 PRINT #1;"PICK";" SELECTION"
1025 LET Z$=INKEY$: IF Z$<"1" OR Z$>"5" THEN GO TO 1025
1028 IF z$="5" THEN GO TO 938
1030 CLS : GO SUB HEAD: GO SUB MEMBER
1035 PRINT AT (11+VAL Z$),13;"<"
1040 GO SUB (VAL Z$*100)+1000
1050 GO TO 1000
1105 LET M=M+1: LET H$="NEW"
1120 GO SUB DATA
1140 GO TO 1000
1200 REM "RENEWAL-1200"
1205 LET H$="RENEWAL": LET M=M+1
1210 GO SUB DATA
1220 GO TO 1000
1300 REM UPDATE-1300"
1305 LET H$="UPDATE": LET M=M+1
1310 GO SUB DATA
1320 GO TO 1000
1400 PRINT AT 2,0;" REVIEW": PRINT
1405 FOR W=1 TO M
1410 FOR E=1 TO 6
1420 PRINT B$(W,E)
1430 NEXT E
1433 PRINT
1435 INPUT "CORRECTIONS ? Y/N";Q$: IF Q$="Y" THEN GO SUB 5000
1450 INPUT "NEXT RECORD? Y/N";Q$: IF Q$="N" THEN LET W=M
1460 CLS : NEXT W
1470 RETURN
1510 GO TO 938
2005 CLS : GO SUB HEAD: GO SUB MONEY
2015 PRINT #1;"PICK";" SELECTION"
2020 LET Z$=INKEY$: IF Z$<"1" OR Z$>"5" THEN GO TO 2020
2022 IF z$="5" THEN GO TO 938
2024 IF Z$="4" THEN GO TO 2030
2025 CLS : GO SUB HEAD: GO SUB MONEY: PRINT AT (4+VAL Z$),16;">"
2030 GO SUB (VAL Z$*100)+2000
2040 GO TO 2000
2105 GO SUB HEAD: GO SUB MONEY
2110 PRINT AT 12,0;"ENTER Bank balance"''"To EDIT - reENTER new amount"''"You will erase the AMOUNT if you"'"PICK this selection again."
2120 INPUT "BALANCE-";M$
2125 PRINT "$";M$: INPUT "OK ? Y/N";Q$: IF Q$="N" THEN GO TO 2110
2130 LET BALANCE=VAL M$
2198 RETURN
2202 PRINT AT 4,1; INK 8;"NOTE: dues are";AT 5,1;"included in the";AT 6,1;"final totals"
2205 GO SUB HEAD: GO SUB MONEY
2208 LET INC=0: DIM i(10): DIM i$(10,15)
2210 PRINT AT 12,0;"ENTER number of incomes- ": INPUT INC
2215 FOR k=1 TO INC
2220 PRINT AT 12,0;"ENTER source of income #";k: INPUT i$(k)
2230 PRINT AT 12,0;"ENTER amount of income #";k: INPUT i(k)
2231 NEXT k
2233 PRINT AT 12,0;"SOURCE OF and AMOUNT of incomes"
2234 LET TI=0
2235 FOR k=1 TO INC
2238 LET TI=TI+i(k)
2240 PRINT i$(k);"$";i(k)
2245 NEXT k
2246 PRINT ,TI;" Total of "',;INC;" incomes"
2250 INPUT "OK ? Y/N";Q$: IF q$="N" OR q$="n" THEN GO TO 2210
2299 RETURN
2305 GO SUB HEAD: GO SUB MONEY
2308 LET EXP=0: DIM E(10): DIM E$(10,15)
2310 PRINT AT 12,0;"ENTER number of EXPENSES- ": INPUT EXP
2315 FOR k=1 TO EXP
2320 PRINT AT 12,0;"ENTER NAME of EXPENSE - #";k: INPUT E$(k)
2330 PRINT AT 12,0;"ENTER amount of EXPENSE #";k: INPUT E(k)
2331 NEXT K
2333 PRINT AT 12,0;"NAME of and AMOUNT of expenses"
2334 LET TE=0
2335 FOR k=1 TO EXP
2338 LET TE=TE+e(k)
2340 PRINT e$(k);"$";e(k)
2345 NEXT k
2346 PRINT ,TE;" Total of "',;EXP;" expenses."
2350 INPUT "OK ? Y/N";Q$: IF q$="N" OR q$="n" THEN GO TO 2210
2360 RETURN
2405 GO SUB 400
2499 RETURN
2510 GO TO 938
3010 CLS : GO SUB HEAD
3020 GO SUB PRINT
3025 PRINT AT 10,6;"TURN ON PRINTER !!"
3030 PRINT #1;"PICK";" SELECTION"
3050 LET Z$=INKEY$
3060 IF Z$<"1" OR Z$>"3" THEN GO TO 3050
3065 IF Z$="3" THEN GO TO 938
3070 IF Z$="2" THEN GO SUB 3200
3075 IF Z$="1" THEN GO SUB 3100
3080 GO TO 3000
3110 CLS : OPEN #2,"p": GO SUB 1400
3120 CLOSE #2
3125 LPRINT : LPRINT
3199 RETURN
3210 OPEN #2,"p"
3215 GO SUB 400
3230 CLOSE #2
3240 LPRINT : LPRINT
3250 LPRINT "-------------------------------"
3260 LPRINT : LPRINT
3299 RETURN
3999 STOP
4005 CLS : PRINT #1;"TURN ON PRINTER": PAUSE 0
4010 LPRINT "-------------------------------";TAB 12;"\a\b\c\d\e\f\g"
4015 RANDOMIZE USR 57786: LPRINT '"SINclair Computer Users Society": POKE 23607,60: LPRINT '"--------------------------------"'"PO Box 36,Johnson City,NY 13790"
4020 LPRINT TAB 10;"DUES RECEIPT"'TAB (16-(LEN n$+5)/2);n$;" ";year
4025 LPRINT : LET L=M
4029 RANDOMIZE USR 57786
4030 FOR K=1 TO 6
4040 LPRINT B$(L,K)
4050 NEXT K
4055 POKE 23607,60
4060 LPRINT : LPRINT
4070 LPRINT "THANK YOU FOR YOUR DUES. PLEASE"'"CHECK THE ABOVE DATA FOR ERRORS"'"AND BUG FREE COMPUTING TO YOU!"
4080 LPRINT : LPRINT "_______________________________"'"FINANCIAL SECRETARY-\a\b\c\d\e\f\g ",N$;" ";YEAR;: LPRINT : LPRINT
4100 LPRINT "PLEASE";: RANDOMIZE USR 57786: LPRINT " PLEASE ";: POKE 23607,60
4110 LPRINT "LET US KNOW OF A"'"CHANGE OF ADDRESS ASAP"''"LET US KNOW WHAT YOU THINK OF "'"THE NEWSLETTER AND SEND IN "'"IDEAS-FOR PROGRAMMING-HARDWARE"'"PROBLEMS OR SOLUTIONS-BUY OR"'"SELL, OR SWAP"'"THANKS FOR JOINING !!"
4120 LPRINT '"-------------------------------": LPRINT
4999 RETURN
5000 REM CORRECTIONS
5005 CLS : PRINT "CORRECTIONS ONLY !": PRINT
5010 FOR D=1 TO 6
5020 PRINT D;" ";B$(W,D)
5030 NEXT D
5040 PRINT AT 14,0; INVERSE 1;"ENTER LINE # TO BE CORRECTED"; INVERSE 0: INPUT N
5050 PRINT AT 14,0;"ENTER THE CORRECT INFORMATION"
5060 INPUT B$(W,N)
5070 RETURN
5999 STOP
8005 CLS : INK 9: PAPER 6: GO SUB NAME
8010 PRINT AT 10,0;"TO CHANGE YEAR LIST LINE 902."
8015 PRINT AT 16,0;"IF PROGRAM STOPS, GOTO 902 FOR"'"RESTART-WILL CLEAR VARIABLES"''"GOTO 938 TO RESTART AND SAVE"'"VARIABLES"
8020 PAUSE 0: RETURN
8035 DIM A$(3): CLS : POKE 23658,8
8040 GO SUB NAME: INPUT ;"ENTER 1st three letters of month";a$
8045 GO SUB 8500
8050 GO SUB HEAD: PRINT ''"You ENTERed ";n$;" which is"'n;" month(s) to July "
8055 GO SUB 8600
8060 PRINT '"Dues are $";dues;" a year, July to July"''"Dues from this month to July are$";produes
8070 PAUSE 0
8100 RETURN
8499 STOP
8503 RESTORE
8505 LET n=0
8510 READ n$,n
8520 IF a$=n$(1 TO 3) THEN RETURN
8530 IF n$="END" THEN GO TO 8030
8535 GO TO 8510
8540 DATA "DECEMBER",7,"JANUARY",6,"FEBRUARY",5
8550 DATA "MARCH" ,4,"APRIL",3,"MAY",2,"JUNE",1
8560 DATA "JULY",12,"AUGUST",11,"SEPTEMBER",10,"OCTOBER",9,"NOVEMBER",8,"END",13
8605 LET dues=8: LET produes=INT (8/12*N*100+.05)/100
8699 RETURN
9000 CLEAR : STOP
9999 SAVE "file" LINE 900: SAVE "FILE"CODE 57786,30: SAVE "file"CODE 65368,168: BEEP 2,1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.