SINCUS file

Developer(s): Paul Hill
Date: April 8, 1985
Type: Program
Platform(s): TS 2068
Tags: Database

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 RangePurpose
80–99Header display subroutines (NAME and HEAD)
101–197Member data entry (DATA subroutine)
205–399Menu display subroutines: Main, Members, Money, Printout
405–460Financial review display (subroutine 400)
500–530Total dues calculation subroutine
901–950Initialization and main dispatch loop
1010–1510Members submenu and handlers (New, Renewal, Update, Review)
2005–2510Money submenu and handlers (Balance, Incomes, Expenses, Review)
3010–3299Printout submenu (print members, print money report)
4005–4999Receipt printing via LPRINT
5000–5070Record correction subroutine
8005–8100Startup information screen
8035–8699Month entry and prorated dues calculation
9000–9999Cleanup 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:

  1. Record header: membership type + header label + member name + year (line 110)
  2. Full name
  3. Street address
  4. City, state, and ZIP
  5. Telephone number with dues paid amount appended at position 20
  6. 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 902903, 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 101 initializes k=1 (lowercase), but line 110 increments K=K+1 (uppercase). On this platform, variable names are case-sensitive in stored token form, so k and K are distinct variables. The slice index used in subsequent B$ assignments uses K, so the first slice at line 110 correctly uses k (value 1) but then increments K — which is uninitialized (defaults to 0), making K become 1. Subsequent slices use K, 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 138 uses LET B$(M,K, TO LEN C$+4)=C$ — assigning a string of length LEN C$ to a slice of length LEN C$+4 may cause a mismatch error unless the system silently right-pads.
  • Line 2350 in the expenses routine has GO TO 2210 on “N” answer, which jumps back into the incomes section rather than the expenses re-entry point at 2310. This appears to be a copy-paste error from the incomes routine.
  • Line 944 polls INKEY$ in a tight loop to check for keys “1”–”4″, but lines 946950 re-check INKEY$ 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 8035 uses GO SUB 8030 inside the subroutine block starting at 8035 (called from line 936 as GO SUB 8030), targeting a non-existent line — execution will fall through to line 8035, 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

Appears On

Related Products

Related Articles

Related 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.

Scroll to Top