home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
HEATH
/
DIRF38HZ.LBR
/
DIRF38HZ.AZM
/
DIRF38HZ.ASM
Wrap
Assembly Source File
|
2000-06-30
|
34KB
|
1,245 lines
; DIRFILES: Version 3.8 (Heath video only)
;
; Note: this code is riddled with Heath-specific video equates, if
;
; Joe Smith - Heath Users Group
;
;
; Steve Sanders - Tampa Bay Kaypro UG
; (813) 791-1454 or 791-1455 300/1200/2400
;
; Modification History
;
; 09/18/87 Made a Heath-only version from version 3.7
; v3.8 for local use only - not for remotes.
; Changed number of files to 256 for larger
; directory disks, such as hard disk.
;
;
; 01/28/86 Made a Kaypro-only version to show all files, no restrictions,
; v3.7 for local use only - not for remote systems. - S. Sanders
;
; 02/23/85 Corrected bug in MATCH routine that caused failure to
; v3.6 compare if any flag is set. Removed embedded tabs in
; space strings. Thanks to Steve Sanders for secure mode
; improvements. Named Version 3.6 because of existence of
; spurious versions that were created without coordination
; between authors. - C. Horn
;
; 10/24/84 Modified to use C/R to continue instead of "any key"
; v3.1 which caused a lot of problems on-line with 1200 baud
; noise present (infinite loop). Added a CTRL-C option
; to abort listing if desired, entry of CTRL-C while
; printing will abort to options menu. - Steve Sanders
;
; 09/04/84 Modified to write the data file back to disk only if it
; v3.0 was edited while we were here. - C. Horn.
;
; A utility that maintains a data file on any default disk or user area
; containing directory file names for all current files. The data file
; is called in and updated each time DIRFILES is run. The data file
; contains a description of each listed file that is entered by the user
; via the EDIT function within DIRFILES. When the program exits it writes
; the updated data file back to disk. No disk space is needed in this
; process other than the space occupied by the data file when first created.
; When first called, if the data file DIRFILES.DAT does not exist, the
; program provides by menu the option to create it. The maximum number of
; directory entries at the EQUate NUMFILES determines the size of the data
; file. 128 is the correct entry for a standard SSSD CP/M disk, and is
; probably appropriate for SSDD and DSSD disks. This setting creates a
; 10K DIRFILES.DAT file.
;
; This program is a product of Horn Engineering Associates. It is placed
; into the public domain for free use by anybody except that it may not
; be sold, either in itself or as any part of a collection of software,
; without the express permission of Horn Engineering Associates. It is
; requested that any user retain our SIGNON logo.
;
; Copyright (c) 1985 by Charles E. Horn,PE
; for Horn Engineering Associates
;
TRUE EQU 0FFH
FALSE EQU NOT TRUE
;
SECURE EQU FALSE ;TRUE, for RCP/M, uses WHEEL status
NOSYS EQU FALSE ;set TRUE to exclude SYS files
WHEEL EQU 003EH ;address of the WHEEL byte
;
; 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
CONIN EQU 1 ;BDOS console input function
CONOUT EQU 2 ;console output function
PBUF EQU 9 ;print buffer function
RDCON EQU 10 ;read console buffer function
CONSTAT EQU 11 ;console status function
RESDISK EQU 13 ;reset disk system 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
;
; 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
CLRSCR EQU 69
ESC EQU 27
CAD EQU 59
ROW EQU 31
COL EQU 31
;
; Program Equates
;
NUMFILES EQU 255 ;maximum number of directory entries
DATLEN EQU NUMFILES * 80 ;size of DIRFILES.DAT data file
;(80 columns per directory entry)
NUMRECORDS EQU DATLEN / 128 ;number of records in data file
SCREEN EQU 24 ;number of lines per screen
COLUMNS EQU 80 ;80 column screen
;
ORG TPA ;program runs here
;
; Main program
;
START: JMP START1 ;jump over fixed data
DATFNAME:
DB 'DIRFILESDAT' ;name of data file (here for easy patch
; ---- >-----------< ---- ;filenames must be exactly this long
;..space fill - type must be last 3
DIRFNAME:
DB '???????????' ;wild card directory name
START1: LXI H,0 ;find CP/M stack pointer
DAD SP
LXI SP,STACK ;set up our local stack
PUSH H ;store CP/Ms SP on ours
;
CALL CLR ;clear screen
;
LXI D,SIGNON ;point to signon message
MVI C,PBUF ;and show it
CALL BDOS
;
; We will only work on the current default drive which by now we know
; has a mounted disk which might not be logged on. We reset the disk
; system here. If the disk is write protected we find out later.
;
MVI C,GETDISK ;get the default drive
CALL BDOS
PUSH PSW ;save it
MVI C,RESDISK ;reset the disk system
CALL BDOS
POP PSW ;recover the default drive
MOV E,A ;move to E
MVI C,SELDISK ;set default to original
CALL BDOS
;
; Now try to open the directory data file. First we need to move
; in the data file name - case it has been changed or patched.
;
LXI B,11 ;11 char to move in
LXI H,DATFNAME ;point to data file name
LXI D,FCB+1 ;point past the drive number
CALL MOVE ;move it in
;
LXI D,FCB ;point to file control block
MVI C,OPENF ;open the file
CALL BDOS
INR A ;was 0FFH if error
JNZ READIN ;if no error, go read it in
;
; If no data file - create it per menu
;
IF SECURE
LDA WHEEL ;get wheel byte
ORA A ;secure?
JZ EXIT0 ;exit with no support message
ENDIF ;SECURE
;
LXI D,NFDMSG ;file not found and query message
MVI C,PBUF
CALL BDOS ;print it
MVI C,CONIN ;get keyboard response
CALL BDOS
ANI 5FH ;make response UC
CPI 'Y' ;if not yes
JNZ EXITA ;abort program
;
; We must create the data file. Fill data buffer with blanks.
;
LXI H,FILEBUF ;point to data file buffer
LXI B,DATLEN ;length of data file
FILLOOP:
MVI M,BLANK ;insert a space
INX H ;bump pointer
DCX B ;bump count down
MOV A,C ;get count LS
ORA B ;'z' set if done
JNZ FILLOOP ;loop til done
;
; Create, write, and close the new data file
;
LXI D,FCB ;point to FCB
MVI C,MAKEF ;create the file in directory
CALL BDOS
INR A ;was 0FFH if no directory space
JZ EXITB
;
CALL WRITEFILE
JC EXITC ;cy set if disk full
LXI D,FCB ;point to FCB
MVI C,CLOSEF ;close the file
CALL BDOS
;
; Clean up the FCB here to get ready to read in the data file
;
READIN: CALL ZFCB ;zero the FCB
;
; Move in the data file name
;
LXI B,11 ;11 char to move
LXI H,DATFNAME ;point to the data file name
LXI D,FCB+1 ;point past drive in FCB
CALL MOVE ;move it in
;
; If not to show SYS files we set the file attribute
;
IF NOSYS
LXI H,FCB+10 ;point to second type byte
MOV A,M ;get it
ORI 80H ;set the high byte
MOV M,A ;put it back
ENDIF ;NOSYS
;
; At least - set the R/W attribute - case it has been set R/O
;
LXI D,FCB ;point to FCB
MVI C,SETATTR ;set attributes
CALL BDOS
;
; Open the data file
;
LXI D,FCB
MVI C,OPENF
CALL BDOS ;no error expected - we know it's there
;
; Read it into memory and close it
;
CALL READFILE ;read it
LXI D,FCB
MVI C,CLOSEF ;if it is ever to work with MP/M
CALL BDOS
;
; Here we set up the FCB to read the directory, read it, and one by
; one either match an existing entry in the data file or enter the
; new file if not present.
;
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,DEFDMA ;set the CP/M DMA address
MVI C,SETDMA
CALL BDOS
;
; Now start the directory search. We set the maximum number of files
; we will enter into the data file buffer to prevent any attempt to
; write past the buffer if there are more files in the directory than
; we have designated as NUMFILES.
;
MVI B,NUMFILES-1 ;the maximum number to the buffer
PUSH B ;save it
LXI D,FCB ;find first match
MVI C,SRCHF
CALL BDOS
LXI H,DEFDMA ;point to DMA buffer
CALL FINDFN ;find the file name in the DMA space
IF NOSYS
PUSH H ;save DMA filename pointer
LXI D,10 ;index to SYS attribute byte
DAD D ;point to it
MOV A,M ;get it
ANI 80H ;will be zero if not SYS
POP H ;restore pointer
JNZ MOREFILES ;skip it if SYS
ENDIF ;NOSYS
;
INX H ;point past drive number
CALL ADDOT ;put name into FNBUF with dot
;
; SEARCH looks for the file name in the data file. Returns with HL
; pointing to data file entry or CY set if not found. If not found,
; HL points to first available blank line.
;
CALL SEARCH
CC ADDNAME ;add name to file if not found
MVI M,0FFH ;flag the entry good
POP B ;recover maximum files number
DCR B ;bump down - we wrote one
PUSH B ;resave it
MOREFILES:
LXI D,FCB ;look for matches for all files
MVI C,SRCHN ;look for next
CALL BDOS
INR A ;was 0FFH if no more files
JZ PURGE ;if done - go purge erased files
DCR A ;set directory code back to what is was
LXI H,DEFDMA ;point to DMA buffer
CALL FINDFN ;find the name in the DMA space
IF NOSYS
PUSH H ;save pointer
LXI D,10 ;index to SYS byte
DAD D ;point to it
MOV A,M ;get it
ANI 80H ;zero if not set
POP H ;restore pointer
JNZ MOREFILES ;skip it
ENDIF ;NOSYS
;
INX H ;point past drive number in DMA
CALL ADDOT ;file name to FNBUF with dot
CALL SEARCH
CC ADDNAME ;add name to file if not found there
MVI M,0FFH ;flag entry good
POP B ;recover maximum files count
DCR B ;bump down - we wrote one
PUSH B ;save max file count
JNZ MOREFILES ;find all directory entries
;
; At this point all directory entries are matched. Found files are
; flagged 0FFH. Erased files are still flagged 0. Blank lines are
; flagged blank. We go through and blank all lines containing erased
; files, then go through again and flag all current files 0 for next time
;
PURGE: POP B ;clear stack
LXI H,FILEBUF ;point to data file buffer
MVI C,NUMFILES ;maximum entry counter
PURGE1: MOV A,M ;get an entry flag
ORA A ;flag 0 (erased)?
JNZ PURGE2 ;if not
PUSH H ;save buffer pointer
MVI B,COLUMNS ;number of bytes per entry
PURLOOP:
MVI M,BLANK ;enter a space
INX H ;bump pointer
DCR B ;bump column counter down
JNZ PURLOOP ;fill line with blanks
POP H ;recover buffer pointer
PURGE2: LXI D,COLUMNS ;index to next entry
DAD D ;set pointer to next
DCR C ;bump down max files counter
JNZ PURGE1 ;continue for all possible entries
;
; Flag all current files zero
;
LXI H,FILEBUF ;point to data buffer
MVI C,NUMFILES ;max number of entries
FLAGLOOP:
MOV A,M ;get entry flag
CPI 0FFH ;good entry?
JNZ NXTFLAG ;if blank line space
XRA A ;else - get a zero
MOV M,A ;and flag entry good
NXTFLAG:
LXI D,COLUMNS ;index to next entry
DAD D
DCR C ;bump down remaining entries to do
JNZ FLAGLOOP ;fix all entries
;
; We now have a clean updated buffer that is suitable for display.
; First we will sort all entries aphabetically. This sort
; moves all entries to the beginning of the buffer, with all
; blanked entries following.
;
CALL SORT ;sort it
;
; The data file is now sorted and ready for display and edit.
; We enter here with a clean stack and no passed parameters. We
; return here after editing. The only exit from here is via the
; display menu.
;
DISPLAY:
CALL CLR ;clear screen
LXI H,FILEBUF ;point to data buffer
MVI B,NUMFILES ;max entry counter
MVI C,SCREEN-1 ;no of display lines less one for menu
;
; The main display loop
;
DISPLAY1:
MOV A,M ;get status flag
ORA A ;zero if valid entry
JNZ DISPLAY3 ;if not valid
XRA A ;entry is valid - flag at least 1 found
STA NONEFLAG
PUSH H ;save registers
PUSH B
MVI A,CR ;get cursor to left margin
CALL PCHAR ;print CR
POP B ;restore registers
POP H
PUSH H ;resave registers
PUSH B
MVI C,15 ;length of file name entry
CALL PSTRING ;print the entry
MVI C,COLUMNS-15 ;remainder of string space
CALL MINSTRG ;go print minimum text (skip blanks)
CALL CRLF ;set up for next
;
; added following routine to check console for CTRL-C abort request
; - Steve Sanders 10/24/84
;
MVI C,CONSTAT ;any chr waiting at console?
CALL BDOS ;let's see
CPI 0 ;if none waiting
JZ DISPL1B ;then continue displaying
;
MVI C,CONIN ;else check console for
CALL BDOS ;char waiting at keyboard
CPI 'C'-40H ;CTRL-C ?
JZ DISPL1A ;if yes, then abort to menu
JMP DISPL1B ;or jump over DISPL1A routine
;
DISPL1A:
POP B ;restore registers
POP H ; ditto
JMP DISPLAY2 ;before going back to menu
;
DISPL1B:
POP B ;restore registers
POP H
DCR C ;screen full?
JNZ DISPLAY3 ;continue if not
DISPLAY2:
PUSH H ;save registers
PUSH B
LXI D,DISMENU ;point to normal display menu
IF SECURE
LDA WHEEL ;get wheel byte
ORA A ;zero if secure
JNZ DISPLAY6 ;if not secure
LXI D,SECMENU ;else change pointer to secure menu
ENDIF ;SECURE
;
DISPLAY6:
MVI C,PBUF ;print it
CALL BDOS
MVI C,CONIN ;get the console reply
CALL BDOS
POP B ;restore registers
POP H
ANI 5FH ;make assumed ascii UC
CPI 'Q' ;quit?
JZ DISPLAY4 ;check for secure?
CPI 'E' ;edit?
JZ DISPLAY5 ;check for secure?
;
; changed the following routine to wait for CR to continue instead
; of "any key". Remote callers would be hung in an endless loop if
; extreme line noise was present. - Steve Sanders 10/24/84
;
CPI CR ;C/R to continue
JZ DISP6A ;yes,then continue
JMP DISPLAY2 ;not 'Q', 'E', or C/R, ask again...
;
DISP6A:
MVI C,SCREEN-1 ;reset screen line counter
PUSH H ;save pointer
PUSH B ;save counters
MVI A,CR ;to left of current line
CALL PCHAR
MVI A,BLANK ;blank the menu
MVI C,COLUMNS ;number of blanks per line
CALL PCHARS
POP B ;restore counters
POP H ;restore pointer
JMP DISPLAY3 ;continue display
;
DISPLAY4: ;process Quit
IF SECURE
LDA WHEEL ;get wheel byte
ORA A ;zero is secure
JZ EXIT ;without rewriting the file
ENDIF ;SECURE
JMP WRITEBACK ;not secure - write the file back
;
DISPLAY5: ;process Edit
IF SECURE
LDA WHEEL ;wheel byte
ORA A ;zero is secure
JZ DISPLAY3 ;ignore edit - continue display
ENDIF ;SECURE
JMP EDIT ;else not secure - go edit
;
NONEFLAG:
DB 0FFH ;default is files present
;
; Pointer and end of buffer processor
;
DISPLAY3:
LDA CRLFLAG ;are we at end of buffer?
ORA A ;not zero if so
JNZ DISPLAY7 ;reset CRLFLAG and go to top of buffer
LXI D,COLUMNS ;index to next data entry
DAD D ;set the pointer in HL
DCR B ;end of buffer?
JNZ DISPLAY1 ;display more if not
LDA NONEFLAG ;get files present flag
ORA A ;zero if present
JNZ EXITD ;if none to display
LXI H,FILEBUF ;else - reset pointer to top
MVI B,NUMFILES ;and reset entry counter
PUSH H ;save buffer pointer
PUSH B ;save counters
CALL CRLF ;put in a blank line
MVI A,1 ;set the CRLFLAG
STA CRLFLAG
POP B ;restore registers
POP H
JMP DISPLAY2 ;show the menu
;
DISPLAY7:
XRA A ;reset the CRLFLAG
STA CRLFLAG
JMP DISPLAY1
;
CRLFLAG:
DB 0 ;default not flagged
;
DISMENU: ;full access menu
DB CR,' ',1bh,'p'
DB ' [ Options: ',1bh,'p','<Q>',1bh,'q','uit, '
DB 1bh,'p','<E>',1bh,'q','dit, or ',1bh,'p'
DB '<RETURN>',1bh,'q',' shows more ] '
DB 1bh,'y4',' ','$'
;
SECMENU: ;secure menu
DB CR,' [ Options: <Q>=Quit, <C/R>=Continue,'
DB ' or ^C aborts while printing ] $'
;
; The file EDIT code
;
; We first set a flag here to note that we have been here. Flag
; is checked at exit. If there has been no edit, we do not write
; the data file back to disk.
;
EDIT: MVI A,1 ;set flag to 1
STA EDITFLG
MVI A,CR ;move to left margin
CALL PCHAR ;..of current console line
MVI A,BLANK ;fill line with spaces
MVI C,COLUMNS ;number of spaces to print
CALL PCHARS ;print them
LXI D,EDTMENU1 ;show the primary editor menu
MVI C,PBUF
CALL BDOS
EDIT1: LXI D,EDTMENU2 ;show the secondary editor menu
MVI C,PBUF
CALL BDOS
;
; Call for the file name to edit
;
CALL SCIN$NE ;read console buffer - no CRLF echo
LDA CLEFT ;get number of characters entered
ORA A ;zero if none entered
JZ DISPLAY ;so go back to main menu
;
; This code gets the entered file name into FNBUF in a directory
; format that can be matched to the data file name entry. This code
; is a kludge but it allows for entry of the file name in lower case
; in any reasonable way.
;
CALL MAKEUC ;make the buffer alphas upper case
LXI H,CLIN ;point to console buffer text
LXI D,FNBUF ;point to the processed file name buf
MVI B,8 ;8 char spaces for main filename
GETENTRY:
MOV A,M ;get char from buf
ORA A ;end of entry?
JZ FNBLANK ;fill out name field with blanks
CPI '.' ;dot?
JZ FNBLANK
STAX D ;else put char in FNBUF
INX H ;bump pointers
INX D
DCR B ;more?
JZ PUTDOT ;if not
JMP GETENTRY ;else - loop
;
FNBLANK:
MVI A,BLANK ;get a space
STAX D ;put in FNBUF
INX D ;bump pointer
DCR B ;downcount
JZ PUTDOT ;install the dot
JMP FNBLANK ;fill out til 8
;
PUTDOT: MVI A,'.' ;get a dot
STAX D ;install it
INX H ;bump pointers
INX D
MVI B,3 ;3 char in file type field
PUTDOT1:
MOV A,M ;get a type char
ORA A ;zero if past entry
JZ TYPBLANK ;fill field with blanks
CPI '.' ;dot?
JZ TYPBLANK
STAX D ;good char - install it
INX H ;bump pointers
INX D
DCR B ;downcount
JZ FINDMAT ;done - go find a match in data buffer
JMP PUTDOT1 ;else - finish it
;
TYPBLANK:
MVI A,BLANK ;fill unused type field with blanks
STAX D
INX D
DCR B
JNZ TYPBLANK
;
; FNBUF now filled. This code finds the file entry in the data buffer
; and returns with HL point to the head of the entry line. If CY
; returned the search failed.
;
FINDMAT:
CALL SEARCH
JC FNF ;if file not found
PUSH H ;save line pointer
MVI C,COLUMNS
CALL PSTRING ;show the line on the console
MVI A,BS ;backspace to head of text
MVI C,COLUMNS-15 ;number to do
CALL PCHARS ;do it
POP H ;restore line pointer
LXI D,15 ;index to start of text
DAD D ;set text pointer in HL
PUSH H ;save it
;
; We are now ready for editing the text. Existing text will be
; overwritten. Trailing garbage will not be retained.
;
CALL SCIN$NE ;read the console buffer
POP D ;the text pointer
LDA CLEFT ;get number of char entered
ORA A ;zero if none entered
JZ DISPLAY ;back to main menu
LXI H,CLIN ;point to buffer text
MVI B,COLUMNS-15 ;we will accept only this many char
BUFLOOP:
MOV A,M ;get char from con buffer
ORA A ;zero if at end
JZ FILLOUT ;go fill out the line with blanks
STAX D ;else enter the character
INX H ;bump pointers
INX D
DCR B ;countdown
JNZ BUFLOOP ;if not done
JMP EDIT1 ;max characters in text line
;
FILLOUT:
MVI A,BLANK ;get a space
STAX D ;put in text line
INX D ;move to next
DCR B ;countdown
JNZ FILLOUT
JMP EDIT1 ;back to top of EDIT
;
FNF: LXI D,FNFMSG ;file not found prompt
MVI C,PBUF
CALL BDOS
JMP EDIT ;back to top of editor
;
FNFMSG: DB CR,LF,'File not found, check your spelling.',7,CR,LF,'$'
;
EDTMENU1:
DB CR,LF,'Just a RETURN while in EDIT will go to the main '
DB 'menu with no changes...',CR,LF,'$'
EDTMENU2:
DB CR,1bh,'p',' File to ',1bh,'q',' edit ',1bh,'p'
DB ' (RETURN alone exits): ',1bh,'q',' ',17h,'$'
;
; This is where we write the data file back to disk before we exit.
; Here we will set the existing data file to R/W just be be safe,
; erase it, recreate it, open it, write it, and close it. This way,
; we do not need more disk space than we already use.
;
WRITEBACK:
LDA EDITFLG ;did we edit while here?
ORA A ;zero if we did not
JZ RESDMA ;..so don't write a new data file
CALL ZFCB ;clean up the FCB
LXI B,11 ;11 characters in file name
LXI H,DATFNAME ;point to data file name
LXI D,FCB+1 ;place to put it
CALL MOVE ;move it in
;
; Erase the old data file
;
LXI D,FCB
MVI C,DELF ;delete file
CALL BDOS
;
; Create a new one
;
LXI D,FCB
MVI C,MAKEF
CALL BDOS
;
; Open it
;
LXI D,FCB
MVI C,OPENF
CALL BDOS
;
; Write it
;
CALL WRITEFILE
;
; Close it
;
LXI D,FCB
MVI C,CLOSEF
CALL BDOS
;
IF NOSYS ;set it to SYS
LXI H,FCB+10 ;point to SYS attribute byte
MOV A,M ;get it
ORI 80H ;set the high bit
MOV M,A ;put it back
LXI D,FCB
MVI C,SETATTR ;set it to SYS
CALL BDOS
ENDIF ;NOSYS
;
; Reset CP/M DMA
;
RESDMA: LXI D,DEFDMA
MVI C,SETDMA
CALL BDOS
;
; All done
;
JMP EXIT
;
;***********************
;*** EXIT PROCESSORS ***
;***********************
;
EXIT0: LXI D,NSPMSG ;the no support message
MVI C,PBUF ;print it
CALL BDOS
JMP EXIT
;
EXITA: LXI D,ABTMSG ;abort message
MVI C,PBUF ;print it
CALL BDOS
JMP EXIT ;and quit
;
EXITB: LXI D,NDSMSG ;no disk space message
MVI C,PBUF ;print it
CALL BDOS
JMP EXITA ;and do abort report
;
EXITC: LXI D,FULMSG ;disk full message
MVI C,PBUF ;print it
CALL BDOS
JMP EXITA ;and report abort
;
EXITD: LXI D,NONMSG ;no files message
MVI C,PBUF ;print it
CALL BDOS ;fall through to EXIT
;
EXIT: LXI D,CLS
MVI C,PBUF
CALL BDOS
POP H ;recover CP/M SP from stack
SPHL ;set it
RET ;and exit quietly to CP/M
;
;************************
;*** CONSOLE MESSAGES ***
;************************
;
SIGNON: DB CR,LF,1bh,'p'
DB ' DIRFiles v3.8hz (c)1985 Horn Engineering Associates '
DB 1bh,'q',CR,LF,LF
DB ' Heath screen and video by Joe Smith 09/18/87) '
DB CR,LF,LF,LF,'>> Loading data file...','$'
;
NFDMSG: DB CR,'DIRFILES.DAT not found... Create new file? '
DB 1bh,'x4','<Y/N> ',1bh,'y4',7,'$'
;
ABTMSG: DB CR,LF,LF,'DIRFILES Aborted...',7,'$'
;
NDSMSG: DB CR,LF,LF,'No Disk Space...',7,'$'
;
FULMSG: DB CR,LF,LF,'Disk Full...',7,'$'
;
NONMSG: DB CR,LF,LF,'++ NO FILES ++',7,'$'
;
NSPMSG: DB CR,LF,LF,'DIRFILES not supported in this area...',7,'$'
;
;**************************************
;*** THE PRIVATE FILE CONTROL BLOCK ***
;**************************************
;
FCB:
FCB$DISK: DB 0 ;preset default drive
FCB$NAME: DB 'DIRFILES' ;preset default data file name
FCB$TYP DB 'DAT' ;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 ***
;*******************
;
; WRITEFILE - Writes the records at FILEBUF to default disk
;
WRITEFILE:
MVI C,NUMRECORDS ;number of records to write
LXI D,FILEBUF ;set DMA to data file buffer
WRLOOP: PUSH B ;save number of records
PUSH D ;save DMA pointer
MVI C,SETDMA ;set the DMA address
CALL BDOS
LXI D,FCB ;point to the FCB
MVI C,WRITEF ;write a record
CALL BDOS
POP D ;clear stack for possible error
POP B
ORA A ;zero if no error
JNZ RETERR ;if error set cy and return
LXI H,128 ;add 128 to DMA pointer
DAD D ;original pointer in DE
XCHG ;new pointer to DE
DCR C ;bump down record count
JNZ WRLOOP ;do more if not done
XRA A ;clear possible cy flag
RET ;with no error
RETERR: STC ;set cy for error
RET ;with error flag set
;
; READFILE - Read the file specified by the FCB into FILEBUF
;
READFILE:
LXI D,FILEBUF ;point to file buffer
RDLOOP: PUSH D ;save DMA pointer
MVI C,SETDMA ;set the DMA
CALL BDOS
LXI D,FCB ;point to FCB
MVI C,READF ;read a record
CALL BDOS
POP D ;recover DMA pointer
ORA A ;non-zero is EOF
RNZ ;if done
LXI H,128 ;index DMA to next record space
DAD D
XCHG ;pointer to DE
JMP RDLOOP ;loop til done
;
; 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
;
; ADDOT - Moves the file name in the DMA area to FNBUF. Adds the
; dot before file type on the way.
;
ADDOT: MVI C,8 ;8 char in filename
LXI D,FNBUF ;point to name buffer
ADDOT1: MOV A,M ;get a character
ani 7fh ;strip hi bits
STAX D ;put into buffer
INX H ;bump pointer
INX D ;bump pointer
DCR C ;bump down counter
JNZ ADDOT1 ;move all 8
MVI A,'.' ;get a dot
STAX D ;put into buffer
INX D ;bump buffer pointer
MVI C,3 ;3 char in file type
ADDOT2: MOV A,M ;get type char
ani 7fh
STAX D ;to buffer
INX H
INX D
DCR C
JNZ ADDOT2
RET
;
FNBUF: DS 12 ;the 12 char name buffer
;
; SEARCH - Searches for a match between directory file name in FNBUF
; and entries in the data file.
; If found: Returns with HL pointing to data file entry line.
; If not found: Returns with HL pointing to the first available
; blank line. CY flag is set.
;
SEARCH: LXI H,FILEBUF ;point to data file buffer
MVI C,NUMFILES ;max number of tries
SRCHLOOP:
PUSH H ;save buffer pointer
PUSH B ;save try counter
INX H ;point past status flag
LXI D,FNBUF ;point to file name buffer
CALL MATCH ;look for match - CY set if none
POP B ;recover count
POP H ;recover pointer
RNC ;if no CY we found match
LXI D,COLUMNS ;index to next data line + 1
DAD D ;set it
DCR C ;bump down try counter
JNZ SRCHLOOP ;if not done
;
; No match found - find first available blank line - RET to caller
;
LXI H,FILEBUF ;buffer pointer
BLNKLOOP:
MOV A,M ;get flag byte
CPI BLANK ;is it a space?
JZ NOTFND ;return with CY set
LXI D,COLUMNS ;index to next flag
DAD D ;set it
JMP BLNKLOOP ;we'll find one somewhere
NOTFND: STC
RET
;
; MATCH - Checks for 12 char match between (HL) and (DE). Returns
; with CY set if no match.
;
MATCH:
MVI C,12 ;12 char to check
MATLOOP:
LDAX D ;get char from (DE)
ANI 7FH ;strip possible flag (v3.2)
MOV B,A ;char to B
MOV A,M ;(HL) to A
ANI 7FH ;strip possible flag (v3.2)
CMP B ;compare chars
JNZ NOMATCH ;any failure will cause exit with CY
INX H
INX D
DCR C
JNZ MATLOOP ;go for all 12
XRA A ;reset CY flag (if set)
RET ;got a match
NOMATCH:
STC ;set no match flag
RET
;
; ADDNAME - Entry with HL pointing to head of a blank line. Adds
; the file name in FNBUF to the data buffer, adds a trailing
; colon, and returns with HL pointing to head of line.
;
ADDNAME:
PUSH H ;save line pointer
INX H ;point past status flag
XCHG ;put pointer in DE
LXI B,12 ;12 char to move
LXI H,FNBUF ;point to new file name
CALL MOVE ;move it in
MVI A,':' ;get a colon
STAX D ;add at end of filename
POP H ;restore line pointer
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 E,M ;get a character
MVI C,CONOUT ;print it
CALL BDOS
POP B ;restore count
POP H ;restore pointer
INX H ;bump it
DCR C ;done?
JNZ PSTRING ;if not
RET
;
; MINSTRG - Types a string until either 3 blanks in a row or
; the maximum number of characters is reached.
; HL = string pointer
; C = max number of characters in string
;
MINSTRG:
MVI E,3 ;set blank counter
MINSTRG1:
MOV A,M ;get a character
CPI BLANK ;space?
JNZ MINSTRG2 ;no space
DCR E ;bump down counter
RZ ;exit if 3 spaces in row
;
MINSTRG2:
PUSH H ;save registers
PUSH D
PUSH B
PUSH PSW
MOV E,A ;char to E
ani 7fh
MVI C,CONOUT ;out to console
CALL BDOS
POP PSW
POP B ;restore registers
POP D
POP H
INX H ;bump pointer
DCR C ;downcount characters
RZ ;if maximum
CPI BLANK ;was it a blank?
JZ MINSTRG1 ;yes - don't reset blank counter
JMP MINSTRG ;else - loop back to top
;
;
; CLR - Clear local screen
;
CLR: LXI D,CLS
MVI C,PBUF
CALL BDOS
RET
;
CLS DB ESC,CLRSCR,'$'
;
;
; CRLF - Puts a CR and LF out to console
;
CRLF: MVI E,CR
MVI C,CONOUT
CALL BDOS
MVI E,LF
MVI C,CONOUT
CALL BDOS
RET
;
; PCHAR - Prints the character in A
;
PCHAR: MOV E,A
ani 7fh ;strip hi bits
MVI C,CONOUT
CALL BDOS
RET
;
; PCHARS - Prints the character in A the number of times in C
;
PCHARS: PUSH PSW ;save character
PUSH B ;save count
MOV E,A ;char to E
ani 7fh ;strip hi bits
MVI C,CONOUT ;print one
CALL BDOS
POP B ;restore count
POP PSW ;restore character
DCR C ;bump down count
JNZ PCHARS ;do some more
RET
;
; MAKEUC - Makes the alpha characters in the console buffer upper case
;
MAKEUC: LXI H,CLIN ;point to the buffer
MAKEUC1:
MOV A,M ;get a char
ORA A ;zero if past end
RZ
CPI 'A' ;< 'A'?
JC MAKEUC2 ;if not alpha
CPI 'z'+1 ;> 'z'?
JNC MAKEUC2 ;if not alpha
ANI 5FH ;is alpha - make UC
MOV M,A ;and put it back
INX H ;point to next
JMP MAKEUC1 ;and loop
;
MAKEUC2:
INX H ;not alpha - skip it
JMP MAKEUC1
;
; SCIN$NE - Reads the console buffer without a CRLF echo to console
;
SCIN$NE:
LXI H,CLIN ;point to buffer string space
LDA CBUF ;get buffer length
MOV B,A ;put into B
XRA A ;get a zero
SCIN$NE1:
MOV M,A ;move in a zero
DCR B ;countdown
INX H ;bump pointer
JNZ SCIN$NE1 ;fill whole buffer with zeros
;
LXI D,CBUF ;point to buffer
MVI C,RDCON ;read console function
CALL BDOS
RET
;
; The console buffer
;
CBUF: DB CLEN ;buffer length
CLEFT: DB 0 ;number of char in buffer
CLIN: DS 128 ;number of buffer spaces
CLEN: EQU $-CLIN ;buffer length
;
; SORT - Main sort routine - sorts directory entries alphabetically
; Records handled in pairs.
; String1 = first position pointer
; String2 = second position pointer
; Entry: none
; Exit: entries sorted
;
SORT: LXI H,FILEBUF ;point to data buffer first entry
LXI B,NUMFILES-1 ;max number of entry pairs
SORT1: PUSH B ;save counter
PUSH H ;save string1
LXI D,COLUMNS ;offset to string2
DAD D ;string2 to HL
XCHG ;string2 to DE
POP H ;string1 to HL
PUSH H ;save string1
PUSH D ;save string2
MVI C,13 ;length of search string
CALL COMP ;CY set if (string2) < (string1)
POP D ;restore string2
POP H ;restore string1
PUSH D ;resave string2
CC SWAP ;swap string if CY
POP H ;new string1 pointer
POP B ;get counter
DCX B ;bump it down
MOV A,C
ORA B ;zero if at bottom
JZ BOTTOM
JMP SORT1 ;go do next pair
;
BOTTOM: LDA SWAPFLG ;is 1 if anything was swapped
DCR A
STA SWAPFLG ;assume was 1 - reset to zero
JZ SORT ;was 1? - sort entire buffer again
RET ;was 0 - sort done
;
; SWAP - Swaps record string pair.
; Entry: HL points to string1
; DE points to string2
; Process:
; (1) buffer <--- string2
; (2) string2 <--- string1
; (3) string1 <--- buffer
;
SWAP: PUSH H ;save string1 ptr
PUSH D ;save string2 ptr
XCHG ;string2 to HL
LXI D,SWAPBUF ;point to buffer
LXI B,COLUMNS ;size of record
CALL MOVE ;move string2 to buffer
POP D ;restore string2
POP H ;restore string1
PUSH H ;save string1
LXI B,COLUMNS ;size of record
CALL MOVE ;move string1 to string2 position
POP D ;string1 to DE
LXI H,SWAPBUF ;point HL to buffer
LXI B,COLUMNS ;size of record
CALL MOVE ;buffer to string1 position
MVI A,1 ;flag that a swap was done
STA SWAPFLG
RET
;
SWAPFLG:
DB 0 ;default no swap
;
; COMP - Compares two strings.
; Entry: HL points to string1
; DE points to string2
; C = maximum length of search
; Exit: Z set if strings match
; CY set if string2 < string1 (flags swap)
; No CY if (1) string1 < string2
; or (2) string1 = string2 (all blanks - no swap)
;
COMP: LDAX D ;get byte from string2
CMP M ;CY if string2 byte < string1 byte
RNZ ;if no match
INX H ;bump pointers
INX D
DCR C ;downcount
JNZ COMP ;check next
RET ;strings match - no CY
;
EDITFLG:
DB 0 ;default edit never used
;
;************************
;*** UNITIALIZED AREA ***
;************************
;
SWAPBUF:
DS COLUMNS ;string swap buffer
DS 64 ;our private stack area
STACK: EQU $
;
FILEBUF:
DS DATLEN ;the data file buffer
;
END
L BDOS
RET
;
; PCHARS - Prints the character in A the number of times in C
;