Majesti-Calc

Developer(s): Bernard Souchek
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Finance, Home

Majesti-Calc is a personal finance manager for tracking bills and income, implemented in BASIC with a machine code component loaded from tape. The program maintains two parallel data sets — bills and income — each split across five arrays per set (date, description, code, payee, and numeric amount), allowing up to 300 bill entries and 200 income entries. It supports tape-based saving and loading of all array data, on-screen display with optional simultaneous LPRINT output to a printer, and filtering records by a user-supplied code string. A change-data routine allows in-place editing of any record by line number. The machine code block, loaded at address 64719, is invoked at startup via RANDOMIZE USR before the BASIC initializes its arrays.


Program Analysis

Program Structure

The program is organized into clearly delineated sections, each introduced by a REM statement. The entry point at line 10 jumps to line 40, which fires the machine code routine. Lines 2030 handle tape setup and are only reached if the machine code bootstrap at line 40 redirects execution there. After machine code returns, the main BASIC program initializes variables and arrays starting at line 100.

Line RangeSection
10–40Bootstrap / machine code loader
100–150Variable and array initialization
1000–1090Main menu
1300–1350Save bills
1400–1450Save income
1600–1675Load bills
1800–1875Load income
2000–2115Display all bills
2300–2385Sort (filter) bills by code
2500–2610Display all income
2800–2885Sort (filter) income by code
3000–3080Input bills
3500–3580Input income
3600–3730Change (edit) existing record

Data Model

Bills and income are each held in five parallel arrays, indexed by record number. The bills counter is W and the income counter is Q; both are initialized to zero and incremented on each new entry.

  • Bills: D$(300,5) date, C$(300,1) code, b$(300,20) payee, I$(300,20) description, C(300) amount
  • Income: E$(200,5) date, F$(200,1) code, a$(200,20) payee, J$(200,20) description, D(40) amount

Note a significant anomaly: the income numeric array D(40) is dimensioned to only 40 elements, while its companion string arrays allow up to 200 records. This means entering more than 40 income records will cause a subscript-out-of-range error. The load loop at lines 18551870 also iterates up to 500, which would overflow both the bills array (C(300)) and the income array (D(40)).

Tape Save and Load

Each data set is saved as five separate named DATA blocks. The bills set uses names "BILLS", "BILL", "BIL", "billsa", and "BI"; income uses "INCOME", "INCOM", "INCO", "incomea", and "INC". After loading bills, the program scans the numeric array to find the first zero element to determine the active record count, storing it in W (line 1670) or Q (line 1870). This approach relies on the convention that unused numeric array slots remain zero, which is guaranteed by DIM initialization.

Display and Printing

Both the “see” and “sort” sections offer a dual-output mode: option "1" sends output to both the screen and the printer via LPRINT, while option "2" displays on screen only. The printer output uses wider TAB stops to take advantage of a full-width printer line. The screen display uses \:: (█, a solid block graphic) as a visual separator between fields. Running totals are accumulated into L (bills) or Y (income) across the display loop.

Sort / Filter Routine

The “sort” feature is actually a filter: the user inputs a code string Z$, and the loop at lines 23252360 (bills) or 28272860 (income) prints only records whose code field matches. There is a structural bug in the bills sort at line 2345: the display line references b$(J) (using loop variable J from the “see bills” section) instead of b$(B) (the current sort loop variable B). This would display incorrect payee data.

Record Editing

The change-data routine (lines 36003730) prompts for a record index q and new values for all five fields, then writes them back into the appropriate arrays based on whether the user typed "B" (bills) or "I" (income). Each field assignment is a separate IF statement rather than an IF/THEN block, leading to five sequential conditional checks per data set. At line 3705, the bills numeric array is referenced as c(q) (lowercase) rather than C(q) — on this platform, variable names are case-sensitive for numeric arrays, so this would generate a “variable not found” error if that branch were taken. The correct array is C().

Content

Appears On

Related Products

Related Articles

And now, here are a few more words about the last contest. First, we would like to thank all of...

Related Content

Image Gallery

Majesti-Calc

