; MAP.ASM ; version 1.04 ; ; 04/06/85 ; v1.03 had a bug in it. When someone tried to MAP a specific ; drive, the program would report drive A: instead of the selected ; drive. MAP command syntax now makes a little more sense. ; ; 04/02/85 ; Another major change. This version will now let the user select ; which drive to map. In addition, the descriptive mode routines ; are now conditional (see EQUate DESCRIP), this is for sysops who ; don't want to use extra disk space to handle section ; descriptions. In the library, I've changed README.TXT to ; MAPxxx.MOD. ; ; 03/01/85 ; This sucker's getting pretty slick. I've added a routine to ; print a description of the section along with its name ; (description is inside -*.* file, see README.TXT in MAP102.LBR ; for more information). I've also added an abort and XOFF ; handling routine, in the process switching over to all BDOS ; direct console I/O. ; ; * * * ; ; This program was designed for RCP/M systems that, for one reason ; or another, cannot use SECTION (i.e. a system whose download ; areas change daily). It goes through the directory of each ; online user area and drive looking for catalog label files ; (-*.*). Upon finding such a file it displays bytes 2-8 of the ; filename and the drive/user area where the file is located. For ; example, a file in A6: called -UTILITY.05A would be displayed as ; "A6: = UTILITY". Of course, this means that filename bytes 2-8 ; have to be somehow descriptive of that particular section. ; ; If you have any bug reports/fixes, please contact me either by ; calling B-RCP/M (214) 840-9552 and leaving a message via the ; CP/M NOTE command or write to: ; ; Bob Horn ; c/o Horn Engineering Associates ; 1714 Patricia Lane ; Garland, Texas 75042 ; ; PS: The RCP/M hours are pretty sporadic, but if you call about ; 7PM central time or early morning (midnight to 8AM) you ; stand a pretty good chance of getting online. Note that at ; some hours an aux. 5" based system is up with just a ; bulletin board online ; TRUE EQU 0FFH FALSE EQU NOT TRUE ; ; CP/M Equates ; BOOT EQU 0 ;org zero CP/M BDOS EQU BOOT+5 ;bdos entry DEFDMA EQU 80H ;normal default DMA address TPA EQU BOOT+100H ;ORG address DFCB EQU 5CH ;CP/M default FCB CONIN EQU 1 ;BDOS console input function CONOUT EQU 2 ;console output function DIRCON EQU 6 ;direct console I/O PBUF EQU 9 ;print buffer function RDCON EQU 10 ;read console buffer function CONSTAT EQU 11 ;console status function SELDISK EQU 14 ;select default disk function OPENF EQU 15 ;open file function CLOSEF EQU 16 ;close file function SRCHF EQU 17 ;search for first dir file function SRCHN EQU 18 ;search for next file function DELF EQU 19 ;delete file function READF EQU 20 ;read file function WRITEF EQU 21 ;write file function MAKEF EQU 22 ;make file function GETDISK EQU 25 ;get default disk function SETDMA EQU 26 ;set DMA address function SETATTR EQU 30 ;set file attributes USRSTAT EQU 32 ;get/set user number ACHAR EQU 'C'-'@' ;characters for abort and pause, XOFF EQU 'S'-'@' ;respectively. MUST be ctrl chars. ; ; Misc Equates ; BELL EQU 07H ;bell character BS EQU 08H ;backspace character LF EQU 0AH ;line feed CR EQU 0DH ;carriage return BLANK EQU 20H ;space character ; ; Program Equates ; VERS EQU 1 ;version REV EQU 04 ;revision # MONTH EQU 04 ;date of last revision DAY EQU 06 YEAR EQU 85 ; ; If you make any changes, please change the above accordingly ; ; FENCE EQU '|' ;separator between section names NUMCOL EQU 4 ;# of sections to be displayed on ;each line, 4 for 80 column display ; DESCRIP EQU TRUE ;true, produce description code ZCPR EQU TRUE ;true if using ZCPR for MXDRV/USR ; ;if false, see IF NOT ZCPR area below IF ZCPR MXDRV EQU 3DH ;set to location of ZCPR MAXDRV MXUSR EQU 3FH ; " MAXUSER ENDIF ; ORG TPA ;program runs here ; ; Main program ; START: JMP START1 ;jump over fixed data ; IF NOT ZCPR MXDRV: DB 1 ;max drive to search (A:=0, B:=1, etc.) MXUSR: DB 8 ;max user to search +1 ENDIF ; DIRFNAME: DB '-??????????' ;wild card directory name START1: LXI H,0 ;find CP/M stack pointer DAD SP SHLD OLDSP ;save old stack pointer LXI SP,STACK ;set up our local stack ; LDA DFCB+1 ;get first character of command line CPI '?' ;request for help? JZ HELP ;then help 'im ; IF DESCRIP CPI 'D' ;? if descriptive mode JNZ START2 ;it's not, go ahead MVI A,0FFH ;it is, set the flag STA DESFLG ENDIF ;descrip ; START2: LXI H,SIGNON ;point to signon message CALL IPBUF ;and show it ; ; Get the default drive & user, save them, and log onto A0: ; MVI C,GETDISK ;get the default drive CALL BDOS STA DEFDRV ;save it ; MVI C,USRSTAT ;get the default user MVI E,0FFH CALL BDOS STA DEFUSR ;save it ; MVI E,0 ;set default to A: MVI C,SELDISK ; CALL BDOS ; MVI E,0 ;user 0 MVI C,USRSTAT CALL BDOS ; LDA DFCB ;see if specific drive ORA A ;set flags CNZ SPCDRV ;one specific drive, set it ; ; Here we set up the DMA and initialize some values ; LXI D,DEFDMA ;set the CP/M DMA address MVI C,SETDMA CALL BDOS ; ; Now start the directory search. ; LFORFL: CALL ZFCB ;zero the FCB LXI B,11 ;11 char in file name LXI H,DIRFNAME ;the wild card file name LXI D,FCB+1 ;point to FCB file name space CALL MOVE ;move the file name in ; LXI D,FCB ;find first match MVI C,SRCHF CALL BDOS INR A ;returns 0ffh if not found JZ MORETGO ;None there DCR A ;set A back to normal LXI H,DEFDMA ;point to DMA buffer CALL FINDFN ;find the file name in the DMA space ; IF DESCRIP LDA DESFLG ;see if descriptive mode ORA A ;set flags JNZ DESCAL ;call descriptive routine if so ENDIF ;descrip ; CALL PRINTFN ;Print the filename with pertinent data ; MORETGO: LDA CURUSR ;get the current user MOV B,A LDA MXUSR ;and the max user INR B ;bump the current user CMP B ;same as (MXUSR)? JZ NDRIVE ;if so, go to the next drive MOV A,B ;and if not, store new current user STA CURUSR MVI C,USRSTAT ;and move up one MOV E,B CALL BDOS JMP LFORFL ;look for another file ; NDRIVE: LDA DFCB ;see if specific drive ORA A ;set flags JNZ EXIT ;yeah, quit now ; LDA CURDRV ;get current drive MOV B,A LDA MXDRV ;get max drive CMP B ;same? JZ EXIT ;if so, we're done MOV A,B ;if not, get CURDRV back in A INR A ;...bump current drive counter STA CURDRV ;...save it MOV E,A ;...and log onto the next drive MVI C,SELDISK CALL BDOS XRA A ;zero user area count STA CURUSR MOV E,A ;...and log onto user 0 MVI C,USRSTAT CALL BDOS CALL CRLF ;new line LDA CURCOL ;get current column count ORA A ;set flags JZ LFORFL ;it's been reset by ZCOL already ;so look for next file XRA A ;else reset STA CURCOL CALL CRLF ;new line JMP LFORFL ;look for file ; IF DESCRIP DESCAL: CALL DESFN ;call the descriptive filename routine JMP MORETGO ;and go back ENDIF ;descrip ; EXIT: LXI H,QMSG ;tell how to get help CALL IPBUF ; EXIT1: LDA DEFUSR ;get default user area back MOV E,A MVI C,USRSTAT CALL BDOS ;set it ; LDA DEFDRV ;get default drive back MOV E,A MVI C,SELDISK CALL BDOS ;set it ; CALL CRLF ; LHLD OLDSP ;recover CP/M SP SPHL ;set it RET ;and exit quietly to CP/M ; ABORT: MVI C,PBUF ;print abort message LXI D,AMSG CALL BDOS JMP EXIT1 ; ;************************ ;*** CONSOLE MESSAGES *** ;************************ ; SIGNON: DB CR,LF,'MAP v',VERS+'0','.',(REV/10)+'0',(REV MOD 10)+'0',', ' DB (MONTH/10)+'0',(MONTH MOD 10)+'0','-' DB (DAY/10)+'0',(DAY MOD 10)+'0','-' DB '19',(YEAR/10)+'0',(YEAR MOD 10)+'0' DB CR,LF,'from Horn Engineering Associates',CR,LF,LF DB 'Ctrl-',ACHAR+'@' DB ' to abort, Ctrl-',XOFF+'@' DB ' to pause...',CR,LF,LF,'$' ; AMSG: DB CR,LF,LF,'++ Aborted ++',CR,LF,LF,'$' ; SAMSG: DB 'Illegal drive...',CR,LF,'$' ; DRMSG: DB 'MAP of drive $' ; QMSG: DB CR,LF,LF,'Type ''MAP ?'' for assistance with using this' DB ' program.',CR,LF,'$' ; IF DESCRIP ; NULMSG: DB 29,'Description not available...$' ; ^ ^ ; # of bytes in message MUST END WITH $ ; ENDIF ; ;************************************** ;*** THE PRIVATE FILE CONTROL BLOCK *** ;************************************** ; FCB: FCB$DISK: DB 0 ;preset default drive FCB$NAME: DB '-???????' ;preset default file name FCB$TYP DB '???' ;file type FCB$EXTENT: DB 0 ;preset extent FCB$RESV: DB 0,0 ;reserved by CP/M FCB$RECUSED: DB 0 ;records used FCB$ABUSED: DB 0,0,0,0,0,0,0,0 ;assigned blocks DB 0,0,0,0,0,0,0,0 FCB$SEQREC: DB 0 ;sequential record number FCB$RANREC: DW 0 ;random record number FCB$RANRECO: DB 0 ;record overflow ; ;******************* ;*** SUBROUTINES *** ;******************* ; ; PRINTFN - Presents all pertinent section data ; PRINTFN: INX H ;Point past "-" INX H PUSH H ;save it for later ; ; Ok, now, where is the section? ; LDA CURDRV ;get current drive ; ADI 'A' ;make drive ASCII CALL PCHAR ;print it LDA CURUSR ;get current user CALL PASC ;make # ASCII ; MVI A,' ' CALL PCHAR MVI A,'=' CALL PCHAR MVI A,' ' CALL PCHAR ;print " = " ; ; Now, print the section name ; POP H MVI C,7 CALL PSTRING ; ; Check the column counter and act accordingly. Don't want a messy ; screen ; LDA CURCOL ;get the current column CPI NUMCOL-1 ;printed all on this line yet? JZ ZCOL ;yep, zero counter INR A ;nope, bump counter STA CURCOL ;and save it ; MVI A,' ' ;print " | " between section names CALL PCHAR MVI A,FENCE CALL PCHAR MVI A,' ' CALL PCHAR RET ;back we go ; ZCOL: XRA A ;zero A STA CURCOL ;store it as the current column CALL CRLF ;end of line RET ; IF DESCRIP ; ; DESFN - Print filename and description ; DESFN: INX H ;Point past "-" INX H PUSH H ;save it for later ; ; Ok, now, where is the section? ; LDA CURDRV ;get current drive ; ADI 'A' ;make drive ASCII CALL PCHAR ;print it LDA CURUSR ;get current user CALL PASC ;make # ASCII ; MVI A,' ' CALL PCHAR MVI A,'=' CALL PCHAR MVI A,' ' CALL PCHAR ;print " = " ; ; Now, print the section name ; POP H PUSH H MVI C,7 CALL PSTRING MVI A,' ' ;make sure at least 2 spaces between CALL PCHAR ;filename and description MVI A,' ' CALL PCHAR ; ; Now we're ready to move the filename into the FCB, open it, ; and read the description (if any). ; CALL ZFCB ;first clean things up POP H ;recover filename DCX H ;get the "-" back LXI B,11 ;# of characters to move LXI D,FCB+1 ;where to move them CALL MOVE ;do it ; ; Now open the file and read 1 record ; MVI C,OPENF ;BDOS open file LXI D,FCB CALL BDOS ; MVI C,READF ;BDOS read sequential LXI D,FCB CALL BDOS ORA A ;set flags CNZ NULFLE ;must be empty file ; ; Close the file (even though we don't really have to) ; MVI C,CLOSEF ;BDOS close file LXI D,FCB CALL BDOS ; ; Now display information ; LXI H,DEFDMA CALL IPBUF ; CALL CRLF ;new line ; RET ;go home ; NULFLE: LDA NULMSG ;get # of bytes in message MOV C,A ;put it in BC MOV B,0 LXI H,NULMSG+1 ;point to message LXI D,DEFDMA ;put it in the DMA CALL MOVE ;move it RET ;go home to Kansas ; ENDIF ;descrip ; ; ZFCB - Zero the 36 bytes in the designated FCB ; ZFCB: MVI C,36 LXI H,FCB ;point to FCB ZLOOP: MVI M,0 ;enter a zero INX H ;bump pointer DCR C ;bump down counter JNZ ZLOOP ;loop for more RET ; ; FINDFN - Locates directory file name in DMA after directory ; search. Returns pointer in HL. Entry with directory code in A. ; FINDFN: ADD A ;*2 ADD A ;*4 ADD A ;*8 ADD A ;*16 ADD A ;*32 MOV E,A ;offset to DE MVI D,0 DAD D ;add to HL RET ; ; MOVE - Moves the number of characters in BC from (HL) to (DE) ; MOVE: MOV A,M ;get char from (HL) STAX D ;put in (DE) INX H INX D DCX B MOV A,C ;get LS count byte ORA B ;both B & C zero? JNZ MOVE ;loop til done RET ; ; PSTRING - Prints string pointed to by HL. ; Number of characters to print in C ; PSTRING: PUSH H ;save string pointer PUSH B ;save count MOV A,M ;get a character CALL PCHAR ;print it POP B ;restore count POP H ;restore pointer INX H ;bump it DCR C ;done? JNZ PSTRING ;if not RET ; ; IPBUF - Same is BDOS PBUF, 'cept it checks for abort character ; and expects the print string to be pointed to by HL ; IPBUF: PUSH H ;save string pointer MOV A,M ;get a character CPI '$' ;is that all? JZ PDONE ;if so, quit CALL PCHAR ;if not, print a character POP H ;else restore counter INX H ;bump up JMP IPBUF ;go again PDONE: POP H ;save stack RET ; ; ; CRLF - Puts a CR and LF out to console ; CRLF: MVI A,CR CALL PCHAR MVI A,LF CALL PCHAR RET ; ; PCHAR - Prints the character in A ; PCHAR: PUSH PSW ; CALL GETCON ;see if a key pressed CPI ACHAR ;if so, was it an abort request? JZ ABORT ;then abort CPI XOFF ;XOFF? CZ PAUSE ;then pause until key pressed ; POP PSW MOV E,A MVI C,DIRCON CALL BDOS RET ; ; PASC - Unpacks two ascii decimal digits from value in A ; displays them on the console with no leading 0's. ; PASC: MVI C,0 ;initialize quotient PASC1: SUI 10 ;repeatedly subtract 10 JC PASC2 ;if underflow INR C ;else increment the quotient JMP PASC1 ;and subtract again ; PASC2: ADI 10 ;Correct the underflow PUSH PSW ;save the remainder MOV A,C ;get the quotient ORA A ;set flags JZ ONENUM ;only one number to display ADI 030H ;adjust to ascii CALL PCHAR ;print it POP PSW ;get remainder ADI 030H ;make ascii CALL PCHAR ;print it ; MVI A,':' ;print a ":" after the drive/user CALL PCHAR ; RET ; ONENUM: POP PSW ;get the # ADI 030H ;make ASCII CALL PCHAR ;print it MVI A,':' ;and a colon CALL PCHAR MVI A,' ' ;and a space to make up for the leading CALL PCHAR ;0 ; RET ;go home ; GETCON: MVI C,DIRCON ;BDOS direct console I/O MVI E,0FFH ;for input CALL BDOS ;do it RET ; PAUSE: PUSH PSW ;save EVERYTHING PUSH B PUSH D PUSH H ; PLOOP: MVI C,DIRCON ;direct console I/O MVI E,0FFH ;input CALL BDOS ORA A JZ PLOOP ;wait until key pressed ; POP H ;get everything back POP D POP B POP PSW ; RET ; ; SPCDRV - if a specific drive chosen for map, this routine checks ; MXDRV to see if possible, and if so sets up that drive ; as default. ; SPCDRV: LDA MXDRV ;get max drive MOV B,A ;move to B LDA DFCB ;get drive chosen DCR A ;bump down INR B ;and fix B for compare CMP B ;compare the two JNC SPCABT ;not ok, exit MOV E,A MVI C,SELDISK ;select disk CALL BDOS ;do it ; LXI H,DRMSG ;Say MAP of drive x: CALL IPBUF LDA DFCB ;Get MAP drive back DCR A ;bump down STA CURDRV ;store it for display ADI 'A' ;Make ASCII CALL PCHAR ;print it MVI A,':' ;...and a colon CALL PCHAR ; CALL CRLF CALL CRLF ; RET ; SPCABT: LXI H,SAMSG ;print "drive out of range" CALL IPBUF JMP EXIT ;and exit to CP/M. ; HELP: LXI H,HMSG ;print help message CALL IPBUF JMP EXIT1 ;and exit to CP/M ; HMSG: DB CR,LF,LF DB 'Examples of use:',CR,LF,LF DB ' MAP presents a map of all drives/' DB 'user-areas, no' DB CR,LF,' descriptions.' IF DESCRIP DB CR,LF,LF DB ' MAP D presents a map of all drives/' DB 'user-areas with' DB CR,LF,' descriptions.' ENDIF DB CR,LF,LF DB ' MAP B: presents a map of drive B:,' DB ' no descriptions.' IF DESCRIP DB CR,LF,LF DB ' MAP B:D presents a map of drive B:,' DB ' with descriptions.' ENDIF DB CR,LF,'$' ; ; ;************************ ;*** UNITIALIZED AREA *** ;************************ ; DEFUSR: DB 0 ;storage for default user area DEFDRV: DB 0 ;default drive CURUSR: DB 0 ;current user area CURDRV: DB 0 ;current drive ; CURCOL: DB 0 ;current column ; IF DESCRIP DESFLG: DB 0 ;marks descriptive mode ENDIF ;descrip ; OLDSP: DW 0 DS 64 ;our private stack area STACK: EQU $ ; END