Provides a skeleton for writing structured BASIC programs: a header block for the program name and description, a definition block for arrays and documented variables, a program block, a user-routine block and a library of utility subroutines. Each routine’s line number is stored in a named variable such as TITLE, GETKEY or SORT, so code calls them with GOSUB TITLE rather than a bare number. The utilities center a title, wait for a single keypress, format a number to a set of decimal places, sort a value array along with an index array, and show a numbered menu. Three example programs built from the template are on the tape: a formula calculator, a least-squares curve fitter and a lap-time ranking program.
The printed cassette label reads “OMNI TEMPLATE REV. 1” with a handwritten “<135>”, and each program opens with the REM header “OMNI TEMPLATE REV.1 BY MIMI CHO”. A period advertisement from Omni Technology of Pittsburgh, Pennsylvania offered the tape for the ZX80 and ZX81 at $9.50 before September 1, 1982, with a listing and manual, and named RACING, INDEX-CARDS and FIT-POINTS as the example programs. This tape has a CALCULATOR example in place of INDEX-CARDS. The tape files are:
TEMPLATE: the blank template, with empty REM lines left in every block for the user to fill.CALCULATOR(saved asCACULATOR): reads a formula as a string and evaluates it withVAL, printing the result.FITPOINTS: takes up to 50 X,Y pairs and fits a straight line, a semi-log (Y=A*EXP(B*X)) or a log-log (Y=A*X**B) curve by least squares, reporting A, B, the correlation coefficient and standard error, then interpolates Y for entered X values.RACING: takes IDs and three lap times for up to 20 participants and ranks them by any lap or by total time in a formatted table.
Program Analysis
Program Structure
Line numbers are fixed by block: 5–45 header, 1000–1300 definitions (arrays at 1015, string variables A$–Z$ at 1050–1175, numerics after 1185), 1500–1700 routine-address assignments, 2000 main program, 3995 STOP as END, 4000 user routines, and 7000 onward the utilities (TITLE 7100, GETKEY 7200, NUMFORMAT 7300, SORT 7500, MENU 7700). The example programs fill in the REM placeholders, add their own named routines (for instance GETDATA, CALC, OUTRESULT, INTERPOLATION, STRAIGHT, SEMILOG, LOGLOG in FITPOINTS) and customize the menu text.
Notable Techniques
- Computed
GOSUB/GOTOthrough long variable names (GOSUB GETDATA,GOTO END) makes the main program read like a list of procedure calls. - The
GETKEYroutine first waits for all keys to be released, then for a new key, avoiding auto-repeat from a held key. TITLEcenters a string withPRINT AT 0,16-0.5*LEN T$.- The sort carries an index array
I()alongside the valuesR(), so RACING can rank records without moving the name and lap arrays. - FITPOINTS fits the curved models by taking
LNof the data and reusing the linear least-squares routine, then converting A back withEXP. - Long data-entry loops clear the screen every few entries (
(I/9)-INT (I/9)) to avoid the scroll prompt. FASTaround calculations and sorting,SLOWfor display.
Potential Issues
- In the blank template the bubble sort compares
R(I)with(I+1)rather thanR(I+1); RACING has the corrected line. - CALCULATOR’s sort routine is a different, Shell-style version that never ends its inner loop (
Jis incremented without a bound check). CALCULATOR does not call it. NUMFORMATreports a decimal point error whenDECIMis 0 even though the next lines handle that case, computes the fraction asINTNUM-INNUM(negative), and its padding linesLET V$=""+V$add nothing.- In FITPOINTS the log-log result is labeled
Y=EXP (A)*X**B, but A has already been converted withEXPbefore display. - RACING returns to the menu with
GOTO 2011, a line that does not exist; the ZX81 continues at the next line, 2015, which is the intended effect.
Source Code
5 REM OMNI TEMPLATE REV.1
10 REM BY
15 REM MIMI CHO
20 REM ========================
25 REM PROGRAM NAME:
30 REM PROGRAM DESCRIPTION:
35 REM
40 REM
45 REM
1000 REM =======================
1005 REM DEFINITION BLOCK
1010 REM -----------------------
1015 REM ARRAY
1020 REM
1025 REM
1030 REM
1035 REM
1040 REM -----------------------
1045 REM STRING VARIABLES
1050 REM <TITLE> UTILITY
1055 REM B$=
1060 REM C$=
1065 REM D$=
1070 REM E$=
1075 REM F$=
1080 REM G$=INPUT FOR <GET KEY>
1085 REM H$=
1090 REM I$=
1095 REM J$=
1100 REM K$=
1105 REM L$=
1110 REM M$=
1115 REM N$=
1120 REM O$=
1125 REM P$=
1130 REM Q$=
1135 REM R$=
1140 REM S$=
1145 REM T$=TITLE FOR <TITLE>
1150 REM U$=
1155 REM V$=FORMATTED STRING FROM<NUMFORMAT>
1160 REM W$=
1165 REM X$=
1170 REM Y$=
1175 REM Z$=
1180 REM -----------------------
1185 REM NUMERIC VARIABLES
1190 REM I=TEMP
1195 REM J=
1200 REM K=
1205 REM L=
1210 REM M=
1215 REM INTNUM <NUMFORMAT>
1220 REM SIZE <NUMFORMAT>
1225 REM PRTNUM <NUMFORMAY>
1230 REM SORTDIR <SORT>
1235 REM SORTFLAG<SORT>
1240 REM
1245 REM
1250 REM
1255 REM
1260 REM
1265 REM
1270 REM
1275 REM
1280 REM
1285 REM
1290 REM
1295 REM
1300 REM
1500 REM -----------------------
1505 REM DEFINITION OF SUBROUTINES(MODULES)
1510 REM -----------
1515 REM <TITLE> UTILITY
1520 REM CLEARS SCREEN THEN PUTS TITLE AT TOP CENTER
1525 LET TITLE=7100
1530 REM --------
1535 REM <GETKEY> UTILITY
1540 REM GET SINGLE CHARACTER FROM KEYBOARD.RETURNS IN G$
1545 LET GETKEY=7200
1550 REM -------
1555 REM <NUMFORMAT> UTILITY
1560 REM FORMATS NUMBER WITH DECIMAL PLACES.RETURNS IN V$
1565 LET NUMFORMAT=7300
1570 REM --------
1575 REM <SORT> UTILITY
1580 REM SORTS IN SORTDIRECTION;+1:UPWARD
1585 REM -1:DOWNWARD
1590 REM UNSORTED R(N)AND I(N)=>SORTED R(N)AND I(N)
1595 LET SORT=7500
1600 REM -------
1605 REM <MENU>UTILITY
1610 REM DISPLAYS A MENU AND SELECTION
1615 REM IS RETURNED BY G$<GETKEY>
1620 LET MENU=7700
1625 REM ---------
1630 REM <END>
1635 LET END=3995
1640 REM --------
1645 REM <MAIN>
1650 LET MAIN=2000
1655 REM ---------
1660 REM
1665 REM
1670 REM
1675 REM
1680 REM
1685 REM
1690 REM
1695 REM
1700 REM
2000 REM =======================
2005 REM PROGRAM BLOCK
2010 REM
2015 REM
2020 REM
2025 REM
2030 REM
2035 REM
2040 REM
2045 REM
2050 REM
2055 REM
2060 REM
2065 REM
2070 REM
2075 REM
2080 REM
2085 REM
2090 REM
3995 STOP
4000 REM =======================
4005 REM USER ROUTINE BLOCK
4010 REM
4015 REM
4020 REM
4025 REM
4030 REM
4035 REM
4040 REM
4045 REM
4050 REM
4055 REM
4060 REM
4065 REM
4070 REM
4075 REM
4080 REM
4085 REM
4090 REM
4095 REM
4100 REM
7000 REM =======================
7005 REM UTILITY ROUTINE BLOCK
7100 REM --------
7105 REM <TITLE>ROUTINE (T$->CLS,SHOW T$)
7110 CLS
7115 IF LEN T$>32 THEN GOTO 7130
7120 PRINT AT 0,16-0.5*LEN T$;T$
7125 GOTO 7135
7130 PRINT T$
7135 RETURN
7200 REM ---------
7205 REM <GETKEY> ROUTINE(->G$)
7210 IF INKEY$ <>"" THEN GOTO 7210
7215 IF INKEY$ ="" THEN GOTO 7215
7220 LET G$=INKEY$
7225 RETURN
7300 REM ---------
7310 LET V$=""
7315 IF DECIM>0 THEN GOTO 7330
7320 PRINT "DECIMAL POINT ERROR"
7325 GOTO 7395
7330 LET INTNUM=INT (INNUM)
7335 IF DECIM<>0 THEN GOTO 7350
7340 LET V$=STR$ (INTNUM)
7345 GOTO 7380
7350 LET FRTNUM=(INTNUM-INNUM)*10**DECIM
7355 LET V$=STR$ (FRTNUM)
7360 FOR I=1 TO DECIM-LEN (V$)
7365 LET V$=""+V$
7370 NEXT I
7375 LET V$=STR$ (INTNUM)+"."+V$
7380 FOR I=1 TO SIZE-LEN (V$)
7385 LET V$=""+V$
7390 NEXT I
7395 RETURN
7500 REM ---------
7505 REM <SORT> UTILITY
7510 FAST
7515 IF SORTDIR=1 THEN GOTO 7525
7520 LET SORTDIR=-1
7525 LET SORTFLAG=0
7530 FOR I=1 TO N-1
7535 IF SORTDIR*R(I)<=SORTDIR*(I+1) THEN GOTO 7575
7540 LET T=R(I)
7545 LET R(I)=R(I+1)
7550 LET R(I+1)=T
7555 LET T=I(I)
7560 LET I(I)=I(I+1)
7565 LET I(I+1)=T
7570 LET SORTFLAG=1
7575 NEXT I
7580 IF SORTFLAG=1 THEN GOTO 7525
7585 SLOW
7590 RETURN
7700 REM ----------
7705 REM <MENU>ROUTINE(->=>G$)
7710 REM TITLE
7715 LET T$=""
7720 GOSUB TITLE
7725 PRINT
7730 PRINT " 1. "
7735 PRINT " 2. "
7740 PRINT " 3. "
7745 PRINT " 4. "
7750 PRINT " 5. "
7755 PRINT " 6. "
7760 PRINT " 7. QUIT "
7765 PRINT
7770 PRINT " ENTER SELECTION >"
7775 GOSUB GETKEY
7780 IF (VAL (G$)>0) AND (VAL (G$)<8) THEN GOTO 7790
7785 GOTO 7775
7790 RETURN
7795 REM --------
7800 REMNote: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.




