--- title: "Tape File" id: 57611 type: "computer_media" slug: "tape-file" url: "http://localhost/computer_media/tape-file/" markdown_url: "http://localhost/computer_media/tape-file.md" published_at: "2024-10-06T00:26:50+00:00" modified_at: "2026-04-03T07:58:15+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/tape-file-1.png" excerpt: "A fully-featured cassette tape library manager with menu-driven data entry, field-based sorting, and LPRINT support packed into a string array." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Utility" slug: "utility" taxonomy: "genre" url: "http://localhost/type/utility/" media_contents: - id: 56724 title: "Synchro-Sette June 1983" type: "computer_media" url: "http://localhost/computer_media/synchro-sette-june-1983/" media_type: "Program" mediadate: "June 1983" images: - url: "http://localhost/wp-content/uploads/2024/10/tape-file-1.png" media_type_tags: "Utility" --- # Tape File This program is a cassette tape cataloguing system that stores metadata for up to 100 programs in a 10×32 string array. Each record in the array holds a program name (columns 1–8), subject (10–15), counter location (17–22), tape number/side (24–27), and miscellaneous info (29–32). The main menu dispatches to six routines via a computed GOTO using GOTO 1000*VAL B$, covering data entry, viewing, tape save, clear, print, and sort. A Shell sort (gap-halving) at line 6200 allows sorting records by any of the five fields. Data is persisted to tape using the SAVE command at line 3050. *** ## Program Analysis ### Program Structure The program is organised as a menu-driven application with a central dispatch loop and separate numbered subroutine blocks. The main menu lives at lines 20–260; six functional modules begin at multiples of 1000 (1000, 2000, 3000, 4000, 5000, 6000). A second sub-menu for viewing/editing begins at line 2000, itself dispatching via `GOTO (VAL B$*200)+2100` to lines 2300, 2500, 2700, and 2900. Utility subroutines are at lines 9000 (scroll 10 lines) and 9800 (press-enter pause). ### Data Model All records are held in the string array `A$`, dimensioned at line 10 as `DIM A$(10,32)`. Note that the first dimension is 10, yet the entry loop runs up to `N=100` — this is a clear bug; the array can only hold 10 records before an index-out-of-range error occurs. The counter `R1` tracks how many records have been entered and is preserved across menu returns. Each 32-character row is laid out as a fixed-width record: | Columns | Field | Max Length | | --- | --- | --- | | 1–8 | Program name | 8 | | 9 | Separator (space) | — | | 10–15 | Subject | 6 | | 16 | Separator | — | | 17–22 | Counter location | 6 | | 23 | Separator | — | | 24–27 | Tape no./side | 4 | | 28 | Separator | — | | 29–32 | Miscellaneous info | 4 | ### Menu Dispatch Technique The main menu reads a single keypress and validates it by checking `CODE B$` against the range 29–34 (ZX81 character codes for digits 1–6). The computed jump at line 260, `GOTO 1000*VAL B$`, routes directly to the correct module in a single statement — a classic and efficient ZX81 BASIC idiom. The secondary menu at line 2260 uses `GOTO (VAL B$*200)+2100` with valid range 29–32 (digits 1–4), landing at lines 2300, 2500, 2700, and 2900. `VAL B$` here works because `B$` holds a single digit character. ### Inverse Video Title Screen The screen background effect at lines 40–60 fills the display by PRINTing `"% % % % % % % % "` in a loop 96 times — each `%` is an inverse space, alternating with normal spaces to produce a checkerboard pattern. The title text and menu options are then written using `PRINT AT` over this background. A similar 192-iteration loop appears in the sub-menu screen at line 2000. `POKE 16418,0` sets the border colour and `POKE 16418,2` changes it when entering a module. ### Shell Sort Implementation Lines 6200–6370 implement a Shell sort on the array. The gap `N` starts at `INT(R1/2)` and is halved each outer pass (line 6220). The inner loop compares `A$(I, A TO B)` with `A$(L, A TO B)`, where `A` and `B` are set by the earlier field-selection block (lines 6070–6160) to the appropriate column slice for the chosen sort key. Swaps exchange the full 32-character row via the temporary `B$`. Note that `B$` is reused for both menu input and sort temporary storage throughout the program. ### Key BASIC Idioms - `POKE 16418,N` — direct memory write to the system variable controlling the display file border (TV colour register on ZX81). - `SCROLL` used extensively to advance the display without clearing it, providing a rolling-log entry style. - `FAST`/`SLOW` mode switching around `INPUT` statements — `SLOW` is required for the display to work during input; `FAST` is used otherwise to speed up computations and screen fills. - Left-padding of the miscellaneous field in lines 1376–1385 using a prepend loop: `LET B$=" "+B$` repeated `4-LEN B$` times. - The ruler string `Z$` at line 12 is a 32-character row of inverse dashes used as a visual separator wherever data is displayed. ### Bugs and Anomalies - **Array size mismatch:**`DIM A$(10,32)` at line 10 allocates only 10 rows, but the entry loop at line 1000 iterates up to `N=100`. Entering more than 10 programs will cause a subscript error. - **Dead code at lines 8000/8100:** Lines 8842 and 8844 call `GOSUB 8000` and `GOSUB 8100`, but neither subroutine exists in the listing. Editing the counter field will produce an error. - **Unreachable STOP at line 1999:** Line 1999 contains `STOP` but can only be reached by falling through from line 1420’s `NEXT N` loop completing at `N=100`; in practice execution goes to line 1500 when the user enters an empty name. - **Line 2560 is missing:** The search loop at line 2530 branches to `GOTO 2560` on a name match, but line 2560 does not exist — execution falls through to line 2660, which works correctly as the next defined line, making this a deliberate gap-jump technique. - **Typo in label at line 8700:** The prompt reads `"WHAT IS THE NEW STUBJECT?"` — “STUBJECT” instead of “SUBJECT”. - **Print format mismatch at line 8660:** The header printed reads `"NAME PART NO. COST IT/UN IN/S"`, suggesting a parts-inventory header was copied from another program rather than the tape-catalogue header used elsewhere. - **Module 4 (line 4000):** The “clear all data” option simply executes `RUN`, which re-initialises all variables and arrays — a functional but destructive implementation with no confirmation prompt. ## Source Code ``` 10 DIM A$(10,32) 11 LET R1=0 12 LET Z$="%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-" 20 FAST 25 CLS 30 POKE 16418,0 40 FOR N=1 TO 96 50 PRINT "% % % % % % % % "; 60 NEXT N 70 PRINT AT 2,5;" PROGRAM TAPE FILE " 80 PRINT AT 5,1;"%T%O% %E%N%T%E%R% %P%R%O%G%R%A%M%S";TAB 26;"%-% %1" 90 PRINT AT 7,1;"%T%O% %S%E%E% %P%R%O%G%R%A%M%S";TAB 26;"%-% %2" 100 PRINT AT 9,1;"%T%O% %S%A%V%E% %D%A%T%A% %O%N% %T%A%P%E";TAB 26;"%-% %3" 110 PRINT AT 11,1;"%T%O% %C%L%E%A%R% %A%L%L% %D%A%T%A";AT 11,26;"%-% %4" 120 PRINT AT 13,1;"%T%O% %P%R%I%N%T% %D%A%T%A% ";TAB 26;"%-% %5" 130 PRINT AT 15,1;"%T%O% %S%O%R%T% %D%A%T%A% ";TAB 26;"%-% %6" 180 PRINT AT 22,4;"%E%N%T%E%R% %O%N%E% %O%F% %A%B%O%V%E% %:%:%:";AT 22,4;"ENTER ONE OF ABOVE :::";AT 22,4;"%E%N%T%E%R% %O%N%E% %O%F% %A%B%O%V%E% %:%:%:" 190 SLOW 200 LET B$=INKEY$ 210 IF B$="" THEN GOTO 180 220 IF CODE B$<29 OR CODE B$>34 THEN GOTO 180 230 FAST 240 POKE 16418,2 250 CLS 260 GOTO 1000*VAL B$ 1000 FOR N=R1+1 TO 100 1010 GOSUB 9000 1020 PRINT "WHAT IS THE PROGRAM NAME?" 1030 SCROLL 1040 PRINT "PROGRAM NO. ";N;" (8 CHAR. MAX.)" 1050 SCROLL 1055 SLOW 1060 INPUT B$ 1065 FAST 1070 IF B$="" THEN GOTO 1500 1080 LET A$(N, TO 8)=B$ 1090 PRINT A$(N) 1100 GOSUB 9000 1110 SCROLL 1120 PRINT "WHAT IS THE PROGRAM SUBJECT?" 1125 SCROLL 1126 PRINT "(6 CHAR MAX)" 1130 SCROLL 1135 SLOW 1140 INPUT B$ 1142 FAST 1145 IF LEN B$>6 THEN GOTO 1135 1150 LET A$(N,10 TO 15)=B$ 1160 PRINT A$(N) 1170 GOSUB 9000 1190 PRINT "WHAT IS THE COUNTER LOCATION?" 1195 SCROLL 1196 PRINT "(6 CHAR MAX)" 1200 SCROLL 1205 SLOW 1210 INPUT B$ 1212 FAST 1214 IF LEN B$>6 THEN GOTO 1205 1220 SCROLL 1230 LET A$(N,17 TO 22)=B$ 1240 PRINT A$(N) 1250 GOSUB 9000 1260 PRINT "TAPE NO./SIDE? ";N;" (4 CHAR. MAX.)" 1270 SCROLL 1275 SLOW 1280 INPUT B$ 1285 FAST 1290 IF LEN B$>4 THEN GOTO 1275 1300 SCROLL 1320 LET A$(N,24 TO 27)=B$ 1330 PRINT A$(N) 1340 GOSUB 9000 1350 PRINT "MISC. INFO. OR CODE ?" 1351 SCROLL 1352 PRINT "(4 CHAR MAX)" 1355 SLOW 1360 INPUT B$ 1365 FAST 1370 IF LEN B$>4 THEN GOTO 1355 1374 IF LEN B$=4 THEN GOTO 1390 1376 FOR I=1 TO 4-LEN B$ 1380 LET B$=" "+B$ 1385 NEXT I 1390 SCROLL 1400 LET A$(N,29 TO 32)=B$ 1410 PRINT A$(N) 1420 NEXT N 1500 FAST 1510 CLS 1520 LET R1=N-1 1530 SLOW 1540 GOTO 20 1999 STOP 2000 FAST 2010 CLS 2020 POKE 16418,0 2030 FOR N=1 TO 192 2040 PRINT "% % % % "; 2050 NEXT N 2060 PRINT AT 2,8;" PROGRAM DATA " 2070 PRINT AT 5,1;"%T%O% %S%E%E% %A%L%L% %P%R%O%G%R%A%M% %D%A%T%A";TAB 28;"%-% %1" 2080 PRINT AT 7,1;"%T%O% %C%H%A%N%G%E% %P%R%O%G%R%A%M% %N%A%M%E";TAB 28;"%-% %2" 2090 PRINT AT 9,1;"%T%O% %S%E%E% %I%T%E%M% %D%A%T%A";TAB 28;"%-% %3" 2100 PRINT AT 11,1;"%T%O% %E%D%I%T% %D%A%T%A% %I%T%E%M%S";TAB 28;"%-% %4" 2180 PRINT AT 22,4;"%E%N%T%E%R% %O%N%E% %O%F% %A%B%O%V%E% %:%:%:";AT 22,4;"ENTER ONE OF ABOVE :::";AT 22,4;"%E%N%T%E%R% %O%N%E% %O%F% %A%B%O%V%E% %:%:%:" 2190 SLOW 2200 LET B$=INKEY$ 2210 IF B$="" THEN GOTO 2180 2220 IF CODE B$<29 OR CODE B$>32 THEN GOTO 2180 2230 FAST 2240 POKE 16418,2 2250 CLS 2260 GOTO (VAL B$*200)+2100 2300 SLOW 2310 FOR N=1 TO R1 2320 SCROLL 2340 SCROLL 2350 PRINT "NAME SUBJECT C/L T/NO MISC" 2360 SCROLL 2365 PRINT Z$ 2370 SCROLL 2380 PRINT A$(N) 2382 SCROLL 2384 SCROLL 2386 SCROLL 2388 NEXT N 2390 PRINT "PRESS ENTER TO CONTINUE :::" 2392 INPUT B$ 2395 GOTO 20 2500 PRINT AT 10,0;"WHAT IS THE PROGRAM NAME?" 2505 SLOW 2510 INPUT B$ 2515 FAST 2520 FOR N=1 TO R1 2525 FAST 2530 IF A$(N, TO LEN B$)=B$ THEN GOTO 2560 2540 NEXT N 2542 CLS 2544 GOSUB 9000 2546 PRINT "PROGRAM NAME NOT IN FILE :::" 2547 GOSUB 9000 2548 GOSUB 9800 2550 GOTO 20 2660 FAST 2662 CLS 2664 GOSUB 9000 2666 PRINT "NAME SUBJECT C/L T/NO. MISC" 2668 SCROLL 2670 PRINT Z$ 2672 SCROLL 2674 PRINT A$(N) 2676 GOSUB 9000 2678 PRINT AT 20,0;"IS THIS THE CORRECT PROGRAM NAME?" 2679 SLOW 2680 INPUT Y$ 2682 FAST 2683 IF Y$(1)="N" THEN GOTO 2540 2684 SCROLL 2685 SCROLL 2686 PRINT "WHAT IS THE CORRECT NAME?" 2687 SLOW 2688 INPUT B$ 2689 FAST 2690 LET A$(N, TO 8)=B$ 2691 SCROLL 2692 SCROLL 2693 PRINT Z$ 2694 SCROLL 2695 PRINT A$(N) 2696 SCROLL 2697 SCROLL 2698 GOSUB 9800 2699 GOTO 20 2700 CLS 2705 PRINT AT 10,1;"WHAT IS THE PROGRAM NAME?" 2710 SLOW 2715 INPUT B$ 2720 FAST 2725 IF LEN B$>8 THEN GOTO 2710 2730 FOR N=1 TO R1 2735 IF A$(N, TO LEN B$)=B$ THEN GOTO 2760 2740 NEXT N 2745 SCROLL 2750 PRINT TAB 16-((LEN B$)/2);B$ 2755 GOTO 2544 2760 CLS 2765 PRINT ,,,,"PROGRAM -";TAB 24;A$(N, TO 8) 2770 PRINT ,,"SUBJECT -";TAB 24;A$(N,10 TO 15) 2775 PRINT ,,"CTR. LOC. -";TAB 24;A$(N,17 TO 22) 2780 PRINT ,,"TP. NO/SD -";TAB 24;A$(N,24 TO 27) 2785 PRINT ,,"MISC. -";TAB 24;A$(N,29 TO 32) 2815 GOSUB 9800 2820 GOTO 20 2900 CLS 2905 PRINT AT 10,1;"WHAT IS THE PROGRAM NAME?" 2910 SLOW 2915 INPUT B$ 2920 FAST 2925 IF LEN B$>6 THEN GOTO 2910 2930 FOR N=1 TO R1 2935 IF A$(N, TO LEN B$)=B$ THEN GOTO 2950 2940 NEXT N 2945 GOTO 2745 2950 CLS 2955 PRINT "NAME SUBJECT C/L T/NO. MISC" 2960 PRINT Z$;A$(N) 2965 PRINT ,,,,"<1> MISC","<3> CTR LOC","<2> SUBJECT","<4> TP NUM/SD",,,,"CHOOSE ONE?" 2967 SLOW 2970 INPUT B$ 2972 FAST 2974 IF CODE B$<29 OR CODE B$>32 THEN GOTO 2967 2975 GOTO 8500+(100*VAL B$) 2999 GOTO 2999 3000 FAST 3002 CLS 3006 PRINT AT 10,10;"FILE NAME?" 3010 SLOW 3020 INPUT C$ 3030 PRINT AT 12,0;"PREPARE THE RECORDER AND THEN PRESS ENTER :::" 3040 INPUT B$ 3050 SAVE C$ 3060 FAST 3070 CLS 3080 GOTO 20 4000 FAST 4010 CLS 4020 RUN 5000 PRINT AT 10,0;"SET UP PRINTER AND PRESS ENTER." 5010 INPUT B$ 5020 FOR N=1 TO R1 5030 LPRINT 5040 LPRINT "NAME SUBJECT C/L T/NO. MISC" 5050 LPRINT "--------------------------------" 5060 LPRINT A$(N) 5070 NEXT N 5080 GOTO 20 6000 PRINT AT 8,0;"SORT BY?" 6010 PRINT ,"NAME (1)" 6020 PRINT ,"SUBJECT (2)" 6030 PRINT ,"CTR. LOC. (3)" 6040 PRINT ,"TP NUM/SD (4)" 6050 PRINT ,"MISC. (5)" 6055 SLOW 6060 LET B$=INKEY$ 6065 IF CODE B$<29 OR CODE B$>33 THEN GOTO 6060 6066 FAST 6070 IF B$="1" THEN LET A=1 6080 IF B$="1" THEN LET B=8 6090 IF B$="2" THEN LET A=10 6100 IF B$="2" THEN LET B=15 6110 IF B$="3" THEN LET A=17 6120 IF B$="3" THEN LET B=22 6130 IF B$="4" THEN LET A=24 6140 IF B$="4" THEN LET B=27 6150 IF B$="5" THEN LET A=29 6160 IF B$="5" THEN LET B=32 6200 CLS 6210 LET N=R1 6220 LET N=INT (N/2) 6230 IF N=0 THEN GOTO 20 6240 LET J=1 6250 LET K=R1-N 6260 LET I=J 6270 LET L=I+N 6280 IF A$(I,A TO B)K THEN GOTO 6220 6370 GOTO 6260 8600 PRINT ,,"WHAT IS THE NEW INFO?" 8610 SLOW 8620 INPUT B$ 8630 FAST 8640 IF LEN B$>4 THEN GOTO 8610 8650 LET A$(N,29 TO 32)=B$ 8660 PRINT ,,"NAME PART NO. COST IT/UN IN/S";Z$;A$(N) 8670 GOSUB 9800 8680 GOTO 20 8700 PRINT ,,"WHAT IS THE NEW STUBJECT?" 8710 SLOW 8720 INPUT B$ 8730 FAST 8740 IF LEN B$>6 THEN GOTO 8710 8750 LET A$(N,10 TO 15)=B$ 8760 GOTO 8660 8800 PRINT ,,"WHAT IS THE NEW COUNTER?" 8810 SLOW 8820 INPUT B$ 8830 FAST 8840 IF LEN B$>6 THEN GOTO 8810 8842 GOSUB 8000 8844 IF LEN B$<6 THEN GOSUB 8100 8850 LET A$(N,17 TO 22)=B$ 8860 GOTO 8660 8900 PRINT ,,"WHAT IS THE NEW TAPE NO./SIDE?" 8910 SLOW 8920 INPUT B$ 8930 FAST 8940 IF LEN B$>4 THEN GOTO 8910 8950 LET A$(N,24 TO 27)=B$ 8960 GOTO 8660 9000 FOR I=1 TO 10 9010 SCROLL 9020 NEXT I 9030 RETURN 9800 PRINT AT 21,0;"PRESS ENTER TO CONTINUE :::" 9810 INPUT B$ 9820 CLS 9830 RETURN 9998 SAVE "TAPE FIL%E" 9999 RUN ```