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

Library tape of the Indiana Sinclair Timex User’s Group.

Related Products

Related Articles

Related Content

Image Gallery

Magazine File

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