Chapter 3
SpeedScript Source Code

Atari Source Code

The source code for SpeedScript was originally developed using the MAC/65 assembler (from Optimized Systems Software, Inc.). The MAC/65 assembler uses the standard MOS source code format, so this source code can be assembled on a variety of Atari assemblers, including EASMD from OSS and the Atari Assembler/Editor cartridge. The source code was originally broken up into a number of modules, each SAVE#'d to disk. The .INCLUDE pseudo-op was used to link all the modules together. All files must be merged together to be assembled with the Atari Assembler/Editor cartridge. Line numbers are omitted.

Most pseudo-ops are in standard MOS 6502 notation: *= updates the program counter (some assemblers use .ORG instead); .BYTE assembles a list of numbers or an ATASCII character string; .WOR, or .WORD, assembles a list of addresses into low byte/high byte format; < extracts the low byte of a 16-bit expression; > extracts the high byte of a 16-bit expression (some assemblers reverse the use of < and > others, such as EASMD and the Assembler/Editor cartridge, use a suffix of &255 and /256 to achieve the same effect); and = is used to assign an expression to a label (some assemblers use .EQU).

Beginners should make sure they understand Indirect-Y addressing, as in LDA ($FB),Y or LDA (CURR),Y. This mode is used extensively in SpeedScript.

The Atari version of SpeedScript was developed by sending the Commodore 64 source code to the Atari via modem. References to Commodore 64 Kernal ROM routines were replaced with Atari CIO routines. Some routines built into the Commodore 64's ROM had to be programmed into Atari SpeedScript, with resulting code expansion. References to location 1 (which maps banks of ROM in and out in the 64) were omitted. The REFRESH routine, TOPCLR, and a few other routines were changed to compensate for Atari's floating screen memory. The raster interrupt used to highlight the command line in the 64 version became a display-list interrupt. A custom character set was added to take advantage of the Atari's special nine-line character mode. The DOS package was written to support disk functions. But much of the source code did not need to be changed at all, since SpeedScript's machine-specific code is segregated into distinct modules. These modules were rewritten. Approximately one week was required to get a primitive version running, followed by two months of testing, debugging, and refining to complete Atari SpeedScript. Because of the new character set, the DOS package, smoother input/output programming (such as Atari's device-independent I/O), and more logical keyboard layout, the Atari version may be the best version of SpeedScript yet.

SpeedScript is written in small modules. Some people think that subroutines are useful only when a routine is called more than once. I strongly believe in breaking up a problem into a number of discrete tasks. These tasks can be written as subroutines, then tested individually. Once all the modules are working, just link them together with JSRs and you have a working program.

I've also tried to use meaningful labels, but sometimes one just runs out of imagination. Comments are added below as signposts to guide you through the source code (you needn't type them in--if you do, precede each comment with a semicolon for the sake of your assembler). Modules are also set apart with blank lines. Notice that some modules are used in rather creative ways. For example, word left/word right is used both for moving the cursor and in delimiting a word to be erased in the erase mode. Also, note that memory locations are sometimes used instead of meaningful labels. In order to fit the complete source code into memory at once, I sometimes had to compromise readability for the sake of brevity.

Crucial to the understanding of SpeedScript is the REFRESH routine. Study it carefully. REFRESH is the only routine in SpeedScript that writes directly to the screen (CIO is used to print on the command line). It automatically takes care of word-wrap and carriage returns, and provides useful pointers so that the CHECK routine can easily scroll the screen. This frees the rest of SpeedScript to just move and modify contiguous memory. Carriage returns are not padded out in memory with spaces to fill the rest of a line; the REFRESH routine takes care of this transparently.

Speedscript 3.0 Source Code for Atari

Filename: SPEED.0

Location $1F00 is safely above DOS 2.0S, DOS 3,
and OS/A+ DOS. Some DOS's may use more memory, so
you may need to reassemble SpeedScript at a
higher address, usually the address of LOMEM plus
256 bytes to be safe.

    *=  $1F00

Locations used by high-speed memory move
routines.

FROML = $80
FROMH = $81
DESTL = $82
DESTH = $83
LLEN =  $84
HLEN =  $85

CURR: Position of cursor within text memory. SCR:
used by the REFRESH routine.

CURR =  $86
SCR =   $88

TEX: An alternate location used in tandem with
CURR. COLR is used by REFRESH. TEMP is used
throughout as a scratehpad pointer. INDIR is also
a reusable indirect pointer. UNDERCURS stores the
value of the character highlighted by the cursor.

TEX =   $8A
TEMP =  $8C
INDIR = $8E
UNDERCURS = $90

WTNDCOLOR: Color of command line window supported
by HIGHLIGHT. RETCHAR is the screen-code value of
the return-mark (a left-pointing arrow). SPACE is
the screen-code value of the space character, RED
and BLUE are used as command-line colors

WINDCOLR = $91
RETCHAR = 94
SPACE = 0
RED =   $32
BLUE =  $74

Input/Output Control System definitions for
input/output control blocks (IOCBs). CIO is the
entry point for all file-oriented input/output.
SHFLOK is the SHiFtLOcK flag.


ICCOM = $0342
ICBADR = $0344
ICBLEN = $0348
ICAUX1 = $034A
ICAUX2 = $034B
ICSTAT = $0343
SHFLOK = $02BE
CIO =   $E456

Called only when run from DOS. It is assumed that
the author's initials (that conveniently work out
in hex) are not normally present in memory. If
they are, we know that SpeedScript has been run
before, so we avoid the ERASE routine to preserve
the text in memory.

BEGIN LDA 710
    STA 709
    JSR INIT
    LDA #$CB
    CMP FIRSTRUN
    STA FIRSTRUN
    BEQ SKIPERAS
    JSR ERASE
    JSR KILLBUFF

We save the DOS reset vector and change this
vector to point to SpeedScript's SYSTEM RESET
routine. Since this routine is called at
power-up, right after DOS.SYS runs, we need to
disable the cold-start flag (location 580) and
set location $09 to signify a successful disk
boot.

    LDA $0C
    STA JDOS+1
    LDA $0D
    STA JDOS+2
    LDA # <JDOS
    STA $0C
    LDA # >JDOS
    STA $0D
    LDA #0
    STA 580
    LDA #1
    STA $09
SKIPERAS JSR INIT2
    JMP MAIN

The character set for the ANTIC 3 nine-line
character mode must be on an even 512-Syte
boundary, so we force the assembler's program
counter to address $2000 and merge in the
character set. We then link in each successive
module of SpeedScript. Again, if your assembler
cannot handle .INCLUDE, you'll have to merge all
these files together in the order indicated.

    *=  $2000
    .INCLUDE #D:CHSET.SRC
    .INCLUDE #D:SPEED.1
    .INCLUDE #D:SUPPORT
    .INCLUDE #D:DOSPAK
    .INCLUDE #D:SPEED.2
    .INCLUDE #D:DATA
    .END
Filename: CHSET.SRC

The character set here is stored as eight bytes
per line, so each line defines one character.
Sheldon Leemon's INSTEDIT character editor was
used to create the character set, and I wrote a
special program to convert the character set into
.BYTE statements. In ANTIC mode 3, each character
takes up ten scan lines of vertical screen space.
The characters in the lowercase portion of the
character set are displayed with a blank line at
the top line, then the character data from bytes
1-7 of the character set. Byte 0 of the
character's definition is displayed at the ninth
line of the character. The tenth line is always
blank. This lets you define characters with true
descenders. The forced blank line lets you use
more of the character matrix for defining a
character, so these characters are larger than
normal Atari characters.

.BYTE 0,0,0,0,0,0,0,0
.BYTE 0,24,24,24,24,24,0,24
.BYTE 0,102,102,102,0,0,0,0
.BYTE 0,102,255,102,102,255,102,0
.BYTE 24,62,96,60,6,124,24,0
.BYTE 0,204,216,48,96,204,140,0
.BYTE 0,56,108,56,112,222,204,118
.BYTE 0,24,24,48,0,0,0,0
.BYTE 0,24,48,96,96,96,48,24
.BYTE 0,48,24,12,12,12,24,48
.BYTE 0,0,102,60,255,60,102,0
.BYTE 0,0,24,24,126,24,24,0
.BYTE 0,0,0,0,0,48,48,96
.BYTE 0,0,0,0,126,0,0,0
.BYTE 0,0,0,0,0,0,48,48
.BYTE 0,0,6,12,24,48,96,192
.BYTE 0,124,206,222,246,230,198,124
.BYTE 0,24,56,24,24,24,24,126
.BYTE 0,124,198,12,24,48,96,254
.BYTE 0,254,12,24,56,12,198,124
.BYTE 0,28,60,108,204,254,12,12
.BYTE 0,254,192,252,6,6,198,124
.BYTE 0,124,192,252,198,198,198,124
.BYTE 0,126,6,12,24,48,96,96
.BYTE 0,124,198,198,124,198,198,124
.BYTE 0,124,198,198,126,12,24,48
.BYTE 0,0,48,48,0,48,48,0
.BYTE 0,0,48,48,0,48,48,96
.BYTE 0,12,24,48,96,48,24,12
.BYTE 0,0,0,126,0,0,126,0
.BYTE 0,48,24,12,6,12,24,48
.BYTE 0,60,102,6,12,24,0,24
.BYTE 0,124,198,222,214,220,224,60
.BYTE 0,124,198,198,198,254,198,198
.BYTE 0,252,198,198,252,198,198,252
.BYTE 0,124,198,192,192,192,198,124
.BYTE 0,248,204,198,198,198,204,248
.BYTE 0,254,192,192,252,192,192,254
.BYTE 0,254,192,192,252,192,192,192
.BYTE 0,124,198,192,222,198,198,124
.BYTE 0,198,198,198,254,198,198,198
.BYTE 0,126,24,24,24,24,24,126
.BYTE 0,62,12,12,12,12,204,120
.BYTE 0,198,204,216,240,216,204,198
.BYTE 0,192,192,192,192,192,192,254
.BYTE 0,198,238,254,214,198,198,198
.BYTE 0,198,230,246,254,222,206,198
.BYTE 0,124,198,198,198,198,198,124
.BYTE 0,252,198,198,198,252,192,192
.BYTE 0,124,198,198,198,222,124,14
.BYTE 0,252,198,198,252,216,204,198
.BYTE 0,124,198,192,124,6,198,124
.BYTE 0,126,24,24,24,24,24,24
.BYTE 0,198,198,198,198,198,198,124
.BYTE 0,198,198,198,198,198,108,56
.BYTE 0,198,198,198,214,254,238,198
.BYTE 0,198,198,108,56,108,198,198
.BYTE 0,102,102,102,60,24,24,24
.BYTE 0,254,12,24,48,96,192,254
.BYTE 0,30,24,24,24,24,24,30
.BYTE 0,64,96,48,24,12,6,0
.BYTE 0,240,48,48,48,48,48,240
.BYTE 0,8,28,54,99,0,0,0
.BYTE 0,0,0,0,0,0,0,255
.BYTE 0,0,0,0,0,0,0,0
.BYTE 124,194,153,153,129,153,153,230
.BYTE 252,130,153,130,153,153,131,252
.BYTE 124,194,153,158,158,153,194,124
.BYTE 252,130,153,153,153,153,130,252
.BYTE 254,130,158,132,156,158,130,254
.BYTE 126,193,206,194,206,204,204,120
.BYTE 124,194,153,158,145,153,194,124
.BYTE 246,153,153,129,153,153,153,246
.BYTE 127,97,115,50,50,115,97,127
.BYTE 62,50,50,50,50,114,198,124
.BYTE 230,153,146,132,146,153,153,230
.BYTE 120,76,76,76,76,78,66,124
.BYTE 230,153,129,129,137,153,153,230
.BYTE 230,153,137,129,145,153,153,230
.BYTE 124,194,153,153,153,153,194,124
.BYTE 254,195,201,201,195,206,200,240
.BYTE 124,194,153,153,153,146,201,118
.BYTE 124,194,201,201,194,201,201,247
.BYTE 126,195,158,194,249,153,195,126
.BYTE 254,194,102,100,100,100,100,124
.BYTE 246,153,153,153,153,153,194,124
.BYTE 230,153,153,153,153,194,100,56
.BYTE 246,153,153,153,137,129,153,246
.BYTE 230,153,153,194,153,153,153,230
.BYTE 230,153,153,195,230,100,100,124
.BYTE 254,193,249,50,228,206,193,254
.BYTE 120,96,120,96,126,24,30,0
.BYTE 0,24,60,126,24,24,24,0
.BYTE 0,24,24,24,126,60,24,0
.BYTE 0,0,0,12,12,88,112,120
.BYTE 0,24,12,126,12,24,0,0
.BYTE 0,0,24,60,126,126,60,24
.BYTE 0,0,0,124,6,126,198,126
.BYTE 0,0,192,252,198,198,198,252
.BYTE 0,0,0,124,198,192,198,124
.BYTE 0,0,6,126,198,198,198,126
.BYTE 0,0,0,124,198,254,192,124
.BYTE 0,0,62,96,252,96,96,96
.BYTE 6,252,0,126,198,198,198,126
.BYTE 0,0,192,192,252,198,198,198
.BYTE 0,0,24,0,56,24,24,60
.BYTE 24,240,24,0,24,24,24,24
.BYTE 0,0,192,204,216,248,204,198
.BYTE 0,0,56,24,24,24,24,60
.BYTE 0,0,0,204,254,254,214,198
.BYTE 0,0,0,252,198,198,198,198
.BYTE 0,0,0,124,198,198,198,124
.BYTE 192,192,0,252,198,198,198,252
.BYTE 6,6,0,126,198,198,198,126
.BYTE 0,0,0,252,198,192,192,192
.BYTE 0,0,0,126,192,124,6,252
.BYTE 0,0,48,254,48,48,48,30
.BYTE 0,0,0,198,198,198,198,126
.BYTE 0,0,0,198,198,198,108,56
.BYTE 0,0,0,198,214,254,124,108
.BYTE 0,0,0,198,108,56,108,198
.BYTE 6,252,0,198,198,198,198,126
.BYTE 0,0,0,254,12,56,96,254
.BYTE 14,0,14,24,24,56,24,24
.BYTE 24,24,24,24,24,24,24,24
.BYTE 112,0,112,24,24,28,24,24
.BYTE 0,0,0,8,24,56,24,8
.BYTE 0,0,0,16,16,24,28,24
*=  *+16
.END
Filename: SPEED.1

This module is chiefly concerned with
the word processor editing functions.
It contains many common subroutines,
such as TOPCLR and PRMSG to clear the
command line and print messages. It
contains the initialization routines
and takes care of memory moves (inserts
and deletes). A second module, SPEED.2,
is responsible for most input/output,
including the printer routines. SPEED.1
is the largest file in the linked
chain. UMOVE is a high-speed memory
move routine. It gets its speed from
selfmodifying code (the $FFFFs at
MOVLOOP are replaced by actual
addresses when UMOVE is called). UMOVE
is used to move an overlapping range of
memory upward (toward location 0), so
it is used to delete. Set FROML/FROMH
to point to the source area of memory,
DESTL/DESTH to point to the
destination, and LLEN/HLEN to hold the
length of the area being moved.

UMOVE         LDA FROML
              STA MOVLOOP+1
              LDA FROMH
              STA MOVLOOP+2
              LDA DESTL
              STA MOVLOOP+4
              LDA DESTH
              STA MOVLOOP+5
              LDX HLEN
              BEQ SKIPMOV
MOV1          LDA #0
MOV2          STA ENDPOS
              LDY #0
MOVLOOP       LDA $FFFF,Y
    STA $FFFF,Y
    INY
    CPY ENDPOS
    BNE MOVLOOP
    INC MOVLOOP+2
    INC MOVLOOP+5
    CPX #0
    BEQ OUT
    DEX
    BNE MOV1
SKIPMOV LDA LLEN
    BNE MOV2
OUT RTS

DMOVE uses the same variables as UMOVE,
but it is used to move an overlapping
block of memory downward (toward
location $FFFF), so it is used to
insert. If the block of memory to be
moved does not overlap the destination
area, then either routine can be used.

