Personal Accountant is a double-entry bookkeeping program that manages multiple named account files stored in a three-dimensional string array. The program supports four account types (Deposit, Expense, Loan, and Income) and can generate four financial reports: Trial Balance, Expense Account Listing, Balance Sheet, and Income and Expenses statement, with optional output to a printer via LPRINT. Account data is persisted to tape as a numeric array and a string array pair, saved with filenames suffixed “.A1” and “.A2”. A “Forward Balances” function compresses each account to a single opening-balance entry, allowing the array to be cleared for a new accounting period. The number of accounts and entries per account are configurable at startup from a fixed menu of five paired options whose products are constrained to fit within the dimensioned array.
Program Structure
The program is organized into well-delineated functional blocks reached by computed GO TO from the main menu at line 1000. The dispatch expression at line 1170 (GO TO Z*1000+1000) routes menu choices 1–8 to lines 2010, 3010, 4010 … 8010. Financial report generation begins at line 200 and occupies lines 201–980. Shared utilities (header display, tape I/O prompt, number formatting, account search, etc.) live in the 1800–1940 and 9300–9810 ranges.
Data Model
All account data is stored in a single three-dimensional string array C$(NA, NE, 25), dimensioned at line 90 after the user selects a capacity configuration. Each account occupies one slice of the first dimension; the last row (NE) of each account slice is a 25-character control record with a fixed layout:
| Characters | Content |
|---|---|
| 1–10 | Account name (space-padded) |
| 11–21 | Running balance (sign + 10 digits) |
| 22 | Account type: D, E, L, or I |
| 23–25 | Entry count (zero-padded 3-digit string) |
Each transaction row (rows 1 through NE-1) stores 25 characters: 6 for date (MMDDYY), 8 for particulars, and 11 for the signed amount. A deleted account is flagged by setting its control record to "* .00D000".
Capacity Configuration
Lines 75–79 set NE one higher than the advertised entry count per account, because the last row is reserved for the control record. The five permitted configurations are:
| Accounts (NA) | NE (internal) | Entries/account |
|---|---|---|
| 12 | 61 | 60 |
| 20 | 36 | 35 |
| 44 | 16 | 15 |
| 70 | 10 | 9 |
| 144 | 5 | 4 |
Tape Storage
Saving (line 3160–3165) writes C$() under the name N$+".A$" and a companion N(3) numeric array (holding NE, NA, NCO) under N$+".A2". Loading (lines 2090–2092) reads them back and reconstructs the working variables. The RANDOMIZE USR 100 calls before each tape operation appear to invoke a machine code routine, likely to patch the SAVE/LOAD routine or reset hardware state. Note that the SAVE filename in the listing uses ".A$" but the LOAD uses ".A1", which is a bug — saved files would not be found by the loader under the default naming.
Number Formatting — Subroutine 9300
The currency formatting subroutine at line 9300 converts a numeric string in M$ to an 11-character signed field. It first extracts the sign into W$, takes the absolute value, then calls subroutine 9350 (lines 9355–9380) to ensure exactly two decimal places. The result is left-padded with spaces to 10 characters, then the sign character is prepended, yielding an 11-character field stored back in M$. This consistent field width is essential for the array’s fixed-column layout.
Double-Entry Logic
The entry section (lines 4000–4530) implements rudimentary double-entry bookkeeping. The user enters accounts separated by /, parsed at line 4130–4185 into X$(1) and X$(2). For a two-account entry where both accounts are of type D (Deposit), subroutine 4400 inverts the sign of M$ for the second account. The same sign inversion applies when both accounts are non-Deposit types. If an account is not found during entry, subroutine 9650 (line 9652) automatically creates it by calling GO SUB 9005 with RET=1.
Forward Balances
The period-close function (lines 1510–1700, continuing into line 3080) iterates all accounts, reads each running balance, constructs a single “FORWARD” transaction entry in row 1, sets the entry count to "001", and then falls through to the tape save routine. This effectively archives period data by compressing each account history to one line.
Financial Reports
Four reports are generated by separate subroutine blocks. Each iterates all NCO accounts and calls the shared account-data extraction routine at line 8501 to populate N$, M$, and T$. Output is directed to screen (PRINT) or printer (LPRINT) based on the flag P$. Option 5 on the reports menu sets RET=1 and chains all four reports in sequence (lines 950–980), using RETURN at the end of each sub-report rather than jumping to 9800.
Notable Techniques and Idioms
POKE 23658,8sets the Spectrum’s FLAGS2 byte to enable caps-lock for INPUT, used throughout to ensure uppercase entry without the user having to manage keyboard mode.VAL J$with string validation before conversion (line70) avoids crashes from invalid numeric input.- The subroutine at line
9400scans for a deleted slot (C$(X,NE,1)="*") to reuse array space, avoiding fragmentation. - Account search subroutine
9505matches by prefix (C$(F,NE, TO LEN N$)=N$), allowing abbreviated name lookup. - The default account set loaded by
GO SUB 9900(lines9910–9980) seeds 12 typical household accounts, making the program usable immediately without manual setup.
Bugs and Anomalies
- Line
3160saves the data array asN$+".A$"but line2090loads it asN$+".A1"— mismatched filenames mean saved files cannot be reloaded. - Line
7785(the entry point after delete confirmation at line7185) is labelled7810in the listing but line7185branches to7800, which does not exist; the delete path falls through to7810only if line7800is absent, which is the case here — effectively harmless but unconventional. - Line
8500is referenced byGO SUB 8500in report loops, but the actual code begins at line8501; since line8500does not exist, BASIC will run from the next available line (8501), making this work in practice. - Line
4330branches to4000, which does not appear in the listing; the entry section starts at4005. BASIC will execute from line4005instead, which is correct functionally. - Line
3070checksIF N$="N"rather thanIF Z$="N", so a “No” verification response will never trigger a retry — a minor logic error. - Line
9350is called viaGO SUB 9350from line9312, but the subroutine code begins at line9355; the missing line9350causes BASIC to start at9355, which works correctly.
Source Code
6 CLEAR 65535:DIM X$(2,10)
8 DIM N(3):POKE 23658,8
10 DATA "JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"
19 GO SUB 100
20 PRINT "HOW MANY ACCOUNTS WILL YOU NEED?"
25 PRINT :PRINT "12 - (60 ENTRIES PER ACCOUNT)"
30 PRINT "20 - (35 ENTRIES PER ACCOUNT)"
40 PRINT "44 - (15 ENTRIES PER ACCOUNT)"
50 PRINT "70 - (9 ENTRIES PER ACCOUNT)"
60 PRINT "144- ( 4 ENTRIES PER ACCOUNT)"
65 INPUT "ENTER NUMBER ";J$:IF J$="" THEN GO TO 65
70 IF J$ <>"12" AND J$ <>"20" AND J$ <>"44" AND J$ <>"70" AND J$ <>"144" THEN GO TO 65
74 LET NA= VAL J$
75 IF NA=12 THEN LET NE=61
76 IF NA=20 THEN LET NE=36
77 IF NA=44 THEN LET NE=16
78 IF NA=70 THEN LET NE=10
79 IF NA=144 THEN LET NE=5
90 DIM C$(NA,NE,25)
95 GO SUB 9900
99 GO TO 1000
100 BORDER 1:PAPER 1:INK 7:CLS
120 LET A$="*** THE PERSONAL ACCOUNTANT ****"
125 LET V$="** COPYRIGHT 1983 by AL LAITY **"
130 GO SUB 1900
160 RETURN
201 LET A$="****** FINANCIAL REPORTS ******":GO SUB 1900
203 INPUT "DATE OF REPORTS (MMDDYY)?";D$
204 IF D$="Q" THEN GO TO 1000
205 IF LEN D$ <>6 THEN GO TO 203
206 LET D= VAL D$( TO 2):RESTORE 10:FOR X=1 TO D:READ F$:NEXT X
208 LET V$="********** "+F$+" "+D$(3 TO 4)+"/"+D$(5 TO )+" ***********"
209 GO SUB 1900
210 LET H$=F$+" "+D$(3 TO 4)+"/"+D$(5 TO 6)
212 PRINT :PRINT :PRINT
215 PRINT "1. PREPARE TRIAL BALANCE"
220 PRINT "2. EXPENSE ACCOUNTS LISTING ONLY"
225 PRINT "3. ASSETS AND LIABILITIES"
230 PRINT "4. INCOME AND EXPENSES"
240 PRINT "5. PREPARE ALL REPORTS"
250 INVERSE 1:PRINT "NUMBER 5 IS FOR PRINTERS ONLY"
260 PRINT :PRINT "PRECEDE NUMBER BY'P' FOR PRINTER":INVERSE 0
270 POKE 23658,8:INPUT Z$:IF Z$="" THEN GO TO 270
275 LET P$=""
280 IF LEN Z$>1 THEN LET P$="1":LET Z$=Z$(2)
284 IF Z$="Q" THEN GO TO 1000
285 LET Z= VAL Z$
290 IF Z=1 THEN GO TO 300
291 IF Z=2 THEN GO TO 400
292 IF Z=3 THEN GO TO 500
293 IF Z=4 THEN GO TO 700
295 IF Z=5 THEN LET P$="1":GO TO 950
300 LET V$="******** AS AT "+H$+" *******"
301 LET A$="********* TRIAL BALANCE ********":GO SUB 1900:IF P$="1" THEN GO SUB 1800
302 IF P$="" THEN PRINT INVERSE 1;"ACCT TYPE BALANCE "
303 IF P$="1" THEN LPRINT INVERSE 1;"ACCT TYPE BALANCE "
304 LET R=0:LET L=R
305 FOR X=1 TO NCO
308 IF VAL C$(X,NE,11 TO 21)=0 THEN GO TO 360
310 GO SUB 8500:LET N$=N$( TO 6)
311 GO SUB 9300
312 IF P$="1" THEN LPRINT N$;" ";T$;" ";:GO TO 316
315 PRINT N$;" ";T$;" ";
320 IF (T$="D" AND M$(1)="-") OR (T$="E" AND M$(1)="+") THEN LET T=1:GO TO 340
330 IF (T$="L" OR T$="I") AND M$(1)="+" THEN LET T=1:GO TO 340
335 LET T=13
340 IF P$="1" THEN FOR Z=1 TO T:LPRINT " ";:NEXT Z:GO TO 342
341 FOR Z=1 TO T:PRINT " ";:NEXT Z
342 IF P$="1" THEN LPRINT M$(2 TO ):GO TO 355
350 PRINT M$(2 TO )
355 IF T=1 THEN LET L=L+ VAL M$(2 TO )
356 IF T=13 THEN LET R=R+ VAL M$(2 TO )
360 NEXT X
370 IF P$ <>"1" THEN GO TO 380
375 LPRINT TAB 12;"____________________":GO TO 385
380 PRINT TAB 12;"____________________"
385 IF P$="1" THEN GO TO 387
386 LET M$= STR$ L:GO SUB 9300:LET N$=M$:LET M$= STR$ R:GO SUB 9300:IF P$ <>"1" THEN PRINT " ";N$(2 TO );" ";M$(2 TO ):GO TO 395
388 LET M$= STR$ L:GO SUB 9300:LET N$=M$:LET M$= STR$ R:GO SUB 9300:LPRINT " ";N$(2 TO );" ";M$(2 TO )
395 IF RET=1 THEN RETURN
398 GO TO 9800
400 LET V$="******** AS AT "+H$+" *******"
401 LET A$="******* EXPENSE ACCOUNTS *******":GO SUB 1900:IF P$="1" THEN GO SUB 1800
402 IF P$ <>"1" THEN PRINT INVERSE 1;"ACCOUNT NAME BALANCE ":GO TO 405
403 LPRINT INVERSE 1;"ACCOUNT NAME BALANCE "
405 LET L=0
410 FOR X=1 TO NCO
412 GO SUB 8500
413 IF T$ <>"E" OR VAL M$=0 THEN GO TO 450
420 GO SUB 9300
430 IF P$ <>"1" THEN PRINT N$;:FOR J=1 TO 11:PRINT " ";:NEXT J:PRINT M$:GO TO 432
431 LPRINT N$;:FOR J=1 TO 11:LPRINT " ";:NEXT J:LPRINT M$
432 LET L=L+ VAL M$
450 NEXT X
455 LET M$= STR$ L:GO SUB 9300
460 IF P$ <>"1" THEN GO TO 480
470 LPRINT TAB 15;"_________________"
475 LPRINT "TOTAL EXPENSES.......";M$
476 GO TO 490
480 PRINT TAB 15;"_________________"
485 PRINT "TOTAL EXPENSES.......";M$
490 IF RET=1 THEN RETURN
495 GO TO 9800
500 LET A$="******** BALANCE SHEET *********"
501 LET V$="******* AS AT "+H$+" ********"
502 GO SUB 1900:IF P$="1" THEN GO SUB 1800
503 LET TA=0:LET TL=TA
510 IF P$="1" THEN LPRINT INVERSE 1;" ASSETS ":GO TO 516
515 PRINT INVERSE 1;" ASSETS "
516 FOR C=1 TO 2
518 IF C=2 AND P$="1" THEN LPRINT :LPRINT INVERSE 1;" LIABILITIES ":GO TO 520
519 IF C=2 THEN PRINT :PRINT INVERSE 1;" LIABILITIES "
520 FOR X=1 TO NCO
530 GO SUB 8500
540 IF C=1 AND T$ <>"D" THEN GO TO 600
541 IF C=2 AND T$ <>"L" THEN GO TO 600
542 IF VAL M$=0 THEN GO TO 600
545 IF C=1 THEN LET TA=TA+ VAL M$
546 IF C=2 THEN LET TL=TL+ VAL M$
555 GO SUB 9300
556 IF M$(1)="+" THEN LET M$(1)=" "
557 IF M$(1)="-" THEN LET M$="("+M$(2 TO )+")"
560 IF P$ <>"1" THEN PRINT N$;" ";M$:GO TO 570
565 LPRINT N$;" ";M$
600 NEXT X
610 IF P$="1" THEN LPRINT TAB 14;"__________":IF C=1 THEN LPRINT "TOTAL ASSETS";
611 IF P$="1" AND C=2 THEN LPRINT "TOTAL LIAB. ";
615 IF P$ <>"1" THEN PRINT TAB 14;"__________":IF C=1 THEN PRINT "TOTAL ASSETS";
616 IF C=2 AND P$ <>"1" THEN PRINT "TOTAL LIAB. ";
620 IF C=1 THEN LET M$= STR$ TA:GO SUB 9300
621 IF C=2 THEN LET M$= STR$ TL:GO SUB 9300
630 IF P$="1" THEN GO TO 640
631 FOR J=1 TO 9:PRINT " ";:NEXT J
635 PRINT M$:GO TO 645
640 FOR J=1 TO 9:LPRINT " ";:NEXT J
641 LPRINT M$
650 NEXT C
660 LET TT=TA-TL:LET M$= STR$ TT:GO SUB 9300
665 IF P$="1" THEN GO TO 680
668 PRINT TAB 21;"___________":PRINT "ASSETS OVER LIAB. ";M$:GO TO 690
680 LPRINT TAB 21;"___________":LPRINT "ASSETS OVER LIAB. ";M$:LPRINT
690 IF RET=1 THEN RETURN
695 GO TO 9800
700 LET A$="***** INCOME AND EXPENSES ******"
701 LET V$="FOR THE PERIOD ENDED "+H$+" "
702 GO SUB 1900:IF P$="1" THEN GO SUB 1800
705 LET TI=0:LET TL=TI
710 IF P$="1" THEN LPRINT INVERSE 1;" INCOME ":GO TO 712
711 IF P$ <>"1" THEN PRINT INVERSE 1;" INCOME "
720 FOR C=1 TO 2
730 FOR X=1 TO NCO
735 GO SUB 8500
740 IF VAL M$=0 THEN GO TO 800
745 IF C=1 AND T$ <>"I" THEN GO TO 800
746 IF C=2 AND T$ <>"E" THEN GO TO 800
747 GO SUB 9300
748 IF C=1 THEN LET TI=TI+ VAL M$
749 IF C=2 THEN LET TL=TL+ VAL M$
750 IF C=2 AND M$(1)="-" THEN LET M$(1)=" ":GO TO 755
751 IF C=1 AND M$(1)="+" THEN LET M$(1)=" ":GO TO 755
752 LET M$="("+M$(2 TO )+")"
760 IF P$="1" THEN GO TO 780
765 PRINT N$;" ";M$:GO TO 800
780 LPRINT N$;" ";M$
800 NEXT X
803 IF C=1 THEN LET M$= STR$ TI:GO SUB 9300
804 IF C=2 THEN LET M$= STR$ TL:GO SUB 9300
805 IF C=1 AND M$(1)="+" THEN LET M$(1)=" "
806 IF C=2 AND M$(1)="-" THEN LET M$(1)=" "
810 IF P$="1" THEN GO TO 820
811 PRINT TAB 14;"__________"
812 IF C=1 THEN PRINT "TOTAL INCOME ";M$
813 IF C=2 THEN PRINT "TOTAL EXPENSES ";M$
815 GO TO 830
820 LPRINT TAB 14;"__________"
821 IF C=1 THEN LPRINT "TOTAL INCOME ";M$
825 IF C=2 THEN LPRINT "TOTAL EXPENSES ";M$
830 IF C=1 AND P$="1" THEN LPRINT :LPRINT INVERSE 1;" EXPENSES "
831 IF C=1 AND P$ <>"1" THEN PRINT :PRINT INVERSE 1;" EXPENSES "
835 NEXT C
838 LET TL=TL*-1:LET TT=TI-TL:LET M$= STR$ TT:GO SUB 9300
840 IF P$="1" THEN GO TO 860
850 PRINT TAB 22;"__________"
855 PRINT "INCOME OVER EXPENSES:";M$
856 GO TO 880
860 LPRINT TAB 22;"__________"
865 LPRINT "INCOME OVER EXPENSES:";M$
880 IF RET=1 THEN RETURN
890 GO TO 9800
950 LET RET=1:GO SUB 300
955 LPRINT :LPRINT :LPRINT :GO SUB 400
960 LPRINT :LPRINT :LPRINT :GO SUB 500
970 LPRINT :LPRINT :LPRINT :GO SUB 700
975 LPRINT :LPRINT :LPRINT :LPRINT
980 GO TO 9800
1000 LET QS=0
1001 LET RET=0
1005 GO SUB 100
1006 LET V$=""
1010 PRINT "1. LOAD files from tape"
1020 PRINT "2. SAVE files to tape"
1030 PRINT "3. MAKE ENTRIES TO FILES"
1040 PRINT "4. READ a file"
1050 PRINT "5. LIST directory"
1060 PRINT "6. CHANGE OR DELETE an ENTRY"
1070 PRINT "7. CHANGE file NAME or TYPE"
1080 PRINT "8. OPEN A NEW FILE"
1090 PRINT :PRINT "A. FORWARD BALANCES to tape"
1100 PRINT "B. PREPARE FINANCIAL REPORTS"
1110 INVERSE 1:PRINT :PRINT " IF PROGRAM BREAKS IN ERROR IMMEDIATELY TYPE GOTO 1000 "
1111 INVERSE 0
1150 INPUT "CHOOSE BY NUMBER ";Z$:IF Z$="" THEN GO TO 1150
1160 IF Z$="A" THEN GO TO 1500
1165 IF Z$="B" THEN GO TO 200
1167 IF Z$="Q" THEN GO TO 9998
1170 LET Z= VAL Z$:GO TO Z*1000+1000
1510 LET A$="******* FORWARD BALANCES *******":GO SUB 1900
1520 PRINT "MAKE SURE YOU SAVE EXISTING FILES FIRST . THIS SECTION WILLPRESERVE ONLY ACCOUNT BALANCES. ALL OTHER DATA WILL BE LOST !!!"
1525 PRINT
1530 PRINT "PRESS 'C' TO CONTINUE "
1540 PRINT "PRESS 'Q' TO QUIT"
1550 POKE 23658,8:IF INKEY$="" THEN GO TO 1550
1560 IF INKEY$="Q" THEN GO TO 1000
1570 IF INKEY$ <>"C" THEN GO TO 1550
1580 GO SUB 1900
1590 PRINT "NAME OF FORWARDED FILES ?"
1600 POKE 23658,8:INPUT N$:IF N$="" OR LEN N$>10 THEN GO TO 1600
1610 PRINT N$
1620 INPUT "VERIFY (Y OR N)?";Z$:IF Z$="" THEN GO TO 1620
1630 IF Z$="N" THEN GO TO 1580
1640 PRINT "DATE OF FORWARDING "
1650 INPUT "(MMDDYY)";D$:IF D$="Q" THEN GO TO 1000
1660 IF LEN D$ <>6 THEN GO TO 1640
1670 FOR X=1 TO NCO
1675 LET M$=C$(X,NE,11 TO 21):GO SUB 9300
1680 LET C$(X,1)=D$+" FORWARD"+M$
1685 LET C$(X,NE,23 TO 25)="001"
1690 NEXT X
1700 GO TO 3080
1800 FOR X=1 TO 5:PRINT INVERSE 1;" DATA TO PRINTER ":NEXT X
1809 FOR X=1 TO 2:LPRINT "********************************":NEXT X
1810 LPRINT A$
1815 IF V$ <>"" THEN LPRINT V$
1820 FOR X=1 TO 2:LPRINT "********************************":NEXT X
1825 LPRINT
1840 RETURN
1900 CLS
1910 FOR X=1 TO 2:PRINT "********************************":NEXT X
1920 PRINT A$
1925 IF V$ <>"" THEN PRINT V$
1930 FOR X=1 TO 2:PRINT "********************************":NEXT X
1940 PRINT :RETURN
2010 LET A$="******* LOADING FILES ********":GO SUB 1900
2015 GO SUB 2100
2020 PRINT "CAUTION CAUTION CAUTION"
2030 PRINT :PRINT :PRINT "THIS WILL KILL ANY DATA THAT IS PRESENTLY IN MEMORY":PRINT
2040 PRINT "PRESS 'Q' TO QUIT":PRINT "PRESS 'C' TO CONTINUE"
2050 POKE 23658,8
2060 IF INKEY$="Q" THEN GO TO 1000
2070 IF INKEY$="" THEN GO TO 2060
2080 IF INKEY$ <>"C" THEN GO TO 2060
2085 PRINT :PRINT "PRESS PLAY ON RECORDER"
2090 RANDOMIZE USR 100:LOAD N$+".A1"DATA C$():PRINT :PRINT INVERSE 1; FLASH 1;" PLEASE WAIT PLEASE WAIT "
2091 RANDOMIZE USR 100:LOAD N$+".A1"DATA N()
2092 LET NE=N(1):LET NA=N(2):LET NCO=N(3)
2099 GO TO 1000
2100 INPUT "NAME OF FILES ?";N$
2110 IF N$="QUIT" THEN GO TO 1000
2120 RETURN
3010 LET A$="********** SAVE FILES *********":GO SUB 1900
3020 PRINT "NAME OF FILES ? ";
3030 INPUT N$
3040 IF N$="" OR LEN N$>10 THEN GO TO 3030
3050 PRINT N$
3060 POKE 23658,8:INPUT "VERIFY NAME (Y OR N)? ";Z$:IF Z$ <>"Y" AND Z$ <>"N" THEN GO TO 3060
3070 IF N$="N" THEN GO TO 3000
3080 GO SUB 1900
3090 PRINT "PRESS PLAY & RECORD ON RECORDER"
3100 PRINT :PRINT "THEN PRESS 'C' TO CONTINUE"
3110 PRINT " 'Q' TO QUIT"
3115 POKE 23658,8
3120 IF INKEY$="" THEN GO TO 3120
3130 IF INKEY$="Q" THEN GO TO 1000
3140 IF INKEY$ <>"C" THEN GO TO 3120
3160 RANDOMIZE USR 100:SAVE N$+".A$"DATA C$()
3162 DIM N(3):LET N(1)=NE:LET N(2)=NA:LET N(3)=NCO
3163 PRINT INVERSE 1;" LEAVE RECORDER RUNNING ":PRINT FLASH 1;" PRESS ANY KEY "
3165 RANDOMIZE USR 100:SAVE N$+".A2"DATA N()
3170 GO TO 1000
4005 DIM X$(2,10)
4010 LET a$="******** MAKING ENTRIES ********":GO SUB 1900
4020 PRINT "PLUS (+) INCREASES DEPOSIT ACCT"
4021 PRINT " INCREASES LOAN ACCT"
4022 PRINT " INCREASES INCOME ACCT"
4023 PRINT :PRINT "MINUS(-) INCREASES EXPENSE ACCT"
4030 PRINT :PRINT
4050 PRINT "DATE OF ENTRY - ";
4051 POKE 23658,8:INPUT "(MMDDYY)";D$:IF D$="Q" THEN GO TO 1000
4052 IF LEN D$ <>6 THEN GO TO 4051
4053 IF VAL D$( TO 2)>12 OR VAL D$( TO 2)<0 THEN GO TO 4050
4054 PRINT D$
4055 PRINT
4060 PRINT "PARTICULARS - ";
4061 INPUT P$:IF LEN P$>8 THEN LET P$=P$( TO 8)
4062 IF LEN P$<8 THEN LET P$=P$+" ":GO TO 4062
4070 PRINT P$
4075 PRINT
4080 PRINT "AMOUNT $";
4085 INPUT M$:IF M$="Q" THEN GO TO 4085
4086 IF VAL M$>999999.99 THEN GO TO 4085
4087 GO SUB 9300:PRINT M$
4088 PRINT
4090 PRINT "ACCOUNT 1 / ACCOUNT 2"
4100 POKE 23658,8:INPUT Q$
4110 IF Q$="" THEN GO TO 4100
4120 IF Q$(1)="Q" THEN GO TO 1000
4125 PRINT Q$
4130 FOR X=1 TO LEN Q$
4140 IF Q$(X)="/" THEN LET FL=1:GO TO 4180
4150 NEXT X
4160 LET FL=0
4180 IF FL=1 THEN LET Q=2:LET X$(1)=Q$( TO X-1):LET X$(2)=Q$(X+1 TO ):GO TO 4190
4184 LET X$(1)=Q$
4185 LET Q=1
4190 LET DEP=0:LET OTH=0
4195 FOR C=1 TO Q:LET N$=X$(C):GO SUB 9500:IF FL=0 THEN GO SUB 9650
4200 NEXT C
4205 LET FL=0
4210 FOR C=1 TO Q
4220 LET N$=X$(C):GO SUB 9500
4228 LET NUM= VAL (C$(F,NE,23 TO 25))+1:LET Y$= STR$ NUM
4230 IF NUM=NE THEN GO TO 4500
4231 LET T$=C$(F,NE,22)
4232 IF T$="D" THEN LET DEP=DEP+1
4233 IF T$ <>"D" THEN LET OTH=OTH+1
4235 IF LEN Y$<3 THEN LET Y$="0"+Y$:GO TO 4235
4240 LET C$(F,NE,23 TO 25)=Y$
4250 IF C=2 AND DEP=2 THEN GO SUB 4400:LET DEP=0
4260 IF C=2 AND OTH=2 THEN GO SUB 4400:LET OTH=0
4270 LET C$(F,NUM)=D$+P$+M$
4280 LET B= VAL C$(F,NE,11 TO 21)+ VAL M$
4285 LET B$= STR$ B
4290 IF LEN B$<11 THEN LET B$=" "+B$:GO TO 4290
4295 LET C$(F,NE,11 TO 21)=B$
4300 NEXT C
4310 POKE 23658,8:INPUT "ANY OTHER ENTRIES ?";Z$
4320 IF Z$="N" THEN GO TO 1000
4330 GO TO 4000
4400 IF m$(1)="+" THEN LET M$(1)="-":RETURN
4410 IF M$(1)="-" THEN LET M$(1)="+":RETURN
4500 IF Q <>2 OR C <>2 THEN GO TO 4530
4510 LET N$=X$(1):GO SUB 9500
4520 LET NUM= VAL C$(F,NE,23 TO 25)-1
4521 LET AMOUNT= VAL C$(F,NE,11 TO 21)- VAL M$
4522 LET Z$= STR$ AMOUNT
4523 IF LEN Z$<10 THEN LET Z$=" "+Z$:GO TO 4523
4524 LET B$= STR$ NUM
4525 IF LEN B$<3 THEN LET B$="0"+B$:GO TO 4525
4527 LET C$(F,NE,11 TO 21)=Z$
4528 LET C$(F,NE,23 TO 25)=B$
4530 GO SUB 1900
4540 PRINT INVERSE 1:PRINT "ENTRY HAS NOT BEEN MADE TO "
4550 IF Q=2 THEN PRINT "EITHER ";
4560 PRINT "ACCOUNT"
4570 PRINT :PRINT X$(C);" ACCOUNT IS FULL"
4580 PRINT :PRINT "YOU SHOULD FORWARD BALANCES TO TAPE TO CLEAR SPACE FOR FURTHER ENTRIES"
4590 GO TO 9800
5000 LET A$="********* READING FILE *********":GO SUB 1900
5010 GO SUB 9600
5020 GO SUB 1900
5030 PRINT "WHICH FILE ?"
5040 POKE 23658,8:INPUT N$:IF N$="" THEN GO TO 5040
5045 IF N$="Q" THEN GO TO 1000
5050 GO SUB 9500
5060 IF FL=0 THEN PRINT :PRINT "FILE NOT FOUND ":GO TO 9800
5070 LET NU= VAL C$(F,NE,23 TO 25)
5080 IF NU=0 THEN PRINT "THERE ARE NO ENTRIES IN ACCOUNT":GO TO 9800
5085 LET A$="** ACCOUNT LISTING- "+C$(F,NE, TO 10)
5086 IF LEN A$<32 THEN LET A$=A$+"*":GO TO 5086
5090 GO SUB 1900:IF P$="1" THEN GO SUB 1800
5095 IF P$="1" THEN LPRINT "DATE PARTICULARS AMOUNT":LPRINT
5098 IF P$ <>"1" THEN PRINT "DATE PARTICULARS AMOUNT":PRINT
5100 FOR J=1 TO NU
5105 IF C$(F,J,1)="*" THEN GO TO 5200
5110 LET L$=C$(F,J, TO 6)+" "+C$(F,J,7 TO 14)
5112 IF P$="1" THEN LPRINT L$;:GO TO 5115
5113 PRINT L$;
5115 LET TYPE=1
5120 IF C$(F,NE,22)="D" OR C$(F,NE,22)="I" THEN LET TYPE=0
5130 LET M$=C$(F,J,15 TO 25)
5135 IF M$(1)="-" THEN LET T=0:GO TO 5145
5140 LET T=6
5145 IF P$="1" THEN FOR X=0 TO T:LPRINT " ";:NEXT X:GO TO 5170
5150 FOR X=0 TO T:PRINT " ";:NEXT X
5160 PRINT M$(2 TO ):GO TO 5180
5170 LPRINT M$(2 TO )
5200 NEXT J
5205 IF P$="1" THEN GO TO 5220
5210 PRINT TAB 16;"________________"
5215 PRINT "ACCOUNT BALANCE";
5218 GO TO 5230
5220 LPRINT TAB 15;"_________________"
5225 LPRINT "ACCOUNT BALANCE";
5230 LET M$=C$(F,NE,11 TO 21)
5235 LET T=0
5238 GO SUB 9300
5240 IF M$(1)="+" THEN LET T=5
5250 FOR X=0 TO T:IF P$="1" THEN LPRINT " ";:GO TO 5260
5255 PRINT " ";
5260 NEXT X
5270 IF P$="1" THEN LPRINT M$:LPRINT :GO TO 5280
5275 PRINT M$
5300 GO TO 9800
6000 LET A$="******** FILE DIRECTORY ********":GO SUB 1900
6005 GO SUB 9600
6008 IF P$="1" THEN GO SUB 1800
6010 FOR X=1 TO NCO
6020 LET N$=C$(X,NE, TO 10)
6030 IF N$(1)="*" THEN GO TO 6050
6040 IF P$="1" THEN LPRINT TAB 12;N$:GO TO 6050
6045 PRINT TAB 12;N$
6050 NEXT X
6060 GO TO 9800
7010 LET A$="******** CHANGE AN ENTRY *******":GO SUB 1900
7020 PRINT "WHICH ACCOUNT ? ";
7030 POKE 23685,8:INPUT N$:IF N$="" THEN GO TO 7030
7040 IF N$="Q" THEN GO TO 1000
7050 GO SUB 9500
7060 PRINT :PRINT C$(F,NE, TO 10)
7070 PRINT "WHICH ENTRY (TYPE 'U' IF UNKNOWN"
7080 POKE 23685,8:INPUT N$:IF N$="" THEN GO TO 7080
7090 IF N$="Q" THEN GO TO 1000
7100 IF N$="U" THEN GO SUB 7500:GO TO 7070
7110 LET N= VAL N$
7120 IF N<1 OR N> VAL C$(F,NE,23 TO 25) THEN GO TO 7070
7130 GO SUB 1900
7140 PRINT "ACCOUNT - ";C$(F,NE, TO 10)
7150 PRINT "ENTRY NUMBER - ";N
7160 PRINT :PRINT C$(F,N, TO 6);" ";C$(F,N,7 TO 15);" ";C$(F,N,16 TO 25)
7170 PRINT
7180 INPUT "DATE OF NEW ENTRY (MMDDYY) (* = DELETE ENTRY";D$
7185 IF D$="*" THEN GO TO 7800
7186 IF D$="Q" THEN GO TO 1000
7190 IF LEN D$ <>6 THEN GO TO 7180
7200 IF VAL D$( TO 2)<1 OR VAL D$( TO 2)>12 THEN GO TO 7180
7210 POKE 23685,8:INPUT "PARTICULARS";P$:IF LEN P$>8 THEN LET P$=P$( TO 8)
7212 IF LEN P$<8 THEN LET P$=P$+" ":GO TO 7212
7220 INPUT "AMOUNT ";M$
7230 IF M$="Q" THEN GO TO 1000
7240 GO SUB 9300
7250 LET V= VAL C$(F,NE,11 TO 21)- VAL C$(F,N,15 TO 25)+ VAL M$
7260 LET C$(F,N)=D$+P$+M$
7265 LET M$= STR$ V:GO SUB 9300
7270 LET C$(F,NE,11 TO 21)=M$
7280 POKE 23685,8:INPUT "OTHER CHANGES TO THIS FILE?";Z$:IF Z$="" THEN GO TO 7280
7290 IF Z$="Y" THEN GO SUB 1900:GO TO 7070
7300 GO TO 1000
7500 LET E= VAL C$(F,NE,23 TO 25)
7510 FOR X=1 TO E
7520 PRINT X;"...";C$(F,X, TO 6);" ";C$(F,X,7 TO 15);" ";C$(F,X,16 TO 25)
7530 NEXT X
7540 RETURN
7810 LET V= VAL C$(F,NE,11 TO 21)- VAL C$(F,N,15 TO 25)
7815 FOR L=2 TO NE
7820 LET C$(F,L-1)=C$(F,L):NEXT L
7825 LET M$= STR$ V:GO SUB 9300:LET C$(F,NE,11 TO 21)=M$
7830 LET C$(F,NE-1)=""
7840 LET L=(VAL C$(F,NE,23 TO 25))-1:LET L$= STR$ L
7850 IF LEN L$<3 THEN LET L$="0"+L$:GO TO 7850
7855 LET C$(F,NE,23 TO 25)=L$
7860 GO TO 9800
8010 LET A$="******* FILE NAME CHANGE ******":GO SUB 1900
8020 PRINT "FILE NAME TO BE CHANGED ?"
8030 POKE 23658,8:INPUT N$:IF LEN N$>10 THEN GO TO 8030
8031 IF N$="Q" THEN GO TO 1000
8032 IF N$="" THEN GO TO 8030
8035 PRINT N$:PRINT
8040 FOR F=1 TO NCO
8045 IF C$(F,NE, TO LEN N$)=N$ THEN LET FL=1:GO TO 8080
8070 NEXT F
8075 LET FL=0
8080 IF FL=0 THEN PRINT "FILE NOT FOUND":GO TO 9800
8090 PRINT :PRINT "ENTER NEW FILE NAME"
8095 PRINT "(ENTER '*' TO DELETE ";N$;")"
8100 POKE 23658,8:INPUT W$:IF W$="" THEN GO TO 8100
8105 IF W$="Q" THEN GO TO 1000
8110 IF LEN W$>10 THEN PRINT "FILE NAME TOO LONG-MAX 10 CHARS":GO TO 8090
8120 GO SUB 1900
8121 LET G$=W$:IF G$="*" THEN LET G$="DELETED"
8130 PRINT "OLD FILE - ";N$:PRINT "NEW FILE - ";G$
8131 LET Q$=C$(F,NE,22)
8132 IF W$(1)="*" THEN GO TO 8200
8140 PRINT "CHANGE ACCOUNT TYPE?"
8150 POKE 23658,8:INPUT Z$:IF Z$ <>"Q" AND Z$ <>"Y" AND Z$ <>"N" THEN GO TO 8150
8151 IF Z$="Q" THEN GO TO 1000
8160 IF Z$="N" THEN GO TO 8200
8165 LET QS=1
8170 PRINT "ENTER FIRST LETTER OF NEW ACCOUNT TYPE (D,E,L OR I)"
8175 LET Q$=C$(F,NE,22)
8180 POKE 23658,8:INPUT Q$:IF Q$="Q" THEN GO TO 1000
8190 IF Q$ <>"I" AND Q$ <>"E" AND Q$ <>"D" AND Q$ <>"L" THEN GO TO 8180
8200 IF LEN W$<10 THEN LET W$=W$+" ":GO TO 8200
8212 GO SUB 1900:PRINT "OLD ACCOUNT ";C$(F,NE, TO 10):PRINT :IF G$="DELETED" THEN PRINT "*** ";G$;" ***"
8213 IF G$="DELETED" THEN GO TO 8220
8214 PRINT "NEW ACCOUNT ";G$:PRINT
8215 PRINT "ACCOUNT TYPE - ";
8216 IF QS=0 THEN LET T$=C$(F,NE,22):GO SUB 9700:GO TO 8220
8217 LET T$=Q$:GO SUB 9700
8220 IF G$="DELETED" THEN LET C$(F,NE)="* .00D000"
8221 POKE 23658,8:INPUT "VERIFY (Y OR N)?";Z$:IF Z$="Q" THEN GO TO 1000
8222 IF Z$ <>"Y" THEN GO TO 8000
8225 LET C$(F,NE,22)=Q$
8226 LET C$(F,NE, TO 10)=W$
8230 GO TO 9800
8501 LET N$=C$(X,NE, TO 10)
8510 LET M$=C$(X,NE,11 TO 21)
8520 LET T$=C$(X,NE,22)
8540 RETURN
9005 LET FL=0
9006 LET OK=0
9007 IF RET=1 THEN GO TO 9015
9010 LET A$="******** OPEN NEW FILE *********":GO SUB 1900
9015 GO SUB 9400
9016 IF NCO=NA AND FL=1 THEN PRINT "NO FILES AVAILABLE":GO TO 9800
9017 IF OK=0 THEN LET OK=NCO+1:LET NCO=OK
9018 IF RET=1 THEN LET N$=X$(C):GO TO 9050
9020 PRINT "TYPE NEW FILE NAME-";
9030 POKE 23658,8:INPUT N$:IF N$="" THEN GO TO 9030
9050 IF LEN n$>10 THEN PRINT :PRINT "file name too long":GO TO 9020
9055 IF RET=1 THEN LET X$(C)=N$
9060 FOR x=1 TO NCO
9075 IF c$(x,ne, TO LEN n$)=n$ THEN PRINT "file exists under this name":GO TO 9020
9080 NEXT x
9090 PRINT n$
9100 LET QS=1:PRINT :PRINT "FILE TYPE ?"
9110 PRINT TAB 15;"D - DEPOSIT":PRINT TAB 15;"E - EXPENSE":PRINT TAB 15;"L - LOAN":PRINT TAB 15;"I - INCOME"
9120 POKE 23658,8:INPUT T$:IF T$ <>"D" AND T$ <>"L" AND t$ <>"E" AND T$ <>"I" THEN GO TO 9120
9125 IF LEN n$<10 THEN LET n$=n$+" ":GO TO 9125
9130 LET c$(OK,ne)=n$+" .00"+t$+"000"
9140 GO SUB 1900:PRINT :
9150 PRINT "NEW ACCOUNT OPENED - ";N$
9160 PRINT :PRINT "TYPE OF ACCOUNT IS - ";
9163 LET T$=C$(OK,NE,22):GO SUB 9700
9165 IF RET=1 THEN LET RET=0:RETURN
9170 GO TO 9800
9300 IF VAL M$<0 THEN LET W$="-":GO TO 9310
9301 LET W$=""
9305 LET W$="+"
9310 LET W= ABS (VAL M$)
9311 LET M$= STR$ W
9312 GO SUB 9350
9315 IF LEN M$<10 THEN LET M$=" "+M$:GO TO 9315
9320 LET W$=W$+M$
9330 LET M$=W$
9340 RETURN
9355 FOR K=1 TO LEN M$:IF M$(K)="." THEN GO TO 9360
9356 NEXT K
9357 LET M$=M$+".00":RETURN
9360 IF LEN M$=K THEN LET M$=M$+"00"
9365 LET F$=M$(K+1 TO ):IF LEN F$=2 THEN RETURN
9366 LET M$=M$( TO K)
9368 IF LEN F$<2 THEN LET F$=F$+"0":GO TO 9368
9370 LET M$=M$+F$:RETURN
9380 RETURN
9400 FOR X=1 TO NCO
9410 IF C$(X,NE,1)="*" THEN LET OK=X:RETURN
9420 NEXT X
9430 LET FL=1
9440 RETURN
9505 LET FL=0
9510 FOR F=1 TO NCO
9520 IF C$(F,NE, TO LEN N$)=N$ THEN LET FL=1:RETURN
9530 NEXT F
9540 LET FL=0
9550 LET F=0
9560 RETURN
9600 POKE 23685,8:INPUT "DATA TO PRINTER (Y OR N)";Z$
9610 IF Z$ <>"Y" AND Z$ <>"N" THEN GO TO 9600
9620 LET P$="":IF Z$="Y" THEN LET P$="1"
9630 RETURN
9652 GO SUB 1900:PRINT "A NEW ACCOUNT NAMED ";X$(C):PRINT "IS BEING CREATED"
9655 LET RET=1:GO SUB 9005
9699 RETURN
9700 IF T$="D" THEN PRINT "DEPOSIT"
9701 IF T$="E" THEN PRINT "EXPENSE"
9702 IF T$="L" THEN PRINT "LOAN"
9703 IF T$="I" THEN PRINT "INCOME"
9705 RETURN
9800 PRINT :PRINT "press any key for menu"
9810 IF INKEY$="" THEN GO TO 9810
9820 GO TO 1000
9910 LET C$(1,NE)="CHECKING .00D000"
9915 LET C$(2,NE)="SAVINGS .00D000"
9920 LET C$(3,NE)="CHARGECARD .00L000"
9925 LET C$(4,NE)="CAR LOAN .00L000"
9930 LET C$(5,NE)="CAR REPAIR .00E000"
9935 LET C$(6,NE)="CHILDCARE .00E000"
9940 LET C$(7,NE)="RENT .00E000"
9945 LET C$(8,NE)="ENTRTNMENT .00E000"
9950 LET C$(9,NE)="CLOTHING .00E000"
9955 LET C$(10,NE)="UTILITIES .00E000"
9960 LET C$(11,NE)="FOOD .00E000"
9965 LET C$(12,NE)="PAY-INCOME .00I000"
9975 LET nco=12
9980 RETURN
9992 REM CLEAR :RANDOMIZE USR 100:SAVE "BUDGET.B1" LINE 1
9998 REM RANDOMIZE USR 100:LOAD "L.B1"
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

