4cade/src/parse.common.a

271 lines
8.0 KiB
Plaintext

;license:MIT
;(c) 2018-9 by 4am
;
; generic key/value text parser
;
; Public functions:
; - ParseKeyValueList
; - IncAndGetChar
;
;------------------------------------------------------------------------------
; ParseKeyValueList
; parse buffer with KEY=VALUE lines of a text file into an okvs
; keys and values limited to 127 characters, which should be enough for anyone
; if '=' is missing, key is kept and value is a 0-length string
; blank lines are ignored
; '#' character at beginning of line is a comment, entire line is ignored
; '[' character at beginning of line exits the parser
;
; in: stack contains 5 bytes of parameters:
; +1 [word] handle to storage space for okvs
; +3 [word] handle to buffer containing contents of text file
; +5 [byte] max length for okvs records (or 0)
; out: all registers and flags clobbered
; $1F00..$1FFF clobbered
; $00/$01 clobbered
; $02/$03 clobbered
; $04/$05 has the address of the next available byte after the okvs
; $FE/$FF clobbered
;------------------------------------------------------------------------------
ParseKeyValueList
+PARAMS_ON_STACK 5
+LDPARAM 1 ; not LDPARAMPTR, SetKeyPtr requires A/Y!
+ST16 @store2
jsr SetKeyPtr
ldy #5
lda (PARAM),y
sta @maxLength
ldy #$00 ; index into ($FE) pointing to current character
@newkey ldx #$00 ; X = index into current key
stx gValLen ; initialize value length (in case this line has no value)
beq @emptyline ; always branches
@skipLine ; skip to CR
jsr IncAndGetChar
cmp #$0A ; CR
bne @skipLine
@emptyline
jsr IncAndGetChar
cmp #$0A ; CR in first position (blank line) -> no key
beq @emptyline
cmp #$23 ; '#' starts a comment -> no key, skip to CR
beq @skipLine
cmp #$5B ; '[' ends the parsing
beq .parseKeyValueDone
bne @appendToKey
@gatherKey
jsr IncAndGetChar
cmp #$0A ; CR -> finalize key, no value
beq @finalizeKey
cmp #$3D ; '=' -> finalize key, start gathering value
beq @finalizeKey
@appendToKey
sta gKey,x
inx
bpl @gatherKey
@finalizeKey
stx gKeyLen
cmp #$0A
beq @storeInOKVS
ldx #$00 ; now X = index into the current value
@gatherValue
jsr IncAndGetChar
cmp #$0A ; CR -> finalize value
beq @finalizeValue
sta gVal,x
inx
bpl @gatherValue
@finalizeValue
stx gValLen
@storeInOKVS
tya
pha ; okvs functions clobber everything but we need Y
jsr okvs_append
@store2 !word $FDFD ; SMC
!word gKeyLen
!word gValLen
@maxLength
!byte $FD ; SMC
pla
tay
clc
bcc @newkey ; always branches
;------------------------------------------------------------------------------
; SetKeyPtr
;
; in: PARAM set
; out: okvs initialised
; ($FE) -> buffer
;------------------------------------------------------------------------------
SetKeyPtr
jsr okvs_init ; reset key/value store
+LDPARAMPTR 3, $FE
ldy #0
lda ($FE),y
tax
bne +
iny
lda ($FE),y
sta $FF
dec $FF
+ dex
stx $FE
rts
;------------------------------------------------------------------------------
; IncAndGetChar
;
; in: Y = index into ($FE)
; ($FE) -> buffer
; out: A contains next byte from buffer
; Y incremented
; $FF possibly incremented
;------------------------------------------------------------------------------
IncAndGetChar
iny
bne +
inc $FF
+ lda ($FE),y
cmp #$0D ; CR - hide it
beq IncAndGetChar
.parseKeyValueDone
rts
;------------------------------------------------------------------------------
; okvs_append
;
; in: stack contains 7 bytes of parameters:
; +1 [word] handle to storage space
; +3 [word] address of key
; +5 [word] address of value
; +7 [byte] maximum length of value (or 0 to fit)
; out: (new record count is not returned because no one cares)
; all registers clobbered
; $00/$01 clobbered
; $02/$03 clobbered
; $04/$05 has the address of the next available byte after the new record
; $08/$09 clobbered
;------------------------------------------------------------------------------
okvs_append
+PARAMS_ON_STACK 7
jsr GetStoreAddress
; PTR -> store
; Y = 0
lda (PTR),y ; A = number of keys in store
sta WINDEX
iny
lda (PTR), y
sta WINDEX+1
inc WINDEX
bne +
inc WINDEX+1
+
dey
lda WINDEX
sta (PTR),y ; increment number of keys
lda WINDEX+1
iny
sta (PTR),y
iny
lda (PTR),y ; get address of next free space
tax
iny
lda (PTR),y
sta PTR+1
sta SAVE+1
stx PTR
stx SAVE
; PTR -> new record
; SAVE -> new record
jsr incptr
; PTR -> space for new key
+LDPARAMPTR 3, SRC ; SRC -> new key to copy
ldy #0
lda (SRC),y
tay
tax
- lda (SRC),y ; copy new key
sta (PTR),y
dey
cpy #$FF
bne -
;;sec
txa
adc PTR ; update PTR to byte after copied key
sta PTR
bcc +
inc PTR+1
+ ; PTR -> space for new value
+LDPARAMPTR 5, SRC ; SRC -> new value to copy
iny ;;ldy #7
lda (PARAM),y ; get max length of value
tax
bne +
tay
lda (SRC),y ; no max, use actual length instead
tax
+ inx
tay
- lda (SRC),y
sta (PTR),y
dey
cpy #$FF
bne -
txa
clc
adc PTR
tax
lda PTR+1
adc #0
pha
+ jsr GetStoreAddress
; PTR -> store
pla
ldy #3
sta (PTR),y ; update next-free-space pointer in head
dey
txa
sta (PTR),y
sec
sbc SAVE
ldy #0
sta (SAVE),y ; set record length
rts
;------------------------------------------------------------------------------
; okvs_init
;
; in: A/Y = handle to storage space
; out: $00/$01 clobbered
; $02/$03 clobbered
; all registers clobbered
;------------------------------------------------------------------------------
okvs_init
jsr GetStoreAddressFromAY
; PTR -> store
; Y = 0
tya
sta (PTR),y ; set number of keys in store to 0 (word)
iny
sta (PTR),y
iny ; set next-free-space pointer to store + 4
ldx PTR+1
lda PTR
clc
adc #$04
bcc +
inx
+ sta (PTR),y
iny
txa
sta (PTR),y
rts