; LUXI80 - A Library extension system - Version 10 as of 03/22/88 ; ; Supports CPM v2.2 and CPM v3.0 ; ; Allows the user to peer into .ARC, .ARK and .LBR file groups. With ; appropriate peripheral files which accompany this program (or are ; already on most RCPM systems) can type .LBR member files whether ; crunched, squeezed or normal. Can also type files in .ARC or .ARK ; libraries. If using KMD or a comparable program, can easily extract ; member files from .ARC, .ARK or .LBR groups. Options included to use ; KMD clones such as MBKMD and NUKMD. ; ;----------------------------------------------------------------------- ; ; 03/22/88 This is LUXI80. It is basically LUX100 rewritten for the ; v10 Intel 8080 processor. You must use M80, L80 and MAKELUX.COM ; to assemble it. I decided to rename it to LUXI80 and start ; out with version 10 inorder to separate it from other ; versions of LUX being done by Irv Hoff and Tom Brady. ; This code is basically Irv's LUX100 code slightly modified ; for the 8080. LUX100 is a fine piece of software and we all ; owe Irv a large debt of gratitude for it. I'd also like to ; thank Donald Phillips and Douglas Coatney for writing LUX43. ; It was from LUX43 that I got most of the inspiration for ; doing this revision. ; -- Bill Weinel ; Capitol RCP/M ; ; 03/05/87 This is LUX77 renamed to LUX100. It has numerous features ; v100 which make it far more desireable for many RCPM operators ; than Tom Brady's versions called LUX54, LUX75 and LUX80, ; all of which are virtually identical and none of which work ; on CPM v3.0 systems that many of us have. LUX70, LUX77 and ; this LUX100 work great on CPM v3.0 as well as on CPM v2.2 ; systems. Irv had version LUX54 ready in October of 1986 but ; never released it while waiting for Bob Freed to finish NOAH ; since LUX52 already supported both .LBR and .ARC files. ; Tom Brady put out his version called LUX54 so Irv didn't have ; much choice except to skip to LUX70 for his version in a ; courteous way to allow Tom Brady to continue developing his ; LUX54 with LUX55 - should any additional things of merit be ; added. Such has not been the case. Tom has taken a personal ; vendetta to prevent the rest of us from using Irv's version ; which took me all of 5 minutes to install on my CPM v3.0 ; system. This was the first I had been able to even use LUX ; on my system and I for one greatly appreciate what Irv has ; contributed to this excellent program. I don't care for Tom ; Brady trying to play God and dictate to me what I should use ; on my system. I know many of you will agree with me. Tom ; also included UNARC142 in his version, without permission ; from Bob Freed. He specifically distributed that with the ; distinct admonition that it was a beta test version for sysops ; use only. Tom Brady totally ignored this warning and made the ; program public as though it were his to do with as he wished. ; This has upset Bob Freed to the point he may never issue any ; source code to any of his programs, again. He was already ; upset with Tom Brad's stealing the copyrighted routines he ; had given to Irv for exclusive use in KMD. If you never see ; NOAH for CPM it may well be because of Tom Brady's antics. ; (I got some of this information from direct personal calls. ; The rest was already well known in many parts of the country.) ; - Earl Crocket ; Earl's Corner RCPM ; ; 03/04/87 (By Tom Brady, who again totally substituted his version of ; v80 LUX54 in place of LUX77 then put an .ARK extention on it. ; It is an obvious effort to again totally discredit the efforts ; of Irv Hoff to simpifly and adapt the LUX program to use ; normal programs already on most RCPM systems.) ; ; 03/01/87 NOTICE TO TOM BRADY: LEAVE YOUR FINGERS OFF THIS PROGRAM. ; v77 IF YOU WANT TO CONTINUE MUCKING WITH LUX, SUGGEST YOU USE ; THE NUMBER LUX55 TO FOLLOW YOUR OWN LUX54. I INTENTIONALLY ; SKIPPED TO LUX70 SO AS TO NOT PROHIBIT YOU FROM DOING JUST ; THAT, BUT WILL NOT TOLERATE YOUR USING THIS SERIES IN AN ; OBVIOUS ATTEMPT TO PREVENT ME FROM CONTRIBUTING TO THE DE- ; VELOPMENT OF THIS PROGRAM. ; ; Restored LUX v77 to the original intent of the LUX 7x ver- ; sion. I had already skipped to LUX70 to not place Tom Brady ; in a position where he could not continue working with his ; LUX54, calling any subsequent version LUX55. Instead he ; elected to try to totally obliterate any work I had put into ; this program. I will not allow that to occur. Many people ; prefer my version to his, since it can be installed on any ; RCPM as fast as you can extract the files from the libaray. ; - Irv Hoff ; ; 02/28/87 (Tom Brady totally replaced everything in the LUX70A version ; v75 including all auxiliary programs in the library with his own ; LUX54 version. He further decided to jump to LUX75. This ; was done in an obvious attempt to force people to use only ; his version.) ; ; 02/27/87 Added an equate to select MBKMD120 which came out about the ; v70A same time that LUX70 was being released. LUX70A supports ; KMD, MBKMD and NUKMD. Be sure to make the proper selection. ; - Irv Hoff ; ; 02/22/87 MAJOR CHANGE... Rewrote program to use conventional files ; v70 normally found on A0: ; ; LCHEK.COM (Current is LCHEK11.COM) ; DIR.COM (Renamed SD.COM with $L option) ; TYPE.COM (Should handle both squeezed and crunched) ; UNARC.COM (Combination DIR and TYPE for .ARC/.ARK files) ; ; Special files such as LUXCHK, LUXDIR, LUXTYPE, etc. on ; a special drive/user area (usually A15:) no longer needed. ; This greatly simplifies the installation and use of LUX. ; Wheel byte, MAXDRV and MAXUSR bytes no longer used or even ; needed - LUX can be only be called up in whatever drive/user ; area you are currently in, which in itself is the limiting ; factor. This is a radical departure from previous versions ; so the version number has been significantly advanced. This ; allows additional updates of conventional versions if others ; want an additional choice. This makes one universal version ; possible for any size system from small floppies to immense ; hard drives of 100 Mb and more. ; ; Option added to support KMD, MB-KMD or NUKMD added as the ; latter two must have must have both 'A' and 'L' capability ; for various functions. (KMD needs only the 'A', however it ; accepts 'L' interchangeably since versions prior to .ARC or ; .ARK files used 'L' for .LBR files.) Can now exit LUX with ; CTL-C, CTL-K or CTL-X. This standardizes exit with other ; similar programs. - Irv Hoff ; ; 09/09/86 None of the previous LUX files protected its start address, ; v54 allowing long programs to overrun LUX itself. It would then ; lock up the system until reset by the Sysop. This happened ; most often when using the TYPE command to look at lengthy ; .DOC files but was not limited to such files. Reformatted ; and simplified. - Irv Hoff ; ; 08/25/86 Modified for .ARK file support in addition to .ARC and .LBR. ; v53 - Norman Beeler ; ; 06/02/86 Modified for .ARC file support, using UNARCxx for DIR and ; v52 TYPE commands....fully automatic determination of .ARC or ; .LBR file extents, (extent not necessary). Supports .ARC ; member transfer. - Norman Beeler ; ; 06/26/85 Modified for KMD support throughout. Other cosmetic changes. ; v51 KMD offers total automatic protocol detect. (It also offers ; YMODEM-type batch transfers but this is not used with LUX.) ; - Tom Brady ; ; 07/21/85 Added SENDK and SK options for use with 1k blocks which are ; v50 needed for MEX114 and MS-DOS program with YMODEM protocol. ; (1k blocks are fully automatic with IMP. The 'SK' need not ; be manually inserted for 1k protocol.) ; - Steve Sanders ; ; 11/26/83 Original release. Adapted from ATTACH program. ; v12B - Steven Holtzclaw ; ;----------------------------------------------------------------------- ; ; YES EQU 0FFH NO EQU 0 ; KMD EQU YES MBKMD EQU NO NUKMD EQU NO ; ;----------------------------------------------------------------------- ; ; Equates ; CR EQU 0DH LF EQU 0AH ; ;----------------------------------------------------------------------- ; ; ; If RCPM is Yes, change the BYECMD equate at end of this file if your ; logoff program is not called BYE.COM. ; RCPM EQU YES ; Yes, if being used with a RCPM system HLPMSG EQU YES ; Yes, if helpful messages are wanted AUTODR EQU YES ; Yes, if initial auto-directory wanted HLPERS EQU 2 ; Give auto-help after this many errors ; ; ;----------------------------------------------------------------------- ; ; The following files are normally on A0: and are for general purpose as ; well as for use with LUX. ; ; NOTE: The DIR.COM file must be a SD-xx.COM type ; having the $L option (to show library member ; contents). This is normally placed on A0: ; for general use in displaying the directory. ; When choosing a drive, use: 0=A, 1=B, etc. ; CHKDRV EQU 0 ; Drive number for LCHEK.COM (LCHEK11.COM) CHKUSR EQU 0 ; User number for LCHEK.COM ; DIRDRV EQU 0 ; Drive number for DIR.COM (SD.COM) DIRUSR EQU 0 ; User number for DIR.COM (SD.COM) ; KMDRV EQU 0 ; Drive number for KMD, MB-KMD or NUKMD KMDUSR EQU 0 ; User number for KMD, MB-KMD or NUKMD ; TYPDRV EQU 0 ; Drive number for TYPE.COM TYPUSR EQU 0 ; User number for TYPE.COM ; UNADRV EQU 0 ; Drive number for UNARC.COM UNAUSR EQU 0 ; User number for UNARC.COM ; ;----------------------------------------------------------------------- ; BDOS EQU 0005H ; Jumper vector for BDOS calls TPA EQU 0100H ; CP/M program area FCB1 EQU 005CH ; First file control block FCB2 EQU 006CH ; Second file control block REBOOT EQU 0000H ; Cold reboot address TBUFF EQU 0080H ; Default command buffer ; ; ; Macros used ; DRVUSR MACRO DRIVNO,USERNO,FNCNAM,RTN1,RTN2,RTN3,RTN4 CALL FILTYP DB DRIVNO+'A' ; USERN1 SET USERNO ; IF USERN1 GT 9 DB (USERN1 /10)+'0' ; USERN1 SET USERN1-10 ENDIF ; USERN1 GT 9 ; DB USERN1+'0' DB ':' DB FNCNAM DB 0 ; IF NOT NUL RTN1 CALL RTN1 ENDIF ; NOT NUL RTN1 ; IF NOT NUL RTN2 CALL RTN2 ENDIF ; NOT NUL RTN2 ; IF NOT NUL RTN3 CALL RTN3 ENDIF ; NOT NUL RTN3 ; IF NOT NUL RTN4 CALL RTN4 ENDIF JMP PROCES ; NOT NUL RTN4 ENDM ; DVUS MACRO DRIVNO,USERNO,FNCNAM,RTN1,RTN2,RTN3,RTN4 CALL FILTYP DB DRIVNO+'A' ; USERN2 SET USERNO ; IF USERN2 GT 9 DB (USERN2 /10)+'0' USERN2 SET USERN2-10 ENDIF ; USERN2 GT 9 ; DB USERN2+'0' DB ':' DB FNCNAM DB 0 ENDM ; CMDJMP MACRO VERB,VECTOR CALL ILCMP DB VERB DB 0 JNC VECTOR ENDM ; ; Z80 DJNZ code replacement macro ; DJNZ MACRO DJADR DCR B ; DJNZ replacement JNZ DJADR ENDM ; ; Z80 CPIR replacement macro ; CPIR MACRO nm Cp&nm: cmp m ; CPIR replacement code begins push psw inx h dcr c jnz C1&nm pop psw jmp C2&nm C1&nm: pop psw jnz Cp&nm ;; CPIR replacement code ends C2&nm equ $ ENDM ; ; ;======================================================================= ; ; Program starts here ; ;======================================================================= ; START: LXI SP,SSTACK ; Starting stack CALL ILPRT DB CR,LF,'LUXI80 v10' DB CR,LF,0 ; ; ; Check for a blank or null command line ; LDA TBUFF+1 ; Get byte from default command buffer ORA A ; If non-zero then there is a possible JNZ GTDVUS ; File specified ; SPCERR: CALL ILPRT ; Print the error message DB CR,LF DB '++ Examples of valid LUX commands ++',CR,LF,LF DB ' LUX HELLO.ARC',CR,LF DB ' LUX HELLO.ARK',CR,LF DB ' LUX HELLO.LBR',CR,LF,LF DB ' The extent is not needed if no other ',CR,LF DB ' library files have a similar name.' DB CR,LF,0 JMP REBOOT ; Reboot since we have overwritten CCP ; ;..... ; ; GTDVUS: LXI H,TBUFF+2 ; Index default key buffer CALL DRUSR ; Get requested drive/user JC SPCERR ; ; ; Test for drive/user within range ; ; push h ; save command line pointer push b ; save drive/user spec pop h shld rqddrv ; set the requested drive/user pop h XCHG ; DE is source address to create new FCB LXI H,FCB1 ; Index FCB CALL SCANR1 ; Create the new FCB ; ; ; Force the default file type ; LXI H,'RA' ; Set 'AR' into first two bytes of file type SHLD FCB1+9 MVI A,'K' ; Set 'K' into last byte of file type STA FCB1+11 ; ; ; Get the library name from the FCB and store it ; LXI H,FCB1 ; Source for move LXI D,LBRNAM-1 ; Destination for move LXI B,9 ; Max 8 character filename call LDIRs ; Move to local name LXI H,FCB1+1 ; First byte of filename MVI A,'?' ; Character to look for LXI B,11 ; Search thru 11 bytes CPIR 1 ; Do search macro JNZ LOOKUP ; No ? found - continue CALL ILPRT ; Print the error message DB CR,LF DB '++ Ambiguous filenames are not allowed ++',CR,LF,0 JMP SPCERR ;..... ; ; ; Look for the filename on directory ; LOOKUP: CALL GETOLD ; Get the current drive/user CALL SETNEW ; Set requested drive/user LXI D,080H ; Default DMA address MVI C,26 CALL BDOS ; Set the DMA address LXI D,FCB1 ; Index filename specified MVI C,17 CALL BDOS ; Search for first INR A ; Does file exist? JNZ SETARK ; Jump to start of LUX LXI H,'RA' ; Try .ARC file SHLD FCB1+9 MVI A,'C' ; Set .ARC STA FCB1+11 LXI D,FCB1 MVI C,17 ; See if it exists CALL BDOS INR A JNZ SETARC ; Yes so go LXI H,'BL' ; Try .LBR file SHLD FCB1+9 MVI A,'R' ; Set .LBR STA FCB1+11 LXI D,FCB1 MVI C,17 ; See if it exists CALL BDOS INR A JZ NOFILE ; No, error off JMP PRESTR ;..... ; ; SETARC: MVI A,0FFH ; Yes, set ARCFLG STA ARCFLG JMP PRESTR ;..... ; ; SETARK: MVI A,7FH ; Yes, set ARCFLG and .ARK STA ARCFLG ; PRESTR: LXI H,FCB1 LXI D,LBRNAM-1 ; Update library name (.ARC) LXI B,12 call LDIRs JMP PGMSTR ; Go do it ;..... ; ; NOFILE: CALL SETOLD CALL ILPRT ; Print the error message DB CR,LF,'Can''t find ',0 CALL DVUPRT CALL NAMPRT ; Print the filename CALL ILPRT DB ' - check the DIR',CR,LF,0 JMP 0000H ; Reboot since we have destroyed the ccp ;..... ; ; DS 64 ; 32 level stack for here ; SSTACK EQU $ ; FINIS EQU $ ; Finish of program loader ; LODLEN EQU FINIS-START ; Length of loader ; Keep the program in line DS 300H-LODLEN ; Add extra bytes here to make ; 'PGMSTR' start on a 100h byte boundary ; ;----------------------------------------------------------------------- ; This is the start of the relocated program - all of the code from ; 'START' to here is thrown away once LUX begins execution. ;----------------------------------------------------------------------- ; ; set up the BDOS and BIOS patches ; PGMSTR: JMP INIT ; Jump to start of this module DB 'LUXI80 v10' ; The name 'LUX' is a clue to other ; programs that enables them to deter- ; mine if LUX is resident. 'L' is at ; BDOS+3 when LUX is resident. ; ; This is the LUX removal routine, jumped to by the BYE command. It is ; accessable to external programs and is defined to exist at LUX+12 ; (looks like BDOS+12 when LUX is resident). ; REMOVE: IF RCPM LXI SP,TPA+100H ; Use the TPA for a stack LXI B,0 ; First select A0: CALL RESET LXI D,80H ; Clear the DMA buffer PUSH D PUSH D MVI B,128 ; Bytes to clear XRA A ; Easy way to make A=0 ; RZRLP: STAX D ; Null the location INX D ; Next address DJNZ RZRLP ; Loop until 'B' is zero ; MVI A,BYELEN ; Store away the length of the command LXI H,BYECMD ; Now move the commands to the DMA MOV M,A POP D ; Restore the DMA address LXI B,BYELEN call LDIRs ; POP D ; Restore it again MVI C,26 ; Reset the DMA CALL BDOS LXI D,SUBFCB ; Address the .SUB file FCB MVI C,22 ; Make the file CALL BDOS INR A ; Check for errors JZ EXITER ; Oops, no directory space LXI D,SUBFCB ; Else write the data MVI C,21 CALL BDOS INR A JZ EXITER ; Oops, no space left LXI D,SUBFCB MVI C,16 ; Now close the file CALL BDOS LXI H,0 ; Now make the exit routine go to A0: SHLD OLDDRV ENDIF ; RCPM ; JMP UNPATH ; Unpatch the jump table, and warm boot ;..... ; ; ; Error handler for REMOVE routine ; IF RCPM EXITER: CALL ILPRT ; An error when making the .SUB file DB CR,LF,'+ Error: Can''t remove LUX! Please +' DB CR,LF,'+ type CTRL-C to exit LUX, +' DB CR,LF,'+ then type BYE to logoff. +',0 LXI SP,STACK JMP GETCMD ENDIF ; RCPM ;..... ; ; ; This is the LUX intialization ; INIT: LHLD 0005H+1 ; Get BDOS start SHLD PGMSTR+1 ; Set new jump to BDOS LXI H,PGMSTR ; Get local bdos vector SHLD 0005H+1 ; Set it in low memory LXI SP,STACK ; Reset stack LHLD 0000H+1 ; Get BIOS warm boot vector SHLD BIOS3 ; Save old warm boot vector ; ; ; Save the old BIOS vectors ; LHLD BIOS3 ; BIOS warm boot address LXI D,OWBOOT ; Local warm boot address LXI B,12 ; 12 bytes to move call LDIRs ; Move the block ; ; ; Set up the new BIOS vectors ; LXI H,WBOOT ; Source is local table lhld bios3 ; destination is old bios xchg LXI B,12 ; 12 bytes to move call LDIRs ; Move the block MVI A,0FFH ; Set the auto-directory byte STA DOADIR XRA A ; Reset the error count STA HLPCNT ; JMP ENTRY ; Initialize ;..... ; ; OWBOOT: DB 0,0,0 ; Old WBOOT vector is moved to here OCONST: DB 0,0,0 ; Old CONSTAT vector is moved to here OCONIN: DB 0,0,0 ; Old cONIN vector is moved to here OCONOU: DB 0,0,0 ; Old CONOUT vector is moved to here ; WBOOT: JMP ENTRY ; Vector warm boot to entry CONST: JMP VCONST ; Check for carrier CONIN: JMP VCONIN ; Vector conin to CONIN CONOU: JMP VCONOU ; Vector to CONOUT ; VCONST: JMP OCONST ; Jump to old CONSTAT routine ; VCONOU: JMP OCONOU ; Jump to old CONOUT routine ; VCONIN: CALL OCONIN ; Get a byte CPI 'C'-40H ; CTL-C? JZ VCON1 CPI 'K'-40H ; CTL-K? JZ VCON1 CPI 'X'-40H ; CTL-X? RNZ ; Nope - let BIOS have it ; VCON1: LDA ACTIVE ; Is LUX segment active? ORA A MVI A,3 RZ ; Not active - let BIOS have it ; LXI SP,TPA ; Re initialize the stack CALL ILPRT ; Print the following DB ' Exiting LUX',CR,LF,0 ; UNPATH: LXI d,OWBOOT ; Index old warm boot vector lhld bios3 ; bios jump table xchg LXI B,12 ; 12 bytes to move call LDIRs ; Move the old table back CALL SETOLD ; Set old drive/user JMP 0000H ; Warm boot - end of program ;..... ; ; ; This is the LUX entry point ; ENTRY: LXI SP,STACK ; Set up local stack LXI H,PGMSTR ; Dummy BDOS vector SHLD 6 ; Set it LHLD BIOS3 ; BIOS warm boot vector SHLD 1 ; Set it MVI A,0C3H ; (JMP) STA 0 ; Reset warm boot jump STA 5 ; And BDOS jump CALL OCONST ; See if character waiting ORA A ; Test result JZ ENTR1 ; If no character is waiting CALL OCONIN ; Get the console character ; This is done to gobble any ; Possible garbage character ; ENTR1: MVI A,0FFH STA ACTIVE ; Set LUX active ; GETCMD: CALL SETNEW ; Reset drive/user lxi h,tbuff+1 ; Place to put command string shld cptrix XRA A ; Length of command sta tbuff ; IF AUTODR LDA DOADIR ; Shall we do a directory? ORA A JZ PROMPT ; Guess not XRA A ; Else zap the byte STA DOADIR MVI A,3 ; Fake a DIR command STA CMDLEN LXI H,'ID' SHLD CMDLIN+2 MVI L,'R' MVI H,0 SHLD CMDLIN+4 JMP GOCNV ; And do it ENDIF ; AUTODR ;..... ; ; PROMPT: IF HLPMSG CALL ILPRT ; Print the entry message DB CR,LF,'LUXI80 v10 - ^C, ^K or ^X to exit, ? for menu' DB CR,LF,0 ENDIF ; HLPMSG ; PRMPT2: CALL CRLF CALL DVUPRT ; Print the LUX prompt CALL NAMPRT ; Drive/user, library name CALL ILPRT DB ' -->',0 LXI D,CMDLIN ; Index command line MVI C,10 CALL BDOS ; Read console buffer LDA CMDLEN ; Get command length ORA A ; Test it JZ GETCMD ; If null command LDA CMDLIN+2 ; Get first character CPI ';' ; Semicolon ok JZ PRMPT2 ; GOCNV: CALL CNVBUF ; Convert the command line to upper case LXI D,CMDLIN+2 ; Index data from the command line LDA ARCFLG ; Are we looking at .ARC files? ORA A JZ LBRCMD ; Nope, do .LBR commands ani 10000000b ora a JZ ARKFL CMDJMP 'FILES',ACFILES JMP REST ; ARKFL: CMDJMP 'FILES',AKFILES ; REST: CMDJMP 'TYPE',ATYPE CMDJMP 'DIR',UNARC CMDJMP 'D',UNARC CMDJMP 'SD',UNARC CMDJMP 'CHEK',NOARC1 JMP HLP ; LBRCMD: CMDJMP 'TYPE',TIPE ; File type command process CMDJMP 'DIR',DIR ; Directory command process CMDJMP 'D',DIR ; Alternate for DIR CMDJMP 'SD',DIR ; Alternate for DIR CMDJMP 'FILES',FILES ; Run DIR.COM in "$L" (.LBR) mode CMDJMP 'CHEK',LCHEK ; Run LCHEK ; HLP: CMDJMP '?',QKHELP ; Alternate for HELP CMDJMP 'LUX',LUX ; LUX command process ; ; ; If there are other commands a user may use on your system, and you ; want to tell him to exit LUX first, then enter below: ; ; CMDJMP 'CMD',NOGOT. ; ; Place your command in 'CMD' and it will tell the user that that com- ; mand is only available outside of LUX. ; IF RCPM AND KMD CMDJMP 'KMD',KKMD ; KMD command process ENDIF ; RCPM AND KMD ; IF RCPM AND MBKMD CMDJMP 'MBKMD',KKMD ; NUKMD command process ENDIF ; RCPM and MBKMD ; IF RCPM AND NUKMD CMDJMP 'NUKMD',KKMD ; NUKMD command process ENDIF ; RCPM and NUKMD ; IF RCPM CMDJMP 'SEND',SEND ; Synonym for KMD S, MBKMD S or NUKMD S CMDJMP 'SENDK',SENDK ; Synonym for KMD SK, MBkMD SK or NUKMD SK CMDJMP 'CHAT',NOGOT ; Tell user NOGOT here CMDJMP 'BYE',NOGOT ; Tell user NOGOT here ENDIF ; RCPM ; ; ; This will actually print the command in error like this ; ; ERROR, DUR is not a valid LUX command. ; CALL ILPRT DB CR,LF,LF,'ERROR, ',0 ; Point at command error CALL PRTERR ; Print the command just entered MVI A,' ' ; And a space CALL CTYPE LXI H,HLPCNT ; Address the error count INR M ; Bump it MVI A,HLPERS ; Have we reached the limit? CMP M ; JNZ KPTRYN ; No, jump around the rest MVI M,0 ; Else reset the count JMP QKHELP ; And give him help anyway ;..... ; ; KPTRYN: CALL ILPRT ; Tell them it's no good DB ' is not a valid LUX command.',CR,LF,0 JMP GETCMD ;..... ; ; PRTERR: LXI H,CMDLIN+2 ; Index command just entered LDA CMDLEN ; Get the length MOV B,A ; Into 'B' ; GETCM5: MOV A,M ; Get a byte CPI 020H ; Space ? JZ GETCM6 ; Yes - dont print it CPI 000H ; Null JZ GETCM6 ; Yes - all done CALL CTYPE ; Print the character INX H ; Next character DJNZ GETCM5 ; Loop for the rest ; GETCM6: RET ; ; ; 'COMMAND TRANSLATION VECTORS ; ; 'SUMMARY OF AUX ROUTINES: ; ; 'FILTYP' installs the following 'DEFB' into new command line ; specify the drive and user area for each command as in ; the vectors below. remember each 'DEFB' must end with a ; zero. ; ; 'FILNAM' installs the current .LBR name into the new command line ; ; 'FILSPC' installs a space character into the new command line ; ; 'FILMEM' installs the requested member name into the new command line ; ; ACFILES:DRVUSR DIRDRV,DIRUSR,'DIR *.ARC' AKFILES:DRVUSR DIRDRV,DIRUSR,'DIR *.ARK' FILES: DRVUSR DIRDRV,DIRUSR,'DIR *.LBR' ; ATYPE: DRVUSR UNADRV,UNAUSR,'UNARC ',FILNAM,FILSPC,FILMEM DIR: DRVUSR DIRDRV,DIRUSR,'DIR ',FILNAM,FILDIR,FILMEM LCHEK: DRVUSR CHKDRV,CHKUSR,'LCHEK ',FILNAM,FILSPC,FILMEM TIPE: DRVUSR TYPDRV,TYPUSR,'TYPE ',FILNAM,FILSPC,FILMEM UNARC: DRVUSR UNADRV,UNAUSR,'UNARC ',FILNAM ; IF RCPM AND KMD SEND: DRVUSR KMDRV,KMDUSR,'KMD A ',FILNAM,FILSPC,FILMEM SENDK: DRVUSR KMDRV,KMDUSR,'KMD AK ',FILNAM,FILSPC,FILMEM SENDA: DRVUSR KMDRV,KMDUSR,'KMD A ',FILNAM,FILSPC,FILMEM SENDAK: DRVUSR KMDRV,KMDUSR,'KMD AK ',FILNAM,FILSPC,FILMEM ENDIF ; RCPM AND KMD ; IF RCPM AND NUKMD OR MBKMD SEND: LDA ARCFLG ; Are we in an .ARC file? ORA A JNZ SENDA ; Yes, use 'A' for .ARC JMP SEND1 ; No, use 'L' for .LBR ; SENDK: LDA ARCFLG ; Are we in an .ARC file? ORA A JNZ SENDA ; Yes, use 'A' for .ARC JMP SENDK1 ; No, use 'L' for .LBR ENDIF ; RCPM AND MBKMD OR NUKMD ; IF RCPM AND MBKMD SEND1: DRVUSR KMDRV,KMDUSR,'MBKMD L ',FILNAM,FILSPC,FILMEM SENDK1: DRVUSR KMDRV,KMDUSR,'MBKMD LK ',FILNAM,FILSPC,FILMEM SENDA: DRVUSR KMDRV,KMDUSR,'MBKMD A ',FILNAM,FILSPC,FILMEM SENDAK: DRVUSR KMDRV,KMDUSR,'MBKMD AK ',FILNAM,FILSPC,FILMEM ENDIF ; RCPM AND MBKMD ; IF RCPM AND NUKMD SEND1: DRVUSR KMDRV,KMDUSR,'NUKMD L ',FILNAM,FILSPC,FILMEM SENDK1: DRVUSR KMDRV,KMDUSR,'NUKMD LK ',FILNAM,FILSPC,FILMEM SENDA: DRVUSR KMDRV,KMDUSR,'NUKMD A ',FILNAM,FILSPC,FILMEM SENDAK: DRVUSR KMDRV,KMDUSR,'NUKMD AK ',FILNAM,FILSPC,FILMEM ENDIF ; RCPM AND NUKMD ; ; ; Quick help summary ; QKHELP: CALL ILPRT DB CR,LF,LF DB 'You are using the LUX utility to work with an archive ' DB CR,LF DB 'or library file. These are the available commands:' DB CR,LF,LF DB 'CHEK HELLO.EXT - Runs LCHEK on requested member ' DB 'file',CR,LF DB 'DIR - Display member files ' DB 'in this library',CR,LF DB 'FILES - Display other .ARC/.ARK/.LBR ' DB 'files available',CR,LF DB 'LUX NEWNAME - Attach to another ' DB 'LBR/ARC file ',CR,LF ; IF RCPM AND KMD DB CR,LF DB 'KMD S HELLO.EXT - Sends member file ' DB 'via auto-protocol detect',CR,LF DB 'KMD SK HELLO.EXT - Sends member file ' DB 'with manual 1k setting',CR,LF ENDIF ; RCPM AND KMD ; IF RCPM AND MBKMD DB 'MBKMD S HELLO.EXT - Sends member file ' DB 'via auto-protocol detect',CR,LF DB 'MBKMD SK HELLO.EXT - Sends member file ' DB 'with manual 1k setting',CR,LF ENDIF ; RCPM AND MBKMD ; IF RCPM AND NUKMD DB 'NUKMD S HELLO.EXT - Sends member file ' DB 'via auto-protocol detect',CR,LF DB 'NUKMD SK HELLO.EXT - Sends member file ' DB 'with manual 1k setting',CR,LF ENDIF ; RCPM AND NUKMD ; IF RCPM DB 'SEND HELLO.EXT - Same as ''S'' command',CR,LF DB 'SENDK HELLO.EXT - Same as ''SK'' command',CR,LF ENDIF ; RCPM ; DB CR,LF DB 'TYPE HELLO.EXT - Display ASCII file contents' DB CR,LF,CR,LF DB '? - Displays this menu' DB CR,LF,LF,'(Abort to CP/M with ^C, ^K or ^X)',CR,LF DB 0 JMP GETCMD ;..... ; ; ; Tried entering CHAT - tell him to exit LUX first. Add other commands ; as you wish. ; NOGOT: CALL CRLF CALL CRLF CALL PRTERR ; Print the command CALL ILPRT ; And then this DB ' <<== Exit LUX with ^C, ^K or ^C',CR,LF,0 JMP GETCMD ; Go back for another command ;..... ; ; NOARC1: CALL CRLF CALL CRLF CALL ILPRT DB 'Use DIR command for CRC values',CR,LF,0 JMP GETCMD ;..... ; ; ; KMD is a special case since the 'A' and 'R' options are invalid here ; IF RCPM KKMD: CALL ADVANC ; Go to next character MOV A,M ; Get the character CPI 'S' ; If 'S' check for JZ KKMD1 ; Following 'K' CPI 'R' ; Not legal here JZ KKMD2 ; Execute error routine CPI 'A' ; Not legal here JZ KKMD3 ; Execute error routine CPI 'L' ; Not legal here JZ KKMD3 ; Execute error routine ENDIF ; RCPM ; IF RCPM AND KMD DRVUSR KMDRV,KMDUSR,'KMD' ENDIF ; RCPM AND KMD ; IF RCPM AND MBKMD DRVUSR KMDRV,KMDUSR,'MBKMD' ENDIF ; RCPM AND MBKMD ; IF RCPM AND NUKMD DRVUSR KMDRV,KMDUSR,'NUKMD' ENDIF ; RCPM AND NUKMD ; IF RCPM KKMD1: INX H ; Get next chacter MOV A,M CPI 020H ; Is it a space? JZ KKMD1A CPI 'K' ; Or packet request? JZ KKMDK ; KKMD1A: CALL NXTSPC LDA ARCFLG ; Are we in an .ARC file? ORA A JZ SEND ; Nope, send regular JMP SENDA ; Yes, send .ARC ;..... ; ; KKMDK: CALL NXTSPC LDA ARCFLG ; Are we in an .ARC file? ORA A JZ SENDK ; Nope, send regular JMP SENDAK ; Yes, send .ARC ;..... ; ; KKMD2: CALL CRLF CALL PRTERR ; Print the command CALL ILPRT ; Print the following DB ' can''t (R)eceive while in LUX',CR,LF,0 JMP GETCMD ; Return to command ;..... ; ; KKMD3: CALL CRLF CALL PRTERR ; Print the command CALL ILPRT ; Print the following DB ' uses S or SK options while in LUX',CR,LF,0 JMP GETCMD ENDIF ; RCPM ;..... ; ; ; 'LUX' command process ; LUX: LDA CMDLEN ; Get the length of the command line CPI 3 ; Was input only 'LUX' JZ LUX04 ; Error... CALL FNDSPC ; Find a space in command line JC LUX05 ; Error if no space found CALL ADVANC ; Search for the next non-blank character JC LUX05 ; Error if no more characters left CALL DRUSR ; Get drive/user JC LUX05 ; If drive/user specification error push h ; save command pointer mov h,b mov l,c shld tmpdrv ; save the temporary drive/user pop h ; get cmd pointer back XCHG ; De is source address to create new fcb LXI H,TMPFCB ; Index temporary fcb CALL SCANR1 ; Create the new fcb LXI H,'BL' ; Set 'LB' into first two bytes of file type SHLD TMPFCB+9 MVI A,'R' ; Set 'R' into last byte of file type STA TMPFCB+11 CALL SETTMP ; Log into the requested drive/user LXI D,080H MVI C,26 ; BDOS set DMA function CALL 5 ; Set DMA address to 80h LXI D,TMPFCB ; Index temporary FCB MVI C,17 ; Bdos search first function CALL 5 INR A ; Test for existence JNZ LUX01 ; OK, go LXI H,'RA' ; Check for .ARC file SHLD TMPFCB+9 MVI A,'C' STA TMPFCB+11 LXI D,080H MVI C,26 CALL 5 LXI D,TMPFCB MVI C,17 CALL 5 INR A JNZ SETFLG ; Set ARCFLG LXI H,'RA' ; Check for .ARK file SHLD TMPFCB+9 MVI A,'K' STA TMPFCB+11 LXI D,080H MVI C,26 CALL 5 LXI D,TMPFCB MVI C,17 CALL 5 INR A JZ LUX05 ; Cant find file MVI A,07FH STA ARCFLG ; Set .ARK flag true JMP LUX02 ; SETFLG: MVI A,0FFH ; Set .ARC flag true STA ARCFLG JMP LUX02 ;..... ; ; LUX01: MVI A,0 ; Set .ARC flag false STA ARCFLG ; LUX02: LHLD TMPDRV ; Get temporary drive/user SHLD RQDDRV ; Set new drive/user LXI H,TMPFCB+1 ; Source address of new name LXI D,LBRNAM ; Current .lbr name LXI B,12 ; 8 character file name call LDIRs ; Move it CALL ILPRT ; For display neatness DB CR,LF,0 MVI A,0FFH ; Set the auto-directory flag STA DOADIR JMP GETCMD ;..... ; ; LUX04: CALL ILPRT DB CR,LF,'++ Invalid drive/user number ++',CR,LF,0 JMP GETCMD ;..... ; ; LUX05: CALL ILPRT DB CR,LF,LF,'Can''t find ',0 CALL DVUPR1 MVI B,8 LXI H,TMPFCB+1 CALL NAMPR1 ; Print the file name CALL ILPRT DB ' - check your spelling',CR,LF,0 JMP GETCMD ;..... ; ; PROCES: XRA A ; Zero last byte of new command line lhld cptrix mov m,a LXI H,TBUFF+1 STA HLPCNT ; Reset the error count CALL DRUSR ; Get drive/user push h mov h,b mov l,c shld comdrv pop h XCHG ; De is source address to create new FCB CALL SCANER ; Create the new FCB XCHG ; Into 'HL' LXI D,TBUFF+1 ; Start of command buffer PUSH H PUSH D ORA A ; Clear any carry mov a,h sbb d mov h,a mov a,l sbb e mov l,a ; Replace Z80 SBC HL,DE LDA TBUFF ; Get command line length SUB L ; Calculate new length STA TBUFF ; Put new length MVI A,07EH ; Calculate length of block move SUB L MOV C,A ; Set into C MVI B,0 ; 'B' gets zero POP D ; Restore destination POP H ; And source call LDIRs ; Move the block down LXI H,FCB1 ; Set up first FCB LXI D,TBUFF+1 CALL SCANR1 LXI H,FCB2 ; Set up second FCB CALL SCANR1 ; ; ; Force the default file type (.COM) ; LXI H,'OC' ; 'CO' SHLD DEFFCB+9 MVI A,'M' ; 'M' STA DEFFCB+11 XRA A ; Zero the record count and STA DEFFCB+15 ; the extent number STA DEFFCB+32 CALL SETCOM ; Set .COM drive/user LXI D,TPA MVI C,01AH CALL BDOS ; Set DMA to TPA LXI D,DEFFCB MVI C,011H CALL BDOS ; Search for first INR A JNZ PROCE1 ; File found CALL ILPRT DB CR,LF,'Can''t find ',0 MVI B,8 LXI H,DEFFCB+1 CALL NAMPR1 ; Print the file name CALL ILPRT ; CR/LF DB CR,LF,0 JMP ENTRY ; Go for more commands ;..... ; ; PROCE1: LXI D,TPA MVI C,01AH CALL BDOS ; Set DMA to TPA LXI D,DEFFCB MVI C,00FH CALL BDOS ; Open file INR A JNZ PROCE2 CALL ILPRT DB CR,LF,'.COM File error - notify SYSOP',CR,LF,0 JMP ENTRY ;..... ; ; ; Load the .COM file into memory at 100h and call it ; PROCE2: LXI H,080H LXI D,080H ; LODCOM: DAD D ; Add record size offset XCHG ; Get DMA address into 'DE' PUSH D ; Save 'DE' and 'HL' PUSH H MVI C,01AH CALL BDOS ; Set DMA LXI D,DEFFCB ; Index .com file name MVI C,014H CALL BDOS ; Read a record POP H ; Restore 'DE' and 'HL' POP D XCHG ; 'HL' is dma address again ORA A ; End of file ? JZ LODCOM ; No - read another record MVI C,13 CALL BDOS ; Reset drive system CALL SETNEW ; Set new drive/user XRA A STA ACTIVE ; Clear command mode active CALL CRLF CALL TPA ; Call the loaded file @100h LXI D,35 ; Zero out FCB1 LXI H,FCB1 ; ZEROFCB:MVI M,0 INX H DJNZ ZEROFCB JMP ENTRY ; Go for more commands ;..... ; ; NAMPRT: MVI B,8 ; 8 character file name LXI H,LBRNAM ; Index .LBR name ; NAMPR1: MOV A,M ; Get a byte CPI 020H ; Space? JZ NAMPR2 ; Yes - dont print CALL CTYPE ; Else print the character ; NAMPR2: INX H ; Next character DJNZ NAMPR1 ; Process 8 characters MVI A,'.' ; Print a seperator CALL CTYPE MVI B,3 ; 3 character file type ; NAMPR3: MOV A,M ; Get a character CALL CTYPE ; Print it INX H ; Next character DJNZ NAMPR3 ; Process 3 characters RET ;..... ; ; ; Write a string of characters to the crt ; ILPRT: XTHL ; Save return address/get character pointer ; ILPRT1: MOV A,M ; Get a byte ORA A ; Test it JZ ILPRT2 ; Null - end of string CALL CTYPE ; Else type the character INX H ; Next character JMP ILPRT1 ; Loop for more ; ILPRT2: INX H XTHL ; Restore return address RET ; Return to caller ;..... ; ; ; Write a string of characters to the command line ; ; (works like ILPRT above) ; FILTYP: XTHL ; FILTY1: MOV A,M ORA A JZ FILTY2 CALL PUTIN INX H JMP FILTY1 ; FILTY2: XTHL RET ;..... ; ; ; Puts ' $L' on command line ; FILDIR: CALL FILSPC MVI A,'$' CALL PUTIN MVI A,'L' CALL PUTIN ; ; ; Fill command line with a space ; FILSPC: MVI A,20H ; Space character JMP PUTIN ; Fill in ;..... ; ; ; Fill command line with .LBR name ; FILNAM: MVI B,8 ; 8 character file name LXI H,LBRNAM ; Index .LBR name ; FILNA1: MOV A,M ; Get a character CPI 020H ; Space ? JZ FILNA2 ; Yes - dont add to command line CALL PUTIN ; Put character into command line ; FILNA2: INX H ; Next character DJNZ FILNA1 ; Process 8 characters MVI A,'.' ; Put in a seperator character CALL PUTIN MVI B,3 ; 3 character file type ; FILNA3: MOV A,M ; Get a character CALL PUTIN ; Put in command line INX H ; Next character DJNZ FILNA3 ; Process 3 characters RET ; Return to caller ;..... ; ; ; Fill command line with member name ; FILMEM: CALL PARSER ; Parse member name LXI H,MEMBER ; Index member name MVI B,12 ; 12 character max ; FILME1: MOV A,M ; Get a byte ORA A ; End of input RZ ; Yes - return CALL PUTIN ; Fill in one character INX H ; Next character DJNZ FILME1 ; Continue looping RET ; Done ; Putin: push h ; Stuff the character into command line lhld cptrix mov m,a inx h ; Get ready for next character shld cptrix lxi h,tbuff ; Bump command line length inr m pop h RET ; Return to caller ;..... ; ; ; Parse out a member name ; PARSER: LXI H,MEMBER ; Index member name MVI B,12 ; Max 12 character filename ; PARSE1: MVI M,0 ; Zero character INX H ; Next character DJNZ PARSE1 ; Clear the entire member name CALL ADVANC ; Advance to the next non blank character RC ; If at the end of the line LXI D,MEMBER ; DE is index to member, HL set by ADVANC LHLD NXTWRD ; PARSE2: MOV A,M ; Get source byte ORA A ; End of input line ? RZ ; Yes - return ; STAX D ; Put byte INX H ; Next source INX D ; Next destination JMP PARSE2 ; Continue looping ;..... ; ; ; Advance the word at NXTWRD to the next non-blank address of the com- ; mand line. Set carry if no more characters available. ; ADVANC: LHLD NXTWRD ; Get pointer to next word ; ADVAN1: MOV A,M ; Get a byte ORA A ; Test flags JZ ADVAN3 ; Error - null character CPI 020H ; Space ? JNZ ADVAN2 ; Yes - done INX H SHLD NXTWRD ; Put pointer back JMP ADVAN1 ; Loop for more ; ADVAN2: ORA A ; Clear any carry RET ; ADVAN3: STC ; Set error condition RET ;..... ; ; FNDSPC: LXI H,CMDLIN+2 ; Index command line ; FND01: MOV A,M ; Get a byte from command line ORA A ; Eol ? JZ FNDER ; Error... CPI 020H ; Space? JZ FNDEX ; Yes - go find requested file name INX H ; Next character JMP FND01 ; Else continue the search ; FNDER: STC ; All chars. scanned and no space found RET ; FNDEX: SHLD NXTWRD ; Set character location ORA A ; Assure carry reset RET ; ; NXTSPC: LHLD NXTWRD ; Get pointer to next word ; NXTSP1: MOV A,M ; Get a byte ORA A ; Is it a null? JZ NXTSP2 ; Yes - return CPI 020H ; If at a space? JZ NXTSP2 ; Yes - return INX H ; Next character JMP NXTSP1 ; And continue looking ; NXTSP2: SHLD NXTWRD RET ;..... ; ; ; In-line compare. Compares string addressed by 'DE' to string after ; call (ends with zero). Return with carry set means strings not the ; same. All registers except 'A'-reg are unaffected. ; ILCMP: XTHL PUSH D ; ILCMP1: MOV A,M ; Get a byte from source ORA A ; Null JZ SAME1 ; Yes - same so far - test next char LDAX D ; Get a byte from command string CMP M ; Same as source JNZ NOTSAM ; No - not the same INX H ; Next source INX D ; Next compare JMP ILCMP1 ; Loop again ; NOTSAM: XRA A ; Zero for the test ; NSLP: INX H ; Next immediate byte CMP M ; Null yet ? JNZ NSLP ; No - continue ; SAME2: STC ; Set error condition ; SAME: XCHG ; Get command string pointer SHLD NXTWRD ; Store it XCHG ; Restore return address POP D ; Restore source address INX H ; Adjust to stack XTHL ; Replace return address RET ; Return ; SAME1: LDAX D ; Get the next byte from command line ORA A ; Null ? JZ SAME ; Yes - its ok CPI 20H ; Space ? JZ SAME ; Yes - thats ok too... JMP SAME2 ; Not ok- must be another character ;..... ; ; CTYPE: PUSH PSW ; Save all registers PUSH B PUSH D PUSH H ANI 7FH ; Be sure its ASCII MOV E,A ; Into 'E' MVI C,2 ; Cpm console function CALL BDOS POP H ; Restore all registers POP D POP B POP PSW RET ; Return to caller ;..... ; ; CRLF: MVI A,13 CALL CTYPE MVI A,10 JMP CTYPE ;..... ; ; ; Get the drive and user number for a file from command string index by ; 'HL' ; ; On entry: ; ; 'HL' points to first byte of the command string ; ; on exit: ; ; 'HL' points to the byte following ':' in the command string if ; the ':' was found in the first 4 character positions. ; -or- ; 'HL' points to the first byte of the command string if no ':' ; was found. ; ; 'C' contains the requested drive number (0-15) ; ; 'B' contains the requested user number (0-15) ; ; 'AF' the number of characters thru the ':' in the command string. ; ; 'CY' is set if drive or user number is out of range (0-15) ; ;----------------------------------------------------------------------- ; DRUSR: SHLD TEMPHL ; Save the pointer address shld cptrix ; 'IX' get the pointer address LXI B,5 ; MVI A,':' CPIR 2 ; Search for the ':' macro MOV A,C ; Get 'B' result from 'CPIR' instruction STA LENGTH ; Keep for possible adjust XCHG ; De points to the byte following ':' LXI H,VTABLE ; Index address table DAD B ; Add word offset DAD B MOV A,M ; Get routine lsb INX H MOV H,M ; Get routine msb MOV L,A LXI B,0 ; Set up drive/user storage PCHL ; Execute ;..... ; ; VTABLE: DW DRUS0 ; B=0 - FILENAME.EXT DW DRUS1 ; B=1 - A15:FILENAME.EXT DW DRUS2 ; B=2 - A1:FILENAME.EXT DW DRUS3 ; B=3 - A:FILENAME.EXT DW DRUS4 ; B=4 - :FILENAME.EXT ; ; ; Format was - FILENAME.EXT ; DRUS0: CALL GETDFU ; Get the default user CALL GETDFD ; Get the default drive LHLD TEMPHL ; Get old buffer pointer back XRA A ; Zero move length RET ; All done ;..... ; ; ; Format was - DUU:FILENAME.EXT ; DRUS1: CALL GETDRV ; Get the drive parameter push h lhld cptrix mov a,m pop h CPI '0' JC ERROR CPI '9'+1 JNC ERROR SUI '0' MOV B,A ; Put in drive number ADD B MOV B,A push h ; Skip the tens digit lhld cptrix inx h shld cptrix pop h JMP GETUSR ; Get the user number ;..... ; ; ; Format was - DU:FILENAME.EXT ; DRUS2: CALL GETDRV ; Get the drive parameter JMP GETUSR ; Get the user number ;..... ; ; ; Format was - D:FILENAME.EXT ; DRUS3: CALL GETDRV ; Get the drive parameter CALL GETDFU ; Get the default user ; ; ; Format was - :FILENAME.EXT ; DRUS4: JMP DRUS5 ; Getdrv: push h lhld cptrix mov a,m pop h CPI 'A' JC ERROR1 CPI 'Q' JNC ERROR1 SUI 'A' MOV C,A ; Put in drive number push h lhld cptrix inx h shld cptrix pop h RET ;..... ; ; Getusr: push h lhld cptrix mov a,m pop h CPI '0' JC ERROR CPI '9'+1 JNC ERROR SUI '0' ADD B MOV B,A ; ; ; Adjust the byte in 'LENGTH' ; DRUS5: XCHG ; Hl points to byte following ':' if any LDA LENGTH ; Get length of move ORA A ; Test it RZ ; Return if null/ clear carry MOV E,A MVI A,5 SUB E STA LENGTH ORA A ; Clear any error RET ;..... ; ; ERROR1: POP D ; Kill return address from subroutine ERROR: STC ; Set error condition RET ;..... ; ; ; Get default user ; GETDFU: PUSH B PUSH D PUSH H MVI C,020H MVI E,0FFH CALL BDOS POP H POP D POP B MOV B,A ; Set 'B' register to current user RET ;..... ; ; ; Get default drive ; GETDFD: PUSH B PUSH D PUSH H MVI C,19H CALL BDOS POP H POP D POP B MOV C,A ; Set 'C' register to current drive RET ;..... ; ; ; Extract token from command line and place it into DEFFCB; ; format DEFFCB FCB if token resembles file name and type ; (FILENAME.TYP); ; on input, CIBPTR points to character at which to start scan ; on output, CIBPTR points to character at which to continue ; and zero flag is reset if '?' is in token ; ; Entry points: ; scaner - load token into first FCB ; scanr1 - load token into FCB poibted to by HL ; ; SCANER: LXI H,DEFFCB ; Point to DEFFCB ; SCANR1: XRA A ; Set temporary drive number to default STA TEMPDR CALL ADVNCE ; Skip to non-blank or end of line xchg ; Set pointer to non-blank or end of line shld ciptr xchg LDAX D ORA A JZ SCANR2 SBI 'A'-1 MOV B,A INX D LDAX D CPI ':' JZ SCANR3 DCX D ; SCANR2: LDA TDRIVE ; Set 1st byte of deffcb as default drive MOV M,A JMP SCANR4 ; SCANR3: MOV A,B STA TEMPDR MOV M,B INX D ; SCANR4: XRA A ; A=0 STA QMCNT ; Init count of # of question marks in FCB MVI B,8 ; Max of 8 characters in file name CALL SCANF ; Fill FCB file name ; ; ; Extract file type from possible FILENAME.TYP ; MVI B,3 ; Prepare to extract type CPI '.' ; If (de) delimiter is a '.', we have a type JNZ SCANR5 ; Fill file type bytes with INX D ; Pt to char in command line after '.' CALL SCANF ; Fill FCB file type JMP SCANR6 ; Skip to next processing ; SCANR5: CALL SCANF4 ; Space fill ; ; ; Fill in ex, s1, s2, and rc with zeroes ; SCANR6: MVI B,4 ; 4 bytes ; SCANR7: INX H ; Point to next byte in DEFFCB MVI M,0 DJNZ SCANR7 ; ; ; Scan complete -- DE points to delimiter byte after token ; xchg shld cibptr xchg ; ; ; Set zero flag to indicate presence of '?' in FILENAME.TYP ; LDA QMCNT ; Get number of question marks ORA A ; Set zero flag to indicate any '?' RET ; ; ; Scan token pointed to by DE for a maximum of B bytes; place it into ; file name field pointed to by HL; expand and interpret wild cards of ; '*' and '?'; on exit, DE points to terminating delimiter ; SCANF: CALL SDELM ; Done if delimiter encountered - fill JZ SCANF4 INX H ; Pt to next byte in deffcb CPI '*' ; Is (de) a wild card? JNZ SCANF1 ; Continue if not MVI M,'?' ; Place '?' in deffcb and dont advance de if so CALL SCQ ; Scanner count question marks JMP SCANF2 ; SCANF1: MOV M,A ; Store filename char in deffcb INX D ; Pt to next char in command line CPI '?' ; Check for question mark (wild) CZ SCQ ; Scanner count question marks ; SCANF2: DJNZ SCANF ; Decrement char count until 8 elapsed ; SCANF3: CALL SDELM ; 8 chars or more - skip until delimiter RZ ; Zero flag set if delimiter found INX D ; Pt to next char in command line JMP SCANF3 ; ; ; Fill memory pointed to by HL with spaces for B bytes ; SCANF4: INX H ; Pt to next byte in deffcb MVI M,' ' ; Fill filename part with DJNZ SCANF4 RET ;..... ; ; ; Increment question mark count for scanner - this routine increments ; the count of the number of question marks in the current FCB entry ; SCQ: LDA QMCNT ; Get count INR A ; Increment STA QMCNT ; Put count RET ;..... ; ; ; Check to see if DE points to delimiter; if so, return with zero flag ; set. ; SDELM: LDAX D ORA A ; 0=delimiter RZ CPI ' ' ; Error if < RZ ; =delimiter CPI '=' ; '='=delimiter RZ CPI 5FH ; Underscore=delimiter RZ CPI '.' ; '.'=delimiter RZ CPI ':' ; ':'=delimiter RZ CPI ';' ; ';'=delimiter RZ CPI '<' ; '<'=delimiter RZ CPI '>' ; '>'=delimiter RET ;..... ; ; ; Advance input pointr to first non-blank and fall through to SBLANK ; Advnce: xchg shld cibptr xchg ; ; Skip string pointed to by DE (string ends in 0) until end of string ; or non-blank encountered (beginning of token) ; SBLANK: LDAX D ORA A RZ CPI ' ' RNZ INX D JMP SBLANK ;..... ; ; ; Capitalize string (ending in 0) in cmdlin and set pointr for parsing ; CNVBUF: LXI H,CMDLIN+1 ; Point to users command MOV B,M ; Character count in 'B' INR B ; Add 1 in case of zero ; CNVBF1: INX H ; Point to 1st valid character MOV A,M ; Capitalize command character CALL UCASE MOV M,A DJNZ CNVBF1 ; Continue to end of command line ; CNVBF2: MVI M,0 ; Store ending LXI H,CMDLIN+2 ; Set command line pointer to 1st char SHLD CIBPTR RET ;..... ; ; ; Convert character in 'A' to upper case ; UCASE: CPI 61H ; Lower-case a RC CPI 7BH ; Greater than lower-case z? RNC ANI 5FH ; Capitalize RET ;..... ; ; GETOLD: CALL GETDFU ; Get current user into 'B' CALL GETDFD ; Get current drive into 'C' push h mov h,b ; Get the parameters mov l,c shld olddrv pop h RET ;..... ; ; Settmp: push h lhld tmpdrv mov b,h mov c,l pop h JMP RESET ;..... ; ; Setold: push h lhld olddrv mov b,h mov c,l pop h JMP RESET ;..... ; ; Setnew: push h lhld rqddrv ; get the old drive number mov b,h mov c,l pop h JMP RESET ;..... ; ; Setcom: push h lhld comdrv ; Get the old drive number mov b,h mov c,l pop h ; RESET: PUSH B ; Save drive/user PUSH B MOV E,C ; Get selected drive MVI C,14 ; Bdos function CALL BDOS POP B ; Restore drive/user MOV E,B ; Get selected user MVI C,32 ; Bdis set user function CALL BDOS ; ; ; Set up byte at 0004h - some programs may look at it ; POP B MOV A,B ; Get user number RAL RAL RAL RAL ANI 0F0H ORA C STA 4 RET ; DVUPR1: LDA TMPUSR PUSH PSW LDA TMPDRV JMP DVUPR3 ; DVUPRT: LDA RQDUSR ; Get requested drive PUSH PSW LDA RQDDRV ; Get the requested user ; DVUPR3: ADI 'A' CALL CTYPE ; Print the drive 'A'-'P' POP PSW CPI 10 ; Less that 10? JC DVUPR2 ; Yes - dont print the '1' PUSH PSW MVI A,'1' CALL CTYPE POP PSW SUI 10 ; DVUPR2: ADI '0' CALL CTYPE MVI A,':' JMP CTYPE ;..... ;----------------------------------------------------------------------- ; ; This subroutine is a substitute for the Z80 LDIR instruction. ; Borrowed from ZCMD8080.ASM ; LDIRS: PUSH PSW ; Save flags LDIR1: MOV A,M ; Fetch the byte STAX D ; Poke it INX H ; Increment pointers INX D DCX B ; Decrement counter MOV A,B ; Check the counter to ORA C ; see if we are done JNZ LDIR1 ; Not done? POP PSW ; Finished RET ; End of LDIR replacement subroutine ; ;----------------------------------------------------------------------- ; ; IF RCPM SUBFCB: DB 0 ; Use current drive DB '$$$ SUB' DB 0,0,0,0,0,0,0,0 ; Rest of the FCB DB 0,0,0,0,0,0,0,0 ; DB 0,0,0,0,0 DB 0,0,0,0 ; RFU ; ; ; Edit this to contain the console commands necessary to execute the ; logoff sequence for your system. ; BYECMD: DB 0 ; <====== do not touch DB 'BYE',CR,LF ; <====== put any number of cmds here DB 'Z'-40H ; <====== do not touch ; BYELEN EQU $-BYECMD-1 ENDIF ; RCPM ; ; ARCFLG: DB 0 DOADIR: DB 0 HLPCNT: DB 0 BIOS3: DW 0 TEMPDR: DB 0 CIPTR: DW 0 TDRIVE: DB 0 QMCNT: DB 0 CIBPTR: DW 0 TEMPHL: DW 0 LENGTH: DB 0 OLDDRV: DB 0 OLDUSR: DB 0 RQDDRV: DB 0 ; Requested drive RQDUSR: DB 0 ; Requested user COMDRV: DB 0 ; Drive to load .COM file COMUSR: DB 0 ; User to load .COM file TMPDRV: DB 0 ; Temporary drive number TMPUSR: DB 0 ; Temporary user number ACTIVE: DB 0 ; Attach command mode active NXTWRD: DW 0 DW 0 CMDLIN: DB 79 CMDLEN: DB 0 DS 79 DB 0 ; MEMBER: DB ' ' DB 0 DB 0 LBRNAM: DB ' ' ; Library file name DB 'LBR' ; Cptrix: ds 2 ; points to command line ; TMPFCB: DS 36 DEFFCB: DS 36 ; DS 80 ; Area for stack ; STACK EQU $ ; ; END