; Program: NZFCP ; Date: October 9, 1989 ; Author: Carson Wilson ; Version: 1.3 ; Changes: Updated & improved JetLDR signon. ; Changed four JR's to JP's. ; Date: August 21, 1988 ; Author: Carson Wilson ; Version: 1.2 ; Derived from: ; Date: April 1988 ; Name changed and code modified for NZ-COM. ; Derived from: ; PROGRAM: Z34FCP ; AUTHOR: Jay Sage ; VERSION: 1.0 ; DATE: May 25, 1987 ; DERIVATION: FCP10 by Jay Sage (ZSIG) ; ZCPR34 is copyright 1987 by Jay P. Sage. All rights reserved. End-user ; distribution and duplication permitted for non-commercial purposes only. ; Any commercial use of ZCPR34, defined as any situation where the duplicator ; recieves revenue by duplicating or distributing ZCPR34 by itself or in ; conjunction with any hardware or software product, is expressly prohibited ; unless authorized in writing by Jay P. Sage. ;============================================================================= ; ; R E V I S I O N H I S T O R Y ; ;============================================================================= ; ; 21 Aug 88 Added JetLDR signon description. ; IF IN now prints ' (Y/N)? ', and accepts only Y or y or ; N or n. ; Added macro code to show FCP length following assembly. ; ; Carson Wilson. ; ; 6 April 88 Handles latest Type 4 IF.COM ; 1.2 Changed command tail loader to accept :IF. Joe Wright ; ; 12/31/87 Modified for use with Z34CMN.LIB for NZ-COM. Joe Wright. ; 1.1 ; ; 05/25/87 Created ZCPR33 version from the code I released through ZSIG. ; 1.0 This code differs only in the more efficient way in which it ; determines if it was invoked with a directory prefix that ; signals that the transient IF.COM should be used to process ; the IF command. This permits the user to force the use of a ; more powerful option processor in the transient IF.COM than in ; the resident code. Option bytes were added after the end of ; the resident option dispatch table so that SHOW can report ; configuration options to the user. ; ; FCP10 notes ; ; The transient processor can now be loaded at an address other ; than 100h so as not to interfere with code loaded in the TPA. ; Then the GO command can normally be used even after IF.COM is ; used to process the flow test. If the LOADCHK equate ; is true then the FCP will verify that the transient ; processor has been loaded to the page in memory for which ; it was assembled. If loaded to the wrong page, it will ; be reloaded to the correct one. ; ; The test for the form ARG1=ARG2 was tightened up so as not to ; be confused by an equal sign in some later part of the command ; tail (e.g., "IF REG 1 = 2"). Now only the first token ; (contiguous string of characters) is checked. This extra code ; is under the control of the XEQOPT equate. The only option ; that is still a problem is the COMIF form '~='. Since the '=' ; is in the first token, this 'not equal' condition cannot be ; distinguished from an equality test against the character '~'. ; The solution is to turn off equality testing in the resident FCP ; or to use the alternative COMIF options 'NE' or '~EQ' for this ; test. ; ; Added optional commands AND and OR. These work like IF except ; that they affect the current IF level rather than going one ; level deeper. ; ; Added optional command ZIF to zero out all IF states no matter ; whether current state is true or false (XIF only works if state ; is true. ; ; Added new optional command IFQ (if-query) and enhanced the ; IFSTAT code that is invoked when the NOISE equate is true. ; In both cases, the entire tree of IF states is now shown, ; starting with the current level. For example, IFQ might result ; in the display "IF FTT" (we are at third IF level and it is ; false; the second and first IF levels are true). If the ; current IF level is 0, then the display is "IF None". ; ; Added two new resident options: AMBIGUOUS (AM) returns true if ; the file specification in the second token has a '?' (or '*') ; in it; COMPRESSED (CO) returns true if the file specificaton in ; the second token has a 'Z' or a 'Q' in the second character of ; the file type. ; ; Howard Goldstein contributed significantly to the development ; of this code. Bridger Mitchell also offered helpful ; suggestions. ; ; Jay Sage ; ; Notes from earlier SYSFCP revisions ; ; 09/12/85 Fixed bug in my code used when IF.COM is found in a specified ; drive/user area. The values of CDISK and CUSER were not being ; set, and as a result the user was not returned to the correct ; directory. The EXIST and EMPTY tests did not work correctly ; unless a DIR: or DU: was given explicitly with each file name. ; Jay Sage ; 08/29/85 Reorganized code so that COMIF code handles only those ; options not in the table of local IF functions. Also changed ; code to allow searching for IF.COM in a specified directory ; instead of using the ROOT of the path. Also renamed macros ; to make code ZAS compatible. ; Jay Sage ; 07/21/85 Corrected reversed sensing of program error flag in the ; IF ERROR test. ; Jay Sage ; 01/02/85 Revised to correct a bug in the IF EMPTY test. First, the ; current record byte was not being set to zero before trying ; to read from the file. Secondly, the test for error was not ; testing for FF but for 00. My BDOS does not return 0 for ; success. It seems to return 00, 01, 02, or 03. This made the ; file appear to be empty. ; Jay Sage ;============================================================================= ; ; M A C R O S A N D E Q U A T E S ; ;============================================================================= name ('FCP') ; External macro references maclib Z34CMN.LIB ; Source of system addresses maclib NZFCP.LIB ; Source of configuration options maclib Z34MAC.LIB ; Z34 macros ; Equates section version equ 13 lf equ 0ah cr equ 0dh bell equ 07h base equ 0 wboot equ base+0000h ; CP/M warm boot address udflag equ base+0004h ; User num in high nybble, disk in low bdos equ base+0005h ; BDOS function call entry point tfcb equ base+005ch ; Default FCB buffer fcb1 equ tfcb ; 1st and 2nd FCBs fcb2 equ tfcb+16 tbuff equ base+0080h ; Default disk I/O buffer tpa equ base+0100h ; Base of TPA ;============================================================================= ; ; J e t L D R S I G N - O N ; ;============================================================================= ; This prints an extended ID message upon loading with JetLDR. ; These are NOT the command names. COM /_ID_/ db 'Copyright 1989 ZSA',cr,lf db 'Commands:',cr,lf db ' IF ELSE FI XIF ' if andopt db 'AND ' endif if oropt db 'OR ' endif if ifqopt db 'IFQ ' endif if zifopt db 'ZIF ' endif db cr,lf,'Options' if ifoneg db ' (use "',negchar,'" to negate)' endif if noise db '; (noise)' endif db ':',cr,lf if ifotrue db ' T F ' endif if ifambig db 'AMbig ' endif if ifcompr db 'COmpr ' endif if ifoempty db 'EMpty ' endif if ifoeq db 'x=y ' endif if ifoerror db 'ERror ' endif if ifoexist db 'EXist ' endif if ifoinput db 'INput ' endif if ifonull db 'NUll ' endif if iforeg db 'REgs ' endif if ifotcap db 'TCap ' endif if ifowheel db 'WHeel ' endif if comif db cr,lf,' Use ' if pathroot db 'root:' endif db 'IF.COM' endif db 0 ; End of JetLDR sign-on message CSEG ;============================================================================= ; Start of code start: db 'Z3FCP' ; Flag for Package Loader ;============================================================================= ; ; C O M M A N D T A B L E ; ;============================================================================= ; The command name table is structured as follows: ; ; The first byte is the number of characters in each command name. ; Next come records consisting of command names followed by entry ; point addresses for the code to process the command. Finally, ; there is a null to indicate the end of the dispatch table. db cmdsize ; Size of text entries ctab: ctable ; Macro defined in NZFCP.LIB db 0 ;============================================================================= ; ; I F C O N D I T I O N O P T I O N S ; ;============================================================================= condtab: if ifotrue db 'T ' ; TRUE dw ifctrue db 'F ' ; FALSE dw ifcfalse endif ; ifotrue if ifambig ; Ambiguous file spec db 'AM' dw ifcambig endif ; ifambig if ifcompr ; Squeezed or crunched db 'CO' dw ifccompr endif ; ifcompr if ifoempty db 'EM' ; File empty dw ifcempty endif ; ifoempty if ifoerror db 'ER' ; Error message dw ifcerror endif ; ifoerror if ifoexist db 'EX' ; File exists dw ifcex endif ; ifoexist if ifoinput db 'IN' ; User input dw ifcinput endif ; ifoinput if ifonull db 'NU' dw ifcnull endif ; ifonull if ifotcap ; Z3 TCAP available db 'TC' dw ifctcap endif ; ifotcap if ifowheel ; Wheel Byte db 'WH' dw ifcwheel endif ; ifowheel db 0 ; Option bytes: these option bytes can be used to convey information to ; programs such as SHOW. The first one is used to reduce the chance of ; misinterpreting data from an earlier version of the FCP that does not ; have the option bytes. The next byte tells if COMIF has been activated ; and if the root of the path will be used as the directory in which to look ; for IF.COM. If PATHROOT is not selected (or if the path is empty), then ; the specified drive/user will be used. The overflow bit in case the user ; number is greater than 15 is kept in bit 2 of the second option byte. The ; combined user/drive value is kept in the third option byte. highuser defl ifusr gt 15 opt0: db 34h ; ZCPR34 version ID opt1: optflag highuser,pathroot,comif opt2: db ( ifusr and 0fh ) shl 4 + ( ifdrv - 'A' ) ; user/drive flag ;============================================================================= ; ; C O M M A N D P R O C E S S I N G C O D E ; ;============================================================================= ; Command: ZIF ; ; This command zeros out the IF system no matter what the current ; level IF state is. if zifopt ifzero: if noise call nl ; Print new line endif ; noise jr ifexit1 endif ; zifopt ;----------------------------------------------------------------------------- ; Command: XIF ; ; If current IF state is true, XIF terminates all IFs, restoring a basic ; TRUE state. ifexit: if noise call nl ; Print new line endif ; noise call iftest ; See if current IF is running and FALSE if noise jr z,ifstat ; Abort with status message if so else ; not noise ret z ; Or just return if false endif ; noise ifexit1: ld hl,z3msg+1 ; Pt to IF flag ld (hl),0 ; Zero IF flag jr ifendmsg ; Print message ;----------------------------------------------------------------------------- ; Command: FI ; ; FI decrements to the previous IF level. It does this by shifting the ; current-if-bit in the first 'if' message in the Z3MSG buffer right one ; position. ifend: if noise call nl ; Print new line endif ; noise ; ld hl,z3msg+1 ; Point to IF flag ; ld a,(hl) ; Get it ; or a ; No IF active? call msgbf1 dec hl ; Save a byte over the three lines above jr z,ifnderr ifendmsg: if noise call print dc 'To ' ; Prefix to status display endif ; noise srl (hl) ; Adjust active bit if noise jr nz,ifstat ; Print status if IF still active endif ; noise ifnderr: if noise call print ; Print message dc 'No ' jp prif else ; not noise ret endif ; noise ;----------------------------------------------------------------------------- ; Command: ELSE ; ; ELSE complements the Active Bit for the Current IF provided the ; previous IF state was true. If the previous state was false, the ; command is flushed. ; ; This is accomplished according to the following algorithm. If the ; current IF is 0 (no IF) or 1 (one IF), then take the previous state ; to be true and perform the toggle. Otherwise, test the previous ; IF level condition and toggle only if it is true. ifelse: if noise and (not ifqopt) call nl ; Print new line endif ; noise and (not ifqopt) call msgbf1 ; Get current if ld b,a ; Save in B srl a ; Back up if pointer bit to previous IF level jr z,iftog ; If no previous IF level, go to toggle code and (hl) ; Determine state of previous IF level if noise if ifqopt jr z,ifstat0 ; Print status on new line else jr z,ifstat ; If false, just print status endif ; Ifqopt else ; not noise ret z ; Or simply return endif ; noise iftog: ld a,(hl) ; Get if-status message byte xor b ; Flip current state ld (hl),a ; Put result back in message byte ; ..and fall thru to print status if not noise ret endif ;----------------------------------------------------------------------------- ; Indicate if current IF is True or False ifstat0: call nl ifstat: call prif ; Print 'IF ' call msgbf1 ; Get current if byte and set flags ld b,a ; Get it into B jr nz,ifstat1 ; Nz means if active call print dc 'None' ret ifstat1: ld a,(hl) ; Get if-status message byte and b ; Mask in currently active IF level status ld c,'F' ; Load with false indicator jr z,ifstat2 ; If current IF is false, jump ld c,'T' ; Else, load with true indicator ifstat2: ld a,c call conout srl b ; Drop one IF level jr nz,ifstat1 ; Loop through all IF states ret ;------------------------- ; Output CRLF nl: call print dc cr,lf ret ;----------------------------------------------------------------------------- ; Command: OR ; This command performs a logical or operation by updating the ; if state without going to a new level. If there are active ; IFs and the current state is true, we do nothing. Else we back ; up one level and fall through to normal IF processing. if oropt orstart: call msgbf1 ; Get if active byte jr z,backup ; Treat like if if no IFs active and (hl) ; Check current state jr z,backup ; Current STATE false so go proecess if noise jr ifstat0 ; Else return and show status else ret ; Or just return endif ; Noise endif ; Oropt ;----------------------------------------------------------------------------- ; Command: AND ; This command performs a logical and operation by updating the ; if state without going to a new level. If there are active ; IFs and the current state is false, we do nothing. Else we back ; up one level and fall through to normal IF processing. if andopt andstart: call iftest ; Test for IF running and false if noise jr z,ifstat0 ; Condition met, show status & return else ret z ; Condition met, return endif ; Noise endif ; Andopt ; Common stuff for and and or if andopt or oropt backup: dec hl ; Pt to flag byte srl (hl) ; Drop back one level ; ; Poke "IF" into external fcb for transient ; if comif pokefcb: ld de,extfcb+1 ; Pt to external fcb ld hl,ifcmd ; Pointer to IF command in table ld bc,cmdsize ; Length ldir ; Move it in endif ; comif ; Fall through to IF PROCESSING endif ;Andopt or oropt ;----------------------------------------------------------------------------- ; FCP Command: IF ; ; If current IF state is false, then advance to next level and set it ; to false also. If current IF state is true, then test condition and ; set the next level accordingly. ifstart: if not ifqopt ld a,(extfcb) ; NZ if explicit ld hl,tbuff or (hl) jp z,ifstat0 ; Report IF status endif ; not ifqopt ifstrt: if noise call nl ; Print new line endif ; noise call iftest ; See if current IF is running and FALSE jP z,ifcf ; Yes, do the right thing ; Test for presence of colon in command. If colon present, then go directly ; to COMIF processing. if comif ld a,(extfcb) ; Check drive byte of external FCB or a ; If it is zero, no colon was present jp nz,runcomif ; If colon, go to comif processing ; Else fall through to resident processing endif ; comif ;----------------------------------------------------------------------------- ; ; R E S I D E N T C O M M A N D P R O C E S S I N G ; ;----------------------------------------------------------------------------- resident: ; Test for Equality if Equal Sign in Token if ifoeq ld hl,tbuff+1 if xeqopt ; Extended equal testing skipsp: ; Skip over any space to first token ld a,(hl) or a ; Check for end of tail jr z,ifck0 ; If so , go on cp ' '+1 ; Test for space or control character jr nc,tsteq ; If not, we are at first token inc hl ; Otherwise advance to next character jr skipsp ; ..and continue testing endif ; xeqopt tsteq: ld a,(hl) ; Get character from command tail inc hl ; Point to next one or a ; EOL? jr z,ifck0 ; Continue if so if xeqopt cp ' '+1 ; End of token? jr c,ifck0 ; If so, go on endif ; xeqopt cp '=' ; Found '=' ? jr nz,tsteq ; If not, continue scan ld hl,fcb1+1 ; Else, get ready to compare FCBs ld de,fcb2+1 ld b,11 ; 11 bytes eqtest: ld a,(de) ; Compare cp (hl) jr nz,ifcf inc hl ; Pt to next inc de djnz eqtest jr ifct endif ; ifoeq ifck0: ld de,fcb1+1 ; Point to first character in FCB1 if ifoneg ld a,(de) ; Get it ld (negflag),a ; Set negate flag cp negchar ; Is it a negate? jr nz,ifck1 ; If not, go on inc de ; Else point to character after negchar ifck1: endif ; ifoneg if iforeg ; REGISTERS call regtest ; Test for register value jr nz,runreg endif ; iforeg call condtest ; Test of condition match jr nz,runcond ; If found, process condition if comif jp runcomif ; If function not found in table, use transient else call print ; Beep to indicate error dc bell if noise jp ifstat ; No condition, display current condition else ; no noise ret endif ; noise endif ; comif ;----------------------------------------------------------------------------- ; ; Process register - register value is in A ; ;----------------------------------------------------------------------------- if iforeg runreg: push af ; Save value call getnum ; Extract value in FCB2 as a number pop af ; Get value cp b ; Compare against extracted value jr jrtrue ; True if match; false if not endif ; iforeg ;----------------------------------------------------------------------------- ; ; Process conditional test - address of conditional routine is in HL ; ;----------------------------------------------------------------------------- runcond: jp (hl) ; "call" routine pted to by HL ;============================================================================= ; ; R E S I D E N T C O N D I T I O N O P T I O N S ; ;============================================================================= ; Condition: AMBIGUOUS if ifambig ifcambig: ld hl,fcb2+1 ; Scan FCB2 for a '?' character ld bc,11 ; Characters to scan ld a,'?' ; Reference character cpir jr jrtrue ; True if '?' found; false if not endif ; ifambig ;----------------------------------------------------------------------------- ; Condition: COMPRESSED if ifcompr ifccompr: ld a,(fcb2+10) ; Get middle character of file type cp 'Z' ; Crunched jr z,ifctrue cp 'Q' ; Squeezed jr jrtrue endif ; ifcompr ;----------------------------------------------------------------------------- ; Condition: TRUE ; IFCTRUE enables an active IF ; Condition: FALSE ; IFCFALSE enables an inactive IF if ifoempty or ifoerror or ifoexist or ifowheel jrfalse: jr z,ifcfalse endif ; Ifoempty or ifoerror or ifoexist or ifowheel ifctrue: if ifoneg call negtest ; Test for negate jr z,ifcf endif ; ifoneg ifct: ld b,0ffh ; Active jp ifset if iforeg or ifambig or ifcompr or ifoinput or ifonull jrtrue: jr z,ifctrue endif ; Iforeg or ifambig or ifcompr or ifoinput or ifonull ifcfalse: if ifoneg call negtest ; Test for negate jr z,ifct endif ; ifoneg ifcf: ld b,0 ; Inactive jp ifset ;----------------------------------------------------------------------------- ; Condition: EMPTY filename.typ if ifoempty ifcempty: call tlog ; Log into FCB2's DU ld de,fcb2 ; Pt to fcb2 ld c,15 ; Open file push de ; Save fcb ptr call bdos pop de inc a ; Not found? jr z,ifctrue ld c,20 ; Try to read a record xor a ; set cr value to zero ld (fcb2+32),a ; to attempt to read first record call bdos or a ; 0=OK jr jrfalse ; true if no read endif ; ifoempty ;----------------------------------------------------------------------------- ; Condition: ERROR if ifoerror ifcerror: ld a,(z3msg+6) ; Get error byte or a ; 0=FALSE (no error registered) jr jrfalse endif ; ifoerror ;----------------------------------------------------------------------------- ; Condition: EXIST filename.typ if ifoexist ifcex: call tlog ; Log into DU ld de,fcb2 ; Pt to fcb ld c,17 ; Search for first call bdos inc a ; Set zero if error jr jrfalse endif ; Ifoexist ;----------------------------------------------------------------------------- ; Condition: INPUT (from user) ; Modified to say " (Y/N)? ", and accept ONLY Y or y or N or n ; Carson Wilson 3/1/88 if ifoinput ifcinput: call print dc ' (Y/N)? ' ifcinp1: ld hl,z3msg+7 ; Pt to ZEX message byte ld (hl),10b ; Suspend ZEX input push hl ; Save ptr to ZEX message byte ifcinp2: ld e,0ffh ld c,6 ; Direct input from console call bdos or a ; Any input yet? jr z,ifcinp2 ; Nope, try again pop hl ; Get ptr to ZEX message byte ld (hl),0 ; Return ZEX to normal processing and 5fh ; Mask and capitalize user input cp 'Y' jr nz,testN ; No, check if 'N' call conout ; Display 'Y' jr ifctrue ; Process as true testN: cp 'N' jr nz,notN ; Not 'N' or 'n' call conout ; Display 'N' jr ifcfalse ; Process as false notN: ld a,bell ; Protest! call conout jr ifcinp1 ; Force either Y or y or N or n endif ; ifoinput ;----------------------------------------------------------------------------- ; Condition: NULL (2nd file name) if ifonull ifcnull: ld a,(fcb2+1) ; Get first char of 2nd file name cp ' ' ; Space = null jr jrtrue endif ; ifonull ;----------------------------------------------------------------------------- ; Condition: TCAP if ifotcap ifctcap: ld a,(z3env+80h) ; Get first char of Z3 TCAP Entry cp ' '+1 ; Space or less = none jP c,ifcfalse jP ifctrue endif ; ifotcap ;----------------------------------------------------------------------------- ; Condition: WHEEL if ifowheel ifcwheel: ld hl,(z3env+29h) ; Get address of wheel byte ld a,(hl) ; Get byte or a ; Test for true jP jrfalse ; False if 0 endif ; ifowheel ;============================================================================= ; ; S U P P O R T R O U T I N E S ; ;============================================================================= ; Convert chars in FCB2 into a number in B if iforeg getnum: ld b,0 ; Set number ld hl,fcb2+1 ; Pt to first char getn1: ld a,(hl) ; Get char inc hl ; Pt to next sub '0' ; Convert to binary ret c ; Done if error cp 10 ; Range? ret nc ; Done if out of range ld c,a ; Value in C ld a,b ; A=old value add a,a ; *2 add a,a ; *4 add a,b ; *5 add a,a ; *10 add a,c ; Add in new digit value ld b,a ; Result in B jr getn1 ; Continue processing endif ; iforeg ;----------------------------------------------------------------------------- ; Log into DU in FCB2 if ifoexist or ifoempty tlog: ld a,(fcb2) ; Get disk or a ; Current? jr nz,tlog1 ld c,25 ; Get disk call bdos inc a ; Increment for following decrement tlog1: dec a ; A=0 ld e,a ; Disk in E ld c,14 call bdos ld a,(fcb2+13) ; Pt to user ld e,a ld c,32 ; Set user jp bdos endif ; ifoexist or ifoempty ;----------------------------------------------------------------------------- ; Test of Negate Flag = negchar if ifoneg negtest: negflag equ $+1 ; Pointer for in-the-code modification ld a,0 ; 2nd byte is filled in cp negchar ; Test for No ret endif ; ifoneg ;----------------------------------------------------------------------------- ; Test FCB1 against a single digit (0-9) ; Return with register value in A and NZ if so if iforeg regtest: ld a,(de) ; Get digit sub '0' jr c,zret ; Z flag for no digit cp 10 ; Range? jr nc,zret ; Z flag for no digit ld hl,z3msg+30h ; Pt to registers add a,l ; Pt to register ld l,a ld a,h ; Add in H adc 0 ld h,a xor a ; Set NZ dec a ld a,(hl) ; Get register value ret zret: xor a ; Set Z ret endif ; iforeg ;----------------------------------------------------------------------------- ; Test to see if a current IF is running and if it is FALSE ; If so, return with Zero Flag Set (Z) ; If not, return with Zero Flag Clear (NZ) ; Affect only HL and PSW iftest: call msgbf1 ; Test for active IF jr z,ifok ; No active IF and (hl) ; Check active flag ret z ; Return Z since IF running and FALSE ifok: or 255 ; Return NZ for OK ret msgbf1: ld hl,z3msg+1 ; Get IF active flag ld a,(hl) inc hl ; Pt to If status byte or a ; Set z if no IF active ret ;----------------------------------------------------------------------------- ; Test FCB1 against condition table (must have 2-char entries) ; Return with routine address in HL if match and NZ flag condtest: ld hl,condtab ; Pt to table condt1: ld a,(hl) ; End of table? or a ret z ld a,(de) ; Get char cp (hl) ; Comppare entries inc hl ; Pt to next inc de jr nz,condt2 ld a,(de) ; Get 2nd char cp (hl) ; Compare jr nz,condt2 inc hl ; Pt to address ld a,(hl) ; Get address in HL inc hl ld h,(hl) ld l,a ; HL = address jr ifok ; Set NZ for OK condt2: inc hl ; Pt to next entry inc hl ; Skip over addr inc hl dec de ; Pt to 1st char of condition jr condt1 ;----------------------------------------------------------------------------- ; Turn on next IF level ; B register is 0 if level is inactive, 0FFH if level is active ifset: ; ld hl,z3msg+1 ; Get IF flag ; ld a,(hl) ; or a ; If no if at all, start 1st one call msgbf1 dec hl jr z,ifset1 ifset0: add a,a ; Advance to next level jr c,iferr ; Check for overflow (8 IFs max) ld (hl),a ; Set IF byte jr ifset2 ifset1: inc a ; A=1 ld (hl),a ; Set 1st IF ifset2: ld d,a ; Get IF byte and b ; Set interested bit ld b,a inc hl ; Pt to active flag ld a,d ; Complement IF byte cpl and (hl) ; Mask in only uninterested bits or b ; Mask in interested bit ld (hl),a ; Save result if noise jp ifstat ; Print status and exit else ret ; Or just exit endif ; noise iferr: call print ; Beep to indicate overflow dc bell ret ;============================================================================= ; ; T R A N S I E N T I F P R O C E S S I N G ; ;============================================================================= if comif runcomif: ; First we have to find IF.COM ld bc,100h*(ifdrv-'A')+ifusr ; Values to use if null path if pathroot ld hl,(expath) ; Point to symbolic path (indirect) fndroot: ld a,(hl) ; Check for end of path or a jr z,froot2 ; If end, branch ; Process Next Path Element cp curint ; Current disk/user symbol? jr nz,froot0 ; If not, branch ld a,(curdr) ; Get current disk inc a ; Compensate for following decrement froot0: dec a ; Shift to range 0..15 ld b,a ; Set disk inc hl ; Point to user in path ld a,(hl) ; Get user cp curint ; Current drive/user symbol? jr nz,froot1 ; If not, branch ld a,(curusr) ; Get current user froot1: ld c,a ; Set user inc hl ; Point to next element in symbolic path jr fndroot ; Done with Search - BC Contains ROOT DU (or specified DU if path is empty) endif ; pathroot froot2: call logbc ; Log into IF.COM's directory ; Try to Open File IF.COM ld de,extfcb ; Point to command FCB xor a ld (de),a ; Force current drive ld c,15 ; Open file call bdos inc a jr nz,ifload ; Branch if file found ; IF.COM not found - process as IF F ifnotfnd: call iferr ; Ring bell call reset ; Return home jp ifcf ; Load File IF.COM ifload: call defdma ; First record to tbuff call readcmd ; Read 1st record from IF.COM jr nz,ifnotfnd ; If eof, treat as if file not found ld (extfcb+32),a ; Start from scratch (record 0) ld a,(tbuff+8) cp 3 jr c,ifnotfnd ; Only Types 3 and 4 are acceptable call loadif ; Load IF.COM and set IFADR appropriately ; ; Build the command tail at tbuff ; ld de,tbuff ; Point DE to tbuff push de ; Save it for later ld hl,(z3msg+4) ; Points into MCL buffer ; ; Advance HL to first 'space' after IF or .IF or :IF ; advsp: inc hl ld a,(hl) cp ' '+1 ; Carry if space or null jr nc,advsp ld c,0 ; Clear a counter putt: inc de ; Advance tbuff pointer ld a,(hl) ; From MCL ld (de),a ; To tbuff inc hl ; Advance MCL pointer or a ; Check for null jr z,putx ; End of command line cp ';' ; Command separator jr z,putx ; End of command inc c ; Count it up jr putt ; Next.. putx: xor a ; Get a null ld (de),a ; Terminate the line in tbuff pop hl ; Beginning of tbuff ld (hl),c ; Character count ; ; Pick up the execution address for Type 3 or 4 ; ld hl,(ifadr) ; Load address ld a,(hl) ; First byte at load address cp 0c7h ; Test for RST 0 jr nz,runif ; Nope, execute it ld (hl),0c3h ; Plug in a JP ; ; Arrive here to execute IF.COM ; runif: ld hl,z3env ; Pass environment in HL db 0c3h ; JP instruction ifadr: dw 0 ; Load/Execution address of IF.COM ; ; Load IF.COM ; loadif: ld hl,(tbuff+11) ; Type 3 load address jr z,loada ; Load as Type 3 ; ; Assume Type 4 (or higher) ; ld hl,extfcb+32 ; Point to CR of extfcb ld (hl),2 ; Set up for record 2 push hl ; Save the pointer call readcmd ; Get it into tbuff pop hl jp nz,ifnotfnd ; Too short ld (hl),a ; Record 0 again ld hl,(tbuff+11) ; Size word push hl ; Save it call readcmd ; Read record 0 again pop bc ; Size ld de,(ccp) ; CCP start ld hl,z3env dec a ; Phony fullget flag call tbuff+9 ; Call Type 4 loader push hl ; Save load address call readcmd ; Read record 1 to tbuff (point to record 2) pop hl ; Load address ; loada: ld (ifadr),hl ; Save it ; ; Load IF.COM to (HL) until end of file, reset DMA and DU and return ; load: push hl ; Save loading address call setdma ; According to HL call readcmd ; Read a record from file pop hl ; Get current loading address back jr nz,reset ; End of file ld de,128 ; Advance it by one record add hl,de jr load ; Back to read some more ; Reset DMA and Current DU reset: call defdma ld bc,(curusr) ; Return home ; Log Into DU in BC logbc: ld e,b ; Set disk push bc ld c,14 ; Select disk call bdos pop bc ld e,c ; Set user ld c,32 ; Select user jp bdos ; Set default DMA address defdma: ld hl,tbuff ; Set DMA to address according to HL setdma: push hl ; Save it ex de,hl ; To DE ld c,26 ; Set DMA command call bdos ; Do it pop hl ; DMA address ret ; Read a record from file in EXTFCB readcmd: ld de,extfcb ld c,20 call bdos or a ; Set NZ if error (end of file) ret endif ; comif ;============================================================================= ; ; U T I L I T Y S U B R O U T I N E S ; ;============================================================================= ; Print "IF " prif: call print dc 'IF ' ret ;----------------------------------------------------------------------------- ; Print String (terminated in 0 or MSB Set) at Return Address print: ex (sp),hl ; Get address call print1 ex (sp),hl ; Put address ret ; Print String (terminated by MSB Set) pted to by HL print1: ld a,(hl) ; Done? inc hl ; Pt to next call conout ; Print char or a ; Set msb flag (m) ret m ; Msb terminator jr print1 ;----------------------------------------------------------------------------- ; Console Output Routine conout: push hl ; Save regs push de push bc push af and 7fh ; Clear msb ld e,a ; Char in E ld c,2 ; Output call bdos pop af ; Get regs pop bc pop de pop hl ret ;============================================================================= ; ; Display current length in records ; prtval macro m1,v1,m2,v2,m3 .radix 10 .printx m1 v1 m2 v2 m3 endm length equ $ - start recs equ length / 128 bytes equ length mod 128 .printx prtval ,%recs,,%bytes, .printx end ; End of NZFCP.Z80