DMOVE LDA HLEN
    TAX
    ORA LLEN
    BNE NOTNULL
    RTS
NOTNULL CLC
    TXA
    ADC FROMH
    STA DMOVLOOP+2
    LDA FROML
    STA DMOVLOOP+1
    CLC
    TXA
    ADC DESTH
    STA DMOVLOOP+5
    LDA DESTL
    STA DMOVLOOP+4
    INX
    LDY LLEN
    BNE DMOVLOOP
    BEQ SKIPDMOV
DMOV1 LDY #255
DMOVLOOP LDA $FFFF,Y
    STA $FFFF,Y
    DEY
    CPY #255
    BNE DMOVLOOP
SKIPDMOV DEC DMOVLOOP+2
    DEC DMOVLOOP+5
    DEX
    BNE DMOV1
    RTS

REFRESH copies a screenful of text from
the area of memory pointed to by
TOPLIN. It works like a printer
routine, fitting a line of text between
the screen margins, wrapping words, and
restarts at the left margin after
printing a carriage return. SpeedScript
constantly calls this routine while the
cursor is blinking, so it has to be
very fast. To eliminate flicker, it
clears out the end of each line instead
of first clearing the screen. It stores
the length of the first screen line for
the sake of the CHECK routine (which
scrolls up by adding that length to
TOPLIN) and the last text location
referenced (so CHECK can see if the
cursor has moved off the visible
screen). REFRESH can automatically
handle different screen widths.

REFRESH LDA #40
    INY
    CLC

RLM: Left margin. Location $58/$59
points to the address of screen memory.


    ADC RLM
    CLC
    ADC $58
    STA SCR
    LDA $59
    ADC #0
    STA SCR+1

TOPLIN points to the first character
within text to be printed at the
top-left comer of the screen.


    CLC
    LDA TOPLIN
    STA TEX
    LDA TOPLIN+1
    STA TEX+1
    LDX #1
    LDA INSMODE
    STA WINDCOLR
PPAGE LDY #0
PLINE LDA (TEX),Y
    STA LBUFF,Y
    INY
    AND #127
    CMP #RETCHAR
    BEQ BREAK
    CPY LINELEN
    BNE PLINE
    DEY
SLOOP LDA (TEX),Y
    AND #127
NXCUR CMP #SPACE
    BEQ SBRK
    DEY
    BNE SLOOP
    LDY LINELEN
    DEY
SBRK INY
BREAK STY TEMP
    LDY #0
COPY LDA LBUFF,Y
    STA (SCR),Y
    INY
    CPY TEMP
    BNE COPY
    CLC
    TYA
    ADC TEX
    STA TEX
    LDA TEX+1
    ADC #0
    STA TEX+1
    CPX #1
    BNE CLRLN
    STY LENTABLE
CLRLN CPY LINELEN
    BEQ CLEARED

Character #64 (ATASCII value of O)
fills the gap when a line is broken. It
can be redefined to show or not show
these false spaces.

    LDA #64
    STA (SCR),Y
    INY
    JMP CLRLN
CLEARED CLC
    LDA SCR
    ADC #40
    STA SCR
    BCC INCNOT
    INC SCR+1
INCNOT INX
    CPX #19
    BEQ PDONE
    JMP PPAGE
PDONE LDA TEX
    STA BOTSCR
    LDA TEX+1
    STA BOTSCR+1
    RTS

The following routine fills the entire
text area with space characters (screen
code 0), effectively erasing all text.
It is called when the program is first
run and when an Erase All is performed.
It also initializes the cursor position
(CURR) and the end-of-text pointer
(LASTLINE).

ERASE LDA TEXSTART
    STA TEX
    STA TOPLIN
    STA LASTLINE
    STA CURR
    LDA TEXSTART+1
    STA TEX+1
    STA TOPLIN+1
    STA LASTLINE+1
    STA CURR+1
    SEC
    LDA TEXEND+1
    SBC TEXSTART+1
    TAX
    LDA #SPACE
CLRLOOP LDY #255
    DEC TEX+1
    STA (TEX),Y
    INY
    INC TEX+1
CLR2 STA (TEX),Y
    INY
    BNE CLR2
    INC TEX+1
    DEX
    BNE CLR2
    STA (TEX),Y
    RTS

PRMSG is used anytime we need to print
something at the top of the screen (the
command line). Pass it the address of
the message to be printed by storing
the low byte of the address in the
accumulator and the high byte in the Y
register. The message in memory must
end with a zero byte. The routine does
not add a carriage return. CHROUT
(character out) prints the character in
the accumulator to the screen. CHROUT
is a subroutine in the SUPPORT package.

PRMSG STA TEMP
    STY TEMP+1
    LDA #1
    STA 752
    LDY #0
PRLOOP LDA (TEMP),Y
    BEQ PREXIT
    JSR CHROUT
    INY
    BNE PRLOOP
PREXIT RTS
GETAKEY JSR GETIN
    BEQ GETAKEY
    RTS
JDOS JSR PREXIT
    LDA BLINK
    BEQ NOBLINK
    LDY #0
    LDA UNDERCURS
    STA (CURR),Y
NOBLINK JSR INIT2
    JMP MAIN

The initialization routine sets up the
memory map, clears out certain flags,
and enables the display-list interrupt.

INIT LDA #125
    JSR CHROUT
    LDA #0
    STA INSMODE
    STA TEXSTART
    STA TEXEND
    STA TEXBUF
    STA BUFEND
    STA HUNTLEN
    STA REPLEN
    STA ESCFLAG
    STA SHFLOK
    STA RLM
    LDA #40
    STA LINELEN

Label END is at the end of the source
code, so it points to the last address
used by the object code. We use it to
calculate the start-of-text memory.

    LDA # >END
    CLC
    ADC #1
    STA TEXSTART+1

Location 561 points to the display
list, which holds screen information at
the top of memory. We use it as the
last address available for storing text
or buffer text.

    LDA 561
    SEC
    SBC #1
    STA BUFEND+1
    SEC
    SBC #8
    STA TEXBUF+1
    SEC
    SBC #1
    STA TEXEND+1
    LDA #$FF
    STA FPOS+1

If location $4B is 0, then SpeedScript
is booted from disk. if we booted from
cassette, we free up the DOS area
($0700-$1E00) for use as the text
buffer, and free up the text memory
used by disk-based SpeedScript as the
text buffer.

    LDA $4B
    BEQ DISKBOOT
    LDA BUFEND+1
    STA TEXEND+1
    LDA #$07
    STA TEXBUF+1
    LDA #$1E
    STA BUFEND+1
DISKBOOT RTS

The second initialization routine turns
on the display-list interrupt (HIGH-
LIGHT), homes the cursor, and prints
the credit line.


INIT2 JSR HIGHLIGHT
    LDA TEXSTART
    STA CURR
    LDA TEXSTART+1
    STA CURR+1
    JSR REFRESH
    JSR SYSMSG
    LDA # <MSG2
    LDY # >MSG2
    JSR PRMSG
    INC MSGFLG
    JMP CHECK

SYSMSG displays "SpeedScript 3.0." The
message flag (MSGFLG) is set when a
message is to be left on the screen
only until the next keystroke. After
that keystroke, SYSMSG is called. The
INIT2 routine prints the credit line
with the MSGFLG set so that you won't
have to stare at the author's name
while you're writing--a modesty
feature.

SYSMSG JSR TOPCLR
    LDA # <MSG1
    LDY # >MSG1
    JSR PRMSG
    LDA #0
    STA MSGFLG
    RTS

TOPCLR keeps the command line clean. It
is called before most messages. It's
like a one-line clear-screen. It also
forces the left margin (82) to 0, and
homes the cursor to the beginning of
the command line by zeroing out the X
and Y cursor positions (84 and 85).

TOPCLR LDY #39
    LDA #SPACE
TOPLOOP STA ($58),Y
    DEY
    BPL TOPLOOP
    LDA #0
    STA 82
    STA 85
    STA 84
    RTS

Convert ATASCII to screen codes

ASTOIN PHA
    AND #128
    STA TEMP
    PLA
    AND #127
    CMP #96
    BCS LOWR
    CMP #32
    BCS NOTCTRL
    CLC
    ADC #64
    JMP LOWR
NOTCTRL SEC
    SBC #32
LOWR ORA TEMP
    RTS

The MAIN loop blinks the cursor, checks
for keystrokes, converts them from
ATASCII to screen codes, puts them in
text at the CURRent position, and
increments the CURRent position and
LASTLINE. It also checks for special
cases like the RETURN key and passes
control characters to the CONTROL
routine. The INSMODE flag is checked to
see if we should insert a space before
a character.

MAIN LDY #0
    STY BLINK
    LDA (CURR),Y
    STA UNDERCURS
MAIN2 LDY #0
    STY SELFLAG
    LDA (CURR),Y
    EOR #$80
    STA (CURR),Y
    LDA BLINK
    EOR #1
    STA BLINK
    JSR REFRESH
WAIT JSR GETIN
    BNE KEYPRESS

We check for the START key, and if
pressed, go to the HOME cursor routine.

    LDA #8
    STA 53279
    LDA 53279
    CMP #6
    BNE FLIPIT
    LDY #0
    STY BLINK
    LDA UNDERCURS
    STA (CURR),Y
    JSR HOME
    JMP MAIN

The realtime clock (location 20), which
counts in 1/60 seconds, is checked for
16/60 seconds (about 1/5 second) to see
if it's time to blink the cursor.

FLIPIT LDA 20
    AND #16
    BEQ WAIT
    LDA #0
    STA 20
    JMP MAIN2

A key has been pressed. We check the
SELECT key to see if the keystroke
should be inverted.

KEYPRESS TAX
    LDA #8
    STA 53279
    LDA 53279
    CMP #5
    BNE NOTSEL
    LDA #128
    STA SELFLAG
NOTSEL LDY #0
    LDA UNDERCURS
    STA (CURR),Y
NOTBKS LDA MSGFLG
    BEQ NOMSG
    TXA
    PHA
    JSR SYSMSG
    PLA
    TAX
NOMSG TXA
    CMP #155
    BNE NOTCR

Change a carriage return into a back
arrow.

    LDX #30
    JMP OVERCTRL
NOTCR TXA
    BIT ESCFLAG
    BMI OVERCTRL
    CMP #156
    BCS CONTROL
    AND #127
    CMP #32
    BCC CONTROL
    CMP #123
    BCS CONTROL
    CMP #92
    BEQ CONTROL
    CMP #94
    BEQ CONTROL
    CMP #95
    BEQ CONTROL
OVERCTRL TXA
    PHA
    LDY #0
    STY ESCFLAG
    LDA (CURR),Y
    CMP #RETCHAR
    BEQ DOINS
    LDA INSMODE
    BEQ NOINST
DOINS JSR INSCHAR
NOINST PLA
    JSR ASTOIN
    AND #127
    ORA SELFLAG
    LDY #0

Put the character into memory.

    STA (CURR),Y
    JSR REFRESH
    SEC
    LDA CURR
    SBC LASTLINE
    STA TEMP
    LDA CURR+1
    SBC LASTLINE+1
    ORA TEMP
    BCC INKURR
    LDA CURR
    ADC #0
    STA LASTLINE
    LDA CURR+1
    ADC #0
    STA LASTLINE+1

Move the cursor forward.

INKURR INC CURR
    BNE NOINC2
    INC CURR+1
NOINC2 JSR CHECK
    JMP MAIN

CONTROL looks up a keyboard command in
the list of control codes at CTBL. The
first byte of CTBL is the actual number
of commands. Once the position is
found, this position is doubled as an
index to the two-byte address table at
VECT. The address of MAIN-1 is put on
the stack, simulating the return
address; then the address of the
command routine taken from VECT is
pushed. We then perform an RTS. RTS
pulls the bytes off the stack as if
they were put there by a JSR. This
powerful technique is used to simulate
ON-GOTO in machine language.

CONTROL LDX CTBL
SRCH CMP CTBL,X
    BEQ FOUND
    DEX
    BNE SRCH
    JMP MAIN
FOUND DEX
    TXA
    ASL A
    TAX
    LDA # >MAIN-1
    PHA
    LDA # <MAIN-1
    PHA
    LDA VECT+1,X
    PHA
    LDA VECT,X
    PHA
    RTS
CTBL .BYTE 35
    .BYTE 31,30,92,94,2,20,28,29
    .BYTE 126,255,4
    .BYTE 9,125,124,95,5,12,19
    .BYTE 13,18,24,26,16
    .BYTE 254,1,11,6,21,127,157
    .BYTE 3,7,156,27,15
VECT .WORD RIGHT-1,LEFT-1,WLEFT-1,WRIGHT-1,BORDER-1,LETTERS-1
    .WORD SLEFT-1,SRIGHT-1,DELCHAR-1,INSCHAR-1,DELETE-1
    .WORD INSTGL-1,CLEAR-1,PARIGHT-1,PARLEFT-1
    .WORD ERAS-1,TLOAD-1,TSAVE-1
    .WORD DOS-1,INSBUFFER-1,SWITCH-1
    .WORD ENDTEX-1,PRINT-1
    .WORD DELIN-1,ALPHA-1,KILLBUFF-1,HUNT-1,FREEMEM-1,TAB-1
    .WORD LOTTASPACE-1,REPSTART-1,SANDR-1,EATSPACE-1,ESC-1,ONOFF-1

Toggle ESCape mode.

ESC LDA ESCFLAG
    EOR #128
    STA ESCFLAG
    RTS

