Home Asset Manager

Date: 1983
Type: Cassette
Platform(s): TS 1000
Tags: Home

Home Asset Manager is a valuables inventory program that lets users add, delete, search, list, and save records describing household assets with fields for date, serial number, model, description, price, and location. Each record is stored as a fixed-length string in a DIM D$(MAX,RLEN) array, with record indices tracked via a packed string U$ whose characters serve as array row pointers, allowing up to 255 records. The program calculates available memory at runtime using PEEK on system variables 16386/16387 and 16412/16413 to determine how many records will fit before dimensioning the array. A machine code routine at line 9800–9830 is used for fast string searching, invoked via USR 16524 after POKEing the search key into address 16514. The listing routine at line 7000 supports output to screen, printer, or both, and can accumulate running totals for fields whose names begin with a period.


Program Analysis

Program Structure

The program is organized into clearly labeled REM-delineated sections, each reachable via computed GO TO at line 1250 (GOTO VAL "1000+1000*VAL C$"), which dispatches menu choices 1–6 to line 2000 (Add), 3000 (Delete), 4000 (Find/Search), 5000 (Save), 6000 (Quit), and 7000 (List). Control returns to the main loop at line 1000 after most operations.

Line RangeSection
10–860Initialization, screen template, field definitions
1000–1250Main display/menu loop
2000–2240Add record
3000–3090Delete record
4000–4550Search/Find
5000–5080Save to tape
6000–6020Quit
7000–7250List records
8000–8790Utility subroutines (pause, print, totals)
9800–9830Machine code search wrapper

Initialization and Memory Calculation

Lines 20–860 perform a detailed initialization sequence. Constants like O=PI/PI (i.e., 1) and Z=O-O (i.e., 0) are used throughout as integer substitutes, a common ZX81 BASIC idiom to avoid slow integer-parsing of literals. The screen template string S$ is built by concatenation of block-graphic border characters and spaces to create a framed display area.

At line 550, available free RAM is computed directly from system variables:

  • PEEK 16386 + PEEK 16387*256 — RAMTOP (top of usable RAM)
  • PEEK 16412 + PEEK 16413*256 — start of the display file or variables area

After subtracting 400 bytes of overhead, MAX is calculated as how many fixed-length records of size RLEN+5 will fit, capped at 255 (line 565) because record indices are stored as single characters in U$, whose CODE values must fit in one byte.

Record Storage Scheme

Records are stored in D$(MAX,RLEN), a two-dimensional string array where each row is one fixed-length record. The record length RLEN is computed at runtime by summing the field widths F(1) through F(FLDS) (lines 510–540). Six fields are defined:

FieldNameWidth
1DATE8
2SERIAL15
3MODEL10
4DESCRPT15
5.PRICE8
6PLACE10

The “active record index” string U$ tracks which rows of D$ are in use. Each character’s CODE value is the row index into D$. Free row indices are tracked in E$, initialized at lines 860–880 by appending CHR$ B for each possible index from 1 to MAX. When a record is added, a character is consumed from the front of E$ and appended to U$.

Machine Code Usage

Line 10 contains a REM statement with embedded machine code bytes: itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-51725 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.6 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"B itemtype='https://schema.org/Blog' itemscope='itemscope' class="wp-singular computer_media-template-default single single-computer_media postid-51725 wp-custom-logo wp-embed-responsive wp-theme-astra wp-child-theme-astra-child ast-desktop ast-separate-container ast-left-sidebar astra-4.12.6 group-blog ast-blog-single-style-1 ast-custom-post-type ast-single-post ast-inherit-site-logo-transparent ast-hfb-header ast-full-width-primary-header ast-box-layout ast-normal-title-enabled astra-addon-4.12.4"B...\C9. This is a Z80 routine loaded into the REM area, invoked via USR 16524 at line 9820. The search subroutine (lines 9800–9830) POKEs the search character into address 16514, then calls the machine code routine and uses 255-USR 16524 to derive a result. This is a standard technique for embedding and calling machine code within a REM statement on this platform.

