BUDGET is a personal finance tracking program that manages multiple named budget accounts across a 12-month calendar year. It stores account names in a two-dimensional string array and dollar figures in a two-dimensional numeric array, using a shared subroutine (lines 10–38) to format monetary values with a decimal point inserted two places from the right. The menu system offers seven options including summary views, per-account detail with running balances, data entry for spending or credits, budget figure changes, account renaming, and tape/disk save. A substring search routine (line 5000) lets users locate accounts by partial name match, scanning all positions within each stored name.
Program Structure
The program is organized into clearly delineated sections, each starting at a round line number. A GO TO 1000 at line 5 skips past the utility subroutines and data-entry initialization to the main menu after a save/reload. The initialization block (lines 100–615) runs only on first launch and collects the budget item count, names, and monthly amounts before branching to the menu.
| Lines | Section |
|---|---|
| 10–38 | Currency formatting subroutine (GOSUB target stored in G) |
| 100–615 | Initialization: constants, data entry, first totals display |
| 1000–1140 | Main menu |
| 1500–1920 | Account summary (all accounts + monthly totals) |
| 2000–2400 | Per-account detail with monthly and cumulative balances |
| 2500–2710 | New information entry (spending or credits) |
| 3000–3205 | Change a budgeted amount |
| 3500–3580 | Rename an account |
| 4000–4050 | Save to tape/disk |
| 4500–4560 | Exit with confirmation |
| 5000–5130 | Account search subroutine (GOSUB target stored in L) |
| 9898–9899 | STOP / safety net |
Subroutine Address Variables
Rather than hard-coding GOSUB destinations, the program stores two subroutine line numbers in numeric variables set during initialization: G=10 (currency formatter) and L=5000 (account search). All calls throughout the program use GO SUB G and GO SUB L. Similarly, the menu return address is stored in S=1000 and used as GO TO S or GO TO S+ VAL X$. This makes the code compact and means relocating a subroutine only requires changing the initialization constant.
Currency Formatting (Lines 10–38)
The shared formatter converts a floating-point value in M to a display string in M$. It multiplies by 100, rounds with INT(M*100+.5), converts to string with STR$, then splices in a period two characters from the right end. A special case at line 14 forces M$="000" when the value is zero so the splice always finds enough characters. Negative values pass through, but lines 20–26 contain a loop that applies CHR$(CODE(M$(Z))) to each character — a no-op transformation that appears to be vestigial code intended to produce inverse video but has no effect in this context.
Data Storage Arrays
N$(N1,15)— account names, 15 characters each; positions 1–2 hold a zero-padded index number and position 4 onward holds the user-supplied name.D(N1,13)— numeric data per account; column 1 is the monthly budget, columns 2–13 are January through December actual spending.T(14)— column totals; entries 1–13 mirror theDcolumn structure, and entry 14 accumulates the total of all monthly totals.S(N1)— row sums (total spent per account) computed in the summary section.
Note that T(14) is dimensioned at line 340 during initialization and then re-dimensioned at line 1525 inside the summary routine. This re-dimensioning resets all values to zero, which is the intended way to clear totals before recalculating.
Menu Dispatch
The main menu at line 1000 uses a PAUSE F / INKEY$ idiom (F=40000, a very long pause) to wait for a keypress. Choices “1” through “7” are checked with explicit IF X$=... THEN GO TO chains. An ON ERR GO TO 1000 at line 1135 traps any errors, and line 1140 uses GO TO S+ VAL X$ as a computed jump — since S=1000, pressing “1” would jump to line 1001, but that line does not exist; the explicit checks above intercept all valid keys before reaching this line, so it only fires for unexpected input.
Account Search Subroutine (Lines 5000–5130)
The search at line 5000 performs a sliding-window substring match. It accepts a partial name from the user, then iterates over every account and every starting position within the 15-character name field, comparing a substring of length LEN Y$. On a match it sets Y=I (account index) and Y$=N$(I) (full name), clears the screen, and returns. An empty input at line 5021 redirects to line 1E3 (the menu), demonstrating use of VAL-style numeric literals in a GO TO.
Month Name Encoding
All twelve month abbreviations are packed into a single string O$="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC" at line 100. Month n (1-based, where 1=January) is extracted with O$((n-1)*3+1 TO (n-1)*3+3). In the detail and summary displays, months are indexed as columns 2–13 of D, so the extraction formula typically appears as O$((I-2)*3+1 TO (I-2)*3+3).
Balance Display Logic
Throughout the summary and detail sections, balances are printed with an explicit “+” or an inverse-video “−” prefix depending on the sign of M. The currency formatter strips any leading minus sign produced by STR$ and the sign character is prepended separately, allowing consistent right-alignment of the numeric portion via TAB(N- LEN M$).
Notable Anomalies
- Lines 22–26 loop through
M$applyingCHR$(CODE(M$(Z))), which is an identity operation and has no visible effect. The original intent may have been to invert the display of negative amounts using an offset to the inverse character set, but as written it is a no-op. - At line 605, the monthly total
Tis passed to the formatter and printed as an annual figure without multiplying by 12. The label says “TOTAL REQUIRED PER YEAR” but the value displayed is the same as the monthly total computed three lines earlier — an apparent bug. - Line 1520 dimensions
S(N1)using the variable nameS, which shadows the menu return-address variableS=1000. After this pointSis an array, so subsequentGO TO Scalls would fail. However,GO TO Swithin the summary section uses the bare variable which at that stage refers to the numeric value 1000 set at line 160 — the DIM statement creates a separate arrayS()while leaving the scalarSintact in Spectrum BASIC, so in practice this works correctly. - The exit routine at line 4560 directs the user to type
GOTO 1000manually and branches to line 9898 (STOP), providing a way back into the running program without re-executing initialization.
Content
Source Code
1 REM "BUDGET"
5 GO TO 1000
10 LET M= INT (M*100+.5)
12 LET M$= STR$ M
14 IF M=0 THEN LET M$="000"
16 LET M$=M$( TO LEN M$-2)+"."+M$(LEN M$-1 TO )
18 IF VAL M$ >=0 THEN GO TO 38
20 LET M$=M$(2 TO )
22 FOR Z=1 TO LEN M$
24 LET M$(Z)= CHR$ (CODE M$(Z))
26 NEXT Z
38 RETURN
100 LET O$="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"
110 PRINT "\{20}\{1}ENTER THE NUMBER OF BUDGET ITEMS\{20}\{0}"
120 INPUT N1
130 PRINT N1
140 LET L$="\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''"
150 LET C$=" "
160 LET S=1E3
170 LET G=10
180 LET L=5E3
190 LET F=4E4
200 LET E=21
210 LET D$="NEW TAPE"
250 PRINT "\{20}\{1}ENTER THE NAME OF THIS PROGRAM \{20}\{0}"
260 INPUT Q$
270 IF LEN Q$ <=32 THEN GO TO 300
280 PRINT "THE NAME IS TOO L O N G . . ."
290 GO TO 260
300 PRINT Q$
310 PRINT "NOW WE WILL ENTER THE NAMES AND AMOUNTS OF EACH BUDGET ITEM..."
315 REM ***** NAME OF ACCTS*****
320 DIM N$(N1,15)
325 REM ***DOLLAR FIGURES***
330 DIM D(N1,13)
335 REM ***COLUMN TOTALS***
340 DIM T(14)
345 REM ***ROW TOTALS***
350 FOR I=1 TO N1
360 PRINT "NAME OF BUDGET ITEM NUMBER ";I;":"
370 IF I<10 THEN LET N$(I, TO 2)="0"+ STR$ I
380 IF I >=10 THEN LET N$(I, TO 2)= STR$ I
390 INPUT N$(I,4 TO )
410 PRINT N$(I)
430 PRINT "ENTER MONTHLY BUDGET AMOUNT:"
440 INPUT D(I,1)
450 LET M=D(I,1)
460 GO SUB G
480 PRINT "$";M$
500 NEXT I
510 LET T=0
520 FOR I=1 TO N1
530 LET T=T+D(I,1)
540 NEXT I
550 CLS
560 PRINT "TOTAL BUDGET REQUIRED PER MONTH:"
570 LET M=T
575 GO SUB G
580 PRINT "$";M$
600 PRINT "TOTAL REQUIRED PER YEAR:"
605 GO SUB G
610 PRINT "$";M$
615 PAUSE 250
1000 REM ***MENU***
1002 CLS
1005 BORDER 2
1020 PRINT AT 1,1;Q$
1030 PRINT TAB 1;"\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''"
1040 PRINT AT 3,2;"1: SUMMARY OF ALL ACCOUNTS"
1050 PRINT AT 5,2;"2: DETAILS OF ONE ACCOUNT"
1060 PRINT AT 7,2;"3: ENTER NEW INFORMATION"
1070 PRINT AT 9,2;"4: CHANGE A BUDGETED AMOUNT"
1080 PRINT AT 11,2;"5: CHANGE/CORRECT THE NAME OF"; TAB 5;"ACCOUNT"
1085 PRINT AT 14,1;"\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''"
1090 PRINT AT 15,2;"6: SAVE THE DATA"
1100 PRINT AT 17,2;"7: EXIT THE PROGRAM"
1101 PRINT AT 19,1;"\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''"
1105 PRINT TAB 2;"LAST UPDATE: ";D$
1110 PAUSE F
1120 LET X$= INKEY$
1122 IF X$="1" THEN GO TO 1500
1124 IF X$="2" THEN GO TO 2000
1126 IF X$="3" THEN GO TO 2500
1128 IF X$="4" THEN GO TO 3000
1130 IF X$="5" THEN GO TO 3500
1132 IF X$="6" THEN GO TO 4000
1134 IF X$="7" THEN GO TO 4500
1135 ON ERR GO TO 1000
1136 CLS
1140 GO TO S+ VAL X$
1500 REM ***SUMMARY***
1502 CLS
1503 PRINT AT 7,12;"SUMMARY"
1504 PRINT
1505 PRINT INK 2; AT 11,9;"ADDING TOTALS"
1506 PAUSE 100
1520 DIM S(N1)
1525 DIM T(14)
1530 FOR I=1 TO N1
1535 FOR J=2 TO 13
1540 LET S(I)=S(I)+D(I,J)
1545 NEXT J
1550 NEXT I
1560 FOR I=1 TO 13
1565 FOR J=1 TO N1
1570 LET T(I)=T(I)+D(J,I)
1575 NEXT J
1580 IF I>1 THEN LET T(14)=T(14)+T(I)
1585 NEXT I
1587 CLS
1600 FOR I=1 TO N1 STEP G
1605 FOR J=0 TO 9
1610 IF J=0 THEN PRINT AT 0,0;"\{20}\{1}ANNUAL BUDGET SPENT TO DATE \{20}\{0}"
1615 IF J+I>N1 THEN GO TO 1680
1620 PRINT N$(J+I)
1630 PRINT TAB 6;"$";
1635 LET M=12*D(I+J,1)
1640 GO SUB G
1645 PRINT TAB (15- LEN M$);M$," $";
1650 LET M=S(I+J)
1655 GO SUB G
1660 PRINT TAB (28- LEN M$);M$
1670 NEXT J
1680 PRINT AT E,0;"\{20}\{1}\{20}\{0}\{20}\{1}'Z'=COPY 'C'=CONTINUE 'M'=MENU\{20}\{0}"
1690 PAUSE F
1695 LET X$= INKEY$
1700 IF CODE X$=118 OR X$="M" THEN GO TO S
1705 IF X$="Z" THEN PRINT AT 21,0;" "
1710 IF X$="Z" THEN COPY
1715 IF X$="Z" THEN GO TO 1680
1720 CLS
1725 NEXT I
1730 PRINT "\{20}\{1}MONTHLY BUDGET \{20}\{0} $";
1735 LET M=T(1)
1740 GO SUB G
1745 PRINT M$
1750 PRINT
1755 PRINT "SPENT IN"; TAB 12;"AMOUNT"; TAB 20;"""+""=BALANCE"; TAB 0;"MONTH OF"; TAB 12;"SPENT"; TAB 20;"""\{20}\{1}-\{20}\{0}""=DEFICIT"
1757 PRINT "\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\.."
1760 FOR I=2 TO 13
1765 LET M=T(I)
1770 GO SUB G
1775 PRINT TAB 2;O$((I-2)*3+1 TO (I-2)*3+3); TAB 10;"$"; TAB (19- LEN M$);M$;
1780 LET M=T(1)- VAL M$
1785 GO SUB G
1786 IF M >=0 THEN PRINT TAB 20;"+";
1787 IF M<0 THEN PRINT TAB 20;"\{20}\{1}-\{20}\{0}";
1790 PRINT TAB (31- LEN M$);M$
1795 NEXT I
1799 LET T=0
1800 FOR I=2 TO 13
1805 LET T=T+T(I)
1810 NEXT I
1820 PRINT ,,"TOTAL ANNUAL BUDGET: $";
1825 LET M=12*T(1)
1830 GO SUB G
1835 PRINT TAB (31- LEN M$);M$
1840 LET M=T
1845 GO SUB G
1850 PRINT "TOTAL SPENT TO DATE: $"; TAB (31- LEN M$);M$
1855 LET M=12*T(1)-T
1860 IF M >=0 THEN PRINT "BALANCE LEFT:",
1865 IF M<0 THEN PRINT INK 2;"OVERSPENT ",
1870 GO SUB G
1875 PRINT TAB 21;"$"; TAB (31- LEN M$);M$
1880 PRINT AT 21,0;"\{20}\{1}'Z'=COPY 'C'=CONTINUE 'M'=MENU\{20}\{0}"
1890 PAUSE F
1895 LET X$= INKEY$
1900 IF CODE X$=118 OR X$="M" THEN GO TO 1000
1905 IF X$="Z" THEN PRINT AT E,0;" "
1910 IF X$="Z" THEN COPY
1915 IF X$="Z" THEN GO TO 1880
1920 GO TO S
2000 REM ***\{20}\{1}ANALYSIS\{20}\{0}***
2002 CLS
2010 PRINT "\{20}\{1}DETAILS OF AN ACCOUNT\{20}\{0}"
2020 GO SUB L
2021 CLS
2030 PRINT Y$
2040 PRINT "\{20}\{1}BUDGET/MONTH:\{20}\{0} $";
2045 LET M=D(Y,1)
2050 GO SUB G
2055 PRINT M$
2056 PRINT
2060 PRINT "MTH\{20}\{1} \{20}\{0}AMT SPENT\{20}\{1} \{20}\{0} BALANCE\{20}\{1} \{20}\{0}ACCUM BAL"
2070 PRINT L$
2075 LET T=D(Y,1)
2076 LET J=0
2080 FOR I=2 TO 13
2090 PRINT O$((I-2)*3+1 TO (I-2)*3+3);
2100 LET M=D(Y,I)
2105 LET J=J+M
2110 GO SUB G
2120 PRINT TAB 12- LEN M$;M$;
2130 LET M=T-D(Y,I)
2140 GO SUB G
2150 IF M >=0 THEN PRINT TAB 13;"+";
2160 IF M<0 THEN PRINT TAB 13;"\{20}\{1}-\{20}\{0}";
2180 PRINT TAB 22- LEN M$;M$;
2185 LET M=T*(I-1)-J
2190 IF M<0 THEN PRINT TAB 23;"\{20}\{1}-\{20}\{0}";
2195 IF M >=0 THEN PRINT TAB 23;"+";
2200 GO SUB G
2210 PRINT TAB 32- LEN M$;M$
2215 NEXT I
2219 PRINT
2220 PRINT "ANNUAL BUDGET:","$";
2225 LET M=T*12
2239 GO SUB G
2240 PRINT TAB 25- LEN M$;M$
2250 PRINT "SPENT TO DATE:","$";
2260 LET M=J
2270 GO SUB G
2280 PRINT TAB 25- LEN M$;M$
2290 PRINT "BALANCE:",
2300 LET M=T*12-J
2310 IF M >=0 THEN PRINT "+";
2320 IF M<0 THEN PRINT "\{20}\{1}-\{20}\{0}";
2330 GO SUB G
2340 PRINT TAB 25- LEN M$;M$
2350 PRINT AT 21,0;"\{20}\{1} 'Z'=COPY 'M'=MENU \{20}\{0}"
2360 PAUSE F
2365 LET Y$= INKEY$
2375 IF Y$="Z" THEN COPY
2380 IF Y$="Z" THEN GO TO 2350
2390 CLS
2400 GO TO S
2500 REM ***\{20}\{1}NEW INFO\{20}\{0}***
2505 CLS
2510 PRINT "\{20}\{1} NEW INFORMATION ENTRY \{20}\{0}"
2515 GO SUB L
2520 PRINT "\{20}\{1} NEW INFORMATION ENTRY \{20}\{0}"
2525 PRINT Y$
2530 PRINT ,,"WILL YOU ENTER . . ."
2540 PRINT ,,"1: MONEY SPENT FROM THIS ACCOUNT"; TAB 14;" OR ","2: MONEY TO BE CREDITED TO THIS ACCOUNT"
2550 PRINT TAB 6;"\{20}\{1} ENTER '1' OR '2' \{20}\{0}"
2555 PAUSE F
2560 LET X$= INKEY$
2570 IF X$ <>"1" AND X$ <>"2" THEN GO TO 2555
2575 LET X= VAL X$
2580 PRINT ,,,,"WHAT MONTH IS THIS ENTRY FOR ?"
2590 PRINT "\{20}\{1} USE THE 3 LETTER ABBREV.. \{20}\{0}"
2600 INPUT Y$
2605 FOR I=0 TO 11
2610 IF Y$=O$((I*3)+1 TO (I*3)+3) THEN GO TO 2625
2615 NEXT I
2620 PRINT "WHAT ?"
2621 GO TO 2590
2625 LET I=I+2
2630 PRINT "ENTER THE AMOUNT:"
2640 INPUT J
2650 IF J<0 THEN GO TO 2590
2660 IF X=2 THEN LET J=-J
2670 LET D(Y,I)=D(Y,I)+J
2680 PRINT AT 21,0;"\{20}\{1} ANOTHER ENTRY (Y/N) \{20}\{0}"
2690 PAUSE F
2700 IF INKEY$="Y" THEN GO TO 2500
2710 GO TO S
2990 STOP
3000 REM ***\{20}\{1}CHANGE A BUDGET FIGURE\{20}\{0}***
3001 CLS
3010 PRINT "\{20}\{1}CHANGE A BUDGET FIGURE FOR ACCT.\{20}\{0}"
3013 GO SUB L
3020 PRINT Y$
3030 PRINT ,,"WILL YOU ENTER . . ."
3035 PRINT ,,"1: A NEW MONTHLY FIGURE", TAB 14;" OR "
3040 PRINT "2: A CHANGE IN THE ANNUAL TOTAL"
3050 PRINT TAB 6;"\{20}\{1} ENTER '1' OR '2' \{20}\{0}"
3060 PAUSE F
3070 LET X$= INKEY$
3075 IF X$ <>"1" AND X$ <>"2" THEN GO TO 3070
3080 LET X= VAL X$
3090 PRINT "ENTER THE AMOUNT:"
3100 INPUT J
3110 IF X=1 THEN GO TO 3200
3120 LET J=J/12
3130 LET J= INT (J*100)/100
3140 LET D(Y,1)=D(Y,1)+J
3150 GO TO S
3200 LET D(Y,1)=J
3205 GO TO S
3500 REM ***\{20}\{1}CHANGE NAME\{20}\{0}***
3502 CLS
3505 PRINT "TO CHANGE AN ACCOUNT NAME, FIRST"
3510 GO SUB L
3520 PRINT "\{20}\{1}PRESENT NAME\{20}\{0} ";Y$
3530 PRINT ,,"ENTER THE NEW NAME:"
3540 INPUT Y$
3550 LET N$(Y,4 TO )=Y$
3560 PRINT ,,"\{20}\{1}NEW NAME \{20}\{0} ";N$(Y)
3570 PAUSE 250
3580 GO TO S
4000 REM ***\{20}\{1}SAVE\{20}\{0}***
4002 CLS
4010 PRINT "ENTER TODAY'S DATE:"
4015 INPUT D$
4020 PRINT AT 5,0;"PREPARE DISC OR TAPE RECORDER ."
4025 PRINT AT 8,0;"\{20}\{1}REMEMBER TO MAKE A SPARE COPY \{20}\{0}"
4030 PRINT AT 21,0;"PRESS ENTER TO START"
4035 PAUSE F
4040 SAVE "BUDGET" LINE 1000
4050 GO TO S
4500 REM ***\{20}\{1}EXIT\{20}\{0}***
4502 CLS
4510 PRINT "ARE YOU SURE YOU WANT TO QUIT THE PROGRAM WITHOUT SAVING ANY NEW INFORMATION ?"
4520 PAUSE F
4530 IF INKEY$="N" THEN GO TO 1000
4550 PRINT AT 10,0;"IF YOU CHANGE YOUR MIND, ENTER...\{20}\{1}GOTO 1000\{20}\{0}...":PRINT AT 15,0;"DO \{20}\{1}NOT\{20}\{0} PRESS RUN..."
4560 GO TO 9898
5000 REM ***\{20}\{1}SEARCH\{20}\{0}***
5010 PRINT "ENTER THE NAME OF THE ACCOUNT:"
5020 INPUT Y$
5021 IF Y$="" THEN GO TO 1E3
5030 IF LEN Y$>15 THEN LET Y$=Y$( TO 15)
5035 LET Y= LEN Y$-1
5040 FOR I=1 TO N1
5050 FOR J=1 TO 15-Y
5060 IF Y$=N$(I,J TO J+Y) THEN GO TO 5100
5070 NEXT J
5080 NEXT I
5090 PRINT "NO SUCH NAME FOUND .. TRY AGAIN"
5095 GO TO 5020
5100 LET Y=I
5110 LET Y$=N$(I)
5120 CLS
5130 RETURN
9898 STOP
9899 GO TO 1000
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
