--- title: "SINCUS file" id: 53822 type: "computer_media" slug: "sincus-file" url: "http://localhost/computer_media/sincus-file/" markdown_url: "http://localhost/computer_media/sincus-file.md" published_at: "2024-05-13T19:02:00+00:00" modified_at: "2026-03-30T21:45:21+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A full club membership and finance manager prints dues receipts, tracks incomes and expenses, and calculates prorated dues based on the month a member joins." 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: "SINCUS" slug: "sincus" taxonomy: "post_tag" url: "http://localhost/tag/sincus/" - 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: "Paul Hill" slug: "paul-hill" taxonomy: "indiv" url: "http://localhost/indiv/paul-hill/" genre: - name: "Database" slug: "database" taxonomy: "genre" url: "http://localhost/type/database/" media_type: "Program" programmers: - name: "Paul Hill" slug: "paul-hill" taxonomy: "indiv" url: "http://localhost/indiv/paul-hill/" mediadate: "April 8, 1985" images: - url: "http://localhost/wp-content/uploads/2024/05/SCR-20260330-nllh.png" related_content: - id: 24807 title: "Sinclair Computer Users Society (SINCUS)" type: "usergroup" url: "http://localhost/usergroup/sinclair-computer-users-society-sincus/" media_type_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 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: 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 `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 `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 `946`–`950` 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). ## 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 ```