PRO/FILE 2068 is a text-based flat-file database manager that stores up to 15 lines of 32-character text per record within a single large string variable dimensioned at 28,020 bytes. Records are searched, added, edited, deleted, and sorted using a combination of BASIC control flow and machine code routines called via RANDOMIZE USR at addresses in the 63,000–64,000 range. The full-screen editor (lines 5000–5117) uses ON ERR trapping, SCREEN$ reads, and INKEY$ polling to implement cursor movement, insert/overwrite toggle, line insertion and deletion, and a flashing cursor effect. An AUTOSEARCH mode (lines 5200–5441) can sort records by a user-specified line number field and optionally send formatted output to the printer using LPRINT with a configurable C$ format string. The diagnostic routine at line 8990 allows direct inspection and modification of POKEd memory locations in the machine code workspace.
Program Analysis
Program Structure
The program is organized into several functional regions:
- Initialization and main menu (lines 5–50): Sets up display, dimensions the record buffer
E$(15,32), and calls machine code viaRANDOMIZE USR 64268. - Search dispatch loop (lines 100–119): Accepts a search command string
X$and branches to add, load, save, autosearch, or format-change routines. - Search execution and record display (lines 120–2000): Machine code at
USR 64040performs the search;USR 64101returns a pointerb; results are displayed with paged navigation and edit/delete/copy options. - Record modification (lines 4000–4010): Deletes a record via
USR 63640, adjusting the free-space pointerp. - Full-screen editor (lines 5000–5117): A complete cursor-addressed text editor for entering or modifying 15-line records.
- AUTOSEARCH / sort mode (lines 5200–5441): Sorts records by a chosen field line, with optional printer output.
- Tape load/save (lines 5500–5510, line 107): Uses
LOAD F$andSAVE f$ LINE 1for named tape operations. - Record commit (lines 6000–6030): Iterates over all 15 editor lines, calling
USR 63489to write each to the database string, then callsUSR 63530to updatep. - Print format input (lines 6500–6600): Parses a slash-delimited list of line numbers (or “ALL”) into the format string
C$. - Formatted output (lines 7000–7240): Iterates over
C$, usingCODE C$(X)as a 1-based index intoE$()to select which record lines toLPRINT. - Diagnostic POKE/PEEK loop (lines 8990–8998): Allows interactive inspection and patching of the machine code workspace.
- Drawing subroutine (line 9830): Draws a rectangular border around status information using
PLOT/DRAW. - Status display subroutine (line 9850): Prints free bytes, filename, sort order, and format string.
- First-run initialization (lines 9996–9999): Dimensions the main database string
D$(28020), seeds the sentinel record, and prompts to create or load a file.
Machine Code Integration
A substantial portion of the core database logic resides in machine code called from BASIC via RANDOMIZE USR. The BASIC side passes data through shared memory locations and system variables rather than through BASIC parameters. Known entry points and their roles are:
| Address | Role |
|---|---|
64268 | Initialization / bounds check (called at startup and before edit operations) |
64040 | Execute search using current X$ |
64101 | Return current record pointer into b |
63575 | Display next record field line; returns non-zero when more data remains |
63489 | Write one editor line (e$(x)) to the database |
63530 | Finalize record write; returns updated free pointer for p |
63640 | Delete current record; returns bytes freed (subtracted from p) |
64523 | Advance to next record in sort/autosearch pass; returns new pointer b |
64731 | Initialize autosearch/sort pass |
The machine code workspace occupies roughly addresses 63489–64769. The diagnostic loop at lines 8990–8998 iterates over addresses 64468–64769, allowing direct POKE patching of machine code parameters at runtime. The sort field is passed by POKEing address 64602 with the chosen line number s.
Database Storage Model
The database is held in a single string variable D$ dimensioned to 28,020 bytes, providing enough space for hundreds of 15-line × 32-character records. The variable p serves as a free-space pointer: LEN D$ - p (displayed by the status routine at line 9850) gives the number of bytes in use. The sentinel string "*SEARCH IS COMPLETE*" is written into the first 20 bytes of D$ and detected by machine code to signal end-of-file. At startup (line 5), POKE 64035, PEEK 23670 and POKE 64036, PEEK 23671 copy the PROG pointer into the machine code workspace, presumably so the routines can locate the BASIC program area.
Full-Screen Editor (Lines 5000–5117)
The editor uses a 15-row × 32-column grid managed by row l and column c variables, mirrored in the string array E$(15,32). Key techniques include:
- SCREEN$ reads: The flashing cursor is implemented by reading the character under the cursor with
SCREEN$(l,c)and reprinting it withFLASH 1, avoiding the need to store cursor-position characters separately. - ON ERR GO TO 5005: Traps any error (e.g., from
SCREEN$on an attribute boundary) and returns to the cursor flash loop silently. - Key dispatch via GO TO 5100+CODE y$: Control characters (codes 0–15) are dispatched arithmetically. Line 5103 acts as a default (GO TO 5010). Lines 5104–5117 handle specific control codes: cursor up/down/left/right, delete, insert toggle, line feed, line insert, line delete, and the “more commands” overlay.
- Insert/overwrite toggle: Variable
i(0 or 1) selects between modes. In insert mode (line 5025), the existing line content is shifted right by one character before printing. - STOP key detection: Line 5016 checks for
INKEY$=" STOP "(the extended-mode STOP token) to close the editor and commit the record. - Column wrap: At line 5030,
LET c=(c+1)*(c<31)andLET l=l+(c=0)wrap to the next row when column 31 is exceeded.
AUTOSEARCH and Formatted Printing
AUTOSEARCH mode (entered with command "AUTO") optionally sorts records by a chosen line number field (s, stored via POKE 64602,s), then iterates through all records in sorted order. The format string C$ is built in the format parser (lines 6500–6600): each character’s ASCII code (1–15) indexes into E$() to select which of the 15 record lines to print. A CHR$ 0 in C$ causes a blank LPRINT line. This design allows arbitrary reordering and selection of record fields for printed output without any machine code involvement.
Notable BASIC Idioms
LET x$=x$at lines 119 and 5441 is used deliberately: on this platform, assigning a string variable to itself can force a re-evaluation of its storage address, which is required before passingX$to a machine code routine that needs a stable pointer.GO TO 150+(895*a)at line 1060 computes the branch target arithmetically: whena=0it goes to line 150 (normal search loop), and whena=1it goes to line 1045 (autosearch display path).GO TO 119+(A*5121)at line 1090 similarly dispatches between the normal re-search (line 119) and autosearch re-initiation (line 5240) based on theAflag.- The
IF ... THEN(empty THEN clause) construct at lines 1000, 1075, 6005, 7310 is used to call machine code viaUSRin a conditional context: if the USR call returns non-zero, the (empty) THEN branch does nothing and execution falls through; a zero return also falls through. The actual side-effect is the machine code call itself. VAL Z$is used throughout afterINPUT Z$to convert user-entered numeric strings to numbers, withON ERR GO TO 5220providing validation.
Bugs and Anomalies
- Line 115 checks
x$(LEN x$)=" AND ", which tests a single character against a 5-character string — this comparison will always be false, making the multi-wordANDseparator warning dead code. The intent was likely to check whetherX$ends with" AND ", which would requirex$(LEN x$-4 TO)or similar. - The
DIM E$(15,32)at line 1000 re-dimensions the array on every pass through the result display loop, which erases any previously fetched record content. This appears intentional as a way to clear the display buffer before the machine code atUSR 63575refills it. - Line 5222 uses
ON ERR GO TO 5220to catch non-numeric input toVAL Z$, then at line 5230 usesON ERR RESETto clear the handler — a standard pattern for input validation on this platform.
Content
Source Code
5 BORDER 0: PAPER 0: RANDOMIZE p: POKE 64035,PEEK 23670: POKE 64036,PEEK 23671: LET a=0: LET Y=0: DIM E$(15,32): CLS : RANDOMIZE USR 64268
20 PRINT AT 1,7; PAPER 3; INK 0;" PRO/FILE 2068 ": PRINT INK 6;AT 3,4;"Separate MULTI-WORD";TAB 4;"command words with the";TAB 4;"token ""AND"""
30 INK 7: PLOT 120,175: GO SUB 9830: INK 5
40 INK 3: PRINT AT 7,0;: GO SUB 9850
50 INK 6: PRINT AT 14,0;" Type ""A"" to ADD files";TAB 4;"""SAVE"" or ""LOAD"" for tape";TAB 4;"""AUTO"" for AUTOSEARCH";TAB 4;"""DEFP"" changes PRINT format"
100 INPUT "SEARCH COMMAND? ";X$
102 IF x$="DEFP" THEN PRINT AT 14,0;: PLOT 120,70: GO SUB 6500: INK 0: GO SUB 9830: INK 7: PRINT AT 10,7;A$; INK 0;E$(1);E$(1);E$(1): GO TO 50
103 IF x$="AUTO" THEN GO TO 5200
105 INK 5: CLS : IF x$="A" THEN GO TO 5000
106 IF x$="LOAD" THEN GO TO 5500
107 IF x$="SAVE" THEN SAVE f$ LINE 1: GO TO 1
110 IF x$="" THEN GO TO 10
115 IF x$(LEN x$)=" AND " OR LEN X$>32 THEN GO TO 10
119 LET X$=X$
120 RANDOMIZE USR 64040
150 LET b=USR 64101
1000 PRINT AT 0,0;: DIM E$(15,32): LET e$(1)="": IF USR 63575 THEN
1010 IF a=0 AND e$(1, TO 18)=d$(2 TO 19) AND b<>p THEN CLS : GO TO 150
1020 IF y AND B<P THEN GO TO 7205
1040 PRINT AT 21,0;x$
1045 IF A THEN GO TO 7000
1050 PAPER 5: INK 0: PRINT AT 16,0;"Press ENTER to continue","""C"" to COPY",,"""D"" to DELETE",,"""E"" to EDIT",,"""M"" for MORE commands ": INPUT "OPTION? ";y$: IF y$="M" THEN PRINT AT 16,0;"""R"" to RE-INITIATE search","""N"" to start NEW from main menu","""A"" to ADD new file","type a SEARCH COMMAND, or": INPUT "OPTION?";y$: IF y$="M" THEN GO TO 1051
1051 IF Y$="M" THEN PAPER 0: INK 5: PRINT AT 16,0;: GO SUB 9850: PRINT """M"" for MORE commands",: INPUT "OPTION? ";Y$: IF Y$="M" THEN GO TO 1050
1055 PAPER 0: INK 5
1060 IF y$="" AND b<p THEN CLS : GO TO 150+(895*a)
1070 IF y$="N" THEN GO TO 1
1075 IF USR 64268 THEN
1080 IF PEEK 64026+256*PEEK 64027<>PEEK 23627+256*PEEK 23628+6 AND (y$="D" OR y$="E") THEN GO TO 4000
1090 IF y$="R" THEN CLS : LET x$=x$: GO TO 119+(A*5121)
1100 IF y$="C" THEN GO TO 7205
1200 IF y$="DEFP" THEN PRINT AT 20,0,,,,: PRINT AT 16,0;: PLOT 120,50: GO SUB 6500: INK 0: GO SUB 9830: LET y$="M": GO TO 1051
1500 IF y$<>"" AND y$<>"E" AND y$<>"D" THEN LET A=0: LET x$=y$: GO TO 105
2000 GO TO 1050
4000 LET p=p-USR 63640: IF y$="D" THEN LET Y$="": GO TO 1
4010 GO TO 5002
5000 DIM e$(15,32): CLS
5002 LET m=0: LET z=23658: LET i=0: LET l=0: LET c=0
5004 INK 1: PLOT 0,48: PAPER 6: DRAW 255,0: INK 0: PRINT AT 16,0; PAPER 1; INK 7;"CURSOR CONTROLS: ARROWS move cursor one position ENTER: Next line SHIFT 1:Alternate Insert/Over SHIFT 0:Delete character SHIFT 9:More commands ";AT l,c;: LET m=0
5005 INK 6: PAPER 0: FLASH 1: PRINT AT l,c;SCREEN$ (l,c)
5007 ON ERR GO TO 5005
5010 IF INKEY$="" THEN GO TO 5010
5016 IF INKEY$=" STOP " THEN ON ERR RESET : FLASH 0: GO TO 6000
5020 LET y$=INKEY$: FLASH 0: PRINT AT l,c;SCREEN$ (l,c): IF CODE y$<16 THEN GO TO 5100+CODE y$
5025 IF i THEN LET e$(l+1)=e$(l+1, TO c)+" "+e$(l+1,c+1 TO 31): PRINT AT l,0;e$(l+1)
5030 PRINT AT l,c;y$: LET e$(l+1,c+1)=y$: LET c=(c+1)*(c<31): LET l=l+(c=0): LET l=l*(l<15): FLASH 1: PRINT AT l,c;SCREEN$ (l,c)
5040 PRINT INK 6+i;AT l,c; FLASH 1;SCREEN$ (l,c): FOR X=1 TO 5: NEXT X
5103 GO TO 5010
5104 FOR x=l TO 13: LET e$(x+1)=e$(x+2): PRINT AT x,0;e$(x+1): NEXT x: LET e$(15)="": PRINT e$(15): GO TO 5040
5105 LET e$(l+1,c+1 TO )="": PRINT AT l,0;e$(l+1): GO TO 5040
5106 POKE Z,(PEEK z=0)*8: PRINT AT l,c; INK 7; PAPER 1;CHR$ (60+(PEEK z/4)): PAUSE 20: PRINT AT l,c;e$(l+1,c+1): GO TO 5040
5107 LET i=NOT i: GO TO 5040
5108 LET c=c-(c>0): GO TO 5040
5109 LET c=c+(c<31): GO TO 5040
5110 LET l=l+(l<14): GO TO 5040
5111 LET l=l-(l>0): GO TO 5040
5112 LET e$(l+1)=e$(l+1, TO c)+e$(l+1,c+2 TO 31)+" ": PRINT AT l,0;e$(l+1): GO TO 5108
5113 LET c=0: LET l=l+1: LET l=l-(l>14): GO TO 5040
5114 FOR x=15 TO l+2 STEP -1: LET e$(x)=e$(x-1): PRINT AT x-1,0;e$(x): NEXT x: LET e$(l+1)="": PRINT AT l,0;e$(l+1): GO TO 5040
5115 IF m=0 THEN PRINT BRIGHT 1; PAPER 1;AT 16,0;"Press STOP to close file SHIFT-2 for CAPS lock SHIFT-3 for LINE DELETE SHIFT-4 for LINE ERASE SHIFT-SYMBOL SHIFT: line insert ": LET m=-1: GO TO 5040
5116 IF m=-1 THEN PRINT AT 16,0,,: GO SUB 9850: LET m=1: GO TO 5040
5117 GO TO 5004
5200 LET a=1: PRINT AT 14,0; PAPER 0; INK 7;" PRINT OUT? (Y/N)",,,,,,,: INPUT Y$: LET Y=Y$="Y"
5220 LET Z$="0": PRINT AT 14,0;"TYPE LINE NUMBER BY WHICH FILES WILL BE ORDERED. Type ""0"" if ordering is not required": INPUT Z$: IF z$="" THEN GO TO 1
5222 ON ERR GO TO 5220: IF VAL Z$>=0 AND VAL Z$<=15 THEN GO TO 5230
5225 GO TO 5220
5230 ON ERR RESET : IF VAL z$ THEN LET S=VAL Z$: CLS : GO TO 5240
5235 LET a=0: GO TO 100
5240 RANDOMIZE USR 64731: IF s THEN POKE 64602,s
5441 LET x$="*": LET x$=x$: RANDOMIZE USR 64040: GO TO 7000
5500 PLOT 120,50: GO SUB 9830: PRINT AT 16,1;"HAS THIS FILE BEEN SAVED?(Y/N)": INPUT y$: IF y$<>"Y" THEN GO TO 1
5510 PRINT AT 16,1; PAPER 5; INK 0;"WHAT FILE NAME DO YOU WISH ";AT 17,1;"TO LOAD\::";: INPUT F$: PRINT f$: LOAD F$: GO TO 1
6000 FOR x=1 TO 15
6004 LET e$(x)=e$(x)
6005 IF USR 63489 THEN
6010 NEXT x
6020 LET p=USR 63530
6030 GO TO 1
6500 PRINT INK 7;" ENTER DESIRED FORMAT. Type ALL ";" or line numbers separated by"," ""/"". Use ""0"" to print blank"," lines ": GO SUB 9830
6510 LET C$="": LET n=0: INPUT "format?";a$: LET a$=a$+"/": IF a$(1)="/" THEN GO TO 6510
6515 IF A$="ALL/" THEN FOR X=1 TO 15: LET C$=C$+CHR$ X: NEXT X: LET D=3: GO TO 6600
6520 LET D=1: FOR x=1 TO LEN a$: IF a$(x)<"/" OR a$(x)>"9" THEN GO TO 6510
6525 IF X<LEN A$ THEN IF A$(X TO X+1)="//" THEN GO TO 6510
6530 IF a$(x)="/" THEN LET n=VAL a$(d TO x-1): LET d=x+1: IF n<16 THEN LET c$=c$+CHR$ n
6535 IF n>15 THEN GO TO 6510
6540 NEXT x
6600 RETURN
7000 IF VAL z$=0 THEN GO TO 7202
7005 LET b=USR 64523: IF b<p THEN DIM e$(15,32): LET e$(1)="": GO SUB 7310
7010 IF b=p THEN LET a=0: LET x$="ALL DONE": GO TO 110
7202 IF Y=0 THEN GO TO 1050
7205 FOR X=1 TO LEN C$
7210 IF CODE C$(X)=0 THEN LPRINT
7220 IF CODE C$(X) THEN LPRINT E$(CODE C$(X))
7225 NEXT X
7230 IF A AND B<p AND Y$<>"C" THEN CLS : GO TO 7000
7235 IF Y AND A=0 THEN CLS : GO TO 150
7240 GO TO 1050
7310 PRINT AT 0,0;: LET E$(1)="": IF USR 63575 THEN
7311 RETURN
8990 FOR X=64468 TO 64769
8991 INPUT (X;"=";);Y$
8992 IF Y$="" THEN GO TO 8997
8993 IF LEN Y$=5 THEN LET X=VAL Y$: PRINT X;"=";PEEK X: GO TO 8991
8994 POKE X,VAL Y$
8997 PRINT X;"=";PEEK X
8998 NEXT X: STOP
8999 REM
9830 DRAW 134,0: DRAW 0,-48: DRAW -254,0: DRAW 0,48: DRAW 120,0: RETURN
9850 PRINT "OPEN: "; INK 7;LEN d$-p;: PRINT " bytes";TAB 0;: PRINT "FILE: "; INK 7;f$;TAB 0;: PRINT "ORDER: "; INK 7;s;TAB 0;: PRINT "FORMAT:"; INK 7;a$;TAB 0;: RETURN
9996 DIM d$(28020): LET p=20: LET d$( TO 20)="*SEARCH IS COMPLETE*": LET a$="ALL": LET c$="": FOR x=1 TO 15: LET c$=c$+CHR$ x: NEXT x: LET s=0
9997 PRINT AT 19,2; INK 7;"Press""C"" to CREATE a new file or ""L"" to LOAD an existing one": INPUT y$: PRINT AT 19,0;D$(100 TO 164): IF y$="L" THEN GO TO 5510
9998 PRINT AT 19,4; INK 7;"ENTER A NAME FOR THIS FILE": INPUT F$: IF f$="" OR LEN f$>10 THEN GO TO 9998
9999 GO TO 1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

