--- title: "Majesti-Calc" id: 51104 type: "computer_media" slug: "majesti-calc" url: "http://localhost/computer_media/majesti-calc/" markdown_url: "http://localhost/computer_media/majesti-calc.md" published_at: "2023-07-12T01:54:14+00:00" modified_at: "2026-04-01T11:02:45+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A personal finance tracker that manages bills and income across parallel arrays, with printer support and machine code enhancement." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Bernard Souchek" slug: "bernard-souchek" taxonomy: "indiv" url: "http://localhost/indiv/bernard-souchek/" genre: - name: "Finance" slug: "finance" taxonomy: "genre" url: "http://localhost/type/finance/" - name: "Home" slug: "home" taxonomy: "genre" url: "http://localhost/type/home/" media_type: "Program" programmers: - name: "Bernard Souchek" slug: "bernard-souchek" taxonomy: "indiv" url: "http://localhost/indiv/bernard-souchek/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Majesti-Calc%20%281986%29%28Souchek%2C%20Bernard%29%28US%29%28TS2068%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2023/07/SCR-20260401-gtls.png" article_media: - id: 39170 title: "The Fame & The Glory" type: "article" url: "http://localhost/article/the-fame-the-glory/" media_type_tags: "Finance, Home" --- # Majesti-Calc 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 `20`–`30` 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 Range | Section | | --- | --- | | 10–40 | Bootstrap / machine code loader | | 100–150 | Variable and array initialization | | 1000–1090 | Main menu | | 1300–1350 | Save bills | | 1400–1450 | Save income | | 1600–1675 | Load bills | | 1800–1875 | Load income | | 2000–2115 | Display all bills | | 2300–2385 | Sort (filter) bills by code | | 2500–2610 | Display all income | | 2800–2885 | Sort (filter) income by code | | 3000–3080 | Input bills | | 3500–3580 | Input income | | 3600–3730 | Change (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 `1855`–`1870` 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 `2325`–`2360` (bills) or `2827`–`2860` (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 `3600`–`3730`) 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()`. ## 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 " 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 ```