Source Code

   10 GO TO 40
   20 CLEAR 64715
   30 LOAD ""CODE 
   40 RANDOMIZE USR 64719
  100 LET W=0
  105 LET Q=0
  110 DIM D$(300,5)
  115 DIM I$(300,20)
  120 DIM C$(300,1)
  122 DIM b$(300,20)
  125 DIM C(300)
  130 DIM E$(200,5)
  135 DIM J$(200,20)
  140 DIM F$(200,1)
  142 DIM a$(200,20)
  145 DIM D(40)
  150 BORDER 5: PAPER 7: INK 0
 1000 REM MENU
 1002 CLS 
 1005 PRINT ,,"1-SEE BILLS"
 1007 PRINT ,,"  2-SORT BILLS"
 1010 PRINT ,,"3-SEE INCOME"
 1012 PRINT ,,"  4-SORT INCOME"
 1015 PRINT ,,"5-INPUT BILLS"
 1020 PRINT ,,"6-INPUT INCOME"
 1025 PRINT ,,"7-SAVE BILLS"
 1030 PRINT ,,"8-SAVE INCOME"
 1033 PRINT ,,"9-LOAD BILLS"
 1038 PRINT ,,"0-LOAD INCOME"
 1039 PRINT ,,"C-CHANGE DATA"
 1040 INPUT M$
 1050 IF M$="1" THEN GO TO 2000
 1055 IF M$="2" THEN GO TO 2300
 1060 IF M$="3" THEN GO TO 2500
 1065 IF M$="4" THEN GO TO 2800
 1070 IF M$="5" THEN GO TO 3000
 1075 IF M$="6" THEN GO TO 3500
 1080 IF M$="7" THEN GO TO 1300
 1085 IF M$="8" THEN GO TO 1400
 1086 IF M$="9" THEN GO TO 1600
 1088 IF M$="0" THEN GO TO 1800
 1089 IF M$="C" THEN GO TO 3600
 1090 GO TO 1040
 1300 REM SAVE BILLS
 1305 CLS 
 1310 PRINT ,,"Position Tape In Correct Place": PRINT ,,"And Press ENTER"
 1320 INPUT K$
 1330 SAVE "BILLS" DATA D$()
 1335 SAVE "BILL" DATA I$()
 1340 SAVE "BIL" DATA C$()
 1342 SAVE "billsa" DATA b$()
 1345 SAVE "BI" DATA C()
 1350 GO TO 1000
 1400 REM SAVE INCOME
 1405 CLS 
 1410 PRINT ,,"Position Tape In Correct Place": PRINT ,,"And Press ENTER"
 1420 INPUT k$
 1430 SAVE "INCOME" DATA E$()
 1435 SAVE "INCOM" DATA J$()
 1440 SAVE "INCO" DATA F$()
 1442 SAVE "incomea" DATA a$()
 1445 SAVE "INC" DATA D()
 1450 GO TO 1000
 1600 REM LOAD BILLS
 1605 CLS 
 1610 PRINT ,,"Position Tape In Correct Place": PRINT ,,"And Press ENTER "
 1620 INPUT k$
 1630 LOAD "BILLS" DATA D$()
 1635 LOAD "BILL" DATA I$()
 1640 LOAD "BIL" DATA C$()
 1642 LOAD "billsa" DATA b$()
 1645 LOAD "BI" DATA C()
 1650 PRINT ,,"Stop Tape Recorder": PAUSE 100
 1655 FOR I=1 TO 500
 1660 IF C(I)=0 THEN GO TO 1670
 1665 NEXT I
 1670 LET W=I-1
 1675 GO TO 1000
 1800 REM LOAD INCOME
 1805 CLS 
 1810 PRINT ,,"Position Tape In Correct Place": PRINT ,,"And Press ENTER"
 1820 INPUT K$
 1830 LOAD "INCOME" DATA E$()
 1835 LOAD "INCOM" DATA J$()
 1840 LOAD "INCO" DATA F$()
 1842 LOAD "incomea" DATA a$()
 1845 LOAD "INC" DATA D()
 1850 PRINT ,,"Stop Tape Recorder": PAUSE 100
 1855 FOR I=1 TO 500
 1860 IF D(I)=0 THEN GO TO 1870
 1865 NEXT I
 1870 LET Q=I-1
 1875 GO TO 1000
 2000 REM SEE BILLS
 2005 CLS 
 2010 PRINT "1-Print Copy & On Screen": PRINT ,,"2-Print Just On Screen"
 2015 INPUT N$: CLS 
 2020 PRINT TAB 10;"TOTAL BILLS"
 2022 PRINT TAB 10;"-----------"
 2025 IF N$="1" THEN LPRINT TAB 30;"TOTAL BILLS"
 2027 IF N$="1" THEN LPRINT TAB 30;"-----------"
 2030 PRINT : IF N$="1" THEN LPRINT 
 2035 PRINT "DATE";TAB 5;"CODE";TAB 11;"DESCRIPTION";TAB 23;"COST": PRINT 
 2040 IF N$="1" THEN LPRINT "DATE";TAB 7;"CODE";TAB 20;"TO";TAB 40;"DESCRIPTION";TAB 60;"COST":
 2042 IF N$="1" THEN LPRINT "---------------------------------------------------------------------"
 2045 LET L=0
 2050 FOR J=1 TO 150
 2055 IF C(J)=0 THEN GO TO 2080
 2060 PRINT D$(J);TAB 5;"\::";C$(J);"-";I$(J);"      \::";b$(J);TAB 23;"\::";C(J)
 2063 PRINT 
 2065 IF N$="1" THEN LPRINT D$(J);TAB 9;C$(J);TAB 16;b$(J);TAB 39;I$(J);TAB 61;C(J)
 2070 LET L=L+C(J)
 2075 NEXT J
 2080 PRINT : IF N$="1" THEN LPRINT 
 2085 PRINT TAB 10;"TOTAL=$";L
 2090 IF N$="1" THEN LPRINT TAB 50;"TOTAL=$";L
 2095 PRINT : IF N$="1" THEN LPRINT 
 2100 PRINT "1-Return To Main Menu": PRINT "2-Sort Bills"
 2105 INPUT m$
 2110 IF m$="1" THEN GO TO 1000
 2113 IF m$="2" THEN GO TO 2300
 2115 GO TO 2105
 2300 REM SORT BILLS
 2305 CLS : LET L=0
 2310 PRINT "1-Print Copy & On Screen": PRINT ,,"2-Print Just On Screen"
 2315 INPUT N$: PRINT 
 2320 PRINT "Input Code To Sort By": INPUT Z$: PRINT Z$: CLS 
 2321 PRINT "DATE";TAB 5;"CODE";TAB 11;"DESCRIPTION";TAB 23;"COST": PRINT 
 2323 IF N$="1" THEN LPRINT "DATE";TAB 7;"CODE";TAB 20;"TO";TAB 40;"DESCRIPTION";TAB 60;"COST":
 2324 IF N$="1" THEN LPRINT "---------------------------------------------------------------------"
 2325 FOR B=1 TO 200
 2330 IF C(B)=0 THEN GO TO 2370
 2335 IF C$(B)=Z$ THEN GO TO 2345
 2340 NEXT B
 2345 PRINT D$(B);TAB 5;"\::";C$(B);"-";I$(B);"      \::";b$(J);TAB 23;"\::";C(B)
 2348 PRINT 
 2350 IF N$="1" THEN LPRINT D$(B);TAB 9;C$(B);TAB 16;b$(B);TAB 39;I$(B);TAB 61;C(B)
 2355 LET L=L+C(B)
 2360 NEXT B
 2370 PRINT : PRINT TAB 10;"TOTAL=$";L
 2375 IF N$="1" THEN LPRINT : LPRINT TAB 50;"TOTAL=$";L:
 2380 PRINT : PRINT "Press Any Key To Continue": INPUT a$
 2385 GO TO 1000
 2500 REM SEE INCOME
 2505 CLS : LET Y=0
 2510 PRINT "1-Print Copy & On Screen": PRINT ,,"2-Print Just On Screen"
 2515 INPUT N$: CLS 
 2520 PRINT TAB 10;"TOTAL INCOME": PRINT 
 2525 IF N$="1" THEN LPRINT TAB 30;"TOTAL INCOME": LPRINT TAB 30;"------------"
 2530 PRINT "DATE";TAB 6;"CODE";TAB 13;"DESCRIPTION";TAB 25;"AMOUNT": LPRINT 
 2535 IF N$="1" THEN LPRINT "DATE";TAB 7;"CODE";TAB 20;"TO";TAB 40;"DESCRIPTION";TAB 61;"AMOUNT":
 2537 IF N$="1" THEN LPRINT "---------------------------------------------------------------------"
 2540 LET Y=0
 2545 FOR J=1 TO 200
 2550 IF D(J)=0 THEN GO TO 2580
 2555 PRINT E$(J);TAB 5;"\::";F$(J);"-";J$(J);"  \::    ";a$(J);TAB 23;"\::";D(J)
 2558 PRINT 
 2560 IF N$="1" THEN LPRINT E$(J);TAB 9;F$(J);TAB 16;a$(J);TAB 39;J$(J);TAB 61;D(J)
 2565 LET Y=Y+D(J)
 2570 NEXT J
 2580 PRINT : PRINT TAB 10;"TOTAL=$";Y
 2585 IF N$="1" THEN LPRINT : LPRINT TAB 50;"TOTAL=$";Y
 2590 PRINT : IF N$="1" THEN LPRINT 
 2595 PRINT "1-Return To Main Menu": PRINT "2-Sort Income"
 2600 INPUT m$
 2605 IF m$="1" THEN GO TO 1000
 2608 IF m$="2" THEN GO TO 2800
 2610 GO TO 2600
 2800 REM SORT INCOME
 2805 CLS : LET Y=0
 2810 PRINT "1-Print Copy & On Screen": PRINT ,,"2-Print Just On Screen"
 2815 INPUT N$: PRINT 
 2820 PRINT "Input Code To Sort By": INPUT Z$: CLS 
 2822 PRINT "DATE";TAB 5;"CODE";TAB 11;"DESCRIPTION";TAB 23;"COST": PRINT 
 2824 IF N$="1" THEN LPRINT "DATE";TAB 7;"CODE";TAB 20;"TO";TAB 40;"DESCRIPTION";TAB 60;"COST":
 2825 IF N$="1" THEN LPRINT "---------------------------------------------------------------------"
 2827 FOR B=1 TO 200
 2830 IF D(B)=0 THEN GO TO 2870
 2835 IF F$(B)=Z$ THEN GO TO 2845
 2840 NEXT B
 2845 PRINT E$(B);TAB 5;"\::";F$(B);"-";J$(B);"  \::    ";a$(B);TAB 23;"\::";D(B)
 2848 PRINT 
 2850 IF N$="1" THEN LPRINT E$(B);TAB 9;F$(B);TAB 16;a$(B);TAB 39;J$(B);TAB 61;D(B)
 2855 LET Y=Y+D(B)
 2860 NEXT B
 2870 PRINT : PRINT TAB 10;"TOTAL=$";Y: PRINT 
 2875 IF N$="1" THEN LPRINT : LPRINT TAB 50;"TOTAL=$";Y: LPRINT 
 2880 PRINT ,,"Press Any Key To Continue": INPUT a$
 2885 GO TO 1000
 3000 REM INPUT BILLS
 3005 LET W=W+1
 3007 CLS 
 3010 PRINT ,,"Input Date"
 3015 INPUT D$(W): PRINT D$(W)
 3020 PRINT ,,"Input Code"
 3025 INPUT C$(W): PRINT C$(W)
 3027 PRINT ,,"Input Who To "
 3028 INPUT b$(W): PRINT b$(W)
 3030 PRINT ,,"Input Description"
 3035 INPUT I$(W): PRINT I$(W)
 3040 PRINT ,,"Input Cost"
 3045 INPUT C(W): PRINT C(W)
 3050 PRINT : PRINT "Information Correct ?": INPUT M$
 3055 IF M$="n" OR M$="no" THEN GO TO 3007
 3065 PRINT ,,"1-Input More Bills": PRINT "2-Return To Main Menu":
 3068 INPUT m$
 3070 IF m$="1" THEN GO TO 3000
 3075 IF m$="2" THEN GO TO 1000
 3080 GO TO 3068
 3500 REM INPUT INCOME
 3502 LET Q=Q+1
 3505 CLS 
 3510 PRINT ,,"Input Date"
 3515 INPUT E$(Q): PRINT E$(Q)
 3520 PRINT ,,"Input Code"
 3525 INPUT F$(Q): PRINT F$(Q)
 3527 PRINT ,,"Input Who To"
 3528 INPUT a$(Q): PRINT a$(Q)
 3530 PRINT ,,"Input Description"
 3535 INPUT J$(Q): PRINT J$(Q)
 3540 PRINT ,,"Input Amount"
 3545 INPUT D(Q): PRINT D(Q)
 3550 PRINT : PRINT "Information Correct ?": INPUT M$
 3555 IF M$="n" OR M$="no" THEN GO TO 3505
 3565 PRINT : PRINT "1-Input More Income": PRINT "2-Return To Main Menu":
 3568 INPUT m$
 3570 IF m$="1" THEN GO TO 3500
 3575 IF m$="2" THEN GO TO 1000
 3580 GO TO 3568
 3600 REM CHANGE DATA
 3605 CLS 
 3610 PRINT "Do You Want To Change The": PRINT "Bills Or Income ? (B or I)": PRINT 
 3615 INPUT u$
 3620 PRINT ,,"Input Line Number": PRINT "You Want To Change": PRINT 
 3625 INPUT q
 3630 PRINT "Input New Date"
 3635 INPUT q$: PRINT q$: PRINT 
 3640 PRINT "Input New Code"
 3645 INPUT w$: PRINT w$: PRINT 
 3650 PRINT "Input New <who to>"
 3655 INPUT p$: PRINT p$: PRINT 
 3660 PRINT "Input New Description"
 3665 INPUT r$: PRINT r$: PRINT 
 3670 PRINT "Input New Cost"
 3675 INPUT t: PRINT t: PRINT 
 3680 PRINT ,,"Is This Correct ?"
 3685 INPUT y$
 3690 IF y$="n" OR y$="no" THEN GO TO 3600
 3695 IF u$="B" THEN LET D$(q)=q$
 3697 IF u$="B" THEN LET C$(q)=w$
 3700 IF u$="B" THEN LET b$(q)=p$
 3702 IF u$="B" THEN LET I$(q)=r$
 3705 IF u$="B" THEN LET c(q)=t
 3710 IF u$="I" THEN LET E$(q)=q$
 3712 IF u$="I" THEN LET F$(q)=w$
 3715 IF u$="I" THEN LET a$(q)=p$
 3717 IF u$="I" THEN LET J$(q)=r$
 3720 IF u$="I" THEN LET D(q)=t
 3730 GO TO 1000

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top