;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;ADD termination bit to ENCBUF
;
eterm: push af
push bc
push de
push hl
ld hl,encbuf
ld a,(encptr) ;A = no. of characters in buffer.
or a
jr z,eterm2
dec a
eterm1: cp 3 ;Reset the "termination" bit on all
jr c,eterm2 ;characters except the last.
res 7,(hl)
inc hl
inc hl
sub 3
jr eterm1
;
eterm2: or a
jr z,eterm3
ld d,5 ;IF no. of characters remaining is not a
call eaddch ;multiple of 3, append character 5 until it is.
dec a
jr nz,eterm2
eterm3: set 7,(hl) ;SET the termination bit at the end.
;
;<< v0.02 Also set termination bits at encbuf+4 (z1-z3) or encbuf+6 (z4+)
;
ld hl,encbuf+2 ;Start of 2nd word
ld a,(zver)
cp 4
jr c,etermz
ld hl,encbuf+4 ;Start of 3rd word
jr etermz
;
etermz: set 7,(hl) ; >> v0.02
jp popd
;
;Append the character in D to ENCBUF
;
eaddch: push af
push bc
push de
push hl
ld a,d
and 1fh
ld d,a
;
;Append character D to encbuf
;
ld hl,encbuf
ld a,(encptr)
inc a
ld (encptr),a
dec a
encoff: cp 3
jr c,encmap
inc hl
inc hl
sub 3
jr encoff
;
;HL->correct part of the buffer.
;
encmap: or a
jr z,eadd0
dec a
jr z,eadd1
eadd2: inc hl
ld a,(hl)
and 0E0h
or d
ld (hl),a
jp popd
;
eadd0: ld a,(hl)
and 083h
rlc d
rlc d
or d
ld (hl),a
jp popd
;
eadd1: ld a,d
rrca
rrca
rrca ;A is now LLL000HH
ld e,a
and 3
ld d,a ;D is 000000HH
ld a,e
and 0E0h
ld e,a ;E is LLL00000
ld a,(hl)
and 07Ch
or d
ld (hl),a
inc hl
ld a,(hl)
and 1Fh
or e
ld (hl),a
jp popd
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Encode B ASCII chars at z-address HL to z-chars in encbuf. encbuf
; holds big-endian words.
;
encal: defb 0 ;Encoding alphabet
encptr: defb 0 ;No. of characters in ENCBUF
;
encode: push af
push bc
push de
push hl
xor a
ld (encal),a
ld (encptr),a
enchar: call peek64 ;A = ascii character
inc hl
push hl
;
;See if the character can be found in the alphabets al0, al1, al2
;
ld hl,al0+6
call findc
jr z,eadd5
ld hl,al1+6
call findc
jr z,eadd6
ld hl,al2+7
call finda2
jr z,eadd7
;
;ADD literal character...
;
ld d,5 ;Shift to alphabet 2
call eaddch
ld e,a ;E = ASCII character
ld d,6 ;ASCII escape
call eaddch
ld a,e ;A = HHHLLLLL
rlca
rlca
rlca
and 7
ld d,a
call eaddch
ld a,e
and 1fh
ld d,a
call eaddch
jr ence
;
eadd5: call eaddch
jr ence
;
eadd6: ld a,d
ld d,4
jp adds
;
eadd7: ld a,d
ld d,5
adds: call eaddch
ld d,a
call eaddch
ence: pop hl
djnz enchar
ence1: ld a,(encptr)
cp 9
call nc,eterm
jp nc,popd
ld d,5
call eaddch
jr ence1
;
finda2: push bc ;Special case for alphabet 2.
ld c,a
ld b,25
ld d,7
jr findcl
findc: push bc ;Returns Zero set if a character matches,
ld c,a ;D = character number
ld d,6
ld b,26
findcl: ld a,(hl)
cp c
jr z,findc2
inc d
inc hl
djnz findcl
xor a
inc a
ld a,c
findc2: pop bc
ret
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Output a z-char in A.
;
abbrev: defb 0 ;nonzero if expanding an abbreviation
dalpha: defb 0 ;Default alphabet number
alpha: defb 0 ;Alphabet number
shift: defb 0 ;Under shift conditions?
multi: defb 0 ;IN multi-char sequence?
multw: defw 0 ;The character to create in multi-char sequence.
;
op_zchar:
push af
push bc
push de
push hl
ld c,a
ld a,(multi)
or a
jr nz,nabb2 ;IF in a multi-byte char, don't try to
ld a,(abbrev) ;expand it as an abbreviation
or a
jp nz,opabb
ld a,(zver)
cp 3
jr c,nabb1
ld a,c
cp 1 ;1,2,3 are abbreviation characters
jr z,abbr
cp 2
jr z,abbr
cp 3
jr z,abbr
jr nabb2
;
nabb1: cp 2
jr c,nabb2
abbr: ld a,c
ld (abbrev),a
jp popd
;
nabb2: ld a,c ;A = packed char
call zchar2
jp popd
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Expand abbreviation string - A is 1st character, C is second
;
opabb: dec a ;<< v0.02 thoroughly rewritten
rlca
rlca
rlca
rlca
rlca ;A = (Z - 1) * 32
and 60h
add a,c ;A = (Z - 1) * 32 + X
ld c,a
ld b,0 ;BC = abbreviation no.
push bc
ld hl,18h
ld e,0
call ZXPKWI ;BC = base of abbreviation table
pop hl
xor a
ld (abbrev),a ;Reset "expand abbreviation" flag
add hl,hl
add hl,bc
ld e,0
call ZXPKWI ;BC = address of abbreviation string
ld h,b ; (word address, so in the bottom 128k)
ld l,c
ld a,h
add hl,hl ;Convert to byte address
bit 7,a
ld e,0
jr z,abblp
inc e ;High byte of address
abblp: call ZXPKWI
push de
push hl
push bc
ld a,b
rrca
rrca
and 01Fh
call op_zchar ;Recursive call.
ld a,b ;According to the Z-Spec, an abbreviation
rlca ;cannot contain other abbreviations.
rlca ;But since Curses (R12) tries to print
rlca ;abbreviations containing abbreviations,
and 18h ;we have to support it.
ld b,a ;Otherwise, these calls would be to zchar2.
ld a,c
rlca
rlca
rlca
and 7
or b
call op_zchar ;Recursive call.
ld a,c
and 1Fh
call op_zchar ;Recursive call.
pop bc
pop hl
pop de
bit 7,b
jr z,abblp
call rshift ;Swallow any "packing" shift characters
jp popd ;>> v0.02
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Output a Z-char, which we know isn't an abbreviation
;
zchar2: push hl
push bc
ld l,a
ld a,(multi)
or a
jp nz,xmult
ld a,l
cp 8
jp nc,zch0
ld h,0
add hl,hl
ld bc,chartbl
add hl,bc
ld e,(hl)
inc hl
ld d,(hl)
ex de,hl
jp (hl)
;
zch6: ld l,a
ld a,(alpha)
cp 2
jr nz,zch0a
ld a,1
ld (multi),a
jr zcret
zch0: ld l,a
zch0a: ld a,(alpha)
or a
ld de,al0
jr z,xlet
ld de,al1
dec a
jr z,xlet
ld de,al2
ld a,(zver)
cp 1
jr nz,xlet
ld de,al2a
xlet: ld h,0
add hl,de
ld l,(hl)
ld h,0
call ll_zchr
zcret: call rshift
zcr1: pop bc
pop hl
ret
;
rshift: push af ;Reset shifts
xor a
ld (shift),a
ld a,(dalpha)
ld (alpha),a
pop af
ret
;
;;;;;;;;;;;;;;;;;;;;;;
;
;Special handlers for the first 8 characters
;
chartbl:
defw zch0, zch1, zch2, zch3, zch4, zch5, zch6, zch0
;
zch1: ld hl,0dh ;Z-char 1 is a newline in v1
call ll_zchr
jp zcret
;
zch2: ld a,(dalpha) ;Z-char 2: shift to next alphabet
inc a
cp 3
jr c,zch2a
xor a
zch2a: ;ld (dalpha),a ;<< v0.02 >> this is a shift not a lock
ld (alpha),a
jp zcr1
;
zch3: ld a,(dalpha) ;Z-char 3: shift to prev alphabet
dec a
jr z,zch2a
ld a,2
jr zch2a
;
zch4: ld (shift),a ;Z-char 4: shift to alphabet 1 (3+)
ld a,(zver) ;or next alphabet (1,2)
cp 3
jr c,zch4a
ld a,1
ld (alpha),a
jp zcr1
;
zch4a: ld a,(alpha) ;Shift lock to next alphabet
inc a
cp 3
jr c,zch4b
xor a
zch4b: ld (alpha),a
ld (dalpha),a ;<< v0.02 >> this is the shift lock
jp zcr1
;
zch5: ld (shift),a ;Z-char 5: Shift to alphabet 2 (3+)
ld a,(zver) ;or previous alphabet (1,2)
cp 3
jr c,zch5a
ld a,2
ld (alpha),a
jp zcr1
;
zch5a: ld a,(alpha) ;Shift lock to previous alphabet
dec a
jr nc,zch4b
ld a,2
jr zch4b
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Alphabets
; ;0123456789abcdef0123456789abcdef
al0: defb ' *****abcdefghijklmnopqrstuvwxyz'
al1: defb ' *****ABCDEFGHIJKLMNOPQRSTUVWXYZ'
al2: defb ' ******'
defb 0dh
defb '0123456789.,!?_#'
defb 027h
defb '"/\-:()'
al2a: defb ' ******0123456789.,!?_#'
defb 027h
defb '"/\<-:()'
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;CREATE a multi-byte char. A = 1 or 2; L = character
;
xmult: dec a
jr nz,xmult2
ld h,0
add hl,hl
add hl,hl
add hl,hl
add hl,hl
add hl,hl
ld (multw),hl
ld a,2
ld (multi),a
jp zcret
;
xmult2: ld a,l
ld hl,(multw)
or l
ld l,a
call ll_zchr
xor a
ld (multi),a
jp zcret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;This code handles buffering and streamed output. Initialise...
;
inibuf: ld hl,buffer ;Initialise buffers and streams
ld (bufptr),hl
ld hl,0
ld (bufcc),hl
ld (bufcs),hl
ld a,1
ld (bufmde),a
ld hl,t3ptr
ld (t3ptr),hl
scf
xor a
ld (strm2),a
ld (strm3),a
ld (strm4),a
inc a
ld (strm1),a
ld hl,21h
call ZXPK64 ;Screen width
ld (buf_maxw),a
ld a,1
ld (cwin),a
ld hl,34h ;<< v0.04 support alphabet table
ld e,0
call ZXPKWD ;Get alphabet table address
ld a,b
or c
scf
ret z ;Default
ld h,b
ld l,c
ld de,al0+6
ld b,26 ;Values for alphabet 0
call mcpy
ld de,al1+6
ld b,26 ;For alphabet 1
call mcpy
ld de,al2+8
inc hl ;For alphabet 2 (skip nos. 6 & 7)
inc hl
ld b,24
call mcpy
scf
ret
;
mcpy: call ZXPK64
ld (de),a
inc hl
inc de
djnz mcpy
ret ;>> v0.04
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Write the buffer contents to screen
;
flush_buf:
push af
push bc
push de
push hl
;
;The buffer contains a word and some separators. See if the whole lot will fit.
;
ld hl,buffer ;<< v0.02
ld a,(bufcc)
ld b,a
ld a,(bufcs)
ld c,a
call ZXBFIT
cp 2
jr c,flushm ;Yes, it will.
ld hl,0Dh ;No. Write CR; then the whole lot.
call char_out ;Write character
bwrd1: xor a
flushm: or a ;A = 0: flush all. A = 1: print text, not separators
ld hl,(bufcc)
jr nz,flush0
ld de,(bufcs)
add hl,de
flush0: ld bc,buffer ;HL = count of chars to print
ld (bufptr),bc
ld bc,0
ld (bufcs),bc ;Reset buffer counters
ld (bufcc),bc
ld a,(bufmde)
or a
jr z,flush1
ld a,1
ld (bufmde),a
flush1: ld b,h ;BC = no. of bytes to print. See if it will fit
ld c,l ;within the margin
ld de,buffer
flushlp:
ld a,b
or c
jp z,popd
dec bc
ld a,(de)
ld l,a
inc de
ld a,(de)
ld h,a
inc de
push de
push bc
call char_out
pop bc
pop de
jr flushlp
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Passed a character in HL, decide where it goes.
;
ll_zchr:
ld a,(strm3) ;To stream 3?
or a
jp z,strm_gen
;
;Write to stream 3
;
push hl
ld hl,(t3ptr)
ld e,(hl)
inc hl
ld d,(hl) ;DE = address of table
ld h,d
ld l,e ;HL = address of table
call peek64
ld b,a
inc hl
call peek64
ld c,a ;BC = length of text so far
inc hl
add hl,bc
ex (sp),hl
ld a,l ;A = byte to write
ex (sp),hl
call ZXPOKE
inc bc
ex de,hl ;DE = address of table
ld a,b
call ZXPOKE
inc hl
ld a,c
call ZXPOKE
pop hl
scf
ret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Returns Carry set if character in L is a separator
;
issep: ld a,l
cp 21h
ret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Write character in HL to its streams, taking account of buffering
;
strm_gen:
ld a,(cwin) ;Top window?
or a
jp z,char_out
ld a,(bufmde) ;bufmde is: 1 when reading non-separators
or a ; 2 when reading separators
jp z,char_out ; 0 if not buffered
cp 2
jr nz,bufapp ;Append non-separator
call issep
call nc,flush_buf ;Next word; flush the buffer
bufapp: ld a,l
cp 0Dh ;Newline, flush the buffer.
jp z,bufnl
push hl ;Append character in HL to the buffer.
ex de,hl
ld hl,(bufptr)
ld (hl),e
inc hl
ld (hl),d ;Character buffered.
inc hl
ld (bufptr),hl
ex de,hl
call issep ;Was it a separator?
jr c,isep
ld hl,(bufcc)
inc hl
ld (bufcc),hl
jr ckover
;
isep: ld hl,(bufcs)
inc hl
ld (bufcs),hl
ld a,2
ld (bufmde),a
;
;Check for buffer overflow. This happens when:
;
ckover: pop hl ;The character.
;
;* There are <width> non-separators in the buffer.
;
call ZXGETX
ld l,a ;L = total screen width
ld a,(bufcc)
ld c,a
cp l ;Screen width
ccf
jp c,flush_buf
;
;* There are <width> separators in the buffer.
;
ld a,(bufcs)
ld b,a
cp l
ccf
jp c,flush_buf
;
;* There are <width> characters in the buffer in total.
; (doing it separately avoids overflow on very wide screens :-) )
;
ld a,b
add a,c
cp l
ret c
scf
jp flush_buf
;
bufnl: call flush_buf
ld hl,0dh
;
;Fall through to char_out
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Write a character in HL to its streams, with no buffering
;
char_out:
ld a,(strm1)
or a
push hl
ld a,1 ;Stream 1
call nz,ZXZCHR
pop hl
ld a,(strm2)
or a
ld a,2 ;Stream 2
scf ;<< v0.04 support printer abort. IF ZXZCHR
call nz,ZXZCHR ; returns carry clear, turn off
ret c ; printer output and reset the
xor a ; transcript bit.
ld (strm2),a
jp ts_off ;>> v0.04
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Select output stream.
;
ll_strm:
cp 3
jr z,sets3
cp 0FDh
jp z,usets3
bit 7,a
jr z,strmon
strmoff: push af ;Deactivate a stream
neg
dec a
ld hl,strm1
ld e,a
ld d,0
add hl,de
ld (hl),0
pop af
cp 0FEh ;Transcript
jp nz,ZXSTRM
call ZXSTRM
jr c,ts_off
ld a,1
ld (strm2),a
jp ts_err
;
strmon: push af ;Activate a stream
dec a
ld hl,strm1
ld e,a
ld d,0
add hl,de
ld (hl),1
pop af
cp 2
jp nz,ZXSTRM
call ZXSTRM
jr c,ts_on
xor a
ld (strm2),a
jp ts_err
ts_on: ld hl,11h
call ZXPK64
or 1
call ZXPOKE
scf
ret
;
ts_off: ld hl,11h
call ZXPK64
res 0,a
call ZXPOKE
scf
ret
;
sets3: ex de,hl ;DE = data address
ld a,(strm3)
cp 16
ld hl,s3err
ret nc
ld hl,(t3ptr) ;Open a stream 3.
dec hl
ld (hl),d
dec hl
ld (hl),e
ld (t3ptr),hl
ld a,(strm3)
inc a
ld (strm3),a
;
; << v0.04 Reset the "count" to 0 when the stream is selected
;
ex de,hl
xor a
call ZXPOKE
inc hl
xor a
call ZXPOKE
dec hl
ex de,hl
;
; >> v0.04
;
ld a,3
jp ZXSTRM
;
usets3: ld a,(strm3)
or a
scf ;Close a stream 3.
ret z
dec a
ld (strm3),a
ld hl,(t3ptr)
inc hl
inc hl
ld (t3ptr),hl
ld a,0FDh
jp ZXSTRM
;
;Numeric data.
;
cwin: defb 0 ;Current output window no.
bufmde: defb 0 ;Buffered?
buffer: defs 512 ;Wordwrap buffer
bufptr: defw 0 ;Pointer into same
bufcc: defw 0 ;No. of non-separator chars
bufcs: defw 0 ;No. of separator chars
table3: defs 32 ;Table stack for stream 3 to use
t3ptr: defw 0 ;Pointer into the table stack
strm1: defb 1 ;Stream 1 (screen) active?
strm2: defb 0 ;Stream 2 (transcript) active?
strm3: defb 0 ;Stream 3 (memory) active?
strm4: defb 0 ;Stream 4 (scripting) active?
buf_maxw:
defb 0 ;Screen width
s3err: defb 'O Stream 3 nestin' ;Stream 3 nested too deeply.
defb 0E7h ;'g'+80h
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; << v0.04 Validate an input character in A. Invalid characters become " "
;
valid_char:
cp 8
ret z
cp 13
ret z
cp 27
ret z
cp 32
jr c,valid_c2
cp 127
ret c
cp 129
jr c,valid_c2
cp 251
ret c
valid_c2:
ld a,' '
ret
;
; >> v0.04