This program is a simple inventory database manager that stores up to ten records in a two-dimensional string array, each record holding fields such as stock number, description, supplier, quantity, unit price, retail price, low limit, and back-order quantity. Records are entered through a custom character-by-character input routine at line 1500 that supports backspace (CHR$ 12) and fixed-width field formatting with both zero-padded numeric and space-padded text fields. A calculated extended price field is derived automatically by multiplying the unit price by quantity using string-to-value conversion. The program supports searching by stock number, deleting records with array compaction, and saving or loading the data file with an auto-start line. Screen$ reads are used to retrieve displayed field values for the low-stock warning comparison rather than storing them in separate variables.
Program Analysis
Program Structure
The program is organized into distinct subroutine blocks, each starting at a recognizable line number boundary, with a main menu loop at line 9040 dispatching via GO SUB to each module:
| Lines | Module |
|---|---|
| 1001–1080 | Add Records |
| 1500–1535 | Character-by-character field input subroutine |
| 3001–3190 | Search / Display record |
| 5001–5025 | Delete record |
| 8000–8055 | Load / Save file |
| 9040–9090 | Main menu loop |
Line 5 initializes the record pointer p to 1, and line 10 immediately jumps to the main menu at 9040. Line 2 allocates the record array e$(10,100), providing storage for up to ten records of 100 characters each.
Data Storage Format
Each record is serialized into a single string slot of e$. Fields are concatenated into a$ with * as an inter-field delimiter and / appended at the end of a complete record (line 1060). The stock number field (row 2, x=2) is zero-padded to 9 characters using b$="000000000"; text fields at x>=4 are space-padded to field width using c$ (20 spaces). This means the first 9 characters of each record are always the zero-padded stock number, enabling the direct substring comparison at line 3027.
Custom Input Routine (Lines 1500–1535)
Rather than using the built-in INPUT for field data, the program implements its own keystroke loop. PAUSE 0 followed by INKEY$ at line 1500 is a standard efficient keypress-wait idiom. Key behaviors include:
- CHR$ 13 (ENTER) accepts the field when at least one character has been entered (
k<>0). - CHR$ 12 (DELETE/backspace) steps back one position and restores the dash placeholder, trimming
k$. - Characters below CHR$ 32 (control codes) are ignored.
- Printable characters are echoed to screen and appended to
k$; the field auto-accepts when the cursor reaches the field lengthl.
The field descriptors are loaded via READ from the DATA statement at line 1015, supplying the field width l and label l$ for each of the eight fields. The loop variable x tracks screen row (incrementing by 2 per field) and y=11 is the starting column for input areas.
Automatic Extended Price Calculation
Lines 1532–1533 implement an automatic extended price calculation. When the unit price field is entered (x=8), its value is saved in f$. When either the quantity (x=10) or another price field (x=12) is processed, the product VAL f$ * VAL k$ is computed, converted back to a string with STR$, left-padded to 9 characters, and appended to the record as an extra *-delimited field. This stores the extended price without requiring a separate variable in the record layout.
Record Display and SCREEN$ Trick
The search/display module (lines 3060–3145) walks the stored record string character by character, printing non-delimiter characters to a two-column display. Rather than storing the quantity or low-limit values in variables for the reorder warning, the program uses SCREEN$ (lines 3120–3140) to read the displayed digits directly back from the screen — quantity from row 8 and low limit from row 14. If the quantity string is not blank and the low limit is greater than or equal to the quantity, the low-limit value is flashed on screen (line 3145) as a reorder alert.
Record Deletion and Array Compaction
Deletion (lines 5001–5025) first calls GO SUB 3000 (the search routine) to locate and display the record, then prompts for confirmation. On confirmation, it clears the target slot with LET e$(x)=c$ and shifts all subsequent records down by one position in a FOR loop, decrementing p to maintain the record count. The condition at line 5023 contains a logical bug: IF x$<>"Y" OR x$<>"y" is always true (a string cannot equal both “Y” and “y” simultaneously), so the loop to add more deletions at line 5025 is never reached.
File Save and Load
The save/load module at line 8000 uses plain LOAD k$ and SAVE k$ LINE 9040, saving the program with an auto-start at the main menu (line 9040). Because the array e$() is part of the program variables, it is preserved in the saved file, effectively implementing persistent data storage.
Notable BASIC Idioms
VAL "number"is used pervasively inGO TO,GO SUB, and arithmetic contexts as a memory-saving technique, storing a string token rather than a floating-point number in the program.- The
DATAstatement at line 1015 mixes numeric literals written asVAL "n"with string literals, which is valid sinceREADaccepts both forms. - Line 3075 uses the expression
3100+(20*(e$(x,z+1)="/"))to compute a branch target — multiplying the boolean result of a string comparison by 20 to select between line 3100 and line 3120. - The
RESTOREcalls before looping back to line 1001 reset theDATApointer so the field descriptors can be re-read on each new record entry.
Bugs and Anomalies
- Line 9050: calls
GO SUB 1000, but the add-records module starts at line 1001. Line 1000 does not exist; the interpreter will fall through to line 1001, so this works in practice but is technically targeting a non-existent line. - Line 3027: references
GO TO 3060withoutVAL, inconsistent with the rest of the program’s style but functionally correct. - Line 3185:
GO TO 3000targets a non-existent line; execution falls through to 3001, the search module — an intentional well-known technique. - Line 5023: the condition
x$<>"Y" OR x$<>"y"is a tautology (always true), meaning the loop for repeated deletions at line 5025 is unreachable. The intended logic was likelyANDrather thanOR. - Line 3100: the compound
IFconditionIF y=10 AND b=10 OR y=12 AND b=10relies on operator precedence;ANDbinds tighter thanOR, so this evaluates as(y=10 AND b=10) OR (y=12 AND b=10), which is the likely intended meaning.
Content
Source Code
2 DIM e$(10,100)
5 LET p=VAL "1"
10 GO TO VAL "9000"
1001 CLS : LET a$="": LET k$="": LET b$="000000000": LET c$=" "
1005 PRINT AT 0,5; INVERSE 1;"Add records"
1009 LET x=VAL "2": LET y=VAL "11": FOR b=VAL "1" TO VAL "8": READ l,l$
1010 PRINT AT x,VAL "0";l$;: FOR k=VAL "1" TO l: PRINT AT x,y+k;CHR$ VAL "45";: NEXT k: LET k=VAL "1": GO SUB VAL "1500": NEXT b
1015 DATA VAL "9","Stock# ",VAL "20","Discript ",VAL "11","Supplier ",VAL "4","Qty ",VAL "6","Unit Price ",VAL "6","Retail Price ",VAL "3","Low Limit ",VAL "3","Back Order "
1050 INPUT INVERSE 1;"Hit ENTER to log this record or C to reenter it",,x$
1055 IF x$="C" OR x$="c" THEN RESTORE : GO TO VAL "1001"
1060 LET a$=a$+"/": LET e$(p, TO 100)=a$: LET p=p+1
1065 IF p>=10 THEN PRINT ; FLASH 1;"File Full": PAUSE 500: RETURN
1070 INPUT INVERSE 1;"More? Y/N",x$
1075 IF x$="N" OR x$="n" THEN RESTORE : RETURN
1080 RESTORE : GO TO VAL "1001"
1500 PAUSE VAL "0": LET q$=INKEY$
1505 IF q$=CHR$ VAL "13" AND k<>VAL "0" THEN GO TO VAL "1527"
1510 IF q$=CHR$ VAL "12" AND k>VAL "0" THEN LET k=k-1: PRINT AT x,y+k;CHR$ VAL "45": LET k$=k$( TO k-1): GO TO VAL "1500"
1515 IF q$<CHR$ VAL "32" THEN GO TO VAL "1500"
1520 LET k$=k$+q$: PRINT AT x,y+k;q$: LET k=k+VAL "1"
1525 IF k<=l THEN GO TO VAL "1500"
1527 IF x=VAL "2" THEN LET k$=b$( TO l-LEN k$)+k$: LET a$=a$+k$
1528 IF x>=VAL "4" THEN LET k$=k$+c$( TO l-LEN k$)
1530 IF x>VAL "2" AND x<=VAL "16" THEN LET a$=a$+"*"+k$
1532 IF x=VAL "8" THEN LET f$=k$
1533 IF x=VAL "10" OR x=VAL "12" THEN LET k$=STR$ (VAL f$*VAL k$): LET k$=c$( TO VAL "9"-LEN k$)+k$: LET a$=a$+"*"+k$
1535 LET x=x+VAL "2": LET k$="": RETURN
3001 CLS : PRINT INVERSE 1;"Search for a Record",: LET l$="": LET q$=""
3005 INPUT INVERSE 1;"Enter a Stock Number",x$
3010 IF x$="" THEN GO TO VAL "3005"
3015 LET x$=b$( TO VAL "9"-LEN x$)+x$
3025 FOR x=VAL "1" TO p
3027 IF e$(x,1 TO 9)=x$ THEN GO TO 3060
3035 NEXT x
3040 PRINT "File not found": PAUSE 50: RETURN
3060 LET y=VAL "2": PRINT AT VAL "2",VAL "0";"Stock #"''"Discript"''"Supplier"''"Qty"''"Unit Price"''"Rtl Price"''"Low limit"''"Bck Order"
3063 LET d=VAL "0": LET b=VAL "10"
3065 FOR z=VAL "1" TO VAL "100"
3070 IF e$(x,z)<>"*" THEN PRINT AT y,b+(z-x)-d;e$(x,z);
3075 IF e$(x,z+1)="*" OR e$(x,z+1)="/" THEN GO TO 3100+(20*(e$(x,z+1)="/"))
3080 NEXT z
3085 GO TO VAL "3120"
3100 IF y=10 AND b=10 OR y=12 AND b=10 THEN PRINT TAB VAL "18";"Ext ";: LET b=VAL "21": LET d=z-x: NEXT z
3103 PRINT : LET y=y+VAL "2": LET d=z-x: LET b=VAL "10"
3105 NEXT z
3120 FOR z=VAL "1" TO VAL "4": LET q$=q$+SCREEN$ (8,9+z): NEXT z
3140 FOR z=VAL "1" TO VAL "3": LET l$=l$+SCREEN$ (14,9+z): NEXT z
3143 IF q$=" " THEN GO TO VAL "3150"
3145 IF VAL l$>=VAL q$ THEN PRINT FLASH VAL "1";AT VAL "14",VAL "10";l$
3175 INPUT INVERSE 1;"Press enter for new search","Q to quit",,"C to copy",,k$
3180 IF k$="Q" OR k$="q" THEN RETURN
3185 IF k$="" THEN GO TO 3000
3188 IF k$="c" OR k$="C" THEN COPY
3190 GO TO 3175
5001 PAPER 2: INK 7: CLS : PRINT TAB 12; FLASH VAL "1";"WARNING": PRINT TAB VAL "4";"This will erase data!!"; PAPER 7; INK 0: PAUSE 100: GO SUB VAL "3000": INPUT INVERSE 1;"Delete this? Y/N",x$
5010 IF x$="N" OR x$="n" THEN RETURN
5020 LET e$(x)=c$: FOR l=x TO p: LET e$(l)=e$(l+1): NEXT l: LET p=p-1
5023 INPUT INVERSE 1;"More? Y/N ";x$: IF x$<>"Y" OR x$<>"y" THEN PAPER VAL "7": INK VAL "0": RETURN
5025 GO TO VAL "5001"
8000 CLS : INPUT INVERSE 1;"L = load file S = save file",k$
8010 IF k$="L" OR k$="l" THEN INPUT INVERSE 1;"enter file name ";k$: LOAD k$
8050 IF k$="S" OR k$="s" THEN INPUT INVERSE 1;"enter file name ";k$: SAVE k$ LINE 9040
8055 RETURN
9040 CLS : PRINT INVERSE 1;" Main Menu",
9045 PRINT AT 7,VAL "5";"A = Add Records"''TAB VAL "5";"D = Delete a Record"''TAB VAL "5";"S = Search for a Record"''TAB VAL "5";"Q = Quit"
9047 INPUT INVERSE 1;"Select Option and press ENTER",o$
9050 IF o$="A" OR o$="a" THEN GO SUB VAL "1000"
9060 IF o$="D" OR o$="d" THEN GO SUB VAL "5000"
9070 IF o$="S" OR o$="s" THEN GO SUB VAL "3000"
9080 IF o$="Q" OR o$="q" THEN GO SUB VAL "8000"
9090 GO TO VAL "9040"
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
