Tag: basic

  • Word Processors in BASIC, Part 1

    Word Processors in BASIC, Part 1

    Quickwriter

    Found in June 1988 issue of Nibble magazine (Volume 9, Number 6).

    Archive.org link here.

    The project was alerted to the existence of a few text editors and word processors in Nibble magazine by someone on matrix.

    What we found was a great wealth of BASIC programs for the Apple II computer. We uncovered several particularly interesting BASIC word processors. Two that are of particular interest are Quickwriter and Nibblewriter.

    Both programs are quite long and involved, so instead of creating one enormous post, we decided to split the discussion up into two feature posts.

    diskM8 File Dump

    Please find an ASCII conversion of the BASIC dump obtained using the following commands:

    $ diskm8 -ingest /path/to/your/disk/images
    $ diskm8 -search "quickwriter"
    $ diskm8 -with-disk "your_disk_image.do" -file-extract "QUICKWRITER.BAS"

    Code Listing

    10  REM **********************
    20  REM *     TYPEWRITER     *
    30  REM *  BY JAMES D EVANS  *
    40  REM * COPYRIGHT (C) 1988 *
    50  REM * BY MICROSPARC, INC *
    60  REM * CONCORD, MA  01742 *
    70  REM **********************
    80  HIMEM: 38144:X =  FRE (0)
    90  ONERR  GOTO 2740
    100  GOSUB 2220
    110  GOTO 230
    120  REM **WARMSTART 80-COL CARD**
    130  ON  NOT PD GOTO 140: PRINT D$;"PR#A$C307": GOTO 150
    140  POKE 54,7: POKE 55,195: CALL 1002: PRINT 
    150  RETURN 
    160  REM **GET CHAR ROUTINE**
    170  POKE  - 16368,0: ON  NOT PLUS GOTO 180: PRINT  CHR$ (0);: GET A$: ON  NOT  LEN (A$) GOTO 170:B =  ASC (A$): GOTO 190
    180  INVERSE : PRINT " ";BS$;: NORMAL : WAIT  - 16384,128:B = ( PEEK ( - 16384) - 128):A$ =  CHR$ (B): POKE  - 16368,0: PRINT " ";BS$;: ON  NOT B GOTO 180
    190  RETURN 
    200  REM 
    210  REM ***MAIN PROGRAM***
    220  REM 
    230  FOR I = M TO M + 80: POKE I,160: NEXT 
    240  GOSUB 850: GOSUB 2050
    250 C = LM:LL = 0: POKE  - 16368,0
    260  VTAB 2: POKE H,C: INVERSE : PRINT  CHR$ ( PEEK (M + (C - LM)));: NORMAL : POKE H,C: PRINT  CHR$ (24);: ON  NOT PLUS GOTO 270: GET A$: GOTO 280
    270  WAIT  - 16384,128:A$ =  CHR$ ( PEEK ( - 16384) - 128): POKE  - 16368,0
    280  IF A$ < " " OR A$ =  CHR$ (127) THEN  GOSUB 330: GOTO 260
    290  PRINT A$: POKE M + C - LM, ASC (A$) + 128
    300 C = C + (C < RM - 1):LL = LL + (LL < RM - LM): POKE H,5: PRINT C + 1;" "
    310  GOTO 260
    320  REM **CTRL-CHAR EVALUATION**
    330  ON ( LEN (A$) = 0) GOTO 610: PRINT  CHR$ ( PEEK (M + (C - LM))); CHR$ (24)
    340  IF A$ =  CHR$ (127) THEN A$ =  CHR$ (4): ON C = LM GOTO 610:C = C - 1: POKE H,5: PRINT C + 1;" "
    350  IF A$ =  CHR$ (4) AND (LL + LM + 1) > C THEN LL = LL - 1: POKE M + RM - LM,160: FOR I = M + C - LM TO M + LL + 1: POKE I, PEEK (I + 1): NEXT : VTAB 2: POKE H,LM: POKE 8,RM - LM: CALL 768: PRINT : GOTO 610
    360  ON A$ <  >  CHR$ (15) OR C = (RM - 1) GOTO 370:LL = LL + (LL < (RM - LM - 1)): FOR I = M + LL TO M + C - LM STEP  - 1: POKE I, PEEK (I - 1): NEXT : POKE M + C - LM,160: VTAB 2: POKE H,LM: POKE 8,RM - LM: CALL 768: PRINT : GOTO 610
    370  IF A$ =  CHR$ (8) THEN C = C - (C > LM): POKE H,5: PRINT C + 1;" ": GOTO 610
    380  IF A$ =  CHR$ (21) THEN C = C + (C < RM - 1): POKE H,5: PRINT C + 1" ":LL = LL + ((C + 1 - LM) > LL): GOTO 610
    390  IF A$ =  CHR$ (9) THEN  GOSUB 940: GOTO 610
    400  IF A$ =  CHR$ (20) THEN TB(C + 1) =  NOT TB(C + 1):X = 160 * ( NOT TB(C + 1)) + 252 * (TB(C + 1)): PRINT : VTAB 4: POKE H,C: PRINT  CHR$ (X): GOTO 610
    410  IF A$ =  CHR$ (13) THEN  GOSUB 660: POP : GOTO 250
    420  IF A$ =  CHR$ (22) THEN RF = 1: VTAB 6: POKE H,20: PRINT "REVERSE LINEFEEDS ENABLED -- PRESS RETURN ";: GOSUB 170: PRINT : VTAB 6: PRINT LC$: GOTO 610
    430  IF A$ =  CHR$ (18) THEN A$ =  CHR$ (93): VTAB 2: POKE H,C: POP : GOTO 290
    440  IF A$ =  CHR$ (12) THEN A$ =  CHR$ (91): VTAB 2: POKE H,C: POP : GOTO 290
    450  IF A$ =  CHR$ (2) THEN A$ =  CHR$ (92):US = 1: VTAB 2: POKE H,C: PRINT A$: POKE M + C - LM,92: POP : GOTO 300
    460  IF A$ =  CHR$ (14) THEN A$ =  CHR$ (64): VTAB 2: POKE H,C: POP : GOTO 290
    470  IF A$ =  CHR$ (26) THEN  GOSUB 990: GOTO 610
    480  IF A$ =  CHR$ (7) THEN A$ =  CHR$ (95): VTAB 2: POKE H,C: POP : GOTO 290
    490  IF A$ =  CHR$ (24) THEN  GOSUB 1850
    500  IF A$ =  CHR$ (10) THEN  GOSUB 1260: POP : GOTO 260
    510  IF A$ =  CHR$ (19) THEN C = LM: PRINT : VTAB 3: POKE H,5: PRINT C + 1;" ": GOTO 610
    520  ON A$ <  >  CHR$ (5) GOTO 550: FOR I = M + (RM - LM - 1) TO M STEP  - 1: IF  PEEK (I) <  > 160 THEN C = LM + I - M + ((I - M) < (RM - LM - 1)):I = M: GOTO 540
    530  NEXT 
    540  PRINT : VTAB 3: POKE H,5: PRINT C + 1;" ": GOTO 610
    550  IF A$ =  CHR$ (23) THEN  GOSUB 1640: GOTO 610
    560  IF A$ =  CHR$ (6) THEN  GOSUB 1780: GOTO 610
    570  IF A$ =  CHR$ (16) THEN  GOSUB 1170: POP : GOTO 260
    580  IF A$ =  CHR$ (17) THEN  GOSUB 1340: GOTO 610
    590  IF A$ =  CHR$ (27) AND (C < (RM - 1)) THEN  GOSUB 1900: GOTO 610
    600  IF A$ =  CHR$ (30) THEN  GOSUB 2000
    610  RETURN 
    620  REM 
    630  REM ***UTILITY SUBROUTINES***
    640  REM 
    650  REM **PRINT LINE**
    660 X$ = "":X =  VAL (X$) +  PEEK (131) + 256 *  PEEK (132): POKE X,RM - LM: POKE X + 1,(M -  INT (M / 256) * 256): POKE X + 2, INT (M / 256):X$ =  MID$ (X$,1):AP$(R) = X$
    670  PRINT : PRINT D$;"PR#";SL
    680  PRINT  CHR$ (9);"80N";
    690  PRINT  TAB( LM);
    700  ON US GOTO 720
    710  PRINT AP$(R): GOTO 790
    720 J = 1
    730  FOR I = M TO M + LL
    740  ON  PEEK (I) <  > 92 GOTO 760:J =  NOT J: ON J GOTO 750: PRINT U1$;: GOTO 770
    750  PRINT U2$;: GOTO 770
    760  PRINT  CHR$ ( PEEK (I));
    770  NEXT 
    780  PRINT U2$
    790 R = R + 1:US = 0
    800  ON SP < 2 GOTO 810: PRINT : ON SP < 3 GOTO 810: PRINT : ON SP < 4 GOTO 810: PRINT 
    810  GOSUB 130
    820  GOSUB 870
    830  RETURN 
    840  REM **WINDOW**
    850  PRINT CL$
    860  FOR I = 1 TO LM: PRINT  CHR$ (255);: NEXT : POKE H,RM: FOR I = RM TO 79: PRINT  CHR$ (255);: NEXT 
    870  VTAB 1: POKE H,LM: POKE 8,RM - LM: CALL 768: PRINT 
    880  FOR I = M TO M + 80: POKE I,160: NEXT : VTAB 2: POKE H,LM: POKE 8,RM - LM: CALL 768: PRINT 
    890  VTAB 3: PRINT "COL: ";LM + 1;" "
    900  VTAB 5: PRINT "LINE:";R
    910  IF R > 300 THEN  VTAB 10: POKE H,19: PRINT  CHR$ (7);"NO MORE ROOM!  RESTART PROGRAM."
    920  RETURN 
    930  REM **TAB**
    940  FOR I = C + 1 + (C < RM - 1) TO RM - 1:C = I * TB(I) - 1: ON C > 0 GOTO 960: NEXT 
    950 C = RM - 1
    960 I = RM - 1: PRINT : VTAB 3: POKE H,5: PRINT C + 1: IF C + 1 > LL THEN LL = C + 1 - LM
    970  RETURN 
    980  REM **CENTER TEXT**
    990  PRINT : VTAB 6: POKE H,23: PRINT "CENTERING.....": PRINT : VTAB 2
    1000  FOR I = 0 TO LL
    1010  IF  PEEK (M + I) <  > 160 THEN X = I:I = LL: GOTO 1030
    1020  NEXT : GOTO 1140
    1030 Y = 0: FOR I = RM - LM - 1 TO 0 STEP  - 1
    1040 Y = Y + 1: IF  PEEK (M + I) <  > 160 THEN Y = Y - 1:I = 0: GOTO 1060
    1050  NEXT 
    1060 XL = RM - LM - X - Y: REM STRING LENGTH     
    1070 K = 0: FOR J = M + X TO M + X + XL - 1:K = K + ( PEEK (J) < 128): NEXT : REM HANDLE <ESC> AND UNDERLINE CODES
    1080 A = M + X:X$ = "":B =  VAL (X$) +  PEEK (131) + 256 *  PEEK (132): POKE B,XL: POKE B + 1,A -  INT (A / 256) * 256: POKE B + 2, INT (A / 256):X$ =  MID$ (X$,1)
    1090 J = 0:T =  INT ((RM - LM - XL - K) / 2) + K: IF (T + XL) > (RM - LM) THEN  PRINT : VTAB 6: POKE H,9: PRINT  CHR$ (7);"TOO MANY <ESC> CODES TO CENTER. PRESS RETURN TO RESUME TYPING ";: GOSUB 170: PRINT : VTAB 6: PRINT LC$: GOTO 1150
    1100  FOR I = M + X TO M + X + XL: POKE I,160: NEXT :
    1110  FOR I = M + T TO M + T + XL - 1:J = J + 1: POKE I, ASC ( MID$ (X$,J)): NEXT 
    1120  POKE H,LM: POKE 8,RM - LM: CALL 768
    1130 LL = T + XL:C = LM + T + XL: IF C >  = RM THEN C = C - 1
    1140  PRINT : VTAB 6: PRINT LC$: VTAB 3: POKE H,5: PRINT C + 1;" "
    1150  RETURN 
    1160  REM **PRINT TEST PATTERN**
    1170  PRINT : PRINT D$;"PR#";SL
    1180  PRINT  CHR$ (9);"80N";
    1190  PRINT  TAB( LM)"." TAB(  INT (((RM - LM) / 2) - 1))"." TAB(  INT (((RM - LM) / 2)))".";
    1200  IF  NOT RF THEN  PRINT : GOTO 1230
    1210  PRINT RF$
    1220  PRINT FF$
    1230  GOSUB 130
    1240  RETURN 
    1250  REM **ISSUE REVERSE LINEFEED**
    1260  ON  NOT RF GOTO 1320
    1270  PRINT : PRINT D$;"PR#";SL
    1280  PRINT  CHR$ (9);"80N";
    1290  PRINT RF$: PRINT RF$
    1300  PRINT FF$
    1310  GOSUB 130
    1320  RETURN 
    1330  REM **QUIT?**
    1340  PRINT : VTAB 8: POKE H,19: PRINT "Q)UIT   R)ESUME   S)TART ANEW": PRINT : HTAB 20: PRINT "PRESS Q, R, OR S:";: GOSUB 170:A$ =  CHR$ ( ASC (A$) - 32 * (A$ > "S"))
    1350  IF A$ = "Q" THEN  GOSUB 1390: PRINT CL$: END 
    1360  IF A$ = "R" THEN  PRINT : VTAB 8: PRINT LC$: VTAB 10: PRINT LC$: RETURN 
    1370  IF A$ = "S" THEN  GOSUB 1390: RUN 
    1380  GOTO 1340
    1390  PRINT : VTAB 8: PRINT LC$: VTAB 10: PRINT LC$;: POKE H,19: PRINT "SAVE THIS DOCUMENT? (Y/N)";: GOSUB 2870
    1400  IF A$ <  > "Y" AND A$ <  >  CHR$ (121) THEN 1620
    1410  PRINT : VTAB 10: PRINT LC$;: POKE H,19: PRINT "ENTER DOCUMENT NAME: ";: FOR I = 1 TO 15: PRINT "_";: NEXT 
    1420 HZ = 0:FL$ = "": POKE H,40
    1430  GOSUB 170: ON A$ >  CHR$ (31) GOTO 1480
    1440  ON A$ =  CHR$ (13) GOTO 1500
    1450  IF A$ =  CHR$ (8) AND (FL$ = "" OR  LEN (FL$) = 1) THEN 1410
    1460  IF A$ =  CHR$ (8) THEN HZ = HZ - 1: POKE H, PEEK (H) - 1:FL$ =  MID$ (FL$,1, LEN (FL$) - 1): GOTO 1430
    1470  ON A$ =  CHR$ (27) GOTO 1410: ON A$ < " " GOTO 1430
    1480  ON HZ = 15 GOTO 1430: IF A$ >  CHR$ (95) THEN A$ =  CHR$ ( ASC (A$) - 32)
    1490 FL$ = FL$ + A$: PRINT A$;:HZ = HZ + 1: GOTO 1430
    1500  ON FL$ = "" GOTO 1620
    1510  IF  MID$ (FL$,1,1) < "A" THEN  PRINT : VTAB 10: POKE H,19: PRINT LC$;"INVALID NAME -- PRESS RETURN TO REENTER ";: GOSUB 170: GOTO 1410
    1520  FOR I = 1 TO  LEN (FL$):X$ =  MID$ (FL$,I,1): IF X$ = " " THEN FL$ =  LEFT$ (FL$,I - 1) + "." +  RIGHT$ (FL$, LEN (FL$) - I): GOTO 1540
    1530  IF ((X$ < "0") AND (X$ <  > ".")) OR ((X$ > "9") AND (X$ < "A")) OR (X$ > "Z") THEN  PRINT : VTAB 10: POKE H,19: PRINT LC$;"INVALID NAME -- PRESS RETURN TO REENTER ";: GOSUB 170: GOTO 1410
    1540  NEXT 
    1550  PRINT : PRINT D$;"OPEN ";FL$;",D1"
    1560  PRINT D$;"CLOSE ";FL$
    1570  PRINT D$;"DELETE ";FL$;",D1"
    1580  PRINT D$;"OPEN "FL$;",D1"
    1590  PRINT D$;"WRITE ";FL$
    1600  FOR I = 1 TO R: PRINT AP$(I): NEXT 
    1610  PRINT D$;"CLOSE"
    1620  RETURN 
    1630  REM **SET MARGINS**
    1640  PRINT : VTAB 8: POKE H,19: PRINT "LEFT MARGIN...": VTAB 10: POKE H,19: PRINT "<-  ->    <RETURN> = ACCEPT"
    1650  PRINT : VTAB 3: POKE H,5: PRINT LM;" ": VTAB 2: POKE H,LM: PRINT  CHR$ (0);: GOSUB 170
    1660  IF A$ =  CHR$ (8) THEN LM = LM - (LM > 1): PRINT : VTAB 2: POKE H,LM: PRINT " "
    1670  IF A$ =  CHR$ (21) OR A$ =  CHR$ (32) THEN  IF LM < (RM - 2) THEN  PRINT : VTAB 2: POKE H,LM: PRINT  CHR$ (255):LM = LM + 1
    1680  IF A$ <  >  CHR$ (13) THEN 1650
    1690  PRINT : VTAB 8: POKE H,19: PRINT "RIGHT MARGIN..."
    1700  PRINT : VTAB 3: POKE H,5: PRINT RM;" ": VTAB 2: POKE H,RM - 1: PRINT  CHR$ (0);: GOSUB 170
    1710  IF A$ =  CHR$ (8) THEN RM = RM - (RM > LM + 2): PRINT : VTAB 2: POKE H,RM: PRINT  CHR$ (255)
    1720  IF A$ =  CHR$ (21) OR A$ =  CHR$ (32) THEN RM = RM + (RM < 79): PRINT : VTAB 2: POKE H,RM - 1: PRINT " "
    1730  IF A$ <  >  CHR$ (13) THEN 1700
    1740  PRINT : VTAB 8: PRINT LC$: VTAB 10: PRINT LC$
    1750 C = LM: PRINT : VTAB 3: POKE H,5: PRINT C + 1;" ": VTAB 2: POKE H,LM: POKE 8,RM - LM: CALL 768: PRINT 
    1760  RETURN 
    1770  REM **SELECT LINE SPACING**
    1780  PRINT : VTAB 10: POKE H,6: PRINT "ENTER NUMBER OF SPACES BETWEEN LINES (1-4):" SPC( 4)"(CURRENT=";SP;")";: POKE H,49: GOSUB 170
    1790  IF A$ =  CHR$ (13) THEN  GOTO 1820
    1800  IF A$ < "1" OR A$ > "4" THEN 1780
    1810 SP =  VAL (A$)
    1820  PRINT : VTAB 10: PRINT LC$
    1830  RETURN 
    1840  REM **TRUNCATE LINE**
    1850  VTAB 6: POKE H,14: PRINT "OKAY TO ERASE TEXT FROM CURSOR TO END OF LINE? (Y/N) ": VTAB 2: POKE H,C: GOSUB 170: ON (A$ = "N" OR A$ =  CHR$ (110)) GOTO 1870: IF A$ <  > "Y" AND A$ <  >  CHR$ (121) THEN 1850
    1860  FOR I = M + C - LM TO M + LL - 1: POKE I,160: NEXT : VTAB 2: POKE H,C: FOR I = 1 TO RM - C: PRINT " ";: NEXT :LL = C - LM: PRINT 
    1870  PRINT : VTAB 6: PRINT LC$
    1880  RETURN 
    1890  REM **ENTER <ESC> CODE**
    1900 A = C: VTAB 6: POKE H,13: PRINT "TYPE <ESC> CODE & PRESS <RETURN> TO RESUME TEXT ENTRY"
    1910  VTAB 2: POKE H,C: GOSUB 170: IF A$ =  CHR$ (13) THEN  PRINT : GOTO 1970
    1920  IF A$ =  CHR$ (8) THEN B =  PEEK (M + C - LM): POKE H,C: PRINT  CHR$ (B + 227 * (B = 27)):C = C - (C > A): POKE M + C - LM,160: VTAB 2: POKE H,C: PRINT " ": GOTO 1960
    1930  IF B < 27 THEN 1910
    1940  POKE M + C - LM,B:B = B + 227 * (B = 27): INVERSE : VTAB 2: POKE H,C: PRINT  CHR$ (B): NORMAL 
    1950 C = C + (C < RM - 1):LL = LL + (LL < C)
    1960  POKE H,5: PRINT C + 1;" ": GOTO 1910
    1970  VTAB 6: PRINT LC$
    1980  RETURN 
    1990  REM **CTRL-CODE TO PRINTER**
    2000  VTAB 6: POKE H,17: PRINT "TYPE CONTROL-CHARACTER TO BE SENT TO PRINTER: ";: GOSUB 170: ON ((B > 26) OR (B = 13)) GOTO 2020
    2010  PRINT : PRINT D$;"PR#";SL: PRINT  CHR$ (9);"80N";: PRINT A$;: GOSUB 130
    2020  PRINT : VTAB 6: PRINT LC$: IF B < 26 AND B <  > 13 THEN  VTAB 4: POKE H,79: INVERSE : PRINT  CHR$ (B + 64): NORMAL 
    2030  RETURN 
    2040  REM **HELP SCREEN**
    2050  PRINT : VTAB 11: FOR I = 1 TO 80: PRINT U$;: NEXT 
    2060  PRINT "<CTRL-B>: "; CHR$ (92);" (UNDERLINE TEXT)";: POKE H,39: PRINT V$ + " <CRTL-P>: PRINT TEST PATTERN"
    2070  PRINT "<CTRL-D>: CLOSE LINE (DELETE CHAR)";: POKE H,39: PRINT V$ + " <CTRL-Q>: QUIT OR START ANEW"
    2080  PRINT "<CTRL-E>: JUMP TO LAST CHARACTER";: POKE H,39: PRINT V$ + " <CTRL-R>: TYPE "; CHR$ (93)
    2090  PRINT "<CTRL-F>: SET PRINTER LINE SPACING";: POKE H,39: PRINT V$ + " <CTRL-S>: JUMP TO LINE START"
    2100  PRINT "<CTRL-G>: TYPE "; CHR$ (95);: POKE H,39: PRINT V$ + " <CTRL-T>: SET OR CLEAR TAB STOP"
    2110  PRINT "<CTRL-I>: TAB";: POKE H,39: PRINT V$ + " <CTRL-V>: ENABLE REVERSE LINEFEEDS"
    2120  PRINT "<CTRL-J>: REVERSE PRINTER LINEFEED";: POKE H,39: PRINT V$ + " <CTRL-W>: SET LINE WIDTH (MARGINS)"
    2130  PRINT "<CTRL-L>: TYPE "; CHR$ (91);: POKE H,39: PRINT V$ + " <CTRL-X>: ERASE TO END OF LINE "
    2140  PRINT "<CTRL-N>: TYPE "; CHR$ (64);: POKE H,39: PRINT V$ + " <CTRL-Z>: CENTER TEXT"
    2150  PRINT "<CTRL-O>: OPEN LINE";: POKE H,39: PRINT V$ + " <DELETE>: DESTRUCTIVE BACKSPACE"
    2160  PRINT "<CTRL-^>: SEND CONTROL CHAR TO PRINTER";: POKE H,39: PRINT V$ + " <ESC>   : EMBED PRINTER <ESC> CODES"
    2170  FOR I = 1 TO 80: PRINT U$;: NEXT 
    2180  RETURN 
    2190  REM 
    2200  REM ***GLOBAL SETUP***
    2210  REM 
    2220  TEXT : HOME 
    2230  DIM TB(80),AP$(300): REM TAB STOP AND TEXT STRING ARRAYS
    2240  REM **INSTALL BUFFER PRINTER**
    2250  FOR I = 768 TO 792: READ X: POKE I,X: NEXT 
    2260  DATA 169,149,133,7,160,0,132,6,177,6,201,27,208,2,169,126,32,7,195,200,196,8,208,240,96
    2270  REM **MACHINE AND DOS ID**
    2280 PLUS = ( PEEK (64435) = 234 OR  PEEK (64435) = 56):PD = ( PEEK (48640) = 76): REM IF PLUS THEN II OR II+; IF PD THEN PRODOS
    2290  REM ***PRINTER CODES***
    2300 U1$ =  CHR$ (27) +  CHR$ (88): REM ESC+X TURNS ON UNDERLINE
    2310 U2$ =  CHR$ (27) +  CHR$ (89): REM ESC+Y TURNS OFF UNDERLINE
    2320 FF$ =  CHR$ (27) +  CHR$ (102): REM ESC+LOWERCASE F ACTIVATES FORWARD LINEFEEDS
    2330 RF$ =  CHR$ (27) +  CHR$ (114): REM ESC+LOWERCASE R ACTIVATES REVERSE LINEFEEDS
    2340  REM **ALL-PURPOSE REALS**
    2350 I = 0:J = 0:K = 0:X = 0:Y = 0
    2360  REM **DEDICATED REALS**
    2370 SL = 1: REM PRINTER SLOT
    2380 RF = 0: REM REVERSE LINEFEED FLAG
    2390 R = 1: REM ROW
    2400 C = 1: REM COLUMN
    2410 LM = 5: REM LEFT MARGIN
    2420 RM = 75: REM RIGHT MARGIN
    2430 LL = 0: REM LINE LENGTH
    2440 M = 38144: REM START OF TEXT BUFFER
    2450 H = 1403: REM HORZ POSITION
    2460 SP = 1: REM DEFAULT LINE SPACING
    2470  REM **STRING EQUIVALENTS**
    2480 X$ = ""
    2490 V$ =  CHR$ (252)
    2500 U$ =  CHR$ (95)
    2510 D$ =  CHR$ (4)
    2520 CL$ =  CHR$ (12): REM CLEAR SCREEN
    2530 LC$ =  CHR$ (29): REM CLEAR LINE
    2540 BS$ =  CHR$ (8): REM BACKSPACE
    2550  REM   
    2560  REM ***TITLE***
    2570  REM   
    2580  VTAB 4: HTAB 9: PRINT "TURN ON PRINTER OR....": HTAB 6: PRINT "PRESS PRINTER 'SELECT' BUTTON."
    2590  PRINT D$;"PR#1": PRINT 
    2600  HOME : POKE 1912,0
    2610  PRINT D$;"PR#3": PRINT CL$
    2620 A$ = "TYPEWRITER"
    2630 CL =  - 16336: SPEED= 150
    2640  VTAB 6: POKE H,31: FOR I = 1 TO 10: PRINT  MID$ (A$,I,1) + " ";:X =  PEEK (CL) +  PEEK (CL) +  PEEK (CL) +  PEEK (CL) +  PEEK (CL): NEXT 
    2650  SPEED= 255
    2660  PRINT : VTAB 10: POKE H,32: PRINT "BY JAMES D EVANS"
    2670  VTAB 14: POKE H,24: PRINT "COPYRIGHT 1988 BY MICROSPARC, INC."
    2680  VTAB 16: POKE H,27: PRINT "* PRESS <RETURN> TO BEGIN *";
    2690  POKE  - 16368,0: WAIT  - 16384,128: POKE  - 16368,0
    2700  RETURN 
    2710  REM 
    2720  REM ***ERROR TRAP***
    2730  REM 
    2740  POKE 216,0:EC =  PEEK (222):LN =  PEEK (218) +  PEEK (219) * 256: CALL 54915
    2750  PRINT : VTAB 10
    2760  IF EC = 4 THEN  PRINT "DISK IS WRITE-PROTECTED -- PLEASE REMOVE TAB FROM NOTCH ";: GOTO 2830
    2770  IF EC = 8 THEN  PRINT "DISK I/O ERROR -- PLEASE CHECK DISK AND DRIVE ";: GOTO 2830
    2780  IF EC = 9 THEN  PRINT "DISK IS FULL -- PLEASE INSERT A DIFFERENT DISK ";: GOTO 2830
    2790  IF EC = 10 THEN  PRINT "FILE LOCKED -- PLEASE THINK OF A DIFFERENT FILE NAME ";: GOTO 2830
    2800  IF EC = 11 THEN  PRINT "ILLEGAL FILE NAME -- PLEASE THINK OF A DIFFERENT NAME ";: GOTO 2830
    2810  IF EC = 255 THEN  PRINT "<CTRL-C> IS NOT AN ACCEPTABLE KEYSTROKE -- PLEASE NOTE ";: GOTO 2830
    2820  PRINT "ERROR #";EC;" HAS OCCURRED IN LINE ";LN;" -- PLEASE NOTE ";
    2830  PRINT "AND HIT <RETURN> ->";
    2840  GOSUB 170: IF A$ <  >  CHR$ (13) THEN  GOTO 2840
    2850  PRINT : VTAB 10: PRINT LC$: ONERR  GOTO 2740
    2860  GOTO 260
    2870  GET A$: IF A$ <  > "Y" AND A$ <  > "N" AND A$ <  > "y" AND A$ <  > "n" THEN 2870
    2880  RETURN 
    
  • GOBLINS.BAS Live Coding Session

    GOBLINS.BAS Live Coding Session


    “Coding done quick”.

    I sped a ~1 hour stream up by 400% and this is what I got.

    This game was published as a type-in pamphlet here.

    You can also download the finished game here.

    Original blog post here.


    mailto:vidak@member.fsf.org

    https://matrix.to/#/@vidak:solarpunk.au

    https://retro.social/@permacomputer


    Jan 2026.

  • A Simple Guide to Porting Your BASIC

    A Simple Guide to Porting Your BASIC

    You may have considered porting some BASIC code from one dialect to another.

    Do not be dissuaded, the process can sometimes be rewarding.

    When porting on BASIC to another, I have found the following guides to be useful:

    Strip out all lines with references to POKE and PEEK.

    This is my preferred strategy. Almost every system addresses memory differently, and has a different memory map.

    Check the way arrays work on your target machine. Especially string arrays.

    Many systems will allow simple string arrays, such as: S$(100)

    But how long are these strings? How does the machine assign and evaluate each index? Some machines may even accept two-dimensional string arrays.

    Every application will make use of some subset, and not every single feature of it’s machine’s arrays, so don’t be daunted. Sometimes the job can be done with very little modification.

    INPUT statements may be an issue. Some parse input differently.

    Does you machine have LINE INPUT, or just INPUT?

    INPUT splits the input into multiple variables on commas in the input, whereas LINE INPUT puts the entire line into one variable.

    File operations like OPEN and CLOSE will accept different arguments.

    This can be quite tricky.

    Since you have made it this far into the blog post, please consider the following table of conversions between my most used BASICS:

    DartmouthAPPLESOFTATARI 8-BITBBC BASICCOMMODORE BASIC V2
    OPENFILE #file, “filenameOPEN filenameOPEN #fileno,mode control code,filenamevar = OPENIN, var = OPENOUTOPEN #exp, fileno, mode, “filename”
    CLOSECLOSE “filenameCLOSE #fileno, #filenoCLOSE #fileno; CLOSE #0 (all files)CLOSE #fileno
    LOADLOAD filenameLOAD “disk:filenameLOAD “filenameLOAD “filename“,8,[disk]
    PRINTPRINT #file, record, …PRINT exp, exp, …PRINT #fileno, record, record, …PRINT #filename, record, record, …PRINT #fileno, record, record, …
    INPUTINPUT #file, record, …INPUT [string,] var, var, …INPUT #[file,disk] varINPUT #filename, record, record, …INPUT “string” var, var, …

    Is your BASIC indexed from one (1) or zero (0)?

    Because this is an easy one. Convert every index accordingly:

    (e.g.) DIM A(255) -> DIM A(256)
    
    (e.g.) FOR I=0 TO 255 -> FOR I=1 TO 256
  • Watch Me Code A Procedurally Generated Game in BASIC!

    Watch Me Code A Procedurally Generated Game in BASIC!

    “Coding done quick”.

    I sped a ~2 hour stream up by 800% and cut some boring bits out, and this is what i got.

    Experimenting with a large, procedurally generated world.

    mailto:vidak@member.fsf.org

    https://matrix.to/#/@vidak:solarpunk.au

    https://retro.social/@permacomputer

    jan 2026

    https://sr.ht/~vidak/oats-for-my-goats

    https://basiclang.solarpunk.au/d/6-game-oats-for-my-goats

  • L.E.D.

    L.E.D.

    Line-Oriented Text Editor

    Arnie Lee

    ABACUS SOFTWARE

    Published: Compute! Magazine; Feb, 1981.

    The LED is line-oriented as opposed to word-oriented. As such, it cannot be considered a true word processor although it does provide many of the same capabilities as many of the other commercially available word processors. In fact, a slightly modified version of the LED was used to create this article. Although we wrote the LED to maintain program source statements, its usefulness is by no means limited to that application.

    The LED is a line oriented text editor. The entire source program must be in memory while the user is modifying it. Modifications allowed include appending source to the end of the text, inserting lines of text into the middle of existing text, changing occurrence of a character string to another string, and printing the text to a hard copy device. After creating or modifying the text, the user may then save it onto tape or diskette. Some of the key points to note when using the LED are:

    • Each line is numbered;
    • Each line can contain up to 80 characters;
    • When entering 3 line, the line must be terminated by RETURN key;
    • A maximum of 500 lines of text may be entered (this is subject to the memory capacity of your particular computer);
    • As lines arc inserted or deleted from the source program, the remaining lines arc automatically renumbered;
    • A line of source may extend more than one screen line on your CRT.

    Commands.

    The following arc the descriptions of each of the commands:

    ‘F’

    Enter FILER portion of LED.

    This command allows you to use the LOAD or SAVE commands which arc described below:

    ‘L’

    Load file from tape or diskette.

    This command allows you to load a previously edited source program. The source program may have been saved on tape or diskette. After keying ‘L’ the LED will prompt you for the name of the source program. Key in the filename and depress RETURN. Do not key in the suffix .SOURCE. If you decide that you really don’t want to load a file, then enter a null line instead of a filename. At this point you will be asked if the file was saved on tape or diskette (for the PET version of LED). Type ‘T’ or ‘D’ as appropriate. If the source program is on tape, then you must put the source file tape into cassette #1. For either tape or diskette, the filename that is keyed in must match the filename that is on the storage medium.

    ‘S’

    Save file onto tape or diskette.

    This command allows you to save the current source program onto tape or diskette. After keying ‘S’, the LED will prompt you for the name of the file to be saved. Key in the file-name and then depress RETURN. The file-name is limited to twelve characters. The suffix .SOURCE will be added to the filename by the LED. If you decide that you really don’t want to save a file, then enter a null line instead of a filename.

    At this point you will be asked if you want to save the file onto tape or diskette (for PET version of the LED). Type ‘T’ or ‘D’ as appropriate. If the source is to be saved onto tape, then you must put the tape into cassette #1.

    *** Note that tape is supported only in the PET version.

    ‘A’

    Append the end of source.

    This command allows you to add lines to the end of the current source program. If you have not loaded any source program, then this command will allow you to create a new source program. You may append one or as many lines as you desire. To signal the end of append mode press RETURN when the cursor is sitting at the first character after the line number prompt (null line).

    ‘C’

    Change string.

    This command allows you to change an existing string to a new string. It will make changes to either a single line or to a range of lines. Indicate a single line by keying in its line number followed by RETURN. Indicate a range of lines by keying the line number of the first line to be searched followed by ‘-’ and finally followed by the line number of the last line to be searched followed by RETURN. You will then be prompted for the change siring. The format for the changed string is:

    + from-string + to-string +

    where:

    + is a delimiter — any character may be used but it must not be contained in either the from-string or the to-string.

    from-string is the string of characters which are to be replaced

    to-string is the string of characters which are to replace the from-string in the original source line

    e.g.  /abc/xyz/ 

    in the above example all occurrences of abc will be replaced by xyz.

    e.g.  /abc// 

    in the above example all occurrences of ‘abc’ will be eliminated (replaced by nulls).

    ‘D’

    Delete line or range.

    This command allows you to delete a line or a range of lines from the source program in memory.

    DELETE RANGE(LOW,HIGH)-> 80 will delete line 80

    DELETE RANGE(LOW,HIGH)-> 80-90

    will delete lines 80 thru 90

    DELETE RANGE(LOW-HIGH)-> -20

    will delete all lines thru 20

    ‘I’ insert lines into source program

    This command will allow you to insert lines into the existing source program. LED will prompt you for the line number before which you want to insert the new source statements. You may enter one or as many new lines as you desire. Follow each line with RETURN. To signal the end of INSERT mode press RETURN when the cursor is setting at the first character in the line (null).

    ‘L’ list source program

    This command allows you to list a line or range of lines.

    LIST RANGE(LOW-HIGH)-> 80

    will list line 80

    LIST RANGE(LOW-HIGH)-> 80-100

    will list lines 80 thru 100

    LIST RANGE(LOW-HIGH)-> -20

    will list all lines thru 20

    LIST RANGE(LOW-HIGH)-> NULL

    will list all lines

    With the LIST command only the following features are available:

    PET.

    RUN/STOP key – suspends the listing awaiting the depression of the RETURN key.

    SPACE BAR – scrolls the listing one line at a time

    OFF/RVS key – slows the speeds of the listing

    APPLE II.

    ESC key – suspends the listing awaiting the depression of the RETURN key.

    RETURN key – reverts to normal speed listing after ESC

    SPACE BAR – slows the speed of the listing

    ‘M’

    This command allows you to sec a more complete explanation of the commands than the abbreviated version which prompts you,

    ‘P’

    This command allows you to print a line or range of lines to a hard copy printer. The PET is supported thru the IEEE interface as device 4. The APPLE II is supported thru slot 2. The range specifications are identical as LIST.

    ‘Q’

    Quit LED.

    This command allows you to gracefully exit from the LED. The LED gives you a chance to change your mind so that if you accidentally keyed Q, then you will have another opportunity to save your source file.

    ‘R’

    Replace a line.

    This command allows you to replace a single line only. After keying in the line number to be replaced, the LED will prompt you with that line number. Key in the replacement text and press return.

    e.g. 

    REPLACE -LINE#-> 108

    allows you to replace line 108.

    Listing.

    The listing which follows is the version of the LED for the PET/CBM machines. The version for the APPLE II is very similar to the PET/CBM version and runs under APPLESOFT. The major differences between the two versions are in the routines that handle the disk and printer I/O.

    0 REM LINE EDITOR (c)1980 ABACUS SOFTWARE
    10 DIM T$(500):REM BUFFER SPACE
    20 L$="":REM CURRENT LINE
    30 LL=1:REM LAST LINE #
    40 SP$=" ":DL$=CHR$(20)
    50 EE=0:REM DISK ERROR CHANNEL CLOSED
    60 PR=0: REM PRINT CHANNEL
    90 POKE 144,49:REM DISABLE STOP KEY
    100 PRINT "       ABACUS SOFTWARE LINE EDITOR"
    110 PRINT "      FUNCTIONS:"
    130 PRINT
    140 PRINT TAB(8);"A)PPEND-TO END OF TEXT"
    150 PRINT TAB(8);"C)HANGE-STRING"
    160 PRINT TAB(8);"D)ELETE LINE(S)"
    170 PRINT TAB(8);"F)ILER COMMANDS"
    180 PRINT TAB(8);"I)NSERT BEFORE LINE"
    190 PRINT TAB(8);"L)IST LINE(S)"
    200 PRINT TAB(8);"M)ENU DISPLAY"
    210 PRINT TAB(8);"P)RINT LINE(S)"
    220 PRINT TAB(8);"Q)UIT LEAVE EDITOR"
    230 PRINT TAB(8);"R)EPLACE LINE"
    240 PRINT:PRINT "    ENTER SELECTION-> ";
    250 GOTO 510
    500 PRINT:PRINT "ENTER A,C,D,F,I,L,P,Q,R,M)ENU->";
    510 GET A$:IF A$="" THEN 510
    520 J=0:FOR I=1 TO 10
    530 IF A$=MID$("ACDFILRMQP",I,1) THEN J=I:I=10
    540 NEXT I
    550 PRINT A$
    560 IF J=0 THEN 500
    570 ON J GOTO 1000,2000,3000,4000,5000,6000,7000,100,8000,9000
    1000 PRINT
    1005 PRINT "APPEND TO END OF TEXT"
    1010 PRINT:PRINT LL ">";
    1020 GOSUB 10000:REM GO READ LINE
    1030 IF LEN(L$)=0 THEN 500
    1040 T$(LL)=L$
    1050 LL=LL+1
    1060 GOTO 1010
    2000 REM CHANGE STRING
    2010 PRINT:PRINT "CHANGE";:GOSUB 16000:REM GET RANGE
    2020 IF HI=0 THEN 500
    2025 PRINT "CHANGE STRING->";:GOSUB 10000:REM GET STRING
    2030 L=LEN(L$)
    2040 IF L=0 THEN 500
    2050 IF L<4 THEN 2000
    2060 DM$=LEFT$(L$,1):REM DELIMITER
    2070 IF RIGHT$(L$,1)<>DM$ THEN 2000
    2080 J=0: FOR I=2 TO L-1
    2090     IF MID$(L$,I,1)=DM$ THEN J=I
    2100 NEXT I
    2110 IF J=0 THEN 2000
    2120 IF J=2 THEN 2000
    2130 FR$=MID$(L$,2,J-2)
    2140 IF J+1=L THEN TS$="":GOTO 2160
    2150 TS$=MID$(L$,J+1,L-J-1)
    2160 F=LEN(FR$)
    2170 FOR I=LO TO HI
    2180     T=LEN(T$(I)):S=1:NL$=""
    2190     FOR J=1 TO T-F+1
    2200         IF MID$(T$(I),J,F)<>FR$ THEN 2230
    2210         NL$=NL$+MID$(T$(I),S,J-S)+TS$
    2220         S=J+F:J=S-1
    2230     NEXT J
    2240     IF S<>1 THEN NL$=NL$+RIGHT$(T$(I),T=S+1):T$(I)=NL$
    2250 NEXT I
    2260 GOTO 500
    3000 REM DELETE LINES(S)
    3005 PRINT:PRINT "DELETE ";:GOSUB 16000:REM GET RANGE
    3010 IF NOT DF THEN 3015:REM NOT DEFAULT ON ENTIRE FILE
    3011 PRINT "DELETE ENTIRE FILE? ";
    3012 GET A$:IF A$="" THEN 3012
    3013 PRINT A$:IF A$="N" THEN 500
    3014 IF A$<>"Y" THEN 3011
    3015 IF HI>LL-1 THEN 500
    3020 IF HI=LL-1 THEN LL=LO:GOTO 500
    3030 J=HI-LO+1
    3040 FOR I=LO TO LL-J-1
    3050     T$(I)=T$(I+J)
    3060 NEXT I
    3070 LL=LL-(HI-LO)-1
    3080 GOTO 500
    4000 REM FILER
    4010 PRINT "FILER ENTER L)OAD OR S)AVE-> ";
    4020 GET A$:IF A$="" THEN 4020
    4030 IF A$<>"L" AND A$<>"S" THEN PRINT:GOTO 4000
    4040 PRINT A$:M$=A$
    4050 PRINT "ENTER FILENAME-> ";
    4070 GOSUB 10000
    4075 IF LEN(L$)=0 THEN 500
    4076 IF LEN(L$)>12 THEN 4050
    4080 FI$=L$
    4090 PRINT "ENTER D)ISK OR T)APE-> ";
    4100 GET A$:IF A$="" THEN 4100
    4110 PRINT A$
    4120 IF A$<>"D" AND A$<>"T" THEN 4090
    4130 IF A$="D" THEN 4160:REM DISK ROUTINES
    4140 IF M$="L" THEN 4400
    4150 GOTO 4200
    4160 DR$="":IF LEFT$(FI$,2)<>"0:" AND LEFT$(FI$,2)<>"1:" THEN DR$="0:"
    4170 GOTO 4600
    4200 REM TAPE SAVE
    4210 IF LL=1 THEN PRINT "NO FILE TO SAVE":GOTO 500
    4220 OPEN 2,1,2,FI$+".SOURCE"
    4230 FOR I=1 TO LL-1
    4230     FOR J=1 TO LEN(T$(I))
    4250         PRINT# 2,MID$(T$(I),J,1);
    4260	 NEXT J
    4270     PRINT# 2,CHR$(255);
    4280 NEXT I
    4290 CLOSE 2
    4300 PRINT SPC(6);FI$;" SAVED"
    4310 GOTO 500
    4400 REM TAPE LOAD
    4410 OPEN 2,1,0,FI$+".SOURCE"
    4430 IF=L0:REM LINE COUNT
    4440 LL=LL+1:T$(LL)=""
    4450 GET# 2,A$
    4460 IF ST=64 THEN 4500:REM END OF FILE
    4465 IF ST<>0 THEN PRINT "*** LOAD ERROR ***":GOTO 500
    4470 IF A$=CHR$(255) THEN 4440:REM END OF LINE
    4480 T$(LL)=T$(LL)+A$
    4490 GOTO 4450
    4500 CLOSE 2
    4510 PRINT SPC(6);FI$;" LOADED"
    4520 LL+LL+1
    4530 GOTO 500
    4600 REM DISK SAVE
    4610 IF M$="L" THEN 4800
    4620 IF LL=1 THEN PRINT "NO FILE TO SAVE":GOTO 500
    4630 FL$="@0"+DR$+FI$+".SOURCE,S,W"
    4640 OPEN 2,8,2,FL$
    4650 GOSUB 20000:REM ERROR CHECK
    4655 IF E1<>0 THEN 500
    4660 FOR I=1 TO LL-1
    4670     FOR J=1 TO LEN(T$(I))
    4680         PRINT# 2,MID$(T$(I),J,1);
    4690     NEXT J
    4700     PRINT# 2,CHR$(255);
    4710 NEXT I
    4720 CLOSE 2
    4730 PRINT SPC(6);FI$;" SAVED"
    4740 GOTO 500
    4800 REM DISK LOAD
    4810 FL$=DR$+FI$+".SOURCE,S,R"
    4820 OPEN 2,8,2,FL$
    4830 GOSUB 20000:REM ERROR CHECK
    4835 IF E1<>0 THEN 500
    4840 LL=0:REM LINE COUNT
    4850 LL=LL+1:T$(LL)=""
    4860 GET# 2,A$
    4870 IF ST=64 THEN 4500: REM END OF FILE
    4880 IF ST<>0 THEN GOSUB 20000:GOTO 500
    4890 IF A$=CHR$(255) THEN 4850:REM END OF LINE
    4900 T$(LL)=T$(LL)+A$
    4910 GOTO 4860
    4920 CLOSE 2
    4930 PRINT SPC(6);FI$;" LOADED"
    4940 LL=LL+1
    4950 GOTO 500
    5000 REM INSERT LINE
    5010 PRINT:PRINT "INSERT BEFORE ";:GOSUB 17000:REM GET LINE #
    5015 IF LO>LL OR LO<1 THEN 5000
    5020 PRINT:PRINT LO;">";
    5030 GOSUB 10000:REM READ LINE
    5040 IF LEN(L$)=0 THEN 500
    5050 LL=LL+1
    5060 FOR I=LL TO LO STEP -1
    5070     T$(LO)=L$
    5080 NEXT I
    5090 T$(LO)=L$
    5100 LO=LO+1
    5110 GOTO 5020
    6000 REM LIST LINES
    6010 PRINT:PRINT "LIST ";:GOSUB 16000:REM GET RANGE
    6020 IF HI=0 THEN 500
    6030 SS$="N":PRINT:FOR I=LO TO HI:REM PERFORM LIST
    6040 PRINT I;">";T$(I)
    6050 GET A$:OF A$=CHR$(18) THEN FOR J=1 TO 1024:NEXT J
    6060 IF A$<>CHR$(3) THEN 6110
    6070 SS$="Y"
    6080 GET A$:IF A$=CHR$(13) THEN SS$="N":GOTO 6110
    6090 IF A$<>CHR$(32) THEN 6070
    6100 GOTO 6120
    6110 IF SS$="Y" THEN 6070
    6120 NEXT I
    6130 GOTO 500
    7000 REM REPLACE LINE
    7010 PRINT:PRINT "REPLACE ";:GOSUB 17000:REM GET LINE #
    7020 IF LO>=LL OR LO<1 THEN 7000
    7030 PRINT:PRINT LO;">";
    7040 GOSUB 10000:REM READ LINE
    7050 IF LEN(L$)=0 THEN 500
    7060 T$(LO)=L$
    7070 GOTO 500
    8000 REM QUIT
    8010 PRINT:PRINT "     LEAVE EDITOR-ARE YOU SURE? ";
    8020 GET A$:IF A$="" THEN 8020
    8030 PRINT A$
    8040 IF A$<>"Y" AND A$<>"N" THEN 8000
    8050 IF A$="N" THEN 500
    8060 PRINT:PRINT "           ** END LINE EDITOR **"
    8070 POKE 144,46:REM ENABLE STOP KEY
    8080 END
    9000 REM PRINT LINE
    9010 IF PR=0 THEN PR=4 OPEN PR,PR
    9020 PRINT "PRINT ";:GOSUB 16000:REM GET RANGE
    9030 IF HI=0 THEN 500
    9040 FOR I=LO TO HI:REM PERFORM PRINT
    9050     PRINT# PR,I;": ";T$(I)
    9060 NEXT I
    9070 PRINT# PR
    9080 PRINT# PR,"***";LL-1;"LINES IN BUFFER ***"
    9090 PRINT #PR
    9100 GOTO 500
    10000 REM INPUT A LINE OF TEXT
    10010 L$=""
    10020 PRINT "$<-";
    10030 GET A$:IF A$="" THEN 10030
    10040 IF A$=CHR$(13) THEN PRINT " ":RETURN
    10050 IF LEN(L$)>80 THEN GOTO 15000
    10060 IF A$>=SP$ AND A$<=CHR$(95) THEN 10100
    10065 IF A$>=CHR$(161) AND A$<=CHR$(223) THEN 10100
    10070 IF A$<>DL$ THEN GOTO 10030
    10080 IF LEN(L$)>0 THEN PRINT A$;:L$=LEFT$(L$,LEN(L$)-1)
    10090 GOTO 10020
    10100 L$=L$+A$:PRINT A$;:GOTO 10020
    15000 REM LINE INPUT ERROR
    15010 PRINT:PRINT "ERROR LINE TRUNCATED"
    15020 RETURN
    16000 PRINT "RANGE(LOW,HIGH)-> ";
    16010 GOSUB 10000:REM INPUT RANGE
    16020 LO=1:HI=LL-1:REM DEFAULT LIST ALL
    16025 L=LEN(L$)
    16030 DF=0:IF L=0 THEN DF=-1:GOTO 16150
    16040 J=0:FOR I=1 TO L
    16050 A$=MID$(L$,I,1)
    16060 IF A$>="0" AND A$<="9" THEN 16090
    16070 IF A$="-" THEN J=I:GOTO 16090
    16080 J=99:I=99
    16090 NEXT I
    16100 IF J=99 THEN 16000
    16110 IF J=0 THEN LO=VAL(L$):HI=LO:RETURN
    16120 IF J>1 THEN LO=VAL(LEFT$(L$,J-1))
    16130 IF J<L THEN HI=VAL(RIGHT$(L$,L-J))
    16140 IF LO>HI THEN 16000
    16150 RETURN
    17000 PRINT "-LINE#->";
    17010 GOSUB 10000:REM INPUT LINE#
    17020 L=LEN(L$)
    17030 IF L=0 THEN 17000
    17040 J=0
    17050 FOR I=1 TO L
    17060     A$=MID$(L$,I,1)
    17070     IF A$>="0" AND A$<="9" THEN 17090
    17080     J=99:I=L
    17090 NEXT I
    17100 IF J=99 THEN 17000
    17110 LO=VAL(L$)
    17120 RETURN
    20000 IF EE=0 THEN EE=15:OPEN EE,8,EE
    20010 INPUT# EE,E1,E2$,E3,E4
    20020 IF E1=0 THEN RETURN
    20030 PRINT E1;",";E2$;",";E3:",";E4
    20040 PRINT "*** DISK ERROR ***"
    20050 CLOSE 2
    20060 RETURN