Personal Accountant

Developer(s): Al Laity
Date: 1983
Type: Program
Platform(s): TS 2068
Tags: Finance

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:

CharactersContent
1–10Account name (space-padded)
11–21Running balance (sign + 10 digits)
22Account type: D, E, L, or I
23–25Entry 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
126160
203635
441615
70109
14454

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,8 sets 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 (line 70) avoids crashes from invalid numeric input.
  • The subroutine at line 9400 scans for a deleted slot (C$(X,NE,1)="*") to reuse array space, avoiding fragmentation.
  • Account search subroutine 9505 matches by prefix (C$(F,NE, TO LEN N$)=N$), allowing abbreviated name lookup.
  • The default account set loaded by GO SUB 9900 (lines 9910–9980) seeds 12 typical household accounts, making the program usable immediately without manual setup.

Bugs and Anomalies

  • Line 3160 saves the data array as N$+".A$" but line 2090 loads it as N$+".A1" — mismatched filenames mean saved files cannot be reloaded.
  • Line 7785 (the entry point after delete confirmation at line 7185) is labelled 7810 in the listing but line 7185 branches to 7800, which does not exist; the delete path falls through to 7810 only if line 7800 is absent, which is the case here — effectively harmless but unconventional.
  • Line 8500 is referenced by GO SUB 8500 in report loops, but the actual code begins at line 8501; since line 8500 does not exist, BASIC will run from the next available line (8501), making this work in practice.
  • Line 4330 branches to 4000, which does not appear in the listing; the entry section starts at 4005. BASIC will execute from line 4005 instead, which is correct functionally.
  • Line 3070 checks IF N$="N" rather than IF Z$="N", so a “No” verification response will never trigger a retry — a minor logic error.
  • Line 9350 is called via GO SUB 9350 from line 9312, but the subroutine code begins at line 9355; the missing line 9350 causes BASIC to start at 9355, which works correctly.

Related Products

Three integrated programs. Compile reports, automatic posting, data base, add messages to entries, profit/loss statements, amortization/payment schedules; create as many...

Image Gallery

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.