Checkbook Manager is a personal finance tracking program that records checks and deposits in parallel arrays, maintaining a running account balance after each transaction. It allocates five arrays of 250 elements each — date (D), check number (C), payee/source name (N$), amount (A), and post-transaction balance (B) — along with a per-check charge/fee (CC) entered at startup. The transaction display routine at line 3500 uses inverse-video digit characters (CHR$ with offsets of 156) to render transaction numbers visually. Scanning functions allow the user to browse transactions either by date (line 4000) or alphabetically by payee name (line 5000), with the name-scan using a string-comparison loop to find the next alphabetical match. An overdraft warning prompts the user to void the most recent transaction if the balance falls below zero.
Program Analysis
Program Structure
The program is organized into functional blocks separated by line number ranges:
- Lines 1–108: Initialization — prompts for a per-transaction charge/check fee (
CC), dimensions five arrays, and zeroes the balance (BA) and transaction counter (LT). - Lines 200–350: Main menu — displays balance, fee, and five options; polls
INKEY$in a tight loop. - Lines 1000–2460: Transaction entry — shared routine for checks (type
T=1) and deposits (T=2), with overdraft detection and correction. - Lines 3000–3650: Transaction display — shows up to eight recent (or selected) entries in a formatted ledger; subroutine entry at line 3500 (body starts at 3501).
- Lines 4000–4130: Date-range scan — finds the first transaction on or after an entered date and pages forward.
- Lines 5000–5250: Name scan — iterates all transactions alphabetically by payee, displaying matches eight at a time.
Array Layout
| Array | Size | Purpose |
|---|---|---|
D(250) | 250 | Date stored as MMDD integer (e.g., 1225 = Dec 25) |
C(250) | 250 | Check number; 0 indicates a deposit |
N$(250,17) | 250 × 17 chars | Payee name or deposit source |
A(250) | 250 | Transaction amount |
B(250) | 250 | Running balance after each transaction |
Key BASIC Idioms
The main menu (lines 300–350) uses consecutive IF INKEY$="n" THEN GOTO tests with a fall-through GOTO 300, forming a polling loop without PAUSE. This is a standard busy-wait approach for single-keypress menus.
Date parsing at lines 2130–2160 splits a four-digit MMDD integer by integer division: H=INT(D(LT)/100) gives the month and L=D(LT)-H*100 gives the day. The same split is repeated in the display subroutine at lines 3550–3560.
The display subroutine is entered via GOSUB 3500, but because a RETURN statement at 3650 terminates the routine and line 3500 does not exist, execution falls through to line 3501 automatically — a common technique to position a subroutine’s first executable statement one line past its nominal entry point.
Inverse-Video Transaction Numbers
Lines 3570–3585 render transaction sequence numbers using inverse-video digit characters. The variable I$ is set to STR$ Z, and individual digit characters are extracted with VAL I$(n), then offset by 156 and passed to CHR$. This produces the inverse-video versions of the digits 0–9, which reside at character codes 156–165, giving the transaction number a visually distinct appearance in the ledger.
Name-Scan Algorithm
The name-scan routine (lines 5000–5250) performs an alphabetical traversal of the payee name array without sorting. On each pass it scans all LT entries and finds matches equal to the current search key Q$, displaying each as a ledger row. Simultaneously it tracks the lexicographically smallest name greater than Q$ in R$. After displaying eight matches (P=8) or exhausting the array, it advances Q$ to R$ and repeats. The sentinel value R$="""" (a literal quote character) is used as an initial “infinity” string, since the quote character has a high ASCII value relative to typical name strings.
Balance and Fee Calculation
At line 2380, when recording a check, the balance is reduced by both the check amount and the per-transaction fee: BA=BA-A(LT)-CC. Deposits (line 2390) add only the amount with no fee deduction. This models a checking account with a per-item service charge entered at program start.
Bugs and Anomalies
- The date-scan loop at lines 4020–4030 increments
Jand testsD(J)<DTwithout bounds checking againstLT. If no transaction meets the date criterion, the loop reads beyond valid data in the array. - Line 3030 calls
GOSUB 3500, but the subroutine’sFORloop variableZis also used by the name-scan at line 5065 and lines 5080–5090, creating a shared global variable that could cause confusion if routines are interleaved unexpectedly. - Lines 3535–3550 contain a flag
Fintended to allow the name-scan to jump into the middle of the display loop, bypassing theFORstatement. While functional, this pattern uses the subroutine as a re-entrant code block rather than a true subroutine, which is fragile. - Line 5160 compares
R$to""""to detect that no next name was found, but if a payee name actually begins with a quote character, the termination logic would fail. - The initial section (lines 30–60) prints and pauses to show the entered
CCvalue before dimensioning arrays (lines 101–105), meaning that if execution somehow bypassed those lines, the arrays would be undefined. In practice, execution is linear from line 1, so this is not a runtime issue.
Content
Image Gallery
Source Code
1 REM "ACCOUNT"
30 PRINT "ENTER CHARGE/CHECK(C/C):";
40 INPUT CC
50 PRINT CC
60 PAUSE 60
101 DIM D(250)
102 DIM C(250)
103 DIM N$(250,17)
104 DIM A(250)
105 DIM B(250)
108 LET BA=0
109 LET LT=0
200 CLS
205 PRINT "BALANCE:$";BA
210 PRINT "C/C:$";CC
220 PRINT TAB 10;"OPTIONS"
225 PRINT AT 4,9;"1)CHECK ISSUED"
230 PRINT TAB 9;"2)DEPOSIT"
250 PRINT TAB 9;"3)ACCOUNT OF"
260 PRINT TAB 11;"LATEST TRANSACTIONS"
270 PRINT TAB 9;"4)SCAN BY DATE"
280 PRINT TAB 9;"5)SCAN BY NAME"
300 IF INKEY$="1" THEN GOTO 1000
310 IF INKEY$="2" THEN GOTO 2000
320 IF INKEY$="3" THEN GOTO 3000
330 IF INKEY$="4" THEN GOTO 4000
340 IF INKEY$="5" THEN GOTO 5000
350 GOTO 300
1000 LET T=1
1100 GOTO 2050
2000 LET T=2
2050 CLS
2100 LET LT=LT+1
2110 PRINT "ENTER DATE(MMDD):";
2120 INPUT D(LT)
2130 LET H=INT (D(LT)/100)
2140 IF H=0 THEN GOTO 2120
2150 LET L=D(LT)-H*100
2160 PRINT H;"/";L
2170 IF T=2 THEN GOTO 2230
2180 PRINT "ENTER CHECK NUMBER:";
2190 INPUT C(LT)
2200 PRINT C(LT)
2210 PRINT "CHECK ISSUED TO:";
2220 GOTO 2240
2230 PRINT "SOURCE OF DEPOSIT:"
2235 LET C(LT)=0
2240 INPUT N$(LT)
2250 PRINT TAB 7;N$(LT)
2260 IF T=1 THEN PRINT "AMOUNT OF CHECK:";
2270 IF T=2 THEN PRINT "AMOUNT OF DEPOSIT:";
2280 INPUT A(LT)
2290 PRINT A(LT)
2330 PRINT "IS THE INFORMATION CORRECT","(Y OR N)"
2340 INPUT Q$
2350 IF Q$="Y" THEN GOTO 2380
2360 LET LT=LT-1
2370 GOTO 200
2380 IF T=1 THEN LET BA=BA-A(LT)-CC
2390 IF T=2 THEN LET BA=BA+A(LT)
2392 LET B(LT)=BA
2395 IF BA>=0 THEN GOTO 3000
2400 PRINT "YOUR ACCOUNT IS OVERDRAWN"
2410 PRINT "DO YOU WISH TO CORRECT THIS","TRANSACTION(Y OR N)"
2420 INPUT Q$
2430 IF Q$="N" THEN GOTO 3000
2440 LET BA=BA+A(LT)+CC
2450 LET LT=LT-1
2460 GOTO 200
3000 LET UL=LT
3010 LET LL=LT-7
3020 IF LL<1 THEN LET LL=1
3030 GOSUB 3500
3040 PRINT
3050 PRINT "PRESS N FOR NEW OPTION"
3060 IF INKEY$="N" THEN GOTO 200
3070 GOTO 3060
3501 LET F=0
3502 CLS
3505 PRINT "C/C:$";CC;" BALANCE:$";BA
3510 PRINT "TN :DATE :CHCK:CHCK ISSD OR DPST"
3520 PRINT " :AMOUNT :BAL. AFTER TRANS."
3530 PRINT
3535 IF F=1 THEN GOTO 3550
3540 FOR Z=LL TO UL
3550 LET H=INT (D(Z)/100)
3560 LET L=D(Z)-H*100
3565 LET I$=STR$ Z
3570 IF Z<10 THEN PRINT " ";CHR$ (Z+156);
3580 IF Z>9 AND Z<100 THEN PRINT " ";CHR$ (VAL I$(1)+156);CHR$ (VAL I$(2)+156);
3585 IF Z>=100 THEN PRINT CHR$ (VAL I$(1)+156);CHR$ (VAL I$(2)+156);CHR$ (VAL I$(3)+156);
3590 PRINT " ";H;"/";L;TAB 10;
3600 IF C(Z)<>0 THEN GOTO 3610
3604 PRINT "DPST";
3606 GOTO 3620
3610 IF C(Z)<1000 THEN PRINT "0";
3615 PRINT C(Z);
3620 PRINT TAB 14;":";N$(Z)
3630 PRINT TAB 3;"$";A(Z);TAB 14;"$";B(Z)
3635 IF F=1 THEN GOTO 5100
3640 NEXT Z
3650 RETURN
4000 CLS
4005 PRINT "ENTER THE DATE(MMDD) THAT YOU","WISH TO START WITH"
4010 INPUT DT
4015 LET J=0
4020 LET J=J+1
4030 IF D(J)<DT THEN GOTO 4020
4040 IF J+7>=LT THEN GOTO 3000
4050 LET LL=J
4060 LET UL=J+7
4070 GOSUB 3500
4080 PRINT "PRESS N FOR NEW, C FOR CONTINUE"
4090 IF INKEY$="N" THEN GOTO 200
4100 IF INKEY$="C" THEN GOTO 4120
4110 GOTO 4090
4120 LET J=Z
4130 GOTO 4040
5000 CLS
5005 PRINT "ENTER THE NAME THAT YOU WISH TO START WITH"
5010 INPUT Q$
5020 LET P=0
5030 LET R$=""""
5040 FOR J=1 TO LT
5050 IF N$(J)<Q$ THEN GOTO 5150
5060 IF N$(J)=Q$ THEN GOTO 5065
5063 IF N$(J)<R$ THEN LET R$=N$(J)
5064 GOTO 5145
5065 LET Z=J
5070 LET F=1
5080 IF P=0 THEN GOTO 3502
5090 GOTO 3550
5100 LET F=0
5110 LET P=P+1
5145 IF P=8 THEN GOTO 5200
5150 NEXT J
5160 IF R$="""" THEN GOTO 3040
5170 LET Q$=R$
5180 GOTO 5030
5200 LET P=0
5210 PRINT
5220 PRINT "PRESS N FOR NEW, C FOR CONTINUE"
5230 IF INKEY$="N" THEN GOTO 200
5240 IF INKEY$="C" THEN GOTO 5150
5250 GOTO 5230
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.