Search Mechanism

The search routine (lines 4000–4200) calls the Add subroutine at line 2115 to collect search key values into buffer B$. It then iterates over all records in U$, comparing each field in the record against the corresponding field from B$ after stripping trailing spaces (subroutine at 4500). A record matches if every non-empty search field matches as a prefix of the stored field value (Y$(TO LEN X$)=X$). Matching record indices are collected into L$, which is then temporarily substituted for U$ to display results via the List routine.

The delete operation at lines 3000–3090 uses the machine code search subroutine (via GOSUB 9800) to locate the current record’s index J within U$, then splices it out with string slicing.

Navigation and Display

The main loop at line 1015–1170 implements a blinking cursor effect by alternating POKEs at two display file addresses (D+67 and D+98) between two block graphic characters, toggled by FL=NOT FL. The variable D is the display file address computed from system variable at DF (16396).

Record browsing is handled by lines 8500–8530: pressing CHR$ 113 (“q”) increments CR (current record pointer into U$) and pressing CHR$ 112 (“p”) decrements it, with boundary checks. The menu selection animation at lines 1220–1240 scrolls a cursor character down the screen using a FOR loop with STEP -O (i.e., step –1).

Listing and Totals

The List routine (lines 7000–7250) outputs to screen, printer, or both depending on the user’s choice, using a shared output subroutine at line 8100 that conditionally calls LPRINT and/or PRINT. Fields whose names begin with "." (here, .PRICE) are automatically summed into array T(FLDS) at line 7115, and totals are printed by the subroutine at line 8600. A pagination counter LCNT pauses screen output when a page fills.

Notable Techniques and Idioms

  • O=PI/PI and Z=O-O as integer constants 1 and 0 to speed execution and reduce program size.
  • VAL "expression" used in computed GO TO targets and initializations (e.g., line 105 SZ=VAL "22-1-MS") — a known memory-saving technique.
  • Packed index string U$ using character codes as array row pointers — a compact record-tracking approach within BASIC’s string capabilities.
  • Free memory probing via PEEK on system variables before dimensioning arrays, allowing the program to adapt to whatever RAM is available.
  • The GOSUB 2115 call from line 4030 re-uses the Add record input section mid-program, with a sentinel check at line 2180 (IF C$="3" THEN RETURN) to distinguish search-mode entry from actual adds.
  • The blinking cursor at lines 1152–1156 uses direct POKE to the display file rather than PRINT AT, avoiding screen flicker from redrawing.

Bugs and Anomalies

  • Line 1100 uses TAB O (TAB 1) repeatedly in a single PRINT statement to create column separations — these are literal TAB 1 calls, which may not provide the expected spacing since TAB moves to an absolute column position, not a relative one, and repeated TAB 1 calls after text has already passed column 1 would have no effect.
  • The field-width loop at lines 4070–4110 slices T$ and Z$ starting from index 1 each time within the loop but also advances by slicing from F(F)+1, so the first field would correctly use T$(1 TO F(1)) and subsequent iterations also work correctly due to repeated re-slicing — this is slightly inefficient but functionally correct.
  • Line 570 prints “RECORDS AVAILIBLE” — a misspelling of “available” that would appear on screen during initialization.
  • The loop at lines 4042–4044 (FOR H=1 TO 10: NEXT H) is an empty delay loop with no effect in FAST mode (line 4056 sets FAST after this loop, but the delay itself is before FAST). It likely served as a brief pause before the FAST search begins.
  • Line 6020 (GOTO 1000) is unreachable because line 6010 is STOP, so the program can only continue from the Quit section if the user does a CONTINUE command.

Content

Appears On

Related Products

A home inventory program that can be invaluable in case of fire or theft. Records date of purchase, place of...

Related Articles

Related Content

Image Gallery

Home Asset Manager

