VU-File is a database management program that allows users to define record formats, enter and edit data records, search, sort, order, list, and print filed information. The program relies heavily on machine code routines called via RAND USR and USR at addresses such as 17986, 17983, 17989, 19151, 19154, 19157, and 19160, with the BASIC shell acting primarily as a launcher and menu dispatcher. A 9,999-character string array F$ is used as the main data store, with the first 20 characters reserved for the file name and bytes 21–52 used for the printer format. System variables are read directly with PEEK at addresses including 16565, 16566, 16567, 16583, 16584, 16586, and 18585 to display record count, percent-full statistics, and field ordering information. The program includes a Psion-branded title screen and supports cassette saving of the file and data via a USR call to address 8192 with a SAVE command string.
Program Analysis
Program Structure
The BASIC portion of VU-File is a thin shell surrounding a large machine code body embedded within the F$ string array and at fixed memory addresses. The program is organized into distinct line-number regions:
- Lines 50–51: REM statements that serve as containers for the machine code payload (the long token-encoded REM line at line 50 is the MC store).
- Lines 1100–1200: Initialization — dimensioning
F$(9999), setting the default file name, switching to SLOW mode, and jumping into machine code viaRAND USR 17986. - Lines 1300–1400: CLS and dispatch to the status/menu entry point at line 3400.
- Lines 2000–2080: Main menu display (options 1–4) and keypress routing.
- Lines 3200–3810: Option handlers for each menu choice, each delegating immediately to a machine code routine.
- Lines 9995–9996: An alternate save/restart path used by the machine code to re-enter BASIC after a save operation.
Machine Code Integration
Virtually all real work is done in machine code. The BASIC accesses it through two mechanisms:
RAND USR addr— calls the routine and discards the return value (used for side-effecting operations like initializing the MC, setting record/printer formats, and performing the save handshake).LET A=USR addr— calls the routine and uses the integer return value to drive a computedGOTO, implementing a state-machine dispatch back into BASIC.
The key machine code entry points are tabulated below:
| Address | Called via | Purpose |
|---|---|---|
| 17986 | RAND USR | MC initialization / startup |
| 17983 | USR (return used) | LPRINT layout handler, returns dispatch value |
| 17989 | RAND USR | Set printer format |
| 17992 | RAND USR | Set record format (option 1 / layout) |
| 19151 | USR (return used) | Save completion check (0 = success) |
| 19154 | RAND USR | Prepare data for tape save |
| 19157 | USR (return used) | Main database engine entry; returns menu state |
| 19160 | USR (return used) | Status display refresh, returns dispatch value |
| 8192 | USR with string arg | Psion I/O driver — sends “SAVE:P:VU-FILE:” command |
Computed GOTO Dispatch
The program uses a computed GOTO pattern at lines 3400–3410 and 3548–3549 to return control from machine code to the appropriate BASIC handler:
LET A=USR 19157at line 3400 obtains a state index.GOTO 3450+50*Aroutes to one of: 3450 (menu), 3500 (status display), 3550 (LPRINT), 3600 (save), 3800 (layout), etc.- Similarly,
GOTO 3410after updatingAat lines 3548–3549 creates a tight re-entry loop for the status display.
Menu option routing at line 2080 uses GOTO 3000+200*(I-28), mapping key codes 29–32 (characters 1–4) to lines 3200, 3400, 3600, 3800 respectively.
Data Storage in F$
The single string F$(9999) serves as the entire database store. The layout of this string is:
- Characters 1–20: File name / title (read back at line 3500 and written at lines 1150 and 3650).
- Characters 21–52: Printer format record, LPRINTed directly at line 3550.
- Characters 53 onwards: Managed entirely by the machine code for record data and metadata.
System Variable PEEKs
Lines 3500–3510 read system variables directly to display database statistics on screen without machine code assistance:
| Address | System Variable | Use in Program |
|---|---|---|
| 16565–16566 | Record count (lo/hi byte) | Displayed as total records |
| 16567 | Field ordering index | Displayed as “ordered by field” |
| 16583–16584 | Total capacity (lo/hi) | Denominator for percent-full calculation |
| 16586 + 18585 | Used space (lo/hi, split) | Numerator for percent-full calculation |
| 16603 | Field count | Displayed as “fields” |
Note that the percent-full formula uses PEEK 18585 for the high byte of used space alongside PEEK 16586 for the low byte — this address pairing is unusual and likely reflects the machine code’s use of a non-standard RAM location to store a running total.
Tape Save Mechanism
Saving is handled by calling address 8192 (the Psion I/O driver) with the string "SAVE:P:VU-FILE:" as a USR argument — a technique specific to the Psion hardware interface. The machine code at 19151 returns a non-zero value on failure, and the BASIC at line 3695 halts with STOP in that case. Lines 9995–9996 provide an alternative re-entry path that re-runs the program after a successful save triggered from within machine code.
Notable Techniques
- The REM line at line 50 is an unusually large machine code store — the encoded token stream is the MC binary, a common technique for embedding executable code in BASIC programs.
- Key input at line 2060 uses
CODE INKEY$in a busy-wait loop, checking for codes 29–32 (digits 1–4) without anyPAUSEdelay. - The
RAND USRidiom is used consistently for calls whose return values are irrelevant, keeping the BASIC stack clean. - The program uses
FASTmode only during the tape save sequence (line 3645), switching back toSLOWat line 3700 for normal operation. - All user-facing text for the database UI (field entry prompts, search instructions, error messages, command lists) is stored as string literals within the machine code REM block, not in separate BASIC PRINT statements.
Content
Image Gallery
Source Code
50 REM ##[)]# FOR #I#J#K#L#M#N#O#P#Q#R#S#T#U#V#W#X# F###S 3 IF ##▘ ▘####▝#"# ▗# OR #N##B[,,] 3######## ##▘▘####[)]# FOR #I#J#K#L#M#N#O#P#Q#R#S#T#U#V#W#X#; GOSUB # CONT PI# LPRINT SLOW STOP STEP <># TO # AND # FAST LLIST ** THEN>=#<=# OR ""# ##▚##[I]###INKEY$ #[-]PI####PEEK PI# POKE PI#?###PI# FOR INKEY$ #[0]INKEY$ LN [0]INKEY$ LN #INKEY$ ###LN W#LN #INKEY$ #4#LN PLOT #LN [W]PI** GOSUB #[E]RNDE**RND▘#▝[J][Y]C▌ GOSUB [4] STEP / RUN 7[Y]F4 PLOT FOR Q#7 FOR MEXP RND7"#[L]C+[J][Y]UEXP RND4▀W/ GOSUB ></CHR$ FOR Q#7#7TAN UEXP RND><TAN E[E]RND GOSUB #[I]RND GOSUB #**RNDY#[Y]C▌ GOSUB [4] STEP / PLOT VAL 7#7£Y ><$4 CLSAT ""#[L]COS / LLIST GOSUB #[L]RND[J]M AND RNDE>=RND6PEEK RNDLN FOR INKEY$ CG FOR LN #PI AND #PI/ PAUSE ▛▐#K▘8#7#TAN 5▙RND GOSUB # AND RND#[S]COS PRINT WM AND RNDXLN LPRINT INKEY$ GOSUB #[N]RND LET TAN EPEEK RND6>=RNDE[P]RND76[P]RNDY▘##PILN [?]# GOSUB #[N]RNDESTR$ RND7Y#[Y]C▘F[R] GOSUB ##£▞ EPEEK RNDLN #PI**#$ FOR <#[L]C▝ GOSUB [K] GOSUB #PEEK RNDTAN LN ## RETURN STOPTAB -PILN [?]#U AND RNDX4 LOAD LPRINT TAN FASTSTR$ ,, GOSUB #[W]RND[R] GOSUB #ZSGN LPRINT TAN E>=RNDQ TAN U AND RND#ESGN RND[J]▐#K▘8# NEWZ( PLOT TAN ESGN RNDU<=RND#- # NEWZ#;#( UNPLOT #[R]""ESGN RNDTAN LN [0]INKEY$ [J]M AND RNDESGN RND FASTLN FOR INKEY$ LPRINT COS #7 NEWZXC NEXT ▞ #, RETURN#C FOR GOSUB [4] REM [K]PI/ SLOWE**RND)#▝LN PEEK PI GOSUB #[G]RNDE[E]RNDLN ?#**#X#▘ LN -##7▀.[R]4 PLOT LN -##[R]4 LOAD ▀LN -##7.[R]C RUN ▀/ LLIST FASTE>=RND[R] GOSUB PI##▀ LPRINT TAN LN [0]INKEY$ )3 IF LN VAL INKEY$ XC POKE #▚#,, GOSUB # FASTC4 GOSUB #>=RNDLN #PIS,PI#LN POKE PIACS #4~~ GOSUB #>=RND; FOR GOSUB [S]/▖; FOR GOSUB [K]AT [R]TAN AT ▘ TAN E[G]RND,,6[G]RND GOSUB #[E]RND[R] GOSUB #6[I]RNDEINT RND,,6INT RND GOSUB #[G]RND[R] GOSUB #6[C]RNDE>=RND,,6>=RND[R]TAN 6STR$ RNDLN [?]#[J]MNOT RNDLN ##LN ##ENOT RNDACS +ESTR$ RND▘ COPY COPY GOSUB #[L]RNDS# RETURN#4"ACS #4 LPRINT LN [?]#7#[V]# RETURN#4:ACS #4ABS LN [?]#F▘▘ #[V]# RETURN#4)ACS #COS ACS #4[X])5 LN [?]#;#[V]# RETURN#4)ACS #TAB ##)5 LN [?]#[R] GOSUB ##[V]# RETURNRNDK?ACS #TAB ###UNOT RND[E]#7### RETURN#4(ACS #TAB ##UNOT RND INPUT █MNOT RND### RETURN#4.ACS #TAB ## GOSUB #[N]RNDR GOSUB #ESTR$ RND AND ##Q F▘▘ #[V]# RETURN#4+ACS PICOS ACS #TAB ##LN [?]#Y#7[Y]4 CLS7###ACS #4J GOSUB #NOT RNDACS )KB FAST5~~INKEY$ ▘~~ GOSUB [L]4▀[J]/,,▘~~ GOSUB [L]4▝Y█ LPRINT 4$[L]W▘ COPY COPY#7LN [£]#### RETURN STOPTAB ##ACS #TAB ##TAN LN [V]▝GC IF H##LN [X]▛#TAN ▞MVAL LN [V]▝AT G4 PLOT ( PLOT TAN LN [=]#Y█[I]#TAN Y#[Y]4▘,,▘5 GOSUB #**RND FOR R GOSUB #S▖ FOR ,,/£E(RNDR GOSUB # FOR K▀[R] GOSUB PI6STR$ RNDTAN LN [£]#▘[S]"Y "[S]4 CLS###LN ## RETURN STOPCOS U<=RND#U AND RNDX[S]COS ▛#A ▘▙RND,, GOSUB #STR$ RND#7# FOR Q[?]7▘▘ LN [=]# PLOT ▘TAN E**RND)▖ LET GOSUB #[L]RND) GOSUB #[N]RNDLN ###[?]#LN [0]INKEY$ Y M AND RND) SLOW IF GOSUB #[L]RNDE**RNDTAN LN $#Y<M<=RNDU AND RNDWM AND RNDLN ASN #4 POKE U AND RNDXM<=RNDTAN E(RND▘U ,,6[E]RND6[G]RND6INT RND6>=RNDE(RND7#7#,,FFF6[W]RNDE£RND▘[A] ,,6**RND) GOSUB #[P]RND GOSUB #[C]RNDY▘M[R]RNDTAN LN $#LN FOR INKEY$ FOR COS LN ASN #4 PLOT TAN LN ?## NEW##LN #PI6SGN RND4 PRINT #[I]#LN #PI6PEEK RNDTAN LN #PICOS 6SGN RND NEW""TAB [3]# PLOT ▘TAN U[R]RNDM AND RNDLN ▝#LN ?##LN [A]#4▞LN PRINT # PLOT ▘TAN LN [/]#LN ▝#LN [3]#C8LN [/]## GOSUB #[U]RND,: [S]K▝#$▌C▒7<,[Y]4▞( SAVE £C<>[R]USR ▝#/NOT E[S]RND6SGN RND# PLOT █##[-]PIESGN RND6[S]RNDEPEEK RND6[U]RNDTAN EINT RND6SGN RNDTAN #[N]""SGN TAN RND12 COPYSFAAAC~~LN ##LN ## RETURNE4▌LN 2INKEY$ / DIM RETURNF4▌LN 8INKEY$ / STEP RETURN#ABS ########▀##[;]##[▒]##>#####COS ##6##[Y]#LN W#LN ##LN 4#U<=RND[R]C RUN #<=#LN ZINKEY$ LN #####Y▝LN [;]#LN #INKEY$ Y▀#[;]#Y▘LN [;]#LN GOSUB # RETURN#""LN #PI GOSUB #[P]RND. GOSUB #[P]RNDC*##LN NINKEY$ GOSUB #SGN RND GOSUB [K]. GOSUB #>=RNDLN 8INKEY$ COS #5INKEY$ Q 6>=RNDLN ###[L]#EINT RND6SGN RNDTAN LN [V]▝ FOR 5[Z] CLEAR[R] GOSUB #RCOS 5 COPY RETURN[R] GOSUB #4 GOTO TAN Y "[S]4 CLSTAN LN #PI6SGN RNDTAN LN #####[J]M AND RNDLN WINKEY$ C RUN FOR LN [?]#▘#*LN TO #LN ASN #**E[N]RNDLN [?]#/ FASTY▞LN [;]#LN NEXT #U AND RNDM[R]RND#5INKEY$ Y,,LN [;]#[J]M[K]RNDM AND RNDLN ASN #**LN NEXT #U AND RNDM[K]RNDTAN ESTR$ RND7# RETURN#COS FTAN Y▛LN [;]#[J]M AND RND5. IF 6[L]RNDLN WINKEY$ COS FOR LN HINKEY$ RETURN STOPASN EINKEY$ RETURN#4▌LN [?]#/ REM LN [?]#LN [O]# FOR ▄#K▘=LN X# GOSUB #[N]RND[R] GOSUB PI##EPEEK RND£#LN QINKEY$ AND EINKEY$ E>=RND,,6>=RNDEPEEK RND#▞ FOR E[N]RND<$C▝ GOSUB [K]U AND RND PRINT LN EINKEY$ LET M AND RND###LN TINKEY$ 6PEEK RNDTAN LN NEW#COS NEW"" RETURN█4 PLOT PLOT ▘TAN U[R]RNDM AND RNDLN ▝#ESGN RNDLN [?]#LN ###LN [Z]#4▞LN .##[?]#LN [O]#LN ▝#LN [V]#C8LN [O]## GOSUB #[U]RND,: [S]S▝#$▌C▒7<,[Y]4▞( SAVE £C<>[R]>=▝#/NOT LN .##EINKEY$ E[S]RND6SGN RNDTAN Y▖LN [;]#▘RND[0]LN TO #LN [V]▝8""LN 8INKEY$ C FOR TAN LN GOSUB # RETURN STOPCOS RETURN#COS 53 IF 6[L]RND5 6[N]RNDE**RND FAST)6 [R] GOSUB #▞4FQ ( CLS6**RND6STR$ RNDQ█LN ##LN [?]#LN X# GOSUB #**RND[R] GOSUB ####[R]4▞ LPRINT 6**RND/[Q]M2#53# FOR GOSUB [K] LPRINT 6**RNDTAN U2##EPEEK RND# NEWZX[(]**WW#▐#K▘8 FAST$R LPRINT COS F FAST)3#U2##,[Y]4 LOAD <7( SAVE LPRINT [R]TAN U2#WTAB W#LN 7#Y~~▞▜LN [.]#LN S#4" RETURN#TAB ##LN 8INKEY$ # IF #LN ##LN ▛#ESGN RND#K▖ PLOT RND/▝ NEW[Z]#LN NEW#4 FOR LN 5INKEY$ ESGN RND#ACS #CLN LN ZINKEY$ /COS U[K]RND[R]M AND RNDC▞LN [O]##[(]#ESGN RND6PEEK RNDLN [(]#SQR EPEEK RND# NEWZ▐#K▘86PEEK RND GOSUB # AND RND#WM AND RND[S]4 LLIST RTAN LN EINKEY$ LN ▝#LN ### NEW[Z]#LN NEW#4 RUN LN 5INKEY$ Y COPYM2#Y#▞4E£RND▐#K▘8Y#7[Y]C▝Q ( SAVE TAN ESGN RNDACS #TAB W#Y"LN [;]#LN GOSUB # RETURNYCOS RETURNNASN W#/ INPUT ESTR$ RND GOSUB #[Y]RND▘4 GOSUB [K]TAN U""RNDXM""RNDCOS ESTR$ RND)5 ;6STR$ RNDTAN E(RNDF:=[J]F$ASN ##▞4[Y]4▌F( IF / LET #M""RNDE**RND6STR$ RND LPRINT 6AT RNDLN ▗#▘▝ TAN LN [=]#4 POKE EAT RND DIM E(RND), ;6[Y]RNDY COPYM2#▘A 5▙RND) THENRND GOSUB [K]TAN E[G]RND GOSUB #[C]RND#[L]TAB [7]INKEY$ TAN Y▝LN [;]#LN PLOT #LN PLOT #E**RND)#▝LN KINKEY$ GOSUB #INT RNDE[G]RNDLN QINKEY$ **LN ## GOSUB #[G]RNDLN #INKEY$ Y▀LN [;]#LN PLOT #LN (#LN ##COS FAST FOR LN HINKEY$ RETURN STOPQ[?] FOR LPRINT COS #F#/ FOR 5 THENRND# INPUT INKEY$ LN PLOT #[J]M AND RNDESGN RND FASTLN ## LPRINT COS #7 NEWZXC NEXT ▞ #, RETURN#C FOR GOSUB [4] REM ##/ SLOW LPRINT 6VAL RNDY▌LN [;]#LN ##LN [B]#LN [V]▝84▌LN 8INKEY$ C LOAD LN EINKEY$ EVAL RND DIM ▞##[J]LN ##Y£E#RND▘▜ GOSUB [L]+4 SAVE GOSUB #£RND, RETURN#4▀</ SAVE GOSUB [4]# RETURN£4 LET E£RND)▐ ;▞4Q▀7( CLSTAN [W]##SGN ## THEN#LN ### LIST # GOSUB #[P]RND#[N]C5U2#WCODE W#LN 5INKEY$ GOSUB #[P]RND#[N]C?Y£LN ##LN ##LN ## RETURNE4~~Y$LN ##LN 2INKEY$ / TO RETURNC4▌LN [B]#/CHR$ RETURNF4▌LN 8INKEY$ /LN RETURND4▌LN ##/CODE RETURNP4▌LN ##/[V] RETURNQ4▖▘ TAN RETURNR4▌LN 5INKEY$ /[E] RETURNA4▌LN ##/[5] RETURNO4▌LN ##/[/] RETURNB4▌LN ##/[?] RETURNL4▌LN ##/▚ RETURNS4▞LN ### LIST # RETURNITAB LIST # GOSUB #(RNDE[W]RND[R] GOSUB #6SIN RNDE>=RND[R] GOSUB #6TAN RNDY:LN ##▘▘ TAN 5#RND) #▞▒#ACS T*ACS >K▝ INPUT H( PRINT #7U[X]RND[W]4 DIM U[W]RND[X]4 STOPTAN LN [/]#E#RND[R] GOSUB ###COS Y▒LN ##▘▘ TAN LN [/]# GOSUB ##RNDTAN £PRESS NEWLINE TO DELETE£[R][E][C][O][R][D]█[L][A][Y][O][U][T] USE THE KEYBOARDAS A TYPEWRITER TO ENTER TITLESOF A BLANK RECORD. MOVE CURSORWITH THE ARROWS. STOP TO EXIT£[D][A][T][A]█[F][I][E][L][D][S] MOVE THE CURSORUSING THE ARROW KEYS AND PRESSNEWLINE TO MARK THE START OFEACH DATA FIELD. STOP TO EXIT£[L][I][S][T] PRESS ANY KEY TO STOP£[P][R][I][N][T] PRESS ANY KEY TO STOP£USE SHIFT TO MOVE THE CURSOR TO THE FIELD WHICH WILL DEFINE THE RECORD ORDER AND PRESS NEWLINE £[A][L][T][E][R]█[A]█[R][E][C][O][R][D] STOP TO EXITSHIFT-6 TO SKIP A DATA FIELD£CRC CHECK FAILED PLEASE RELOAD£PRESS NEWLINE FOR THE STRING SELECT TO APPLY TO ANY FIELD OR USE SHIFT TO MOVE THE CURSOR TO DESIRED FIELD AND PRESS NEWLINE £[S][E][A][R][C][H]█[M][O][D][E] STOP TO EXITPRESS NEWLINE FOR ANOTHER RECORDOR ENTER A SELECTING STRING £DO YOU WANT THE STRING SELECT TO REMAIN ACTIVE? PRESS Y OR N FOR YES OR NO£[C][O][M][M][A][N][D][S]█[A][R][E][:] ENTER ALTER INFORMFORWARD BACK RESET ORDER SELECTQUIT LIST PRINT COPY DELETE£[E][N][T][E][R]█[A]█[R][E][C][O][R][D] STOP TO EXIT£ FIELDS RECORDS PERCENT FULLORDERED BY FIELD£ REM
51 REM
1100 DIM F$(9999)
1150 LET F$( TO 20)="VU-FILE"
1160 SLOW
1200 RAND USR 17986
1300 CLS
1400 GOTO 3400
2000 CLS
2005 PRINT AT 3,8;"[P][S][I][O][N]█[C][O][M][P][U][T][E][R][S]"
2010 PRINT AT 6,12;"VU-FILE"
2020 PRINT AT 11,6;"1-SET RECORD FORMAT"
2030 PRINT AT 13,6;"2-ENTER VU-FILE"
2040 PRINT AT 15,6;"3-SAVE VU-FILE AND DATA"
2050 PRINT AT 17,6;"4-SET PRINTER FORMAT"
2055 PRINT AT 21,1;"PRESS 1 TO 4 FOR DESIRED OPTION"
2060 LET I=CODE INKEY$
2070 IF I<29 OR I>32 THEN GOTO 2060
2075 CLS
2080 GOTO 3000+200*(I-28)
3200 RAND USR 17989
3220 GOTO 2000
3400 LET A=USR 19157
3410 GOTO 3450+50*A
3450 GOTO 2000
3500 PRINT AT 0,0;F$( TO 20);" ";PEEK 16603
3505 PRINT PEEK 16565+256*PEEK 16566;TAB 17;INT (100*(PEEK 18585+256*PEEK 16586)/(PEEK 16583+256*PEEK 16584))
3510 PRINT TAB 20;PEEK 16567
3548 LET A=USR 19160
3549 GOTO 3410
3550 LPRINT F$(21 TO 52)
3560 LET A=USR 17983
3570 GOTO 3410
3600 CLS
3610 PRINT "ENTER FILE NAME"
3620 PRINT AT 10,0;"SET PLAYER TO RECORD"
3630 PRINT "BEFORE PRESSING NEWLINE"
3640 INPUT N$
3645 FAST
3650 LET F$( TO 20)=N$
3660 CLS
3670 RAND USR 19154
3690 PRINT USR 8192;"SAVE:P:VU-FILE:"
3695 IF USR 19151<>0 THEN STOP
3700 SLOW
3710 GOTO 2000
3800 RAND USR 17992
3810 GOTO 2000
9995 PRINT USR 8192;"SAVE:P:VU-FILE:"
9996 IF USR 19151=0 THEN RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.