This program is a cassette label maker utility that formats and prints centered text across four lines, with an optional “cut-out” title mode for shorter, decorative labels. It uses LPRINT to send output to a compatible printer, and TAB expressions like `TAB 16-(LEN A$/2)` to center each text string on a 32-column line. The `OUT 123,27` and `OUT 123,14` commands in line 500 send escape codes directly to the printer interface, likely to control formatting or character size for the cut-out section. Lines 560–600 handle machine code loading and saving: a binary block of 1080 bytes is stored at address 64456 and managed via direct POKEs to system variables, with the SAVE/VERIFY sequence at line 600 writing both the BASIC program and the code block to tape. The program loops to allow multiple copies, multiple titles, and restarts, with input validation enforcing maximum string lengths throughout.
Program Analysis
Program Structure
The program divides into several functional regions:
- Lines 10–170: Setup, screen formatting, and collection of four label text lines with length validation.
- Lines 180–220: On-screen preview with a correction loop using
INKEY$polling. - Lines 230–370: Print loop — sends the standard four-line label to the printer
Xtimes, then offers to repeat or start over. - Lines 380–490: “Cut-out” label branch — collects a shorter title (max 10 characters) plus two shorter support lines, displays them, then re-enters the preview/print flow.
- Lines 500–540: Cut-out LPRINT section — sends printer escape codes before printing the narrow title.
- Lines 560–600: Loader/saver block — manages a machine code binary at address 64456, POKEs system variables, loads the code from tape, and saves both BASIC and code back to tape with VERIFY.
Text Centering Idiom
Every PRINT and LPRINT line uses the expression TAB 16-(LEN x$/2) to center a string on a 32-column output. Since TAB takes an integer, strings with odd lengths are implicitly truncated by integer division, biasing the result one character to the right of true center. This is a common and compact Sinclair BASIC centering technique.
Input Validation
Each of the four main label lines and the cut-out lines are validated for maximum length before the program proceeds. The thresholds vary by section:
| Variable | Purpose | Max Length | Enforced at |
|---|---|---|---|
A$ | Title line | 31 | Line 30 |
B$ | Line 2 | 31 | Line 60 |
C$ | Line 3 | 31 | Line 90 |
D$ | Bottom line | 31 | Line 130 |
F$ | Cut-out title | 10 | Line 390 |
G$ | Cut-out line 2 | 20 | Line 440 |
H$ | Cut-out line 3 | 18 | Line 470 |
The main lines use >=32 (rejecting strings of exactly 32 characters), while the cut-out lines use >10, >20, and >18 respectively — a slight inconsistency in boundary style.
Printer Escape Codes
Line 500 uses OUT 123,27 followed by OUT 123,14 to send raw bytes to the printer port. Byte 27 is the ASCII ESC character, and byte 14 is the SO (Shift Out) control code, commonly used with Epson-compatible and ZX Printer-style interfaces to switch to double-width or condensed print mode for the decorative cut-out title. This direct port manipulation bypasses the LPRINT channel entirely for control purposes.
Notably, the cut-out title TAB expression in line 500 uses TAB 8-(LEN F$/2) rather than TAB 16-(LEN F$/2), consistent with the title being half-width (double-size characters occupy double the physical space).
INKEY$ Keypress Loop
Lines 200–210 implement a wait-for-keypress idiom: line 200 loops while INKEY$="" (no key held), then line 210 checks for "N". Because INKEY$ is evaluated twice in sequence, there is a small window where a very briefly pressed key could be missed between the two reads — a well-known timing subtlety in this pattern. A more robust approach would store INKEY$ in a variable.
Machine Code Block Management
Lines 560–600 form a self-contained loader/saver that is never called during normal label-making operation (line 590 jumps to line 10, and line 560 is only reachable by direct GO TO or as the auto-start line). Key operations include:
CLEAR 64455— sets RAMTOP just below the code area.- POKEs to addresses 26703–26704 — these are the system variable
PROMS(printer buffer pointer), redirecting LPRINT output to the machine code routine at 64461. - POKEs at 64456–64459 — initialize fields within the machine code data structure (likely a header or parameter block for the custom print driver).
LOAD "labelmkr C" CODE 64456,1111— loads 1111 bytes, though line 600 saves only 1080 bytes, suggesting the load length is intentionally generous or was edited independently of the save.- Line 600 performs a chained SAVE + VERIFY for both the BASIC program (auto-starting at line 560) and the code block.
Notable Anomalies
- Line 550 contains a bare
STOPthat is unreachable under normal execution flow — likely a leftover from development. - Line 270 re-checks
E$inside the print loop, but becauseE$was set before the loop and is never changed within it, the branch is always consistent. The logic mirrors the screen-preview path at lines 160–170. - Lines 180 and 400 both use
PRINT AT 20,0;,,,,— printing five empty items — to blank the bottom area of the screen before theCORRECT?prompt. - The comment in line 220 notes “14 spaces between quotes,” indicating the programmer manually counted spaces to clear the bottom-line prompt area before the copy-count input.
Content
Source Code
10 BORDER 2: PAPER 6: POKE 23658,8: POKE 23609,60
20 CLS : INPUT "PROGRAM TITLE: ";A$
30 IF LEN A$>=32 THEN GO TO 10
40 PRINT TAB 16-(LEN A$/2);A$
50 INPUT "LINE #2 INFO: ";B$
60 IF LEN B$>=32 THEN GO TO 50
70 PRINT TAB 16-(LEN B$/2);B$
80 INPUT "LINE #3 INFO: ";C$
90 IF LEN C$>=32 THEN GO TO 80
100 PRINT TAB 16-(LEN C$/2);C$
110 PRINT : PRINT : PRINT : PRINT : PRINT
120 INPUT "BOTTOM LINE #4: ";D$
130 IF LEN D$>=32 THEN GO TO 120
140 PRINT TAB 16-(LEN D$/2);D$
150 PRINT AT 21,4; FLASH 1;"CUT OUT PRINTED (Y / N)": INPUT E$
160 IF E$="N" THEN GO TO 180
170 IF E$="Y" THEN GO TO 380
180 PRINT AT 20,0,,,,
190 PRINT OVER 1;AT 21,8; FLASH 1;"CORRECT? (/N)"
200 IF INKEY$="" THEN GO TO 200
210 IF INKEY$="N" THEN GO TO 20
220 PRINT AT 21,8;" ": INPUT "NUMBER OF COPIES :";X: REM 14 spaces between quotes
230 FOR I=1 TO X
240 LPRINT TAB 16-(LEN A$/2);A$
250 LPRINT TAB 16-(LEN B$/2);B$
260 LPRINT TAB 16-(LEN C$/2);C$
270 IF E$="N" THEN GO TO 290
280 IF E$="Y" THEN GO TO 500
290 LPRINT : LPRINT : LPRINT : LPRINT : LPRINT
300 LPRINT TAB 16-(LEN D$/2);D$
310 LPRINT : LPRINT
320 NEXT I
330 INPUT "MORE? (Y/N): ";X$
340 IF X$="Y" THEN GO TO 220
350 INPUT "ANOTHER TITLE? (Y/N): ";X$
360 IF X$="Y" THEN GO TO 20
370 CLS : PRINT AT 10,8;"(WORK COMPLETED)": STOP
380 PRINT AT 20,0;"""CUT-OUT"" TITLE : 10 LETTERS MAX";AT 21,0;"X1234567890X ": INPUT F$
390 IF LEN F$>10 THEN GO TO 380
400 PRINT AT 20,0,,,,
410 PRINT AT 3,0;" "
420 PRINT TAB 16-(LEN F$/2);F$
430 INPUT "2nd LINE: ";G$
440 IF LEN G$>20 THEN GO TO 430
450 PRINT TAB 16-(LEN G$/2);G$
460 INPUT "3rd LINE: ";H$
470 IF LEN H$>18 THEN GO TO 460
480 PRINT TAB 16-(LEN H$/2);H$
490 GO TO 180
500 LPRINT : OUT 123,27: OUT 123,14: LPRINT TAB 8-(LEN F$/2);F$
510 LPRINT TAB 16-(LEN G$/2);G$
520 LPRINT TAB 16-(LEN H$/2);H$
530 LPRINT
540 GO TO 300
550 STOP
560 CLEAR 64455: LET PRINTORG=64461: POKE 26704,INT (PRINTORG/256): POKE 26703,PRINTORG-(INT (PRINTORG/256))*256: POKE 64456,1: POKE 64458,0: POKE 64457,0: POKE 64459,79
570 BORDER 2: CLS : PRINT INK 2;AT 8,0;"L O A D I N G T H E C O D E",,,,,,,,;TAB 7;" PLAY THE RECORDER ": LOAD "labelmkr C"CODE 64456,1111
580 POKE 64463,0: POKE 64464,0: POKE 64465,0
590 GO TO 10
600 SAVE "LabelMkr" LINE 560: SAVE "labelmkr C"CODE 64456,1080: BEEP .5,10: PRINT #1;AT 0,5;"***REWIND THE TAPE***": PRINT #1;AT 1,5;"***PLAY TO VERIFY***": VERIFY "": VERIFY ""CODE
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