Source Code

  10 REM 31B1B1B1B1B1B1B1B1B2A1040232323234E2346233A8240EDB1C9
  20 DIM Q$(255)
  60 SLOW 
  70 PRINT "INITIALIZING..."
  80 LET B$="                                "
  85 LET LL=32
  90 LET O=PI/PI
  95 LET Z=O-O
 100 LET MS=6
 105 LET SZ=VAL "22-1-MS"
 110 LET CR=O
 115 LET Z$=B$+B$
 117 LET Z$=B$+B$+":'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''':"
 120 LET X$=":                                :"
 125 FAST 
 130 FOR K=O+O+O TO SZ-O-O
 140 LET Z$=Z$+X$
 150 NEXT K
 160 LET Z$=Z$+":..............................................................:"
 170 LET X$=":             %                   :"
 180 FOR K=O TO MS
 190 LET Z$=Z$+X$
 200 NEXT K
 210 LET Z$=Z$+"''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''"
 220 LET S$=Z$
 230 LET X$="TIMEX VALUABLES PROGRAM"
 235 LET H$="BBOOK"
 240 LET S=16-LEN X$/2
 250 LET S$(S TO S+LEN X$-O)=X$
 260 LET DF=16396
 290 LET NLEN=7
 300 LET FLDS=6
 305 DIM F$(FLDS,NLEN)
 310 DIM F(FLDS)
 320 LET F(1)=8
 330 LET F(2)=15
 335 LET F(3)=10
 340 LET F(4)=15
 350 LET F(5)=8
 355 LET F(6)=10
 400 LET F$(1)="DATE"
 410 LET F$(2)="SERIAL"
 420 LET F$(3)="MODEL"
 430 LET F$(4)="DESCRPT"
 440 LET F$(5)=".PRICE"
 450 LET F$(6)="PLACE"
 498 LET NUM=1
 500 REM CALCULATE RLEN
 510 LET RLEN=Z
 520 FOR F=O TO FLDS
 530 LET RLEN=RLEN+F(F)
 540 NEXT F
 545 SLOW 
 550 LET FRE=VAL "((PEEK 16386+PEEK 16387*256)-(PEEK 16412+PEEK 16413*256)-400)"
 560 LET MAX=INT (FRE/(RLEN+5))
 565 IF MAX>255 THEN LET MAX=255
 570 PRINT "RECORDS AVAILIBLE: ";MAX
 580 DIM D$(MAX,RLEN)
 590 DIM N$(RLEN)
 700 LET T2=1
 710 LET T1=SZ+O
 720 DIM B$(RLEN)
 735 FAST 
 800 FOR F=O TO FLDS
 810 LET S=LL*(F+O+O)+O+O
 820 LET S$(S TO S+NLEN)=F$(F)+":"
 830 NEXT F
 840 LET U$=""
 850 LET E$=""
 860 FOR B=O TO MAX
 870 LET E$=E$+CHR$ B
 880 NEXT B
 1000 REM MAIN LOOP
 1005 SLOW 
 1010 PRINT AT Z,Z;S$
 1015 PRINT AT 3,1;
 1017 LET OF=O
 1018 IF CR>LEN U$ OR U$="" OR CR<1 THEN GOTO 1100
 1020 FOR F=O TO FLDS
 1030 PRINT TAB NLEN+O+O;
 1040 PRINT D$(CODE U$(CR),OF TO OF+F(F)-O)
 1050 LET OF=OF+F(F)
 1060 NEXT F
 1100 PRINT AT SZ,O;"(1) ADD";TAB O;"(2) DELETE";TAB O;"(3) SEARCH";TAB O;"(4) SAVE";TAB O;"(5) QUIT"
 1105 PRINT TAB O;"(6) LIST"
 1110 PRINT AT SZ,14;"SELECT: ";
 1120 LET D=PEEK DF+PEEK (DF+O)*256
 1130 LET FL=1
 1140 LET C$=INKEY$
 1145 IF C$=CHR$ 112 OR C$=CHR$ 113 THEN GOTO 8500
 1150 IF C$>="1" AND C$<="6" THEN GOTO 1200
 1152 POKE D+67,CODE ":'.:"(FL+1)
 1154 POKE D+98,CODE "'::."(FL+1)
 1156 LET FL=NOT FL
 1170 GOTO 1140
 1210 PRINT AT SZ,14;"         "
 1220 FOR J=20 TO SZ+VAL C$-O STEP -O
 1225 IF J<20 THEN PRINT AT J+1,13;"% "
 1230 PRINT AT J,13;"%<"
 1240 NEXT J
 1250 GOTO VAL "1000+1000*VAL C$"
 2000 REM ADD
 2010 IF E$>"" THEN GOTO 2100
 2020 PRINT AT T1,T2;"THERE ARE NO FREE";TAB T2;"RECORDS."
 2030 GOTO 8000
 2100 REM ADD
 2110 PRINT AT Z,Z;S$
 2115 LET OF=O
 2120 FOR F=O TO FLDS
 2130 PRINT AT 2+F,NLEN+O+O;"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"( TO F(F))
 2140 INPUT I$
 2150 LET B$(OF TO OF+F(F)-O)=I$
 2160 PRINT AT 2+F,NLEN+O+O;B$(OF TO OF+F(F)-O)
 2165 LET OF=OF+F(F)
 2170 NEXT F
 2180 IF C$="3" THEN RETURN 
 2190 LET CR=CODE E$
 2200 LET E$=E$(2 TO )
 2220 LET D$(CR)=B$
 2230 LET U$=U$+CHR$ CR
 2240 GOTO 1100
 3000 REM DELETE
 3020 LET E$=E$+CHR$ CR
 3030 LET A$=CHR$ CR
 3040 LET Q$=U$
 3060 GOSUB 9800
 3070 LET U$=U$( TO J-1)+U$(J+1 TO )
 3080 LET D$(CR)=N$
 3090 GOTO 1000
 4000 REM FIND
 4005 LET L$=""
 4007 DIM T(FLDS)
 4010 PRINT AT 0,0;S$
 4020 PRINT AT SZ+2,T1;"ENTER YOUR";TAB T1;"SEARCH KEYS:"
 4030 GOSUB 2115
 4035 PRINT AT SZ+2,T1;"           ";TAB T1;"             "
 4040 PRINT AT SZ+2,1;"SEARCHING.."
 4042 FOR H=1 TO 10
 4044 NEXT H
 4050 FOR J=1 TO LEN U$
 4056 FAST 
 4060 LET Z$=D$(CODE U$(J))
 4065 LET T$=B$
 4070 FOR F=1 TO FLDS
 4080 LET X$=T$( TO F(F))
 4090 LET Y$=Z$( TO F(F))
 4095 GOSUB 4500
 4100 LET T$=T$(F(F)+1 TO )
 4110 LET Z$=Z$(F(F)+1 TO )
 4121 IF X$="" THEN GOTO 4150
 4130 IF Y$( TO LEN X$)=X$ THEN GOTO 4150
 4140 GOTO 4200
 4150 NEXT F
 4160 LET L$=L$+U$(J)
 4200 NEXT J
 4201 IF L$>"" THEN GOTO 4300
 4210 PRINT AT SZ+2,1;"NOT FOUND"
 4220 GOSUB 8200
 4230 GOTO 1000
 4300 REM 
 4305 SLOW 
 4310 LET G$=U$
 4320 LET U$=L$
 4330 GOSUB 7000
 4335 LET U$=G$
 4340 GOTO 1000
 4500 REM REMOVE SPACES FM X$/Y$
 4510 FOR G=1 TO LEN X$
 4520 IF X$(LEN X$)=" " THEN LET X$=X$( TO LEN X$-1)
 4530 IF Y$(LEN Y$)=" " THEN LET Y$=Y$( TO LEN Y$-1)
 4540 NEXT G
 4550 RETURN 
 4999 STOP 
 5000 REM SAVE
 5005 CLS 
 5010 PRINT TAB O;"UNDER WHAT NAME SHALL I SAVE    THE INFORMATION: ";
 5020 INPUT A$
 5030 IF A$="" THEN LET A$=H$
 5040 PRINT TAB O;TAB O;"START THE TAPE, AND THEN PRESS  %E%N%T%E%R."
 5050 INPUT Z$
 5055 CLS 
 5060 SAVE A$
 5070 PRINT TAB O;TAB O;"STOP THE TAPE."
 5080 GOTO 8000
 6000 REM QUIT
 6010 STOP 
 6020 GOTO 1000
 7000 REM LIST
 7005 DIM T(FLDS)
 7010 CLS 
 7020 PRINT "LIST TO PRINTER (P), SCREEN (S) OR BOTH (B)?"
 7030 LET K$=INKEY$
 7040 IF K$<>"S" AND K$<>"B" AND K$<>"P" THEN GOTO 7030
 7050 LET PRI=K$<>"S"
 7060 LET SCR=K$<>"P"
 7070 CLS 
 7075 LET LCNT=INT (18/(FLDS+2))
 7080 FOR K=1 TO LEN U$
 7090 FAST 
 7100 LET Z$=D$(CODE U$(K))
 7110 FOR N=1 TO FLDS
 7115 IF F$(N)(1)="." THEN LET T(N)=T(N)+VAL Z$( TO F(N))
 7120 LET O$=F$(N)
 7130 LET O$=O$+":  "+Z$( TO F(N))
 7140 LET Z$=Z$(F(N)+1 TO )
 7150 GOSUB 8100
 7160 NEXT N
 7170 LET O$=""
 7180 FOR G=1 TO 2
 7190 GOSUB 8100
 7200 NEXT G
 7205 LET LCNT=LCNT-1
 7210 IF (SCR) AND (LCNT=0) THEN GOSUB 8200
 7220 NEXT K
 7230 LET O$="TOTAL RECORDS: "+STR$ LEN U$
 7240 GOSUB 8100
 7242 GOSUB 8600
 7245 GOSUB 8200
 7247 IF C$="3" THEN RETURN 
 7250 GOTO 1000
 8000 REM ENTER
 8010 PRINT AT 20,T2;"PRESS %E%N%T%E%R"
 8020 INPUT Z$
 8030 GOTO 1000
 8100 REM 
 8110 IF PRI THEN LPRINT O$
 8120 IF SCR THEN PRINT O$
 8130 RETURN 
 8200 REM 
 8210 PRINT AT 20,1;"PRESS %E%N%T%E%R."
 8220 INPUT W$
 8230 CLS 
 8235 LET LCNT=INT (18/(FLDS+2))
 8237 IF W$=" STOP " THEN GOTO 1000
 8240 RETURN 
 8500 REM 
 8510 IF C$=CHR$ 113 THEN LET CR=CR+(CR<LEN U$)
 8520 IF C$=CHR$ 112 THEN LET CR=CR-(CR>1)
 8530 GOTO 1015
 8600 REM TOTALS
 8605 IF NOT NUM THEN RETURN 
 8610 LET O$=""
 8620 GOSUB 8100
 8630 GOSUB 8100
 8640 LET O$="TOTALS:"
 8650 GOSUB 8100
 8660 LET O$=""
 8670 GOSUB 8100
 8680 FOR F=1 TO FLDS
 8690 IF F$(F)(1)<>"." THEN GOTO 8750
 8700 LET O$="      "+F$(F)+":  "+STR$ T(F)
 8710 GOSUB 8100
 8750 NEXT F
 8760 LET O$=""
 8770 GOSUB 8100
 8780 GOSUB 8100
 8790 RETURN 
 9800 REM SEARCH
 9810 POKE 16514,CODE A$
 9820 LET J=255-USR 16524
 9830 RETURN 

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

People

No people associated with this content.

Scroll to Top