Magazine File

This file is part of and ISTUG Public Domain Library 6. Download the collection to get this file.
Developer(s): Alan Friedman
Date: 1986
Type: Program
Platform(s): TS 2068
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 rangeFunction
1–30Initialization: splash screen, blank-padding string, array declaration
100–220Main menu display and input dispatch
500–520Unused tape/disk selection subroutine
700–720Unused printer-size subroutine (contains logic bug)
1000–1040Load data from tape/disk
2000–2250New entry input and storage
3000–3050Save and verify data
4000–4350Record correction with character-level editor
5000–5240Search by subject
6000–6240Search by magazine name and date
7000–7320Bubble sort and print listing
8000–8050Exit, with unsaved-data warning
9900–9998REM 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.

Content

Appears On

Run a lemonade stand, manage a radio factory through crises, catch drips as a plumber, or compose three-voice music note by note — ISTUG Library 6 balances business simulations and financial tools with arcade action and creative software.

Related Products

Related Articles

Related Content

Image Gallery

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

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top