VU-File

Date: 1981
Type: Cassette
Platform(s): TS 1000
Tags: Database

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 via RAND 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 computed GOTO, implementing a state-machine dispatch back into BASIC.

The key machine code entry points are tabulated below:

AddressCalled viaPurpose
17986RAND USRMC initialization / startup
17983USR (return used)LPRINT layout handler, returns dispatch value
17989RAND USRSet printer format
17992RAND USRSet record format (option 1 / layout)
19151USR (return used)Save completion check (0 = success)
19154RAND USRPrepare data for tape save
19157USR (return used)Main database engine entry; returns menu state
19160USR (return used)Status display refresh, returns dispatch value
8192USR with string argPsion 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 19157 at line 3400 obtains a state index.
  • GOTO 3450+50*A routes to one of: 3450 (menu), 3500 (status display), 3550 (LPRINT), 3600 (save), 3800 (layout), etc.
  • Similarly, GOTO 3410 after updating A at 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:

AddressSystem VariableUse in Program
16565–16566Record count (lo/hi byte)Displayed as total records
16567Field ordering indexDisplayed as “ordered by field”
16583–16584Total capacity (lo/hi)Denominator for percent-full calculation
16586 + 18585Used space (lo/hi, split)Numerator for percent-full calculation
16603Field countDisplayed 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 any PAUSE delay.
  • The RAND USR idiom is used consistently for calls whose return values are irrelevant, keeping the BASIC stack clean.
  • The program uses FAST mode only during the tape save sequence (line 3645), switching back to SLOW at 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

Appears On

Related Products

High-speed storage and retrieval program. Access personal or business files almost instantly. Design or format files to suit specific needs...

Related Articles

Related 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.

Scroll to Top