;/////////////////////////////////////////////////// ; ; 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)