home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
mbug
/
mbug141.arc
/
IF.LBR
/
IF.AQM
/
IF.ASM
Wrap
Assembly Source File
|
1979-12-31
|
11KB
|
347 lines
;
; IF -- conditionally execute or skip commands witthin a submit file
;
; Written by Marc C. Brooks 1/4/83
;
; based on David Kirkland's version of SKIPIF as of 6/12/83
;
; Usage:
;
; IF A[mbig] fn true if fn is ambigous
; IF E[xists] fn true if file fn exists
; IF M[issing] fn true if file fn does not exist
; IF N[ull] (fn) true if the fn is missing
; IF Z[ero] fn true if file fn is zero length or does not exist
;
; If the condition is true, all commands up to the next ELSE or
; ENDIF statement are executed. If an ELSE is encountered before
; the ENDIF statement is reached, commands are skipped until the
; ENDIF is found. If the condition is false, commands are skipped
; until the matching ELSE or ENDIF is found. Command execution then
; resumes. IF-ELSE-ENDIF groups may be nested to any depth.
;
; Only the first character of the first keyword (the A of Ambig or
; whatever) is checked. If an invalid keyword is entered, all
; commands between the IF and its matching ENDIF will be skipped
; (after a suitable error message.)
;
cpm equ 0000h
tpa equ 0100h
ccpoff equ 0806h ; offset from (bdos+1) to bottom of ccp
bdos equ 0005h
fcb1 equ 005ch ;the first fcb prepared by the CCP
name1 equ fcb1+1 ; start of the filename of fcb1 (AEMN or Z)
fcb2 equ 006ch
name2 equ fcb2+1
fcb2CUR equ fcb2+32 ; current record for fcb2
;
drive equ 'A' ; the drive with the $$$.SUB file
bell equ 07h ; an ASCII bell character
; BDOS codes used
;
PrtStr equ 9 ; Print a string to console (terminated by $)
Open equ 15 ; Open a file
Close equ 16 ; Close a file
Srch1st equ 17 ; Search for the first occurence of a file
Erase equ 19 ; Erase a file
Read equ 20 ; Read a sequential record from a file
SetDma equ 26 ; Set the dma buffer address
;
org tpa
;
; First set the Stack, Dma address and check for a $$$.SUB file
;
lhld bdos+1 ; get the address of the BDOS
lxi d,-ccpoff ; and add the CCP offset
dad d ; set the stack below the CCP
sphl
mvi c,SetDma ; set the dma address to the buffer following
lxi d,dmabuf ; the variables.
call bdos
mvi c,Open ; open $$$.SUB
lxi d,subfile
call bdos
inr a ; check to see if the $$$.SUB exists
jz explain ; if not, explain the syntax and return
;
; Everything is fine so execute the command the caller actually asked for
;
lda name1 ; first character of the AMBIG or EXISTS or ..
cpi 'N' ; Null?
jz null
lda name2 ; check the to see if the user gave
cpi 020h ; a filespec as the second argument
jnz process
mvi c,PrtStr ; fn is null, bitch to user and skip both the
lxi d,FnNulMsg ; IF and ELSE clauses
call bdos
jmp skipboth
process lda name1 ; okay, we have a filespec, branch to command
cpi 'A' ; Ambig?
jz ambig
cpi 'E' ; Exists?
jz exists
cpi 'M' ; Missing?
jz missing
cpi 'Z' ; Zero?
jz zero
mvi c,PrtStr ; no match so print error message
lxi d,BadOptMsg
call bdos
jmp skipboth ; skip both IF anf ELSE clauses
; ambig - do the IF clause if the 2nd argument is ambiguous
ambig mvi b,11 ; 11 characters in filename & filetype
lxi h,name2 ; bypass the drive code
scanlp mov a,m ; scan for '?' in parsed fcb
cpi '?'
jz cpm ; fn is ambiguous, return to CP/M
inx h
dcr b ; done ?
jnz scanlp ; no, loop back for next char
jmp false ; no '?', so false
; exists - do the IF clause if the file exists
exists call search
jnz cpm ; file found, return to CP/M
jmp false
; missing - do the IF clause if the file does not exist
missing call search
jnz false
jmp cpm ; file not found, return to CP/M
; null - do the IF clause if the second parameter is missing
null lda name2 ; Check the second FCB to see if the user
cpi 020h ; gave a filespec as the second arg
jnz false
jmp cpm ; fn is not present, return to CP/M
; zero - do the IF clause if the 2nd argument is a zero length file
zero call search ; does the file exist?
jz cpm ; nope, zero long then so return to CP/M
mvi c,Open ; yes, lets open it
lxi d,fcb2
call bdos
xra a ; zero the current record byte
sta fcb2CUR
mvi c,Read ; now try to read one record (will fail if
lxi d,fcb2 ; the file is zero length)
call bdos
ora a
jz false ; read was OK, so not zero length
jmp cpm ; read failed, return to CP/M
; search - search for the first (possibly) ambiguous file to match fcb
search mvi c,Srch1st
lxi d,fcb2
call bdos
inr a ; adjust the flags
ret
; skipboth - tell the user and skip both clauses of the IF
skipboth mvi c,PrtStr ; tell the user that both the IF and the
lxi d,SkipMsg ; ELSE clauses are being skipped
call bdos
mvi c,Open ; open $$$.SUB
lxi d,subfile
call bdos
call skipend ; skip line till the ENDIF is encountered
mvi c,Close ; close the $$$.SUB to rewrite the modified fcb
lxi d,subfile
call bdos
jmp cpm ; return to CPM
; false - skip all command up to and including the ELSE, then return
false mvi c,Open ; open $$$.SUB
lxi d,subfile
call bdos
call skipelse ; skip lines till ELSE or ENDIF
mvi c,Close ; close the $$$.SUB to rewrite the modified fcb
lxi d,subfile
call bdos
jmp cpm ; return to CP/M to execute else clause
; skipend - skip lines in the $$$.SUB file till an ENDIF is found
skipend call nxtline ; get the next line from the $$$.SUB file
lxi d,EndLit ; point to the ENDIF literal
call compstr ; and compare
jnz skipend ; not equal, loop till it is
ret ; equal, return to caller
; skipelse - skip lines in the $$$.SUB file till an ELSE or ENDIF is found
skipelse call nxtline ; get the next line from the $$$.SUB file
lxi d,ElseLit ; point to the ELSE literal
call compstr ; now compare the record just read to if equal
rz ; yes, return to caller
lxi d,EndLit ; point to the ENDIF literal
call compstr ; and compare
jnz skipelse ; not equal, loop till found
ret ; equal, return to caller
; nxtline - get the next line from the $$$.SUB file (with recursion stuff)
nxtline call nxtcmd ; get the next command line from the $$$.SUB
lxi d,IfLit ; is it an IF statement?
call compstr
rnz ; nope, okay, return the line to caller
call skipend ; yes, skip both clauses of this nested IF
jmp nxtline ; and now get the next command line
; nxtcmd - get the command line from the $$$.SUB file and chop it off the file
nxtcmd lda subCNT ; get the current record count for $$$.SUB
dcr a ; decrement by one
sta subREC ; and set the current record
mvi c,Read ; read the next command
lxi d,subfile
call bdos
inr a
jz killsub ; if error, kill $$$.SUB and exit
lxi h,dmabuf ; load the address of the command buffer
mov e,m ; get the byte count
mvi d,0
dad d
inx h
mvi m,0 ; and terminate the command with a zero
lxi h,subs2 ; zero the S2 byte of the fcb to force the
mvi m,0 ; BDOS to rewrite it
inx h ; now point to the record count byte
mov a,m ; and see if it is a zero
ora a
jz erasub ; yes, erase the $$$.SUB and return to CP/M
dcr m ; no, decrement the record count and return
ret
; compstr - compare the command just read to the literal point to by DE
compstr lxi h,dmabuf+1 ; get the address of the command and
; skip the leading whitespace
skipblk mov a,m ; end of command string ?
ora a
jz nomatch ; yes, signal no match
cpi 021h ; is it whitespace ?
jnc complp ; no, start comparing
inx h ; yes, next character
jmp skipblk
nomatch ori 0ffh ; clear the zero flag to signal no match
ret ; and return to caller
complp ldax d
ora a ; end of the comparison string ?
rz ; yes, they must match
mov c,a
mov a,m ; not eos, get next byte
cpi 061h ; is 'a' <= a <= 'z' ?
jc compit
cpi 07ah
jnc compit
ani 05fh ; yes, fold to upper case
compit cmp c ; match ?
rnz ; no , return non zero
inx h
inx d
jmp complp
; killsub - kill the submit file and return to CP/M
killsub mvi c,PrtStr
lxi d,TermMsg ; tell the user
call bdos
erasub mvi c,Erase ; now kill the $$$.SUB file
lxi d,subfile
call bdos
jmp cpm ; return to CP/M
; explain - give the syntax and an operational synopsis since the user
; involked IF with no $$$.SUB file present (i.e. from console)
explain mvi c,PrtStr
lxi d,HelpMsg
call bdos
jmp cpm ; return to CP/M
;
;
IfLit db 'IF',0
;
ElseLit db 'ELSE',0
;
EndLit db 'ENDIF',0
;
;
;
TermMsg db bell,bell,bell,'ERROR - Submit procedure terminated'
db 13,10,'$'
;
FnNulMsg db bell,bell,bell,'A filespec must be given with this command'
db 13,10,'$'
;
BadOptMsg db bell,bell,bell,'That is not a legal option (A,E,M,N or Z)'
db 13,10,'$'
;
SkipMsg db bell,bell,bell,'ERROR - Skipping both IF and ELSE clauses'
db 13,10,'$'
;
HelpMsg db bell,13,10,'IF and its companion programs (ELSE, ENDIF and GOTO) are',13,10
db 'used within submit files to allow conditional execution of',13,10
db 'commands. See IF.DOC for examples.',13,10
db 13,10
db 'Usage: IF A[mbig] fn true if fn is ambigous',13,10
db ' IF E[xists] fn true if file fn exists',13,10
db ' IF M[issing] fn true if file fn does not exist',13,10
db ' IF N[ull] (fn) true if the fn is missing',13,10
db ' IF Z[ero] fn true if file fn is zero length or',13,10
db ' does not exist',13,10
db 13,10
db 'If the condition is true, all commands up to the next ELSE or',13,10
db 'ENDIF statement are executed. If an ELSE is encountered before',13,10
db 'the ENDIF statement is reached, commands are skipped until the',13,10
db 'ENDIF is found. If the condition is false, commands are skipped',13,10
db 'until the matching ELSE or ENDIF is found. Command execution',13,10
db 'then resumes. IF-ELSE-ENDIF groups may be nested to any depth.',13,10
db 13,10
db 'Only the first character of the first keyword (the A of Ambig or',13,10
db 'whatever) is checked.',13,10
db '$'
;
;
subfile db drive+1-'A' ; drive for the $$$.SUB file
db '$$$ SUB' ; and the parsed name
db 0,0 ; and extent and S1 bytes
subs2 ds 1 ; and the S2 byte (0'ed to cause BDOS rewrite)
subCNT ds 1 ; and the record count
ds 16 ; room for the allocation map
subREC ds 1 ; room for the current record number
ds 3 ; and finally, room for the random rec num
;
dmabuf ds 128 ; the dma buffer for all operations
;
end