--- title: "Magazine File" id: 54991 type: "computer_media" slug: "magfile" url: "http://localhost/computer_media/magfile/" markdown_url: "http://localhost/computer_media/magfile.md" published_at: "2024-06-10T01:44:45+00:00" modified_at: "2026-03-30T21:43:33+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A menu-driven magazine article database packs up to 500 records into a string array, with subject search, bubble sort printing, and a character-by-character record editor." 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 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Alan Friedman" slug: "alan-friedman" taxonomy: "indiv" url: "http://localhost/indiv/alan-friedman/" genre: - name: "Database" slug: "database" taxonomy: "genre" url: "http://localhost/type/database/" media_contents: - id: 54964 title: "ISTUG Public Domain Library 6" type: "computer_media" url: "http://localhost/computer_media/istug-public-domain-library-6/" media_type: "Program" programmers: - name: "Alan Friedman" slug: "alan-friedman" taxonomy: "indiv" url: "http://localhost/indiv/alan-friedman/" mediadate: "1986" images: - url: "http://localhost/wp-content/uploads/2024/06/SCR-20260329-nvhe.png" media_type_tags: "Database" --- Magazine File is a database management program for cataloging magazine articles, storing up to 500 records in a string array where each 32-character record packs a 4-character magazine name, 7-character subject, 13-character article title, and 5-character date. The program offers a menu-driven interface with eight options: loading and saving data via tape or disk, adding new entries, correcting existing records with a cursor-based character editor, searching by subject or by magazine name and date, and printing a sorted listing. The sort routine at line 7015–7080 implements a bubble sort over the entire array before printing. Several bugs are present, including a logic error in the input validation at line 700 (using OR instead of AND), off-by-one field slicing in the subject search at line 5010 (requesting 6 characters instead of 7), and an unused commented-out GO SUB dispatch at line 215. *** ## Program Analysis ### Program Structure The program is organized into clearly separated functional blocks, each at a round line-number boundary that corresponds to a menu selection. Navigation is achieved by the dispatch at line 220: `GO TO s*1000`, routing selections 1–8 directly to lines 1000–8000. A shared tape/disk prompt subroutine lives at lines 500–520, and a printer-size prompt subroutine (partially broken) occupies lines 700–720, though neither is actually called in the final code. | Line range | Function | | --- | --- | | 1–30 | Initialization: splash screen, blank-padding string, array declaration | | 100–220 | Main menu display and input dispatch | | 500–520 | Unused tape/disk selection subroutine | | 700–720 | Unused printer-size subroutine (contains logic bug) | | 1000–1040 | Load data from tape/disk | | 2000–2250 | New entry input and storage | | 3000–3050 | Save and verify data | | 4000–4350 | Record correction with character-level editor | | 5000–5240 | Search by subject | | 6000–6240 | Search by magazine name and date | | 7000–7320 | Bubble sort and print listing | | 8000–8050 | Exit, with unsaved-data warning | | 9900–9998 | REM note and SAVE header | ### Data Layout All records are stored in the two-dimensional string array `w$(500,32)`, declared at line 30. Each row is exactly 32 characters, packed as follows: - Characters 1–4: Magazine name (4 letters) - Characters 5–11: Subject (7 letters) — though the entry routine pads to 8 with `e$( TO 8)` - Characters 12–24: Article name (13 letters) — padded to 14 with `n$( TO 14)` - Characters 25–29: Date (5 characters, format xx/xx) — padded to 5 with `d$( TO 5)` The fields as entered total 4+8+14+5 = 31 characters, leaving one character unused or causing the date to overflow beyond column 29 into 30. This is a latent layout inconsistency. The variable `n` tracks the number of active records; on load, lines 1020–1023 scan for the first blank entry to determine `n`. The blank-padding string `b$` at line 20 is 128 spaces, used throughout to right-pad inputs before slicing to the required field width — a standard Sinclair BASIC string-truncation idiom. ### Character-Level Record Editor The correction routine (lines 4026–4110) implements a simple cursor editor over a 32-character string. It loops `l` from 0 to 31, displaying the record and flashing a block cursor at position `l` using `FLASH 1` and `OVER 1`. On each iteration it calls `PAUSE 0` followed by `INKEY$` to capture a keypress without blocking indefinitely. The cursor can move left with CHR$ 8 (the cursor-left key) by decrementing `l` by 2 (the loop `NEXT l` adds 1 back). Printable characters (CODE 32–143) overwrite the character at `m$(l+1)`. Pressing ENTER (CHR$ 13) commits the edit by jumping to line 4300. ### Search Routines Both search routines (lines 5000 and 6000) use the same nested-loop pattern: an outer loop over all `n` records with index `j`, and an inner loop over each character of the search key with index `f`, branching out on the first mismatch. A match falls through to a PRINT and then rejoins the outer loop’s NEXT to continue searching, allowing all matching records to be displayed. The subject search at line 5030 slices `w$(j)(6 TO 12)` — a 7-character window — and compares it character-by-character against `t$`. However, line 5010 pads and slices `t$` to 6 characters (`t$( TO 6)`), then the inner loop runs `f=1 TO 7`, meaning the 7th comparison always reads `t$(7)` which is out of the declared slice. This is a bug that will cause an error in practice. ### Bubble Sort Lines 7015–7080 implement a standard bubble sort over all `n` records. The outer loop runs `q=1 TO n-1` and the inner loop `r=1 TO n-q`. Adjacent records are compared as full 32-character strings (lexicographic order by magazine name first), and swapped if out of order. This sorts the in-memory array in place before printing, but permanently reorders `w$()` for the rest of the session. ### Bugs and Anomalies - **Line 700 — printer validation logic:** The condition `l$<>"Y" OR l$<>"y" OR l$<>"N" OR l$<>"n"` is always true (a string cannot simultaneously equal “Y” and “y”), so the INPUT loop never exits. The correct operator is `AND`. This subroutine is also never called. - **Line 215 — commented-out dispatch:** The REM at line 215 contains a computed GO SUB formula (`25*(s*s-4*s+63)/3`) that would route options 1, 3, and 7 through the tape and printer subroutines. This was commented out and replaced with the simpler direct GO TO at line 220, leaving the subroutines unreachable. - **Line 2010 — field width off-by-one:** The prompt says “4 letters” but `e$( TO 5)` retains 5 characters. The subject prompt says “7 letters” but `s$( TO 8)` retains 8. These inconsistencies shift the expected field positions. - **Line 5010 — subject search truncation:**`t$( TO 6)` produces a 6-character key, but the inner comparison loop runs to 7, accessing `t$(7)` which is beyond the slice and will cause a Subscript out of range error. - **Line 4026 — FOR loop missing colon:**`FOR l=0 TO 31: PRINT AT 10,0;m$;AT 15,0;b$` places the PRINT on the same line as the FOR, which is valid syntax but means the display refresh only happens on each iteration’s start, not after a keypress — the cursor flash may not render correctly. - **Line 7100 — `POKE 23692,255`:** This pokes the system variable SCRCT (scroll counter) to prevent the “scroll?” prompt during the print loop, a common Spectrum BASIC technique for uninterrupted output. ### Notable Techniques - Use of `b$` (a long blank string) concatenated before slicing to guarantee fixed-width field padding without error-checking the input length. - `GO TO s*1000` as a compact computed dispatch replacing a chain of IF statements. - `PAUSE 0` / `INKEY$` idiom for single-keypress capture in the character editor. - `POKE 23692,255` to suppress the scroll prompt during bulk list printing. - The REM at line 9900 preserves a TS2068 MOVE command (for DOS file copy) as documentation of the intended disk deployment path. ## Source Code ``` 1 REM Junk; needs debugging start to finish 5 CLS : FLASH 1: BORDER 6: PAPER 6: INK 0: PRINT AT 10,10;"Magazine File";AT 11,8;"by Alan Friedman": PAUSE 120: FLASH 0 7 REM from CTM 5/86 10 LET n=0 20 LET b$=" " 30 DIM w$(500,32) 100 CLS : PRINT " MAGAZINE FILE" 110 LET l$=" ": PRINT ''l$;"Menu"'l$;"1 Read data from tape/disc"'l$;"2 New Entry"'l$;"3 Save data to tape/disc"' 120 PRINT l$;"4 Correction"'l$;"5 Search by subject"'l$;"6 Search by Mag./Date"'l$;"7 Print List"'l$;"8 Exit"' 200 PRINT l$; FLASH 1;"Choose one" 210 INPUT s: FLASH 0: IF s<1 OR s>8 OR s<>INT s THEN GO TO 210 215 REM IF s=1 OR s=3 OR s=7 THEN CLS : GO SUB 25*(s*s-4*s+63)/3 220 GO TO s*1000 500 INPUT "Using Tape(T) or Disc(D)?";y$ 510 IF y$="T" OR y$="t" OR y$="D" OR y$="d" THEN GO TO 520 515 GO TO 500 520 RETURN 700 INPUT "Want full size printer (Y/N)";l$: IF l$<>"Y" OR l$<>"y" OR l$<>"N" OR l$<>"n" THEN GO TO 700 720 RETURN 1000 CLS : PRINT AT 12,0;"Start the Tape and"; FLASH 1';"Press enter": INPUT y$ 1010 LOAD "mag data" DATA W$() 1020 FOR n=1 TO 500: IF w$(n,1 TO 4)=" " THEN GO TO 1023 1022 NEXT n 1023 LET n=n-1 1040 CLS : GO TO 100 2000 CLS 2010 PRINT AT 10,0;"Enter magazine name (4 letters)": INPUT e$: LET e$=e$+b$: LET e$=e$( TO 5) 2020 PRINT AT 0,0;e$;AT 10,0;b$ 2030 PRINT AT 10,0;"Enter subject (7 letters)": INPUT s$: LET s$=s$+b$: LET s$=s$( TO 8) 2050 PRINT AT 1,0;s$;AT 10,0;b$ 2060 PRINT AT 10,0;"Enter article name (13 letters)": INPUT n$: LET n$=n$+b$: LET n$=n$( TO 14) 2080 PRINT AT 2,0;n$;AT 10,0;b$ 2090 PRINT AT 10,0;"Enter magazine date (xx/xx)": INPUT d$: LET d$=d$+b$: LET d$=d$( TO 5) 2110 PRINT AT 3,0;d$;AT 10,0;b$ 2120 PAUSE 120: CLS : PRINT AT 10,5;e$;AT 11,5;s$;AT 12,5;n$;AT 13,5;d$ 2125 INPUT "Is this OK? Y/N";a$: CLS : IF a$="n" OR a$="N" THEN GO TO 2000 2200 LET n=n+1 2210 LET w$(n)=e$+s$+n$+d$ 2220 INPUT "Another entry? Y/N";a$: IF a$="y" OR a$="Y" THEN GO TO 2000 2250 CLS : GO TO 100 3000 CLS 3010 SAVE "mag data" DATA w$(): PRINT "rewind to verify": VERIFY "mag data" DATA w$() 3050 CLS : GO TO 100 4000 CLS 4010 PRINT AT 10,0;"Enter the number of the listing to be corrected": INPUT v 4020 CLS : PRINT AT 10,0;w$(v): LET m$=w$(v) 4025 INPUT "Is this OK? Y/N";y$: IF y$="n" OR y$="N" THEN GO TO 4000 4026 FOR l=0 TO 31: PRINT AT 10,0;m$;AT 15,0;b$ 4050 PRINT AT 10,l; FLASH 1; OVER 1;CHR$ 32 4060 PAUSE 0: LET i$=INKEY$ 4070 IF i$=CHR$ 8 AND l THEN LET l=l-2 4100 IF CODE i$>31 AND CODE i$<144 THEN LET m$(l+1)=i$ 4105 IF CODE i$=13 THEN GO TO 4300 4110 NEXT l 4300 LET w$(v)=m$: CLS : PRINT AT 10,0;"New entry # ";v;"is"'w$(v) 4320 INPUT "Another change? Y/N";a$: IF a$="y" OR a$="Y" THEN GO TO 4000 4350 CLS : GO TO 100 5000 CLS 5010 INPUT "Enter Subject";t$: LET t$=t$+b$: LET t$=t$( TO 6): PRINT AT 0,10;t$ 5030 FOR j=1 TO n: LET i$=w$(j)(6 TO 12) 5060 FOR f=1 TO 7: IF t$(f)<>i$(f) THEN GO TO 5200 5080 NEXT f 5090 GO TO 5300 5200 NEXT j 5240 INPUT "Press enter to return to menu";a$: CLS : GO TO 100 5300 PRINT w$(j): GO TO 5200 6000 CLS 6010 PRINT AT 10,0;"Enter magazine name (4 letters)": INPUT a$: LET a$=a$+b$: LET a$=a$( TO 4) 6020 PRINT AT 10,0;b$;AT 10,0;"Enter magazine date (xx/xx)": INPUT k$: LET k$=k$+b$: LET k$=k$( TO 5) 6025 LET a$=a$+k$ 6030 CLS : FOR j=1 TO n: LET i$=w$(j)(1 TO 4)+w$(j)(28 TO 32) 6050 FOR f=1 TO 9: IF a$(f)<>i$(f) THEN GO TO 6200 6080 NEXT f: GO TO 6300 6200 NEXT j 6240 INPUT "Press any key to return to menu";z$: CLS : GO TO 100 6300 PRINT w$(j): GO TO 6200 7000 CLS 7010 INPUT "Want a hard copy? Y/N";y$: CLS 7015 FOR q=1 TO n-1: FOR r=1 TO n-q 7020 LET h$=w$(r): LET i$=w$(r+1) 7030 IF h$<=i$ THEN GO TO 7080 7050 LET w$(r)=i$: LET w$(r+1)=h$ 7080 NEXT r: NEXT q 7100 FOR a=1 TO n: POKE 23692,255 7200 IF y$="y" OR y$="Y" THEN LPRINT 'w$(a) 7300 PRINT a'w$(a) 7310 NEXT a 7320 INPUT "Press any key to return to menu";v$: CLS : GO TO 100 8000 CLS 8010 FLASH 1: PRINT AT 12,0;"Magazine file end"'"Has data been saved?": INPUT y$: IF y$="y" OR y$="Y" THEN GO TO 8050 8020 FLASH 0: GO TO 3000 8050 FLASH 0: CLS : STOP 9899 STOP 9900 REM OUT 244,1: MOVE "Mag File.bas",5: OUT 244,0 9997 STOP 9998 SAVE "Mag File" LINE 5 ```