2019-06-02 14:05:20 -04:00
|
|
|
; *** Consts ***
|
|
|
|
; maximum number of bytes to receive as args in all commands. Determines the
|
|
|
|
; size of the args variable.
|
|
|
|
.equ PARSE_ARG_MAXCOUNT 3
|
|
|
|
|
|
|
|
; *** Code ***
|
|
|
|
|
|
|
|
; Parse arguments at (HL) with specifiers at (DE) into (IX).
|
|
|
|
;
|
|
|
|
; Args specifiers are a series of flag for each arg:
|
|
|
|
; Bit 0 - arg present: if unset, we stop parsing there
|
|
|
|
; Bit 1 - is word: this arg is a word rather than a byte. Because our
|
|
|
|
; destination are bytes anyway, this doesn't change much except
|
|
|
|
; for whether we expect a space between the hex pairs. If set,
|
|
|
|
; you still need to have a specifier for the second part of
|
|
|
|
; the multibyte.
|
|
|
|
; Bit 2 - optional: If set and not present during parsing, we don't error out
|
|
|
|
; and write zero
|
|
|
|
;
|
|
|
|
; Bit 3 - String argument: If set, this argument is a string. A pointer to the
|
|
|
|
; read string, null terminated (max 0x20 chars) will
|
|
|
|
; be placed in the next two bytes. This has to be the
|
|
|
|
; last argument of the list and it stops parsing.
|
|
|
|
; Sets A to nonzero if there was an error during parsing, zero otherwise.
|
|
|
|
parseArgs:
|
|
|
|
push bc
|
|
|
|
push de
|
|
|
|
push hl
|
|
|
|
push ix
|
|
|
|
|
|
|
|
; init the arg value to a default 0
|
|
|
|
xor a
|
|
|
|
ld (ix), a
|
2019-06-14 21:10:18 -04:00
|
|
|
ld (ix+1), a
|
|
|
|
ld (ix+2), a
|
|
|
|
ld b, PARSE_ARG_MAXCOUNT
|
|
|
|
.loop:
|
2019-06-02 14:05:20 -04:00
|
|
|
ld a, (hl)
|
|
|
|
; is this the end of the line?
|
|
|
|
or a ; cp 0
|
|
|
|
jr z, .endofargs
|
|
|
|
|
|
|
|
; Get the specs
|
|
|
|
ld a, (de)
|
|
|
|
bit 0, a ; do we have an arg?
|
|
|
|
jr z, .error ; not set? then we have too many args
|
2019-06-02 14:46:07 -04:00
|
|
|
|
|
|
|
ld c, a ; save the specs for multibyte check later
|
2019-06-02 14:05:20 -04:00
|
|
|
bit 3, a ; is our arg a string?
|
|
|
|
jr z, .notAString
|
|
|
|
; our arg is a string. Let's place HL in our next two bytes and call
|
|
|
|
; it a day. Little endian, remember
|
|
|
|
ld (ix), l
|
|
|
|
ld (ix+1), h
|
|
|
|
jr .success ; directly to success: skip endofargs checks
|
2019-06-02 14:46:07 -04:00
|
|
|
|
2019-06-02 14:05:20 -04:00
|
|
|
.notAString:
|
|
|
|
call parseHexPair
|
|
|
|
jr c, .error
|
2019-06-02 14:46:07 -04:00
|
|
|
|
2019-06-02 14:05:20 -04:00
|
|
|
; we have a good arg and we need to write A in (IX).
|
|
|
|
ld (ix), a
|
|
|
|
|
|
|
|
; Good! increase counters
|
|
|
|
inc de
|
|
|
|
inc ix
|
|
|
|
inc hl ; get to following char (generally a space)
|
2019-06-02 14:46:07 -04:00
|
|
|
|
|
|
|
; Our arg is parsed, our pointers are increased. Normally, HL should
|
|
|
|
; point to a space *unless* our argspec indicates a multibyte arg.
|
|
|
|
bit 1, c
|
|
|
|
jr nz, .nospacecheck ; bit set? no space check
|
|
|
|
; do we have a proper space char (or null char)?
|
|
|
|
ld a, (hl)
|
|
|
|
or a
|
|
|
|
jr z, .endofargs
|
|
|
|
cp ' '
|
|
|
|
jr nz, .error
|
|
|
|
inc hl
|
|
|
|
.nospacecheck:
|
2019-06-02 14:05:20 -04:00
|
|
|
djnz .loop
|
|
|
|
; If we get here, it means that our next char *has* to be a null char
|
|
|
|
ld a, (hl)
|
2019-06-02 14:46:07 -04:00
|
|
|
or a ; cp 0
|
2019-06-02 14:05:20 -04:00
|
|
|
jr z, .success ; zero? great!
|
|
|
|
jr .error
|
|
|
|
|
|
|
|
.endofargs:
|
|
|
|
; We encountered our null char. Let's verify that we either have no
|
|
|
|
; more args or that they are optional
|
|
|
|
ld a, (de)
|
2019-06-02 14:46:07 -04:00
|
|
|
or a
|
2019-06-02 14:05:20 -04:00
|
|
|
jr z, .success ; no arg? success
|
|
|
|
bit 2, a
|
2019-06-02 14:46:07 -04:00
|
|
|
jr z, .error ; if unset, arg is not optional. error
|
|
|
|
; success
|
2019-06-02 14:05:20 -04:00
|
|
|
.success:
|
|
|
|
xor a
|
|
|
|
jr .end
|
|
|
|
.error:
|
|
|
|
inc a
|
|
|
|
.end:
|
|
|
|
pop ix
|
|
|
|
pop hl
|
|
|
|
pop de
|
|
|
|
pop bc
|
|
|
|
ret
|
2019-11-15 15:37:49 -05:00
|
|
|
|