Change the character definition of the
character used to fill in the end of a
line. It alternates between being a
blank space, and being a blank space
with a tiny dot visible. This lets you
see which spaces are actually part of
your text and which are just used to
parse the screen. Beware of the address
$2204 if you reassemble at a different
address (sorry, I didn't use a label).

ONOFF LDA $2204
    EOR #16
    STA $2204
    RTS

The CHECK routine first prevents the
cursor from disappearing past the
beginning or end-of-text memory and
prevents us from cursoring past the
end-of-text pointer. It also checks to
see if the cursor has left the visible
screen, scrolling with REFRESH to make
the cursor visible. The double-byte
SBCs are used as a 16-bit CMP macro,
setting the Z and C flags just like CMP
does.

CHECK JSR CHECK2
    SEC
    LDA CURR
    SBC TOPLIN
    LDA CURR+1
    SBC TOPLIN+1
    BCS OK1
    SEC
    LDA TOPLIN
    SBC TEXSTART
    STA TEMP
    LDA TOPLIN+1
    SBC TEXSTART+1
    ORA TEMP
    BEQ OK1
    LDA CURR
    STA TOPLIN
    LDA CURR+1
    STA TOPLIN+1
    JSR REFRESH
OK1 SEC
    LDA BOTSCR
    SBC CURR
    STA TEX
    LDA BOTSCR+1
    SBC CURR+1
    STA TEX+1
    ORA TEX
    BEQ EQA
    BCS OK2
EQA CLC
    LDA TOPLIN
    ADC LENTABLE
    STA TOPLIN
    LDA TOPLIN+1
    ADC #0
    STA TOPLIN+1
REF JSR REFRESH
    JMP OK1
OK2 RTS
CHECK2 SEC
    LDA LASTLINE
    SBC TEXEND
    STA TEMP
    LDA LASTLINE+1
    SBC TEXEND+1
    ORA TEMP
    BCC CK3
    LDA TEXEND
    STA LASTLINE
    LDA TEXEND+1
    STA LASTLINE+1
CK3 SEC
    LDA CURR
    SBC TEXSTART
    STA TEMP
    LDA CURR+1
    SBC TEXSTART+1
    ORA TEMP
    BCS INRANGE
    LDA TEXSTART
    STA CURR
    LDA TEXSTART+1
    STA CURR+1
    RTS
INRANGE SEC
    LDA CURR
    SBC LASTLINE
    STA TEMP
    LDA CURR+1
    SBC LASTLINE+1
    ORA TEMP
    BCS OUTRANGE
    RTS
OUTRANGE LDA LASTLINE
    STA CURR
    LDA LASTLINE+1
    STA CURR+1
    RTS

Move cursor right. If the OPTION key is
held down, we instead increase the line
length.

RIGHT
    LDA #8
    STA 53279
    LDA 53279
    CMP #3
    BNE CRIGHT
    LDA LINELEN
    CMP #40
    BEQ NOBIGGER
    INC LINELEN
    INC LINELEN
    DEC RLM
    JSR REFRESH
    JSR CHECK
    LDA #125
    JSR CHROUT
NOBIGGER JMP SYSMSG
CRIGHT INC CURR
    BNE NOINCR
    INC CURR+1
NOINCR JMP CHECK

Move cursor left. If the OPTION key is
held down, we instead decrease the line
length.

LEFT LDA #8
    STA 53279
    LDA 53279
    CMP #3
    BNE CLEFT
    LDA LINELEN
    CMP #2
    BEQ TOOSMALL
    DEC LINELEN
    DEC LINELEN
    INC RLM
    JSR REFRESH
    JSR CHECK
    LDA #125
    JSR CHROUT
TOOSMALL JMP SYSMSG
CLEFT LDA CURR
    BNE NODEC
    DEC CURR+1
NODEC DEC CURR
    JMP CHECK

Word left. We look backward for a space.

WLEFT LDA CURR
    STA TEX
    LDA CURR+1
    STA TEX+1
    DEC TEX+1
    LDY #$FF
STRIP LDA (TEX),Y
    CMP #SPACE
    BEQ STRLOOP
    CMP #RETCHAR
    BNE WLOOP
STRLOOP DEY
    BNE STRIP
WLOOP LDA (TEX),Y
    CMP #SPACE
    BEQ WROUT
    CMP #RETCHAR
    BEQ WROUT
    DEY
    BNE WLOOP
    RTS
WROUT SEC
    TYA
    ADC TEX
    STA CURR
    LDA TEX+1
    ADC #0
    STA CURR+1
    JMP CHECK

Word right. We scan forward for a
space. OIDS is not a meaningful label.

WRIGHT LDY #0
RLOOP LDA (CURR),Y
    CMP #SPACE
    BEQ ROUT
    CMP #RETCHAR
    BEQ ROUT
    INY
    BNE RLOOP
    RTS
ROUT INY
    BNE OIDS
    INC CURR+1
    LDA CURR+1
    CMP LASTLINE+1
    BCC OIDS
    BNE LASTWORD
OIDS LDA (CURR),Y
    CMP #SPACE
    BEQ ROUT
    CMP #RETCHAR
    BEQ ROUT

Add the Y register to the CURRent
cursor position to move the cursor.
CHECK prevents illegal cursor movement.
LASTWORD is called if the end of the
word cannot be found before we reach
the end-of-text.

ADYCURR CLC
    TYA
    ADC CURR
    STA CURR
    LDA CURR+1
    ADC #0
    STA CURR+1
WRTN JMP CHECK
LASTWORD LDA LASTLINE
    STA CURR
    LDA LASTLINE+1
    STA CURR+1
    JMP CHECK

ENDTEX is tricky. If the end-of-text
pointer would point to an area already
visible on the screen, we just move the
cursor there and call REFRESH.
Otherwise, we step back 1K from the
end-of-text and then scroll to the end.
This is necessary since in the worst
case only 18 characters of return-marks
would fill the screen.

ENDTEX LDA #0
    STA TOPLIN
    LDA LASTLINE+1
    SEC
    SBC #4
    CMP TEXSTART+1
    BCS SAFE
    LDA TEXSTART+1
SAFE STA TOPLIN+1
    JSR REFRESH
    JMP LASTWORD

Change the border color. The display
list interrupt automatically places
SCRCOL into the hardware background
color register #2.

BORDER INC SCRCOL
    INC SCRCOL
    RTS
SCRCOL .BYTE 8

Change text luminance. TEXCOLR is
stored into hardware color register #1
during the display-list interrupt.

LETTERS INC TEXCOLR
    INC TEXCOLR
    LDA TEXCOLR
    AND #15
    STA TEXCOLR
    RTS
TEXCOLR .BYTE 2

Sentence left. We look backward for
ending punctuation or a return-mark,
then go forward until we run out of
spaces.

SLEFT LDA CURR
    STA TEX
    LDA CURR+1
    STA TEX+1
    DEC TEX+1
    LDY #$FF
PMANY LDA (TEX),Y
    CMP #'.-32
    BEQ PSRCH
    CMP #'!-32
    BEQ PSRCH
    CMP #'?-32
    BEQ PSRCH
    CMP #RETCHAR
    BNE PSLOOP
PSRCH DEY
    BNE PMANY
    RTS
PSLOOP LDA (TEX),Y
    CMP #'.-32
    BEQ PUNCT
    CMP #'!-32
    BEQ PUNCT
    CMP #'?-32
    BEQ PUNCT
    CMP #RETCHAR
    BEQ PUNCT
    DEY
    BNE PSLOOP
    DEC TEX+1
    LDA TEX+1
    CMP TEXSTART
    BCS PSLOOP
    JMP FIRSTWORD
PUNCT STY TEMP
    DEC TEMP
SKIPSPC INY
    BEQ REPEAT
    LDA (TEX),Y
    CMP #SPACE
    BEQ SKIPSPC
    DEY
    JMP WROUT
REPEAT LDY TEMP
    JMP PSLOOP
FIRSTWORD LDA TEXSTART
    STA CURR
    LDA TEXSTART+1
    STA CURR+1
    JMP CHECK

Sentence right. We look forward for
ending punctuation, then skip forward
until we run out of spaces.

SRIGHT LDY #0
SRLP LDA (CURR),Y
    CMP #'.-32
    BEQ PUNCT2
    CMP #'!-32
    BEQ PUNCT2
    CMP #'?-32
    BEQ PUNCT2
    CMP #RETCHAR
    BEQ PUNCT2
    INY
    BNE SRLP
    INC CURR+1
    LDA CURR+1
    CMP LASTLINE+1
    BEQ SRLP
    BCC SRLP
SREXIT JMP LASTWORD
PUNCT2 INY
    BNE NOFIXCURR
    INC CURR+1
    LDA CURR+1
    CMP LASTLINE+1
    BCC NOFIXCURR
    BEQ NOFIXCURR
    JMP LASTWORD
NOFIXCURR LDA (CURR),Y
    CMP #SPACE
    BEQ PUNCT2
    CMP #'.-32
    BEQ PUNCT2
    CMP #'!-32
    BEQ PUNCT2
    CMP #'?-32
    BEQ PUNCT2
    CMP #RETCHAR
    BEQ PUNCT2
    JMP ADYCURR

The text buffer starts at a fixed
location, but the end of the buffer is
changed as text is added to it. To
clear the buffer, we just set the end
of the buffer to the value of the start
of the buffer. No text is actually
erased.

KILLBUFF LDA TEXBUF
    STA TPTR
    LDA TEXBUF+1
    STA TPTR+1
    JSR TOPCLR
    LDA # <KILLMSG
    LDY # >KILLMSG
    JSR PRMSG
    LDA #1
    STA MSGFLG
    RTS

This is the second level of the
general-purpose delete routines. UMOVE
is the primitive core of deleting. For
CTRL-D, the CURRent cursor position is
the source; then a cursor command is
called to update the cursor pointer.
This becomes the destination. For
CTRL-E, the CURRent cursor position is
the destination; a cursor movement
routine is called, and this becomes the
source. UMOVE is then called. We
actually move more than the length from
the source to the end-of-text. Some
extra text is moved from past the
end-of-text. Since everything past the
end-of-text is spaces, this neatly
erases everything past the new
end-of-text position. Naturally, the
end-of-text pointer is updated. Before
the actual delete is performed, the
text to be deleted is stored in the
buffer so that it can be recalled in
case of error. The buffer doubles as a
fail-safe device, and for moving and
copying text. Checks are made to make
sure that the buffer does not overflow.

DEL1 SEC
    LDA CURR
    SBC TEXSTART
    STA TEMP
    LDA CURR+1
    SBC TEXSTART+1
    ORA TEMP
    BNE DEL1A
DELABORT PLA
    PLA
    RTS
DEL1A LDA CURR
    STA FROML
    LDA CURR+1
    STA FROMH
    RTS
DEL2 SEC
    LDA CURR
    STA DESTL
    EOR #$FF
    ADC FROML
    STA GOBLEN
    LDA CURR+1
    STA DESTH
    EOR #$FF
    ADC FROMH
    STA GOBLEN+1
DELC LDA FROML
    STA FROMSAV
    LDA FROMH
    STA FROMSAV+1
    LDA DESTL
    STA DESTSAV
    STA FROML
    LDA DESTH
    STA DESTSAV+1
    STA FROMH
    SEC
    LDA GOBLEN+1
    ADC TPTR+1
    CMP BUFEND+1
    BCC GOSAV
    JSR TOPCLR
    LDA # <BUFERR
    LDY # >BUFERR
    JSR PRMSG
    LDA #1
    STA MSGFLG
    RTS
GOSAV LDA TPTR
    STA DESTL
    LDA TPTR+1
    STA DESTH
    LDA GOBLEN
    STA LLEN
    CLC
    ADC TPTR
    STA TPTR
    LDA GOBLEN+1
    STA HLEN
    ADC TPTR+1
    STA TPTR+1
    JSR UMOVE
    LDA FROMSAV
    STA FROML
    LDA FROMSAV+1
    STA FROMH
    LDA DESTSAV
    STA DESTL
    LDA DESTSAV+1
    STA DESTH
    SEC
    LDA LASTLINE
    SBC DESTL
    STA LLEN
    LDA LASTLINE+1
    SBC DESTH
    STA HLEN
    JSR UMOVE
    SEC
    LDA LASTLINE
    SBC GOBLEN
    STA LASTLINE
    LDA LASTLINE+1
    SBC GOBLEN+1
    STA LASTLINE+1
    RTS

Most delete commands end up calling the
above routines. The single-character
deletes must subtract 1 from the buffer
pointer so that single characters are
not added to the buffer. But note how
short these routines are.

Delete character (BACK S)

DELCHAR JSR DEL1
    JSR LEFT
    JSR DEL2
FIXTP SEC
    LDA TPTR
    SBC #1
    STA TPTR
    LDA TPTR+1
    SBC #0
    STA TPTR+1
    RTS

CTRL-BACK S

DELIN JSR RIGHT
    JSR DEL1
    JSR LEFT
    JSR DEL2
    JMP FIXTP

Called by CTRL-D. As mentioned, it
stores CURR into FROML/FROMH, moves the
cursor either by sentence, word, or
paragraph, then stores the new position
of CURR into DESTL and DESTH. The above
routines perform the actual delete.
CTRL-D always discards the previous
contents of the buffer, for deleting
text backward creates a buffer of
out-of-order text. Notice how we change
the color of the command window to red
to warn the user of the impending
deletion.

DELETE JSR KILLBUFF
    LDA #RED
    STA WINDCOLR
    JSR TOPCLR
    LDA # <DELMSG
    LDY # >DELMSG
    JSR PRMSG
    JSR GETAKEY
    PHA
    JSR SYSMSG
    PLA
    AND #95
    ORA #64
    CMP #'W
    BNE NOTWORD
DELWORD JSR DEL1
    JSR WLEFT
    JMP DEL2
NOTWORD CMP #'S
    BNE NOTSENT
DELSENT JSR DEL1
    JSR SLEFT
    JMP DEL2
NOTSENT CMP #'P
    BNE NOTPAR
    JSR DEL1
    JSR PARLEFT
    JMP DEL2
NOTPAR RTS

Home the cursor. This is called by the
START key. We check to see if START is
held down for at least 1/2 second. If
it is, we move the cursor to the top of
text.

HOME SEC
    LDA CURR
    SBC TOPLIN
    STA TEMP
    LDA CURR+1
    SBC TOPLIN+1
    ORA TEMP
    BEQ TOPHOME
    LDA TOPLIN
    STA CURR
    LDA TOPLIN+1
    STA CURR+1
WAITST LDA #0
    STA 20
    STA 53279
HOMEPAUSE LDA 20
    CMP #30
    BNE HOMEPAUSE
OUTHOME JMP CHECK
TOPHOME LDA TEXSTART
    STA CURR
    LDA TEXSTART+1
    STA CURR+1
    JMP WAITST

This deletes all spaces between the
cursor and following nonspace text.
Sometimes inventing labels can be fun.

EATSPACE LDA CURR
    STA TEX
    STA DESTL
    LDA CURR+1
    STA TEX+1
    STA DESTH
    LDY #0
SPCSRCH LDA (TEX),Y
    CMP #SPACE
    BNE OUTSPACE
    INY
    BNE SPCSRCH
    LDA TEX+1
    CMP LASTLINE+1
    BCC GOINC
    LDA LASTLINE
    STA TEX
    LDA LASTLINE+1
    STA TEX+1
    LDY #0
    JMP OUTSPACE
GOINC INC TEX+1
    JMP SPCSRCH
OUTSPACE CLC
    TYA
    ADC TEX
    STA FROML
    LDA #0
    ADC TEX+1
    STA FROMH
    SEC
    LDA LASTLINE
    SBC DESTL
    STA LLEN
    LDA LASTLINE+1
    SBC DESTH
    STA HLEN
    SEC
    LDA FROML
    SBC DESTL
    STA GOBLEN
    LDA FROMH
    SBC DESTH
    STA GOBLEN+1
    JSR UMOVE
    SEC
    LDA LASTLINE
    SBC GOBLEN
    STA LASTLINE
    LDA LASTLINE+1
    SBC GOBLEN+1
    STA LASTLINE+1
    RTS

Insert 255 spaces. Notice how it and
other insert routines use TAB2.

LOTTASPACE LDA #255
    STA INSLEN
    JMP TAB2
TAB LDA #5
    STA INSLEN
    JSR TAB2
    LDA (CURR),Y
    CMP #SPACE
    BNE NOINCY
    INY
NOINCY JMP ADYCURR
TAB2 LDA #0
    STA INSLEN+1
    JSR INSBLOCK
    LDA #SPACE
    LDX INSLEN
    LDY #0
FILLSP STA (CURR),Y
    INY
    DEX
    BNE FILLSP
    RTS

Insert a single space.

INSCHAR LDA #1
    STA INSLEN
    LDA #0
    STA INSLEN+1
    JSR INSBLOCK
    LDA #SPACE
    LDY #0
    STA (CURR),Y
    JMP CHECK

A general routine to insert as many
spaces as are specified by INSLEN.

INSBLOCK CLC
    LDA LASTLINE
    ADC INSLEN
    LDA LASTLINE+1
    ADC INSLEN+1
    CMP TEXEND+1
    BCC OKINS
    PLA
    PLA
    JMP INOUT
OKINS CLC
    LDA CURR
    STA FROML
    ADC INSLEN
    STA DESTL
    LDA CURR+1
    STA FROMH
    ADC INSLEN+1
    STA DESTH
    SEC
    LDA LASTLINE
    SBC FROML
    STA LLEN
    LDA LASTLINE+1
    SBC FROMH
    STA HLEN
    JSR DMOVE
    CLC
    LDA LASTLINE
    ADC INSLEN
    STA LASTLINE
    LDA LASTLINE+1
    ADC INSLEN+1
    STA LASTLINE+1
INOUT RTS

Toggle insert mode. The INSMODE nag
doubles as the color of the command
line.

INSTGL LDA INSMODE
    EOR #BLUE
  STA INSMODE
  RTS

Another example of modular code. This
is called anytime a yes/no response is
called for. It prints "Are you sure?
(Y/N)," then returns with the zero flag
set to true if Y was pressed, ready for
the calling routine to use BEQ or BNE
as a branch for yes or no. We trap out
the clear-screen key in case this
routine is called by Erase All, since
otherwise repeating keys may instantly
cancel the command. The AND #223 zaps
out the distinction between uppercase
and lowercase Y.

YORN LDA # <YMSG
  LDY # >YMSG
  JSR PRMSG
YORNKEY JSR GETIN
  AND #127
  BEQ YORNKEY
  CMP #125
  BEQ YORNKEY
  AND #223
  CMP #'Y
  RTS

Erase all text. Allowed only if the
OPTION key is held down with
SHIFT-CLEAR. It calls YORN to affirm
the deadly deed, then calls ERASE to
erase all text, INIT2 to reset some
flags, then jumps back to the MAIN
loop. LDX #$FA / TXS is used to clean
up the stack.

CLEAR LDA #8
  STA 53279
  LDA 53279
  CMP #3
  BEQ OKCLEAR
  RTS
OKCLEAR LDA #RED
  STA WINDCOLR
  JSR TOPCLR
  LDA # <CLRMSG
  LDY # >CLRMSG
  JSR PRMSG
  JSR YORN
  BEQ DOIT
  JMP SYSMSG
DOIT LDX #$FA
  TXS
  JSR ERASE
  JSR INIT2
  JMP MAIN

Paragraph right.

PARIGHT LDY #0
PARLP LDA (CURR),Y
  CMP #RETCHAR
  BEQ RETFOUND
  INY
  BNE PARLP
  INC CURR+1
  LDA CURR+1
  CMP LASTLINE+1
  BCC PARLP
  BEQ PARLP
  JMP LASTWORD
RETFOUND INY
  BNE GOADY
  INC CURR+1
GOADY JMP ADYCURR

Paragraph left. Notice the trick of
decrementing the high byte of the
pointer, then starting the index at 255
in order to search backward.

PARLEFT LDA CURR
  STA TEX
  LDA CURR+1
  STA TEX+1
  DEC TEX+1
  LDY #$FF
PARLOOP LDA (TEX),Y
  CMP #RETCHAR
  BEQ RETF2
PARCONT DEY
  CPY #255
  BNE PARLOOP
  DEC TEX+1
  LDA TEX+1
  CMP TEXSTART+1
  BCS PARLOOP
  JMP FIRSTWORD
RETF2 SEC
  TYA
  ADC TEX
  STA TEX
  LDA #0
  ADC TEX+1
  STA TEX+1
  SEC
  LDA TEX
  SBC CURR
  STA TEMP
  LDA TEX+1
  SBC CURR+1
  ORA TEMP
  BNE TEXTOCURR
  STY TEMP
  CLC
  LDA TEX
  SBC TEMP
  STA TEX
  LDA TEX+1
  SBC #0
  STA TEX+1
  JMP PARCONT
TEXTOCURR LDA TEX
  STA CURR
  LDA TEX+1
  STA CURR+1
  JMP CHECK

This enables the display-list interrupt
(DLI). The DLI allows separate
background colors for the command line
and the rest of the screen. It lets us
change the color of the top line to
flag insert mode or to warn the user
with a red color that he/she should be
careful. Since it is an interrupt, it
is always running in the background.
Interrupt routines must always be
careful not to corrupt the main
program.

HIGHLIGHT turns off any DLIs (by
storing #64 into $D40E), sets the NMI
pointer ($200/$201), creates a custom
display list of IRG mode 3 (lowercase
descenders, GRAPHICS 0 1/2) With DLI
set in one line, then enables DLIs ($C0
into $D40E) and returns. The routine
DLI is now running constantly in the
background, changing the screen color
of all text below the DLI.

HIGHLIGHT LDA #64
  STA $D40E
  LDA # <DLI
  STA $0200
  LDA # >DLI
  STA $0201
  LDA 560
  STA TEMP
  LDA 561
  STA TEMP+1
  LDY #0
DLOOP LDA DLIST,Y
  STA (TEMP),Y
  INY
  CPY #28
  BNE DLOOP
  LDY #4
  LDA $58
  STA (TEMP),Y
  LDA $59
  INY
  STA (TEMP),Y
  LDY #26
  LDA TEMP
  STA (TEMP),Y
  LDA TEMP+1
  INY
  STA (TEMP),Y
  LDA #$C0
  STA $D40E
  RTS

The custom display list.

DLIST .BYTE 112,112,112,3+64+128,0,0
  .BYTE 3,3,3,3,3,3,3,3,3,3,3,3,3
  .BYTE 3,3,3,3,3,16,65,0,0

The display-list interrupt routine
stores the SCReen COLor and TEXt COLoR
into the appropriate hardware
registers, then stores the WINDow COLoR
into 710, and #10 into 709 to set the
color of the top line of the screen.
This line is automatically set by the
normal vertical- blank interrupt. We
also force the character-set pointer to
keep our character set in place
whenever we're on the editing screen.

DLI PHA
  LDA SCRCOL
  STA $D40A
  STA $D018
  STA 712
  LDA TEXCOLR
  STA $D017
  LDA WINDCOLR
  STA 710
  LDA #10
  STA 709
  LDA #$20
  STA 756
  LDA #0
  STA $02B6
  PLA
  RTI

ERAS is called by CTRL-E. It works much
like CTRL-D. Notice that the ORA #64
allows users to press either S, W, P,
or CTRL-S, CTRL-W, CTRL-P, in case they
have a habit of leaving the control key
held down. It must call RE- FRESH after
each move and adjust the new position
of the cursor. If OPTION is held down
with CTRL-E, we don't erase the
previous contents of the buffer,
letting the user chain non-contiguous
sections into the buffer for later
recall.


ERAS LDA #8
  STA 53279
  LDA 53279
  CMP #3
  BEQ ERAS1
  JSR KILLBUFF
ERAS1 JSR TOPCLR
  LDA # <ERASMSG
  LDY # >ERASMSG
  JSR PRMSG
ERASAGAIN LDY #0
  LDA (CURR),Y
  EOR #$80
  STA (CURR),Y
  JSR REFRESH
  LDY #0
  LDA (CURR),Y
  EOR #$80
  STA (CURR),Y
  LDA #RED
  STA WINDCOLR
  JSR GETAKEY
  AND #95
  ORA #64
  CMP #'W
  BNE NOWORD
ERASWORD JSR ERA1
  JSR WRIGHT
  JMP ERA2
NOWORD CMP #'S
  BNE UNSENT
ERASENT JSR ERA1
  JSR SRIGHT
  JMP ERA2
UNSENT CMP #'P
  BNE NOPAR
  JSR ERA1
  JSR PARIGHT
  JMP ERA2
NOPAR JSR CHECK
  JMP SYSMSG
ERA1 LDA CURR
  STA DESTL
  STA SAVCURR
  LDA CURR+1
  STA DESTH
  STA SAVCURR+1
  RTS
ERA2 SEC
  LDA CURR
  STA FROML
  SBC SAVCURR
  STA GOBLEN
  LDA CURR+1
  STA FROMH
  SBC SAVCURR+1
  STA GOBLEN+1
  JSR DELC
  LDA SAVCURR
  STA CURR
  LDA SAVCURR+1
  STA CURR+1
  JSR REFRESH
  JMP ERASAGAIN

The INPUT routine is used to get
responses from the command line. It
returns the complete line in INBUFF.
INLEN is the length of the input. A
zero byte is stored at INBUFF+INLEN
after the user presses RETURN. This
routine is foolproof (I know...), since
no control keys other than BACK S are
allowed, unless preceded by ESCape. The
SELECT key can be held down to enter
inverse-video characters. The system
cursor is turned on for this routine
(by putting #0 into 752), then turned
off when we exit (by putting #1 into
752). This routine also prevents the
user from typing past the end of the
command line. If the limit of typing
length must be set arbitrarily, LIMIT
is preset and INPUT is called at INP1.
CURSIN is the MAIN loop.

INPUT LDA #39
  SBC 85
  STA LIMIT
INP1 LDY #0
  STY INLEN
  STY 752
  LDA #32
  JSR CHROUT
  LDA #126
  JSR CHROUT
CURSIN STY INLEN
  JSR GETAKEY
  LDY INLEN
  BIT ESCFLAG
  BMI ESCKEY
  CMP #27
  BNE NOESC
  LDA #128
  STA ESCFLAG
  STA $02A2
  JMP CURSIN
NOESC CMP #155
  BEQ INEXIT
  CMP #126
  BNE NOBACK
  DEY
  BPL NOTZERO
  INY
  JMP CURSIN
NOTZERO LDA #126
  JSR CHROUT
  JMP CURSIN
NOBACK STA TEMP
  AND #127
  CMP #32
  BCC CURSIN
  CMP #125
  BCS CURSIN
  CPY LIMIT
  BEQ CURSIN
  LDA TEMP
ESCKEY AND #127
  LDX #8
  STX 53279
  LDX 53279
  CPX #5
  BNE SKIPSEL
  ORA #128
SKIPSEL STA INBUFF,Y
  JSR CHROUT
  LDA #0
  STA ESCFLAG
  INY
  JMP CURSIN
INEXIT LDX #1
  STX 752
  LDA #0
  STA INBUFF,Y
  TYA
  RTS
  .END
Filename: SUPPORT

This module supports most primitive
input/output functions, including a
routine to clear the screen and reset
the screen editor (OPENEDITOR), print a
character (CHROUT), and get a key from
the keyboard (GETAKEY).

OPENEDITOR LDX #0
      LDA #12
      STA ICCOM
      JSR CIO
      LDX #0
      LDA # <ENAME
      STA ICBADR
      LDA # >ENAME
      STA ICBADR+1
    LDA #2
    STA ICBLEN
    STX ICBLEN+1
    LDA #3
    STA ICCOM,X
    JMP CIO

Put the ATASCII value of the character
into the accumulator and call CHROUT
to print a character. The Y register is
preserved. We call CIO with a buffer
length of zero.

CHROUT STY CHRYSAVE
    LDX #0
    STX ICBLEN
    STX ICBLEN+1
    STX $02FF
    LDY #11
    STY ICCOM
    JSR CIO
    LDY CHRYSAVE
    RTS

The filename of the Editor device.

ENAME .BYTE "E:"

OUTNUM and PROUTNUM print decimal
numbers to the display or printer. The
integer to be printed is passed with
the low byte in the X register and the
high byte in the accumulator. The
integer to floating-point routine
($D9AA) is called first, followed by
floating-point to ATASCII routine,
which creates a string of ATASCII
digits. The last digit of the number
has bit 7 set, which we use to
terminate printing.

PROUTNUM LDY #128
    JMP OVERZAP
OUTNUM LDY #0
OVERZAP STY WHICHFLAG
    STX $D4
    STA $D5
    JSR $D9AA
    JSR $D8E6
    LDY #0
ONUMLOOP LDA ($F3),Y
    PHA
    AND #$7F
    BIT WHICHFLAG
    BMI GOPCHR
    JSR CHROUT
    JMP OVERPCHR
GOPCHR JSR PCHROUT
OVERPCHR PLA
    BMI ONUMEXIT
    INY
    BNE ONUMLOOP
ONUMEXIT RTS
CHRYSAVE .BYTE 0

The system keyboard fetch routine
interferes with the display-list
interrupt, since the blip of each key
is timed with WSYNC, which freezes the
ANTIC chip for one line. This causes
annoying flicker. This routine uses
POKEY sound decaying from volume 15 to
0 for the keyboard feedback tone. It's
not hard to create any sound effect you
want for the keyboard blip. This
routine mimics the system routine
fairly closely. It's easy to expand it
to allow many more keyboard functions
and full processing of new keystrokes
just by changing some of this code and
the keyboard table.

GETIN LDA 764
    CMP #$FF
    BNE GETCHAR
    LDA #0
    RTS
GETCHAR LDA 764
    CMP #$FF
    BEQ GETCHAR
    STA KEYVAL
    LDA #$FF
    STA 764

Clear break flag.

    STA $11
    JSR BLIP
    LDA KEYVAL

Check for SHIFT+CTRL.

    CMP #$C0
    BCS GXIT
    AND #63
    CMP #60
    BNE NOTCAPS
    LDA KEYVAL
    AND #64
    BEQ NOTSET
    STA SHFLOK
GXIT LDA #0
    RTS

The CAPS/LOWR key toggles the SHiFtLOcK
flag to allow either only uppercase, or
both uppercase and lowercase.

NOTSET LDA SHFLOK
    EOR #64
    STA SHFLOK
    LDA #0
    RTS
NOTCAPS LDX KEYVAL
    LDA KEYBOARD,X
    BIT SHFLOK
    BVC NOTLOCKED
    CMP #'a
    BCC NOTLOCKED
    CMP #'z+1
    BCS NOTLOCKED
    AND #223
NOTLOCKED CMP #$80
    BEQ GXIT
    RTS

The sound effect for the keyboard
"blip."

BLIP PHA
    LDA #50
    STA $D200
    LDX #$AF
SNDLOOP STX $D201
    LDY #128
SLOW DEY
    BNE SLOW
    DEX
    CPX #$9F
    BNE SNDLOOP
    PLA
    RTS
KEYBOARD .BYTE 108,106,59,128,128,107
    .BYTE 43,42,111,128,112,117
    .BYTE 155,105,45,61,118,128
    .BYTE 99,128,128,98,120,122
    .BYTE 52,128,51,54,27,53
    .BYTE 50,49,44,32,46,110
    .BYTE 128,109,47,$80,114,128
    .BYTE 101,121,127,116,119,113
    .BYTE 57,128,48,55,126,56
    .BYTE 60,62,102,104,100,128
    .BYTE 130,103,115,97,76,74
    .BYTE 58,128,128,75,92,94
    .BYTE 79,128,80,85,155,73
    .BYTE 95,124,86,128,67,128
    .BYTE 128,66,88,90,36,128
    .BYTE 35,38,27,37,34,33
    .BYTE 91,32,93,78,128,77
    .BYTE 63,$80,82,128,69,89
    .BYTE 159,84,87,81,40,128
    .BYTE 41,39,156,64,125,157
    .BYTE 70,72,68,128,131,71
    .BYTE 83,65,12,10,123,128
    .BYTE 128,11,30,31,15,128
    .BYTE 16,21,155,9,28,29
    .BYTE 22,128,3,128,128,2
    .BYTE 24,26,128,128,133,128
    .BYTE 27,128,253,128,0,32
    .BYTE 96,14,128,13,128,$80
    .BYTE 18,128,5,25,158,20
    .BYTE 23,17,128,128,128,128
    .BYTE 254,128,125,255,6,8
    .BYTE 4,128,132,7,19,1
    .END
Filename: DOSPAK

DOSPAK is a self-contained substitute
for the DOS menu, although it uses
several routines built into
SpeedScript. The concept of DOSPAK is
that all directory entries should fit
on one screen. A large cursor is used
to move from filename to filename. At
any time, you can delete, rename, lock,
unlock, or load the selected filename,
just by pressing one key, or a CTRL key
combination. Except for Rename, you
don't have to type the filename. You
can also format the entire disk or
redisplay the directory.

CATALOG fits the entire disk directory
onto the screen by skipping over the
sector counts, trimming up spacing, and
placing three items per line. The
cursor position of each filename is
saved into a slot in memory so that the
cursor routine can quickly and easily
skip about.

CATALOG JSR CLOSE7
      LDX #$70
      LDA # <DIRNAME
      STA ICBADR,X
      LDA # >DIRNAME
      STA ICBADR+1,X
      LDA #5
      STA ICBLEN,X
      LDA #0
    STA ICBLEN+1,X
    LDA #6
    STA ICAUX1,X
    LDA #3
    STA ICCOM,X
    JSR CIO
    BMI CLOSE7
    LDA #0
    STA XPTR
REDIR LDX XPTR
    LDA $64
    STA SLOT,X
    LDA $65
    STA SLOT+1,X
    INC XPTR
    INC XPTR
    JSR GET7
    BMI CLOSE7
    CMP #'*+1
    BCS ENDIR
    JSR CHROUT
    JSR GET7
    BMI CLOSE7
    LDA #0
    STA DIRCOUNT
DIRLOOP JSR GET7
    BMI CLOSE7
DNOTCR JSR CHROUT
    INC DIRCOUNT
    LDA DIRCOUNT
    CMP #8
    BNE DNOT8
    LDA #'.
    JSR CHROUT
    JMP DIRLOOP
DNOT8 CMP #11
    BNE DIRLOOP
    LDA #5
    STA TEMP
THROW5 JSR GET7
    DEC TEMP
    LDA TEMP
    BNE THROW5
    JMP REDIR
CLOSE7 LDX #$70
    LDA #12
    STA ICCOM,X
    JSR CIO
    LDX #$70
    LDY ICSTAT,X
    RTS
ENDIR PHA
    LDA #155
    JSR CHROUT
    PLA
    JSR CHROUT
ENDLP JSR GET7
    BMI CLOSE7
    JSR CHROUT
    JMP ENDLP
GET7 LDX #$70
    LDA #0
    STA ICBLEN,X
    STA ICBLEN+1,X
    LDA #7
    STA ICCOM,X
    JMP CIO

The main DOS routine calls the CATALOG
routine to fill the screen with
filenames, then puts the cursor on the
current filename, waiting for a
keypress.

DOS JSR DELITE
    JSR OPENEDITOR
    JSR DELITE
    LDA #1
    STA 752
    STA 82
    LDA #125
    JSR CHROUT
    JSR CATALOG
    JSR DOSMSG
GETNAME LDA SLOT
    STA SCR
    LDA SLOT+1
    STA SCR+1
    LDA #0
    STA XSLOT
    DEC XPTR
    DEC XPTR
NAMELP JSR INVNAME
    JSR GETAKEY
    LDX #1
    STX 752

Now that we've got a keypress, we look
it up in the keypress table, then
vector to the appropriate routine. This
is the same ML ON-GOTO routine that
we've used in several places in
SpeedScript, including the CONTROL
routine.

    LDX DOSTABLE
    CMP #97
    BCC NOPROB
    AND #95
NOPROB STA TEMP
FINDIT CMP DOSTABLE,X
    BEQ FOUNDIT
    DEX
    BNE FINDIT
    JMP JNAME
FOUNDIT DEX
    TXA
    ASL A
    TAX
    LDA DOSADR+1,X
    PHA
    LDA DOSADR,X
    PHA
    RTS

The braces surround control characters,
some entered with the ESCape key:
cursor-left, cursor-right, cursor-up,
cursor-down, CTRL-D, ESCape, and
CTRL-L.

DOSTABLE .BYTE 15
    .BYTE "{LEFT}{RIGHT}{UP}{DOWN}{D}RLUF1234{ESC}{L}"
DOSADR .WORD DLEFT-1,DRIGHT-1,DUP-1,DDOWN-1,DELFILE-1,RENAME-1
    .WORD LOCK-1,UNLOCK-1,FORMAT-1,DRIVE-1,DRIVE-1,DRIVE-1
    .WORD DRIVE-1,ESCDOS-1,LOADIT-1

Move bar cursor left by decrementing
slot pointer.


DLEFT JSR INVNAME
    LDX XSLOT
    BEQ NRANGE
    DEX
    DEX
    JMP RESLOT

Move bar cursor right by incrementing
slot pointer.

DRIGHT JSR INVNAME
    LDX XSLOT
    INX
    INX
    CPX XPTR
    BCS NRANGE

Store new slot index.

RESLOT STX XSLOT
    LDA SLOT,X
    STA SCR
    LDA SLOT+1,X
    STA SCR+1
NRANGE JMP NAMELP

Move bar cursor up by subtracting 6
from the slot pointer (each slot is two
bytes).

DUP JSR INVNAME
    LDA XSLOT
    CMP #6
    BCC NRANGE
    SEC
    SBC #6
    TAX
    JMP RESLOT

Move bar cursor down by adding 6 to
the slot pointer.

DDOWN JSR INVNAME
    LDA XSLOT
    CLC
    ADC #6
    CMP XPTR
    BCS NRANGE
    TAX
    JMP RESLOT

This routine turns a filename pointed
to by the bar cursor into a legal CIO
filename, complete with Dx: and legal
extension.

NAMER LDX #0
COPYD LDA DIRNAME,X
    STA FNBUFF,X
    INX
    CPX #3
    BNE COPYD
    LDY #1
COPYNAME LDA (SCR),Y
    AND #127
    JSR INTOAS
    CMP #32
    BEQ NOSTOR
    STA FNBUFF,X
    INX
NOSTOR INY
    CPY #13
    BNE COPYNAME
    LDA FNBUFF-1,X
    CMP #'.
    BNE NOTDOT
    DEX
NOTDOT STX FNLEN
    LDA #0
    STA FNBUFF,X
    RTS

This routine passes any CIO command
along with a formed filename.

XIO LDX #$70
    STA ICCOM,X
    LDA FNLEN
    STA ICBLEN,X
    LDA #0
    STA ICBLEN+1,X
    LDA # <FNBUFF
    STA ICBADR,X
    LDA # >FNBUFF
    STA ICBADR+1,X
    JMP CIO

The DOS functions are quite short.
NAMER builds the name; then we simply
pass the number of the DOS CIO function
unto XIO. If there's no error, we
return to waiting for the next
keystroke; otherwise, print the DOS
error message and wait for a keystroke.

DELFILE JSR NAMER
    LDA #33

Jump to the XIO routine.

GOXIO JSR XIO
    BPL JNAME
    JMP DOSERR
JNAME JSR INVNAME
    JMP NAMELP

Lock a file.

LOCK JSR NAMER
    LDA #35
    JMP GOXIO

Unlock a file.

UNLOCK JSR NAMER
    LDA #36
    JMP GOXIO

We ask for the new name of the file,
build the rename string, then jump to
the XIO routine.

RENAME JSR BOTCLR
    LDA # <RENMSG
    LDY # >RENMSG
    JSR PRMSG
    LDA #64
    STA $02BE
    JSR INPUT
    LDA #0
    STA $02BE
    LDA INLEN
    BEQ NONAME
    JSR NAMER
    LDX #0
    LDY FNLEN
    LDA #',
    STA FNBUFF,Y
    INY
COPYR LDA INBUFF,X
    STA FNBUFF,Y
    INY
    INX
    CPX INLEN
    BNE COPYR
    STY FNLEN
    LDA #0
    STA FNBUFF,Y
    JSR DOSMSG
    LDA #32
    JMP GOXIO
NONAME JSR DOSMSG
    JMP JNAME

Format routine. We use YORN to af firm
this operation, which erases an entire
disk. BOTCLR clears the bottom line of
the screen.

FORMAT JSR BOTCLR
    LDA # <FORMSG
    LDY # >FORMSG
    JSR PRMSG
    JSR YORN
    BNE NONAME
    JSR DOSMSG
    JSR NAMER
    LDA #254
    JMP GOXIO

Select new drive number and redisplay
directory.

DRIVE LDA TEMP
    STA DIRNAME+1
    JMP DOS

The Load-from-directory routine opens
the file, then jumps into the SpeedScript
Load routine.

LOADIT LDX #$70
    STX IOCB
    LDA #4
    STA ICAUX1,X
    LDA #0
    STA INDIR
    STA INDIR+1
    JSR NAMER

Command 3 is for OPEN file.

    LDA #3
    JSR XIO
    BMI DOSERR
    JSR ERASE
    JSR LOADLINK

If the load ended with an error, we
display the error; otherwise, we exit
the DOSPAK at ESCDOS.

    BMI DOSERR

The ESCape DOS routine clears the
stack, clears the screen, reenables the
display-list interrupt, prints the
"SpeedScript" message, then jumps back
to the editing loop.

ESCDOS LDX #$FA
    TXS
    LDA #125
    JSR CHROUT
    JSR HIGHLIGHT
    JSR SYSMSG
    JMP MAIN

BOTCLR erases the bottom two lines of
the screen by positioning the cursor on
the next-to-the-last line, then
printing two INSERT LINE characters
that push any text on these lines off
the bottom of the screen. Nifty, eh?

BOTCLR LDA #22
    STA 84
    LDA #157
    JSR CHROUT
    JMP CHROUT

This is the error routine for the
DOSPAK. We print "ERROR #", then print
the error number with OUTNUM, a bell
character (actually sounds like an
annoying buzzer, appropriate Pavlovian
treatment), then "Press RETURN." We
wait for a keystroke, then return to
getting keys for the DOSPAK commands.

DOSERR STY YSAVE
    JSR CLOSE7
    JSR BOTCLR
    LDA # <ERRMSG
    LDY # >ERRMSG
    JSR PRMSG
    LDX YSAVE
    LDA #0
    JSR OUTNUM
    LDA #253
    JSR CHROUT
    LDA # <DIRMSG
    LDY # >DIRMSG
    JSR PRMSG
    JSR GETAKEY
    JSR DOSMSG
    JMP JNAME

Inverse the filename field of the
currently selected filename. Used to
create the bar cursor.

INVNAME LDY #12
INVLP LDA (SCR),Y
    EOR #128
    STA (SCR),Y
    DEY
    BPL INVLP
    RTS

DOSMSG erases the bottom line of the
screen and prints the DOSPAK command
line, an abbreviated menu.

DOSMSG JSR BOTCLR
    LDA # <DIRINS
    LDY # >DIRINS
    JSR PRMSG
    LDA DIRNAME+1
    JMP CHROUT
    .END
Filename: SPEED.2

This is the main input/output portion
of SpeedScript, responsible for loading,
saving, and all printing functions.

CAST and CINSTOAS (standing for Convert
to ASCII and Convert INTernal code to
ASCII) translate the way SpeedScript
stores text in memory (internal screen
codes) into ASCII so that disk files
will be compatible with most other
software. In addition, the return- mark
is changed to character 155, and vice
versa. This is why you can't load a
machine language file into SpeedScript,
edit it, then save it back as a
runnable modification. All back-arrows
are turned into carriage returns on
output, and all carriage returns
(155's) are turned into back-arrows
(30's) on input.

CAST  LDA #0
      STA CONVFLAG
      JMP CAST1
CINTOAS LDA #128
      STA CONVFLAG
CAST1 LDA TEXSTART
      STA TEX
      LDA TEXSTART+1
      STA TEX+1
    JMP CIN
CASTOIN LDA #0
    STA CONVFLAG
    LDA CURR
    STA TEX
    LDA CURR+1
    STA TEX+1
CIN SEC
    LDA LASTLINE+1
    SBC TEX+1
    TAX
    INX
    LDY #0
CVLOOP LDA (TEX),Y
    BIT CONVFLAG
    BMI COTHER
    CMP #155
    BNE NOTRTN
    LDA #RETCHAR
    JMP OVEROTHER
NOTRTN JSR ASTOIN
    JMP OVEROTHER
COTHER CMP #RETCHAR
    BNE NOTRC
    LDA #155
    JMP OVEROTHER
NOTRC JSR INTOAS
OVEROTHER STA (TEX),Y
    INY
    BNE CVLOOP
    INC TEX+1
    DEX
    BNE CVLOOP
    RTS

Here is where most of the input/output
routines start. TSAVE saves the entire
document area using the CIO block
output routine (PUT TEXT). TOPEN is
called by both TSAVE and TLOAD to get
the filename and open the file. The
device specification (D: or C:) must be
typed in by the user.

TSAVE prints the Save: prompt, goes to
TOPEN with an 8 (for output, the same
number in OPEN 1,8,0,"D:file"), and
uses IOCB #7 (LDX #$70) to send a PUT
TEXT command (11). Text is written from
the start-of-text with a length of
LASTLINE - TEXSTART.

TSAVE JSR TOPCLR
    LDA # <SAVMSG
    LDY # >SAVMSG
    JSR PRMSG
    LDA #8
    JSR TOPEN
    BMI ERROR
    JSR CINTOAS
    LDX #$70
    LDA TEXSTART
    STA ICBADR,X
    LDA TEXSTART+1
    STA ICBADR+1,X
    SEC
    LDA LASTLINE
    SBC TEXSTART
    STA ICBLEN,X
    LDA LASTLINE+1
    SBC TEXSTART+1
    STA ICBLEN+1,X
    LDA #11
    STA ICCOM,X
    JSR CIO

The N (negative) bit is set when an
error occurs after a call to CIO or a
routine that ends up calling CIO.
Therefore, we can use BMI to branch on
an error condition.

    BMI ERR1
    JSR CAST
    JSR CLOSE7
    BMI ERROR
    JMP FINE
ERR1 TYA
    PHA
    JSR CAST
    PLA
    TAY

The error routine uses the error number
found in the Y register, prints the
error message with PRMSG, and the error
number with OUTNUM. The open file is
closed. If the BREAK key was used to
stop the operation, we distinguish this
from an ordinary error, and print
"BREAK Abort" instead.

ERROR CPY #128
    BEQ STOPPED
    TYA
    PHA
    LDA #125
    JSR CHROUT
    LDA # <ERRMSG
    LDY # >ERRMSG
    JSR PRMSG
    PLA
    TAX
    LDA #0
    JSR OUTNUM
ERXIT JSR IOCLOSE
    JSR HIGHLIGHT
    LDA #1
    STA MSGFLG
    RTS
STOPPED JSR TOPCLR
    LDA # <BRMSG
    LDY # >BRMSG
    JSR PRMSG
    JMP ERXIT

General file closing routine. IOCB
contains the channel number times 16.

IOCLOSE LDX IOCB
    LDA #12
    STA ICCOM,X
    JMP CIO

TOPEN is used to get a filename,
including the device specification.
It's used by Save, Load, and Print. It
forces the CAPS key to uppercase for
the filename, which is not quite as
satisfactory as converting the filename
if lowercase was used. It does return
the CAPS key to its former value,
though. TOPEN opens the file and
returns with the error code in the Y
register.

TOPEN LDX #$70
    STX IOCB
    STA ACCESS

Save current CAPS value.

    LDA SHFLOK
    PHA

CAPS On.

    LDA #64
    STA SHFLOK
    JSR INPUT

Restore CAPS value.

    PLA
    STA SHFLOK
    LDA INLEN
    BNE OPCONT
OPABORT JSR SYSMSG
    PLA
    PLA
    JMP HIGHLIGHT
OPCONT JSR IOCLOSE
    LDX IOCB
    LDA # <INBUFF
    STA ICBADR,X
    LDA # >INBUFF
    STA ICBADR+1,X
    LDA INLEN
    STA ICBLEN,X
    LDA #0
    STA ICBLEN+1,X
    LDA ACCESS
    STA ICAUX1,X
    LDA #3
    STA ICCOM,X
    JMP CIO

The Load routine checks the cursor
position. If the cursor is at the
top-of-text (CURR=TEXSTART), we call
the ERASE routine to wipe out memory
before the load. Otherwise, the load
starts at the cursor position,
performing an append, and we change the
command line to green ($C4, sorry about
not using a label) to warn the user. We
open the file for reading by passing a
4 to TOPEN, then at LOADLINK use GET
TEXT (command 7) to get no more than
the length of the text area. The actual
length loaded is found in ICBLEN, so we
add this to TEXSTART and the offset
between the cursor position and
TEXSTART to get the position of the
end-of-text (LASTLINE).

A funny thing happens, though. Up to
255 garbage characters appear following
an otherwise normal load, after the
end-of-text. I was never able to figure
out why (and I puzzled over it for a
week), so I wrote a stopgap routine to
just clear out one page past the
end-of-text. The bug is not fixed per
se, but it has no effect anymore! I
still think it must be the fault of the
operating system (I know...).

TLOAD SEC
    LDA CURR
    SBC TEXSTART
    STA TEX
    STA INDIR
    LDA CURR+1
    SBC TEXSTART+1
    STA TEX+1
    STA INDIR+1
    ORA TEX
    BEQ LOAD2
    LDA #$C4
    STA WINDCOLR
LOAD2 JSR TOPCLR
    LDA # <LOADMSG
    LDY # >LOADMSG
    JSR PRMSG
    LDA #4
    JSR TOPEN
    BPL OKLOD
GOERROR JMP ERROR
OKLOD LDA WINDCOLR
    CMP #$C4
    BEQ NOER
    JSR ERASE
NOER JSR LOADLINK
    CPY #128
    BCC JFINE
    JMP ERROR
JFINE JMP FINE

Entry point for linked files loading.

LOADLINK LDX IOCB
    LDA CURR
    STA ICBADR,X
    LDA CURR+1
    STA ICBADR+1,X
    SEC
    LDA TEXEND
    SBC CURR
    STA ICBLEN,X
    LDA TEXEND+1
    SBC CURR+1
    STA ICBLEN+1,X
    LDA #7
    STA ICCOM,X
    JSR CIO
    BPL TEXOK
    CPY #136
    BEQ TEXOK
    RTS
TEXOK LDX IOCB
    CLC
    LDA ICBLEN,X
    ADC TEXSTART
    STA LASTLINE
    LDA ICBLEN+1,X
    ADC TEXSTART+1
    STA LASTLINE+1
    CLC
    LDA LASTLINE
    ADC INDIR
    STA LASTLINE
    LDA LASTLINE+1
    ADC INDIR+1
    STA LASTLINE+1
    JSR CASTOIN
    LDA LASTLINE
    STA TEX
    LDA LASTLINE+1
    STA TEX+1
    LDA #0
    TAY
NOGARBAGE STA (TEX),Y
    INY
    BNE NOGARBAGE
    RTS
FINE JSR IOCLOSE
    BPL PROKMSG
    JMP ERROR
PROKMSG LDA #125
    JSR CHROUT
    LDA # <OKMSG
    LDY # >OKMSG
    JSR PRMSG
    JMP ERXIT

Disable display-list interrupt and
restore screen colors.

DELITE LDA #$40
    STA $D40E
    LDA SCRCOL
    STA 710
    STA 712
    LDA TEXCOLR
    STA 709
    RTS

A rather short routine that converts a
string of ASCII digits into a number in
hex and the accumulator. It takes
advantage of decimal mode. In decimal
mode, the accumulator is adjusted after
additions and subtractions so that it
acts like a two-digit decimal counter.
We shift BCD over a nybble and add in
the left nybble of the ASCII number
until we reach the end of the ASCII
number. We then subtract 1 from BCD and
increment X (which doesn't conform to
decimal mode) until BCD is down to 0.
The X register magically holds the
converted number. Naturally, decimal
mode is cleared before this routine
exits, or it would wreak major havoc.
ASCHEX is used to convert the
parameters of printer commands like
left margin.

ASCHEX LDX #0
    STX BCD
    STX BCD+1
    STX HEX
    STX HEX+1
DIGIT SEC
    LDA (TEX),Y
    SBC #16
    BCC NONUM
    CMP #10
    BCS NONUM
    ASL BCD
    ROL BCD+1
    ASL BCD
    ROL BCD+1
    ASL BCD
    ROL BCD+1
    ASL BCD
    ROL BCD+1
    ORA BCD
    STA BCD
    INY
    BNE DIGIT
    INC TEX+1
    JMP DIGIT
NONUM SED
DECHEX LDA BCD
    ORA BCD+1
    BEQ DONENUM
    SEC
    LDA BCD
    SBC #1
    STA BCD
    LDA BCD+1
    SBC #0
    STA BCD+1
    INC HEX
    BNE NOHEXINC
    INC HEX+1
NOHEXINC JMP DECHEX
DONENUM LDA HEX
    CLD
    RTS

Insert the buffer. This is the recall
routine called by CTRL-R. It must not
allow an insertion that would overfill
memory. It calls DMOVE to open a space
in memory, then UMOVE (which is a
little faster than DMOVE) to copy the
buffer to the empty space.

INSBUFFER SEC
    LDA TPTR
    SBC TEXBUF
    STA BUFLEN
    LDA TPTR+1
    SBC TEXBUF+1
    STA BUFLEN+1
    ORA BUFLEN
    BNE OKBUFF
    JSR TOPCLR
    LDA # <INSMSG
    LDY # >INSMSG
    JSR PRMSG
    LDA #1
    STA MSGFLG
    RTS
OKBUFF CLC
    LDA CURR
    STA FROML
    ADC BUFLEN
    STA DESTL
    LDA CURR+1
    STA FROMH
    ADC BUFLEN+1
    STA DESTH
    SEC
    LDA LASTLINE
    SBC FROML
    STA LLEN
    LDA LASTLINE+1
    SBC FROMH
    STA HLEN
    CLC
    ADC DESTH
    CMP TEXEND+1
    BCC OKMOV
    JSR TOPCLR
    LDA # <INSERR
    LDY # >INSERR
    JSR PRMSG
    LDA #1
    STA MSGFLG
    RTS
OKMOV JSR DMOVE
    CLC
    LDA BUFLEN
    STA LLEN
    ADC LASTLINE
    STA LASTLINE
    LDA BUFLEN+1
    STA HLEN
    ADC LASTLINE+1
    STA LASTLINE+1
    LDA CURR
    STA DESTL
    LDA CURR+1
    STA DESTH
    LDA TEXBUF
    STA FROML
    LDA TEXBUF+1
    STA FROMH
    JSR UMOVE
    JMP CHECK

Exchange the character highlighted by
the cursor with the character to the
right of it. Not a vital command, but
it was included due to the brevity of
the code.

SWITCH LDY #0
    LDA (CURR),Y
    TAX
    INY
    LDA (CURR),Y
    DEY
    STA (CURR),Y
    INY
    TXA
    STA (CURR),Y
    RTS

Change the case of the character
highlighted by the cursor.

ALPHA LDY #0
    LDA (CURR),Y
    AND #63
    CMP #33
    BCC NOTALPHA
    CMP #59
    BCS NOTALPHA
    LDA (CURR),Y
    EOR #64
    STA (CURR),Y
NOTALPHA JMP RIGHT

Convert internal (screen code) format
to Atari ASCII (ATASCII). Used to
convert the screen-code format of
SpeedScript documents to ASCII for the
sake of printing.

INTOAS PHA
    AND #128
    STA TEMP
    PLA
    AND #127
    CMP #96
    BCS XINT
INCONT CMP #64
    BCC INT1
    SBC #64
    JMP XINT
INT1 ADC #32
XINT ORA TEMP
    RTS

The start of the printer routines. This
part could logically be called a
separate program, but many variables
are common to the above code.

DEFTAB: Table of default settings for
left margin, right margin, page length,
top margin, bottom margin, etc. See the
table starting at LMARGIN at the end of
this source code.

DEFTAB .BYTE 5,75,66,5,58,1,1,1,0,1,0,80

Table of default printer codes.

PRCODES .BYTE 27,14,15,18

Another advantage of modular coding is
that you can change the behavior of a
lot of code by just changing one small
common routine. This is a substitute
for the normal CHROUT routine. It
checks to see if the current page
number equals the page number specified
by the user to start printing. It also
checks for the BREAK to abort the
printing and permits printing to be
paused with CTRL-1.

PCHROUT STA PCR
    TXA
    PHA
    TYA
    PHA
    SEC
    LDA PAGENUM
    SBC STARTNUM
    LDA PAGENUM+1
    SBC STARTNUM+1
    BCC SKIPOUT
    LDA #1
    STA 766
    LDX #$70
    LDA #0
    STA ICBLEN,X
    STA ICBLEN+1,X
    LDA #11
    STA ICCOM,X
    LDA PCR
    JSR CIO
    PHP
    LDA #0
    STA 766
    PLP
    BPL SHIFTFREEZE
ERRLINK JSR ERROR
    LDX #$FA
    TXS
    JMP MAIN
SHIFTFREEZE LDA $02FF ;CTRL-1
    BNE SHIFTFREEZE
SKIPOUT PLA
    TAY
    PLA
    TAX
    LDA PCR
    RTS

Displays "Printing..."

PRIN JSR TOPCLR
    LDA # <PRINMSG
    LDY # >PRINMSG
    JMP PRMSG
PBORT JMP PEXIT

Called by CTRL-P. We get the filename
to print to (usually P:, although you
can use E: to print to the screen) with
ICAUX1 set to 8 for output. We exit on
any error. The DELITE routine turns off
the display-list interrupt, which might
otherwise interfere with output timing.

PRINT JSR TOPCLR
    LDA # <FNMSG
    LDY # >FNMSG
    JSR PRMSG
    JSR DELITE
    LDA #8
    JSR TOPEN
    BPL PROK
    JMP PEXIT

Reset several flags (footer length,
header length, true ASCII, underline
mode, and linefeed mode). Notice how
DELITE is called again. This isn't a
mistake. The first time we called
DELITE, we then may have opened a file
to the Editor device. This reset the
screen to the default colors, so the
second DELITE retains the user's true
color choice.

PROK JSR DELITE
    JSR PRIN
    LDX #0
    STX FTLEN
    STX HDLEN
    STX NEEDASC
    STX UNDERLINE
    STX LINEFEED

Copy definition tables and default
printercodes.

COPYDEF LDA DEFTAB,X
    STA LMARGIN,X
    INX
    CPX #12
    BNE COPYDEF
    LDA #$FF
    STA LINE
    STA NOMARG
    LDX #4
COPYDEFS LDA PRCODES-1,X
    STA CODEBUFFER+16,X
    DEX
    BNE COPYDEFS

Reentry point for printing after linked
files.

RETEX LDA TEXSTART
    STA TEX
    LDA TEXSTART+1
    STA TEX+1

Main printing loop. We print the left
margin, grab a line of text, scan
backward until we find a space or a
carriage return, then break the line
there. If printer codes are
encountered, they're passed on to the
SPECIAL routine. Otherwise, we end up
calling BUFPRT to print the line and
process some other control codes.

PLOOP LDY #0
    STY POS
    CPY NOMARG
    BEQ PLOOP1
    LDA LMARGIN
    STA POS
PLOOP1 LDA (TEX),Y
    BPL NOTSP
    JMP SPECIAL
NOTSP CMP #RETCHAR
    BEQ FOUNDSPACE
NOTRET STA PRBUFF,Y
    INY
    INC POS
    LDA POS
    CMP RMARGIN
    BCC PLOOP1
    STY FINPOS
FINDSPACE LDA (TEX),Y
    CMP #SPACE
    BEQ FOUNDSPACE
    DEC POS
    DEY
    BNE FINDSPACE
    LDY FINPOS
FSPACE INY
    LDA (TEX),Y
    CMP #SPACE
    BEQ FOUNDSPACE
    DEY
FOUNDSPACE STY FINPOS
OVERSTOR TYA
    SEC
    ADC TEX
    STA TEX
    LDA TEX+1
    ADC #0
    STA TEX+1
    LDY #0

If this is the first page, we need to print
the header, if any, with JSR TOP.

DOBUFF LDA LINE
    CMP #$FF
    BNE DOBUF2
    JSR TOP
DOBUF2 LDA NOMARG
    BEQ OVERMARG
    JSR LMARG
OVERMARG SEC
    ROL NOMARG
    LDA FINPOS
    STA ENDPOS
    LDA # <PRBUFF
    STA INDIR
    LDA # >PRBUFF
    STA INDIR+1
    JSR BUFPRT

A line has been printed. We check to
see if we've hit the bottom margin and,
if so, go to PAGE, which goes to the
end of the page, prints the footer (if
any), and feeds to the next page.

ZBUFF JSR CRLF
    LDA LINE
    CMP BOTMARG
    BCC NOTPAGE
    JSR PAGE

Have we reached the end-of-text?

NOTPAGE SEC
    LDA TEX
    SBC LASTLINE
    STA TEMP
    LDA TEX+1
    SBC LASTLINE+1
    ORA TEMP
    BEQ DORPT
    BCC DORPT

If so, we check for a footer. If there
is one, we set HDLEN and TOPMARG to 0
(so that the printhead will end up at
the right place on the last page) and
call PAGE, which prints the footer. If
there is no footer, we leave the
printhead on the same page so that
paper isn't wasted.

    LDA FTLEN
    BEQ PXIT
    LDA #0
    STA HDLEN
    STA TOPMARG
    JSR PAGE

Exit routines. If screen output was
selected, we wait for a keystroke
before going back to editing mode.

PXIT LDA INBUFF
    CMP #'E
    BNE PEXIT
    LDA #155
    JSR CHROUT
    LDA # <DIRMSG
    LDY # >DIRMSG
    JSR PRMSG
    JSR GETAKEY
PEXIT JSR CLOSE7
    LDX #$FA
    TXS
    JSR HIGHLIGHT
    LDA #125
    JSR CHROUT
    JSR SYSMSG
    JMP MAIN
DORPT JMP PLOOP

Paging routines. We skip (PAGELENGTH -
LINE) -- two blank lines to get to the
bottom of the page, print a footer (if
there is one) or a blank line (if not),
then page to the beginning of the next
page, skipping over the paper
perforation. If the wait mode is
enabled, we wait for the user to insert
a new sheet of paper.

PAGE SEC
    LDA PAGELENGTH
    SBC LINE
    TAY
    DEY
    DEY
    BEQ NOSK
    BMI NOSK
NEXPAGE JSR CR
    DEY
    BNE NEXPAGE
NOSK LDA FTLEN
    BEQ SKIPFT
    STA ENDPOS
    LDA # <FTBUFF
    STA INDIR
    LDA # >FTBUFF
    STA INDIR+1
    JSR LMARG
    JSR BUFPRT
SKIPFT JSR CR
    JSR CR
    JSR CR

Increment the page number.

    INC PAGENUM
    BNE NOIPN
    INC PAGENUM+1

The page wait mode is inappropriate
when printing to the screen or to disk,
or when skipping over pages with the ?
format command.

NOIPN LDA CONTINUOUS
    BNE TOP
    SEC
    LDA PAGENUM
    SBC STARTNUM
    LDA PAGENUM+1
    SBC STARTNUM+1
    BCC TOP
    JSR TOPCLR
    LDA # <WAITMSG
    LDY # >WAITMSG
    JSR PRMSG
    JSR GETAKEY
    JSR PRIN

Print the header; skip to the top
margin.

TOP LDA HDLEN
    BEQ NOHEADER
    STA ENDPOS
    LDA # <HDBUFF
    STA INDIR
    LDA # >HDBUFF
    STA INDIR+1
    JSR LMARG
    JSR BUFPRT
NOHEADER LDY TOPMARG
    STY LINE
    DEY
    BEQ SKIPTOP
    BMI SKIPTOP
TOPLP JSR CR
    DEY
    BNE TOPLP
SKIPTOP RTS

Left margin routine. This routine is not
called if NOMARG is selected (margin
release).

LMARG LDA #32
    LDY LMARGIN
    STY POS
    BEQ LMEXIT
LMLOOP JSR PCHROUT
    DEY
    BNE LMLOOP
LMEXIT RTS

CRLF is called at the end of most
printed lines. It increments the LINE
count and takes into account the
current line spacing mode set by the a
format command.

CRLF LDY SPACING
    CLC
    TYA
    ADC LINE
    STA LINE
CRLOOP JSR CR
    DEY
    BNE CRLOOP
    RTS

CR just prints a single carriage return
and linefeed (if specified).

CR  LDA #155
    JSR PCHROUT
    LDA LINEFEED
    BEQ NOLF
    JSR PCHROUT
NOLF RTS

Handle special printer codes like left
margin. This looks up the printer code
using a routine similar to CONTROL.

SPECIAL STA SAVCHAR
    AND #127
    JSR INTOAS
    LDX SPTAB
SRCHSP CMP SPTAB,X
    BEQ FSP
    DEX
    BNE SRCHSP
    DEC POS
    JMP DEFINE
FSP DEX
    TXA
    ASL A
    TAX
    STY YSAVE
    LDA # >SPCONT-1
    PHA
    LDA # <SPCONT-1
    PHA
    LDA SPVECT+1,X
    PHA
    LDA SPVECT,X
    PHA
    RTS

After the format code is processed, we
must skip over the format command
and its parameter so that it's not
printed.

SPCONT SEC
    LDA YSAVE
    ADC TEX
    STA TEX
    LDA TEX+1
    ADC #0
    STA TEX+1
    JMP PLOOP

If the format command ends with a
return-mark, we must skip over the
return-mark as well.


SPCEXIT LDA (TEX),Y
    CMP #RETCHAR
    BEQ NOAD
    DEY
NOAD STY YSAVE
    RTS

Special format code table. It starts with
the number of format commands, then
the characters for each format
command.

SPTAB .BYTE 17
    .BYTE "wlrtbsnhf@p?xmigj"

The address-1 of each format routine.

SPVECT .WORD PW-1,LM-1,RM-1,TP-1
    .WORD BT-1,SP-1,NX-1,HD-1,FT-1
    .WORD PN-1,PL-1,SPAGE-1,ACROSS-1
    .WORD MRELEASE-1,COMMENT-1,LINK-1
    .WORD LFSET-1

m Margin release. INY is used to skip
over the format character.

MRELEASE INY
    LDA #0
    STA NOMARG
    JMP SPCEXIT

x Columns across, used by centering.

ACROSS INY
    JSR ASCHEX
    STA PAGEWIDTH
    JMP SPCEXIT

? Start printing at specified page.

SPAGE INY
    JSR ASCHEX
    STA STARTNUM
    LDA HEX+1
    STA STARTNUM+1
    JMP SPCEXIT

@ Set starting default page number.

PN  INY
    JSR ASCHEX
    STA PAGENUM
    LDA HEX+1
    STA PAGENUM+1
    JMP SPCEXIT

p Page length.

PL  INY
    JSR ASCHEX
    STA PAGELENGTH
    JMP SPCEXIT

w Set page wait mode.

PW  LDA #0
    STA CONTINUOUS
    INY
    JMP SPCEXIT

j Set linefeed mode.

LFSET LDA #10
    STA LINEFEED
    INY
    JMP SPCEXIT

l Left margin.

LM  INY
    JSR ASCHEX
    STA LMARGIN
    JMP SPCEXIT

r Right margin.

RM  INY
    JSR ASCHEX
    STA RMARGIN
    JMP SPCEXIT

t Top margin.

TP  INY
    JSR ASCHEX
    STA TOPMARG
    JMP SPCEXIT

b Bottom margin.

BT  INY
    JSR ASCHEX
    STA BOTMARG
    JMP SPCEXIT

s Set line spacing.

SP  INY
    JSR ASCHEX
    STA SPACING
    JMP SPCEXIT

n Jump to next page.

NX  LDY YSAVE
    INY
    TYA
    PHA
    JSR PAGE
    PLA
    TAY
    STY YSAVE
    RTS

h Define header. Copy header into
header buffer.

HD  JSR PASTRET
    DEY
    STY HDLEN
    LDY #1
HDCOPY LDA (TEX),Y
    STA HDBUFF-1,Y
    INY
    CPY HDLEN
    BCC HDCOPY
    BEQ HDCOPY
    INY
    JMP SPCEXIT

Skip just past the return-mark.

PASTRET INY
    LDA (TEX),Y
    CMP #RETCHAR
    BNE PASTRET
    RTS

f Define footer.

FT  JSR PASTRET
    DEY
    STY FTLEN
    LDY #1
FTCOPY LDA (TEX),Y
    STA FTBUFF-1,Y
    INY
    CPY FTLEN
    BCC FTCOPY
    BEQ FTCOPY
    JMP SPCEXIT

i Ignore a line of information.

COMMENT JSR PASTRET
    JMP SPCEXIT

Define programmable printkeys. We
check for =. If not found, this is not an
assignment, so we just skip past the
code. Otherwise, we use the screen
code value as the index into the
CODEBUFFER and put the value there,
ready to be called during printing by
BUFPRT.

DEFINE INY
    LDA (TEX),Y
    CMP #'=-32
    BEQ DODEFINE
    DEY
    LDA SAVCHAR
    JMP NOTRET
DODEFINE INY
    JSR ASCHEX
    PHA
    LDA SAVCHAR
    AND #127
    TAX
    PLA
    STA CODEBUFFER,X
    JSR SPCEXIT
    JMP SPCONT

g Link to next file. We get the
filename from text and put it into the
input buffer, just as if the filename
were typed in with INPUT. We then jump
into the TOPEN routine to open the
file, and into the Load routine to load
the file. After the load, we check for
a load error, then jump to RETEX to
continue printing.

LINK LDY #1
    LDX #0
FNCOPY LDA (TEX),Y
    CMP #RETCHAR
    BEQ FNEND
    JSR INTOAS
    STA INBUFF,X
    INY
    INX
    CPX #14
    BNE FNCOPY
FNEND STX INLEN
    LDA #0
    STA INBUFF,X
    LDX #$60
    STX IOCB
    LDA #4
    STA ACCESS
    JSR OPCONT
    BPL LNOERR
    JMP ERRLINK
LNOERR LDA #0
    STA INDIR
    STA INDIR+1
    JSR ERASE
    JSR LOADLINK
    BPL LCONT
    JMP ERRLINK
LCONT PLA
    PLA
    LDX #$70
    STA IOCB
    JMP RETEX

Global search and replace. This just
links together the search-specify
routine, the replace-specify routine,
then repeatedly calls Hunt and Replace,
until Hunt returns "Not Found." (FPOS+1
is $FF after a search failure.)

SANDR JSR RESET
    LDA HUNTLEN
    BEQ NOSR
    JSR ASKREP
SNR JSR CONTSRCH
    LDA FPOS+1
    CMP #$FF
    BEQ NOSR
    JSR REPL
    JSR REFRESH
    JMP SNR
NOSR JMP SYSMSG

If OPTION is held down with CTRL-F, we
ask for and store the search phrase. If
OPTION is not down, we perform the
actual search. The line in the INBUFF
is compared with characters in text. If
at any point the search fails, we
continue the comparison with the first
character of INBUFF. The search is a
failure if we reach the end-of-text. If
the entire length of INBUFF matches,
the search succeeds, so we change the
CURRent cursor position to the found
position, save the found position for
the sake of the replace routine, then
call CHECK to scroll to the found
position.

HUNT LDA #8
    STA 53279
    LDA 53279
    CMP #3
    BNE CONTSRCH
RESET JSR TOPCLR
    LDA # <SRCHMSG
    LDY # >SRCHMSG
    JSR PRMSG
    JSR INPUT
    STA HUNTLEN
    BNE OKSRCH
    JMP SYSMSG
OKSRCH LDY #0
TOBUFF LDA INBUFF,Y
    STA HUNTBUFF,Y
    INY
    CPY INLEN
    BNE TOBUFF
    JMP SYSMSG
CONTSRCH LDA CURR
    STA TEX
    LDA CURR+1
    STA TEX+1
    LDA #$FF
    STA FPOS+1
    LDY #1
SRCH0 LDX #0
    LDA HUNTLEN
    BEQ NOTFOUND
SRCH1 LDA HUNTBUFF,X
    JSR ASTOIN
    CMP (TEX),Y
    BEQ CY
    CPX #0
    BNE SRCH0
    DEX
CY  INY
    BNE NOVFL
    INC TEX+1
    LDA TEX+1
    CMP LASTLINE+1
    BEQ NOVFL
    BCS NOTFOUND
NOVFL INX
    CPX HUNTLEN
    BNE SRCH1
    CLC
    TYA
    ADC TEX
    STA TEMP
    LDA TEX+1
    ADC #0
    STA TEMP+1
    LDA LASTLINE
    CMP TEMP
    LDA LASTLINE+1
    SBC TEMP+1
    BCC NOTFOUND
    SEC
    LDA TEMP
    SBC HUNTLEN
    STA CURR
    STA FPOS
    LDA TEMP+1
    SBC #0
    STA CURR+1
    STA FPOS+1
    JSR CHECK
    RTS
NOTFOUND JSR TOPCLR
    LDA # <NFMSG
    LDY # >NFMSG
    JSR PRMSG
    LDA #1
    STA MSGFLG
    RTS

The change (replace) routine checks to
see if OPTION is held down with CTRL-C.
If it is, we ask for a replace phrase,
and exit. If not, we check to see if
the cursor is at the position
previously located by the search
routine. If it is, we delete the found
phrase, then insert the replace phrase.
The cursor is moved past the replace
phrase for the sake of the next search.
This also prevents endless recursion,
as in replacing in with winner.

REPSTART LDA #8
    STA 53279
    LDA 53279
    CMP #3
    BNE REPL
ASKREP JSR TOPCLR
    LDA # <REPMSG
    LDY # >REPMSG
    JSR PRMSG
    JSR INPUT
    STA REPLEN
    BEQ NOREP
    LDY #0
REPMOV LDA INBUFF,Y
    STA REPBUFF,Y
    INY
    CPY INLEN
    BNE REPMOV
NOREP JMP SYSMSG
REPL SEC
    LDA CURR
    STA DESTL
    SBC FPOS
    STA TEMP
    LDA CURR+1
    STA DESTH
    SBC FPOS+1
    ORA TEMP
    BNE NOREPL
    LDA #$FF
    STA FPOS+1
    CLC
    LDA HUNTLEN
    ADC CURR
    STA FROML
    LDA #0
    ADC CURR+1
    STA FROMH
    SEC
    LDA LASTLINE
    SBC DESTL
    STA LLEN
    LDA LASTLINE+1
    SBC DESTH
    STA HLEN
    JSR UMOVE
    SEC
    LDA LASTLINE
    SBC HUNTLEN
    STA LASTLINE
    LDA LASTLINE+1
    SBC #0
    STA LASTLINE+1
    LDA REPLEN
    BEQ NOREPL
    STA INSLEN
    LDA #0
    STA INSLEN+1
    JSR INSBLOCK
    LDY #0
REPLOOP LDA REPBUFF,Y
    JSR ASTOIN
    STA (CURR),Y
    INY
    CPY REPLEN
    BNE REPLOOP
    CLC
    LDA CURR
    ADC REPLEN
    STA CURR
    LDA CURR+1
    ADC #0
    STA CURR+1
NOREPL JMP CHECK

Suddenly, we're back to a PRINT
subroutine. This examines the buffer as
it's being printed, checking for
printkeys and Stage 2 commands like
centering.

BUFPRT LDY #0
BUFLP CPY ENDPOS
    BEQ ENDBUFF
    LDA (INDIR),Y
    BMI SPEC2
    JSR INTOAS
    JSR PCHROUT

In underline mode, after we print the
character, we backspace the printhead
and print an underline character.

    LDA UNDERLINE
    BEQ NOBRK
    LDA #8
    JSR PCHROUT
    LDA #95
    JSR PCHROUT
NOBRK INY
    JMP BUFLP
ENDBUFF RTS

Stage 2 format commands.

SPEC2 STY YSAVE
    AND #127
    STA SAVCHAR
    JSR INTOAS
OTHER CMP #'c
    BNE NOTCENTER

c Centering looks at the length of the
line, then sends out extra spaces (the
left margin has already been printed) to
move the printhead to the right place.

    SEC
    LDA PAGEWIDTH
    SBC ENDPOS
    LSR A
    SEC
    SBC LMARGIN
  TAY
  LDA #32
CLOOP JSR PCHROUT
  DEY
  BNE CLOOP
  LDY YSAVE
  JMP NOBRK
NOTCENTER CMP #'e
  BNE NOTEDGE

e Edge right. This subtracts the length
of the line from the right margin
position and moves the printhead to
this position.

EDGE SEC
  LDA RMARGIN
  SBC ENDPOS
  SEC
  SBC LMARGIN
  TAY
  LDA #32
  JMP CLOOP
NOTEDGE CMP #'u
  BNE NOTOG

u Toggle underline mode. L

  LDA UNDERLINE
  EOR #1
  STA UNDERLINE
NOTOG CMP #'#
  BNE DOCODES

# Substitute the current page number
for the # symbol.

DOPGN STY YSAVE
  LDX PAGENUM
  LDA PAGENUM+1
  JSR PROUTNUM
  LDY YSAVE
  JMP NOBRK

Do special format codes. This just uses
the screen-code value of the character
as an index into the CODEBUFFER, then
sends out the code. SpeedScript makes
no judgment on the code being sent out.

DOCODES LDX SAVCHAR
  LDA CODEBUFFER,X
  JSR PCHROUT
  JMP NOBRK

Display free memory using OUTNUM.

FREEMEM JSR TOPCLR
  SEC
  LDA TEXEND
  SBC LASTLINE
  TAX
  LDA TEXEND+1
  SBC LASTLINE+1
  JSR OUTNUM
  LDA #1
  STA MSGFLG
  RTS
  .END
Filename: DATA

Data tables

Messages are stored in ATASCII, with a
zero byte for a delimiter.

MSG1 .BYTE "SpeedScript 3.0"
    .BYTE 0
MSG2 .BYTE " by Charles Brannon"
    .BYTE 0
KILLMSG .BYTE "Buffer Cleared"
    .BYTE 0
BUFERR .BYTE "Buffer Full"
    .BYTE 0
DELMSG .BYTE "Delete (S,W,P)"
    .BYTE 0
YMSG .BYTE ": Are you sure? (Y/N):"
    .BYTE 0
CLRMSG .BYTE "ERASE ALL TEXT"
    .BYTE 0
ERASMSG .BYTE "Erase (S,W,P): {inv}RETURN{inv} to exit"
    .BYTE 0
SAVMSG .BYTE "Save (Device:Filename)>"
    .BYTE 0
ERRMSG .BYTE "Error #"
    .BYTE 0
BRMSG .BYTE "BREAK Key Abort"
    .BYTE 0
OKMSG .BYTE "No Errors"
    .BYTE 0
LOADMSG .BYTE "Load (Device:Filename)>"
    .BYTE 0
DIRMSG .BYTE " Press {inv}RETURN{inv}"
    .BYTE 0
DIRNAME .BYTE "D1:*.*"
INSERR .BYTE "Memory Full"
    .BYTE 0
INSMSG .BYTE "No text in buffer"
    .BYTE 0
FNMSG .BYTE "Print (Device:Filename)>"
    .BYTE 0
PRINMSG .BYTE "Printing..."
    .BYTE 155,155,0
WAITMSG .BYTE "Insert next sheet, press {inv}RETURN{inv}"
    .BYTE 0
SRCHMSG .BYTE "Find:"
    .BYTE 0
NFMSG .BYTE "Not found"
    .BYTE 0
REPMSG .BYTE "Change to:"
    .BYTE 0

The {ESC}'s represent the ESCape key.
The arrows are the cursor keys, which
must be preceded by ESC to be entered
into text. There is actually only one
space between the e of Rename and the
E of ESC.

DIRINS .BYTE "{ESC}{up}{ESC}{down}{ESC}{left}
        {ESC}{right} {inv}CTRL-D{inv}elete
        {inv}L{inv}ock {inv}U{inv}nlock
        {inv}R{inv}ename {inv}ESC{inv}
        {inv}CTRL-L{inv}oad Drive [
        {inv}1{inv} {inv}2{inv}
        {inv}3{inv} {inv}4{inv}
        ]: ",0
RENMSG .BYTE "Rename to:",0
FORMSG .BYTE "Format disk",0

The .OPT NO OBJ and .OPT OBJ pseudo-ops
turn on and off object code generation.
This insures that no object code is
generated for the variable table.

    .OPT NO OBJ

TEXSTART *= *+2         ; Start-of-text area
TEXEND *= *+2           ; End-of-text area
TEXBUF *= *+2           ; Start of buffer
BUFEND *= *+2           ; End-of-buffer area
LENTABLE *= *+1         ; Length of first screen line
TOPLIN *= *+2           ; Home position in text
MSGFLG *= *+1           ; Messageflag
INSMODE *= *+1          ; Insertmode
ENDPOS *= *+1           ; Used by delete routines
FINPOS *= *+1           ; "
LASTLINE *= *+2         ; End-of-text position
LIMIT *= *+1            ; Used by INPUT
INLEN *= *+1            ; "
BOTSCR *= *+2           ; Bottom of screen in text
LBUFF *= *+40           ; Linebuffer (REFRESH)
INBUFF *= *+40          ; INPUT buffer
SAVCURR *= *+2          ; Used by delete routines
BCD *=  *+2             ; Usedby ASCHEX
HEX *=  *+2             ; "
TPTR *= *+2             ; Last character in buffer
BUFLEN *= *+2           ; Buffer length
GOBLEN *= *+2           ; Size of deleted text
FROMSAV *= *+2          ; Used by delete routines
DESTSAV *= *+2          ; "
HDLEN *= *+1            ; Header length
FTLEN *= *+1            ; Footer length
LMARGIN *= *+1          ; Holds left margin
RMARGIN *= *+1          ; Right margin
PAGELENGTH *= *+1       ; Pagelength
TOPMARG *= *+1          ; Topmargin
BOTMARG *= *+1          ; Bottom margin
SPACING *= *+1          ; Linespacing
CONTINUOUS *= *+1       ; Pagewait mode
PAGENUM *= *+2          ; Page number
STARTNUM *= *+2         ; Start printing at #
PAGEWIDTH *= *+1        ; Columns across
NOMARG *= *+1           ; Margin release flag
POS *=  *+1             ; POSition within line
LINE *= *+1             ; Linecount
YSAVE *= *+1            ; Preserves Y register
SAVCHAR *= *+1          ; Preserves accumulator
INSLEN *= *+1           ; Length of an insertion
DEVNO *= *+1            ; Device number
NEEDASC *= *+1          ; True ASCII flag
UNDERLINE *= *+1        ; Underline mode flag
FPOS *= *+2             ; Found position
PCR *=  *+1             ; Usedby PCHROUT
HUNTLEN *= *+1          ; Length of hunt phrase
HUNTBUFF *= *+30        ; Holds hunt phrase
REPLEN *= *+1           ; Length of replacephrase
REPBUFF *= *+30         ; Holds replace phrase
CODEBUFFER *= *+128     ; Holds definable printkeys
PRBUFF *= *+256         ; Printer line buffer
HDBUFF *= *+256         ; Holds header
FIRSTRUN *= *+1         ; Has program been run before?
FTBUFF *= *+256         ; Holds footer
SAVCOL *= *+1           ; Save SCRCOL
LINEFEED *= *+1         ; Linefeed mode flag
ESCFLAG *= *+1          ; Was ESC pressed?
CONVFLAG *= *+1         ; Used by CAST and CINTOAS
SELFLAG *= *+1          ; The SELECT key flag
IOCB *= *+1             ; Which IOCB is OPEN
ACCESS *= *+1           ; Direction of ACCESS (read/write)
FNBUFF *= *+40          ; Filename buffer
FNLEN *= *+1            ; Filename Length
XSLOT *= *+1            ; Number of filename slots (DOSPAK)
SLOT *= *+130           ; Slot positions (DOSPAK)
XPTR *= *+1             ; Current filename slot (DOSPAK)
WHICHFLAG *= *+1        ; Which key is pressed
DIRCOUNT *= *+1         ; Directory count
BLINK *= *+1            ; Cursor blink flag
LINELEN *= *+1          ; Length of screen lines
RLM *=  *+1             ; REFRESH Left margin value
KEYVAL *= *+1           ; Which key is pressed
END =   *               ; High byte of this +$100 is TEXSTART

    .OPT OBJ

Autorun vector

    *=  $02E2
    .WORD BEGIN
    .END

Label Cross Reference. This chart makes it easier to find your place in the object code while looking at the source code. The number to the left of each label is its value or position within the object code. Labels preceded by an = mark are equates. Others are internal labels for object code positions.

43BA ACCESS
3A2E ACROSS
294B ADYCURR
3721 ALPHA
3614 ASCHEX
3C3C ASKREP
262C ASTOIN
3FCD BCD
1FOO BEGIN
446A BLINK
3029 BLIP
= 0074 BLUE
2983 BORDER
33AA BOTCLR
3FEI BOTMARG
3F79 BOTSCR
24D3 BREAK
3E3A BRMSG
3A92 BT
3F6C BUFEND
3DBB BUFERR
3FD3 BUFLEN
3CDE BUFLP
3CDC BUFPRT
33FF CAST
340C CAST1
3419 CASTOIN
3100 CATALOG
27CF CHECK
282D CHECK2
2F7F CHROUT
2FCB CHRYSAVE
3426 CIN
3407 CINTOAS
= E456 CIO
284C CK3
2D02 CLEAR
2501 CLEARED
28E2 CLEFT
3DIF CLOOP
3184 CLOSE7
254C CLR2
24F4 CLRLN
2543 CLRLOOP
3DED CLRMSG
4033 CODEBUFFER
3AFO COMMENT
3FE3 CONTINUOUS
2732 CONTROL
3BB7 CONTSRCH
43B7 CONVELAG
24D7 COPY
3296 COPYD
37EC COPYDEF
3801 COPYDEFS
32A3 COPYNAME
3332 COPYR
3446 COTHER
3998 CR
2SAF CRIGHT
3986 CRLF
3991 CRLOOP
2753 CTBL
= 0086 CURR
2EE7 CURSIN
3430 CVLOOP
3BDC CY
3282 DDOWN
3654 DECHEX
3AF6 DEFINE
3752 DEFTAB
2A6C DELI
2A80 DELlA
2A89 DEL2
2A7D DELABORT
2AAO DELC
2B32 DELCHAR
2B5C DELETE
32E5 DELFILE
2B4D DELIN
35FF DELITE
3DC7 DELMSG
288A DELSENT
2B7D DELWORD
= 0083 DESTH
= 0082 DESTL
3FD9 DESTSAV
3FEF DFVNO
3622 DIGIT
4469 DIRCOUNT
3F00 DIRINS
3156 DIRLOOP
3E6C DIRMSG
3E7A DIRNAME
25E9 DISKBOOT
3247 DLEFT
2EOA DLI
2DEE DUST
2DC8 DLOOP
2474 DMOVI
244D DMOVE
2476 DMOVLOOP
3170 DNOT8
315B DNOTCR
3873 DOBUF2
3869 DOBUFF
3D62 DOCODIIS
3B04 DODEFINE
26F4 DOINS
2D25 DOLT
3678 DONENUM
3D50 DOPGN
38EB DORPT
3IBB DOS
3229 DOSADR
33B6 DOSERR
33FF DOSMSG
3219 DOSTABLE
3254 DRIGHT
336F DRIVE
3271 DUP
2BD9 EATSPACE
3D2F EDGE
2F99 ENAME
= 446E END
31300 ENDBUFF
3194 ENDIR
319E ENDLP
3F73 ENDPOS
2967 ENDTEX
2814 EQA
2E97 ERAI
2EA6 ERA2
2E33 ERAS
2E42 ERAS1
2E4C ERASAGAIN
251F ERASE
2E7B ERASENT
3DFC ERASMSG
2E6E ERASWORD
34A7 ERR1
379B ERRLINK
3E32 ERRMSG
34AE ERROR
34C7 ERXIT
27BD ESC
3399 ESCDOS
43B6 ESCFLAG
2F2E ESCKEY
2C75 FILLSP
3201 FINDIT
3841 FINDSPACE
35E8 FINE
3F74 FINPOS
4283 FLRSTRUN
29F4 FIRSTWORD
2B3B FIXTP
2687 FLIPIT
43BB FNBUFF
3B1D FNCOPY
3B2F FNEND
43E3 FNLEN
3E9E FNMSG
3355 FORMAT
3F5A FORMSG
2740 FOUND
320C FOUNDIT
3858 FOUNDSPACE
3FF2 FPOS
3D6E FREEMEM
= 0081 FROMH
0080 FROML
3FD7 FROMSAV
39BF FSP
3850 FSPACE
3AD7 FT
42B4 FTBUFF
3AEO FTCOPY
3FDC FTLEN
31A9 GET7
256F GETAKEY
2FD6 GETCHAR
2FCC GETIN
31D6 GETNAME
2D4F GOADY
3FD5 GOBLEN
3565 GOERROR
2C06 GOINC
2FC1 GOPCHR
2AD4 GOSAV
32EA GOXIO
3001 GXIT
3AB5 HD
4183 HDBUFF
3ABE HDCOPY
3FDB HDLEN
3FCF HEX
2DAD HIGHLIGHT
= 0085 HLEN
2BAI HOME
2BC3 HOMEPAUSE
3B85 HUNT
3FF6 HUNTBUFF
3FF5 HUNTLEN
= 034A ICAUX1
= 034B ICAUX2
= 0344 ICBADR
= 0348 ICBLEN
= 0342 ICCOM
= 0343 ICSTAT
3FA3 INBUFF
250C INCNOT
3744 INCONT
= 008E INDIR
2F4D INEXIT
2589 INIT
25EA INIT2
2726 INKURR
3F78 INLEN
2CEI INOUT
2ED5 INP1
2ECE INPUT
2868 INRANGE
2C92 INSBLOCK
367D INSBUFFER
2C7C INSCHAR
3E80 INSERR
3FEE INSLEN
3F72 INSMODE
3E8C INSMSG
2CE2 INSTGL
374D INTl
3738 INTOAS
33E5 INVLP
33E3 INVNAME
3B9  IOCB
34E0 IOCLOSE
2575 JDOS
357B JFINE
32F2 JNAME
3040 KEYBOARD
2694 KEYPRESS
446D KEYVAL
2A50 KILLBUFF
3DAC KILLMSG
3F75 LASTLINE
295A LAST WORD
3F7B LBUFF
3B5A LCONT
28B8 LEFT
3F6E LENTABLE
298B LETTERS
3A68 LFSET
3F77 LIMIT
3FEB LINE
43B5 LINEFEED
446B LINELEN
3B19 LINK
= 0084 LLEN
3A74 LM
3975 LMARG
3FDD LMARGIN
3985 LMEXIT
397F LMLOOP
3B49 LNOERR
3554 LOAD2
3377 LOADIT
357E LOADLINK
3E54 LOADMSG
32F8 LOCK
2C4C LOTTASPACE
2645 LOWR
2648 MAIN
2651 MAIN2
2428 MOV1
242A MOV2
242F MOVLOOP
3A25 MRELEASE
3D88 MSG1
3D98 MSG2
3F71 MSGFLG
31E5 NAMELP
3294 NAMER
3FFO NEEDASC
38FC NEXPAGE
3EEB NFMSG
39ED NOAD
2F1B NOBACK
28AC NOBIGGER
2583 NOBLINK
3CFC NOBRK
28E8 NODEC
3571 NOER
2F04 NOESC
2A37 NOFIXCURR
35E2 NOGARBAGE
3963 NOHEADER
3675 NOHEXINC
272C NOINC2
28B5 NOINCR
2C63 NOINCY
3929 NOIPN
39A5 NOLF
3FE9 NOMARG
26B8 NOMSG
334F NONAME
3653 NONUM
2E91 NOPAR
31FF NOPROB
3C5C NOREP
3CD9 NOREPL
3902 NOSK
3B82 NOSR
32B2 NOSTOR
3735 NOTALPHA
26AC NOTBKS
300F NOTCAPS
3D2B NOTCENTER
26C2 NOTCR
2642 NOTCTRL
32BF NOTDOT
3D40 NOTEDGE
3C20 NOTFOUND
26F7 NOTINST
3024 NOTLOCKED
2455 NOTNULL
3D4C NOTOG
389E NOTPAGE
2BAO NOTPAR
344F NOTRC
382F NOTRET
3440 NOTRTN
26A6 NOTSEL
2B93 NOTSENT
3004 NOTSET
382B NOTSP
2B86 NOTWORD
2F13 NOTZERO
3BEA NOVFL
2E77 NOWORD
326E NRANGE
3AA6 NX
24C7 NXCUR
2941 OIDS
27FF OK1
282C OK2
36A5 OKBUFF
2DOF OKCLEAR
2CA9 OKINS
3568 OKLOD
36DF OKMOV
3E4A OKMSG
3BA6 OKSRCH
27C6 ONOFF
2FCA ONUMEXIT
2FBI ONUMLOOP
3508 OPABORT
3510 OPCONT
2F59 OPENEDITOR
3DOC OTHER
244C OUT
2BC9 OUTHOME
2FAO OUTNUM
287A OUTRANGE
2COB OUTSPACE
26E2 OVERCTRL
387B OVERMARG
3452 OVEROTHER
2FC4 OVERPCHR
385B OVERSTOR
2FA2 OVERZAP
38EE PAGE
3FDF PAGELENGTH
3FE4 PAGENUM
3FE8 PAGEWIDTH
2D64 PARCONT
2D31 PARIGHT
2D52 PARLEFT
2D5E PARLOOP
2D33 PARLP
3ACF PASTRET
37BB PBORT
3762 PCHROUT
3FF4 PCR
2514 PDONE
38D7 PEXIT
3A58 PL
24B1 PLINE
3814 PLOOP
3824 PLOOPI
29A7 PMANY
3A48 PN
3FEA POS
24AF PPAGE
40B3 PRBUFF
375E ERCODES
256E PREXIT
37B1 PRIN
3EB7 PRINMSG
37BE PRINT
2564 PRLOOP
2559 PRMSG
37D5 PROK
35F0 PROKMSG
2F9B PROUTNUM
29BD PSLOOP
29B9 PSRCH
29DE PUNCT
2A26 PUNCT2
3A62 PW
38C1 PXIT
= 0032 RED
312D REDIR
2826 REF
248B REFRESH
3308 RENAME
3F4F RENMSG
4015 REPBUFF
29EF REPEAT
3C5F REPL
4014 REPLEN
3USD REPLOOP
3C50 REPMOV
3EF5 REPMSG
3C30 REPSTART
3B91 RESET
3261 RESLOT
= 005E RETCHAR
380A RETEX
2D75 RETF2
2D4A RETFOUND
2885 RIGHT
446C RLM
2925 RLOOP
3A7E RM
3FDE RMARGIN
2933 ROUT
297A SAFE
3B64 SANDR
3FED SAVCHAR
43B4 SAVCOL
3FCB SAVCURR
3E1A SAVMSG
24D2 SBRK
= 0088 SCR
298A SCRCOL
43B8 SELFLAG
= O2BE SHFLOK
37A4 SHIFTFREEZE
2481 SKIPDMOV
1F34 SKIPERAS
3918 SKIPFT
2448 SKIPMOV
37A9 SKIPOUT
2F3E SKIPSEL
29E2 SKIPSPC
3974 SKIPTOP
299B SLEFT
24C3 SLOOP
43E5 SLOT
3036 SLOW
3031 SNDLOOP
3B6F SNR
3A9C SP
= 0000 SPACE
3FE2 SPACING
3A38 SPACE
39E6 SPCEXIT
39D5 SPCONT
2BE7 SPCSRCH
3D01 SPEC2
39A6 SPECIAL
39F1 SPTAB
3A03 SPVECT
2735 SRCH
3BC6 SRCHO
3BCD SRCH1
3EE5 SRCHMSG
39B1 SRCHSP
2A23 SREXIT
2A01 SRIGHT
2A03 SRLP
3FE6 STARTNUM
34D3 STOPPED
28F9 STRIP
2903 STRLOOP
37B1 SWITCH
260A SYSMSG
2C54 TAB
2C66 TAB2
= 008C TEMP
= 008A TEX
3F6A TEXBUF
299A TEXCOLR
3F68 TEXEND
35AB TEXOK
3F66 TEXSTART
2DA2 TEXTOCURR
3178 THROWS
3539 TLOAD
3BA8 TOBUFF
28DF TOOSMALL
394D TOP
261A TOPCLR
34EB TOPEN
2BCC TOPHOME
3F6F TOPLIN
261E TOPLOOP
396E TOPLP
3FEO TOPMARG
3A88 TP
3FD1 TPTR
345D TSAVE
2410 UMOVE
= 0090 UNDERCURS
3FF1 UNDERLINE
3300 UNLOCK
2E84 UNSENT
2777 VECT
2667 WAIT
3EC5 WAITMSG
2BBC WAITST
4468 WHICHFLAG
= 0091 WINDCOLR
28ED WLEFT
2906 WLOOP
2923 WRIGHT
2914 WROUT
2957 WRTN
374F XINT
32C8 XIO
4467 XPTR
43E4 XSLOT
3DD6 YMSG
2CEB YORN
2CF2 YORNKEY
3FEC YSAVE
3890 ZBUFF


Return to Table of Contents | Previous Chapter