Estex-DSS/SHELL/Commands/IF.ASM

242 lines
4.8 KiB
NASM

;///////////////////////////////////////////////////
;
; IF - conditional command (MS-DOS style)
;
; IF [NOT] ERRORLEVEL number command
; IF [NOT] EXIST filename command
; IF [NOT] string1 == string2 command
;
; If the condition is true, the rest of the line is
; executed as an ordinary command (GOTO, ECHO, a
; program, another IF, ...).
;
;///////////////////////////////////////////////////
; in: de -> argument string (everything after "IF ")
cmd_if:
ex de,hl ; hl -> args
xor a
ld (.neg),a
call IF_SKIPB ; skip leading blanks
; --- optional NOT ---
ld de,.kw_not
call IF_KW
jr nc,.noNOT
ld a,1
ld (.neg),a
.noNOT:
; --- ERRORLEVEL n ? ---
ld de,.kw_errlvl
call IF_KW
jr nc,.notErr
ld de,Buffers.work.buffer1
ld c,Dss.GSwitch ; extract the number token
RST ToDSS
ld (.cmd),hl ; rest of line = command part
ld de,Buffers.work.buffer1
call IF_ATOI8 ; a = number (0..255)
ld b,a ; b = threshold
ld c,Dss.Get_Err ; a = exit code of last program
RST ToDSS
cp b ; A >= n ? (NC = yes)
ld a,0
jr c,.decide ; A < n -> false
inc a ; true
jr .decide
.notErr:
; --- EXIST filename ? ---
ld de,.kw_exist
call IF_KW
jr nc,.strcmp
ld de,Buffers.work.buffer1
ld c,Dss.GSwitch ; extract the filename token
RST ToDSS
ld (.cmd),hl ; rest of line = command part
ld a,FAT_ATTR.NoVolID ; any file/dir (not the volume label)
ld hl,Buffers.work.buffer1 ; filespec (NUL-term DOS name)
ld de,Buffers.work.buffer2 ; F_First work buffer
ld bc,Dss.F_First.DOSname ; B=1, C=#19
RST ToDSS
ld a,0
jr c,.decide ; CF=1 -> not found -> false
inc a ; exists -> true
jr .decide
.strcmp:
; hl -> string1 "==" string2 [blank] command
push hl ; s1 start
.find: ld a,(hl)
or a
jr z,.bad ; no "==" -> malformed
cp "="
jr nz,.fnext
inc hl
ld a,(hl)
cp "="
jr z,.foundEq
dec hl
.fnext: inc hl
jr .find
.bad: pop hl
ret ; syntax error -> no-op
.foundEq:
dec hl ; hl -> first '=' of "=="
pop de ; de = s1 start
push de
or a
sbc hl,de ; hl = len1 (line < 256 -> h=0)
ld a,l
ld (.len1),a
pop de ; de = s1 start
ld hl,0
ld l,a
add hl,de ; hl = s1 + len1 = first '='
inc hl
inc hl ; hl = s2 start
ld (.s2),hl
ld b,0 ; len2
.s2l: ld a,(hl)
cp " "+1 ; <=' ' (space/tab/CR/0) -> token end
jr c,.s2e
inc hl
inc b
jr .s2l
.s2e: ld (.cmd),hl ; command part starts here
ld a,(.len1)
cp b ; len1 == len2 ?
jr nz,.neq
or a
jr z,.eq ; both empty -> equal
ld c,a ; c = length
ld hl,(.s2)
.cl: ld a,(de) ; de = s1
cp (hl) ; case-sensitive (MS-DOS)
jr nz,.neq
inc de
inc hl
dec c
jr nz,.cl
.eq: ld a,1
jr .decide
.neq: xor a
;
.decide:
; a = raw condition (0/1)
ld b,a
ld a,(.neg)
xor b ; cond ^ NOT
and 1
ret z ; false -> nothing to do
ld hl,(.cmd)
jp IF_RUN ; true -> run the command part
;
.kw_not: db "NOT",0
.kw_errlvl: db "ERRORLEVEL",0
.kw_exist: db "EXIST",0
.neg: db 0
.cmd: dw 0
.len1: db 0
.s2: dw 0
;-------------------------------------------------
; Skip blanks (space / TAB) at (hl)
;-------------------------------------------------
IF_SKIPB:
.l: ld a,(hl)
cp " "
jr z,.i
cp "\t"
ret nz
.i: inc hl
jr .l
;-------------------------------------------------
; Case-insensitive keyword test.
; in: hl -> text, de -> keyword (UPPER, 0-term)
; out: CF=1 - matched, hl past keyword + blanks
; CF=0 - no match, hl unchanged
;-------------------------------------------------
IF_KW: push hl
.l: ld a,(de)
or a
jr z,.kend ; keyword consumed
ld c,a
ld a,(hl)
call COMPARE.cmp_AZ ; -> upper
cp c
jr nz,.no
inc hl
inc de
jr .l
.kend: ld a,(hl) ; must be a blank delimiter
cp " "
jr z,.ok
cp "\t"
jr z,.ok
.no: pop hl ; restore, no match
or a ; CF=0
ret
.ok: inc hl ; skip delimiter + following blanks
.ok2: ld a,(hl)
cp " "
jr z,.oki
cp "\t"
jr nz,.done
.oki: inc hl
jr .ok2
.done: pop bc ; discard saved hl
scf
ret
;-------------------------------------------------
; ASCII decimal -> A (0..255, saturating)
; in: de -> digits
;-------------------------------------------------
IF_ATOI8:
ld hl,0
.l: ld a,(de)
sub "0"
jr c,.end
cp 10
jr nc,.end
ld c,a ; c = digit
ld b,0
push de
ld d,h
ld e,l
add hl,hl ; *2
add hl,hl ; *4
add hl,de ; *5
add hl,hl ; *10
add hl,bc ; + digit
pop de
inc de
jr .l
.end: ld a,h
or a
jr nz,.sat
ld a,l
ret
.sat: ld a,255
ret
;-------------------------------------------------
; Run the conditional command.
; in: hl -> command text (NUL-term at line end)
;-------------------------------------------------
IF_RUN:
call IF_SKIPB
ld a,(hl)
or a
ret z ; empty -> no-op
ld d,h
ld e,l ; de = command start
ld bc,0 ; b=0, c = token length
.tl: ld a,(hl)
cp " "+1 ; <=' ' -> end of command token
jr c,.tle
inc hl
inc c
jr .tl
.tle: ld hl,BATLIST ; bat + dos commands
jp COMP.start ; dispatch (recurses for nested IF)