VF17 A86E?!VF DOCFXVF17 CMDZ:JVERS EQU 20 ;version number ; starting definitions M EQU Byte Ptr [BX] TRUE EQU 0FFFFH ;define true and.. FALSE EQU 0 ;..false. CRC_Opt EQU FALSE ; true for CRC check in copy ENH@VID EQU TRUE ;true for enhanced video HIDDEN EQU TRUE ;true for hidden video attribites ON@OFF EQU TRUE ;true for cursor on/off control GET EQU 0FFH ;get user area e-reg value EPS EQU 16*4 ;16 lines x 4 cols per screen ; EPS = Entries Per Screen ; cursor positioning as per the user's particular terminal ; this is set for the APC's arrow keys USER@UP EQU 0BH ;^K USER@DOWN EQU 0AH ;^J USER@RIGHT EQU 0CH ;^L USER@LEFT EQU 1DH ;^] SCR@FOR EQU 06H ; ^F screen forward SCR@BACK EQU 01H ; ^A screen back ; cursor positioning addresses EPSLINE EQU (EPS/4)+5 ;position of last line of EPS BANADR EQU 1*256+22 ;banner address CURHOME EQU 4*256+1 ;home address of cursor BOTADR EQU 24*256+1 ;bottom of screen CPMADR EQU EPSLINE*256+1 ;command prompt message CPADR EQU EPSLINE*256+30 ;command prompt ERADR EQU (EPSLINE+1)*256+30 ;error message FSADR EQU ERADR ;file size message FNADR EQU (EPSLINE+1)*256+15 ;address of file name RingEntSize EQU 16 Home_Row EQU CURHOME SHR 8 ; 1st line of file display Home_Col EQU CURHOME AND 0FFH ; 1st column of display ; ASCII definitions CTRLA EQU 'A'-'@' CTRLC EQU 'C'-'@' ;..control-C.. CTRLD EQU 'D'-'@' CTRLE EQU 'E'-'@' CTRLF EQU 'F'-'@' CTRLR EQU 'R'-'@' CTRLS EQU 'S'-'@' ;..XOFF.. CTRLX EQU 'X'-'@' BS EQU 08H ;..backspace.. TAB EQU 09H ;..tab.. LF EQU 0AH ;..linefeed.. CR EQU 0DH ;..carriage return.. CAN EQU 18H ;..cancel.. EOFCHAR EQU 1AH ;..end-of-file.. CTRLZ EQU 1AH ;..clear screen.. ESC EQU 1BH ;..and escape character. ; cp/m system functions RDCON EQU 1 ;console input function WRCON EQU 2 ;write character to console.. PUNCH EQU 4 ;..punch and.. LLIST EQU 5 ;..to list logical devices. DIRCON EQU 6 ;direct console i/o RDBUF EQU 10 ;read input string CONST EQU 11 ;get console status RESETDK EQU 13 ;reset disk system LOGIN EQU 14 ;log-in new drive OPEN EQU 15 ;open file CLOSE EQU 16 ;close file SRCHF EQU 17 ;search directory for first.. SRCHN EQU 18 ;..and next occurrence. ERASE EQU 19 ;erase file READ EQU 20 ;read and.. WRITE EQU 21 ;..write 128-record. MAKE EQU 22 ;make file REN EQU 23 ;rename file INQDISK EQU 25 ;get current (default) drive SETDMA EQU 26 ;set dma address INQALC EQU 27 ;allocation vector ATTR EQU 30 ;set file attributes GETPARM EQU 31 ;current drive parameters address SGUSER EQU 32 ;set or get user area COMPSZ EQU 35 ; # of records in file DSEG Data_Start EQU $ ORG 100H ; system addresses FCB EQU 5CH ;default file control block FCBEXT EQU FCB+12 ;extent byte in 'fcb' FCBRNO EQU FCB+32 ;record number in 'fcb' FCB2 EQU 6CH ;2nd FCB TBUF EQU 80H ;default cp/m buffer ; ; DISK/USER LIMITS ; MDISK DB 2 ; MAXIMUM NUMBER OF DISKS MDRIVE DB 0FFH ; MEM DRIVE, = 0FFH IF NONE ; LTPP DB 59 ; LINES OF TEXT PER PAGE LSPP DB 5 ; LINES TO SKIP PER PAGE CTPP DB 22 ; LINES OF TEXT PER SCREEN ; CSEG Code_Start: JMP FILER ; ; Screen Routines ; ; screen routines (set for NEC APC) ; clear screen - must have routine CLS: MOV AL,30 ; home cursor CALL TTYPE MOV AL,26 ; clear screen JMP TTYPE ; position cursor (H=row, L=col) where 0,0=upper left ; must have routine GOTOXY: MOV AL,ESC CALL TTYPE MOV AL,'=' CALL TTYPE ADD BX,(256 * 20H) + 20H ; ascii bias MOV AL,BH ; row CALL TTYPE MOV AL,BL ;column JMP TTYPE ; erase to end of line, must have routine EREOL: MOV AL,ESC CALL TTYPE MOV AL,'[' CALL TTYPE MOV AL,'0' CALL TTYPE MOV AL,'K' JMP TTYPE ; ; Next four routine are for terminals with enhanced video mode. ; The video attributes can be either hidden of take a space. ; Set ENH@VID and HIDDEN equates to suit. ; IF ENH@VID DSEG $ APC_NORM DB ESC,'[0m',0 APC_REVS DB ESC,'[7m',0 APC_HIGH DB ESC,'[17m',0 CSEG $ STD@VID: ;Standard Video Mode MOV SI,Offset APC_NORM JMP ILPRT CUR@VID: ;cursor Video mode MOV SI,Offset APC_REVS ;set mode for cursor display JMP ILPRT TAG@VID: ;tag Video mode -display tagged files MOV SI,Offset APC_HIGH JMP ILPRT STAT@VID: ;Status line Video Mode RET ; for APC for now ENDIF IF NOT ENH@VID STD@VID: CUR@VID: TAG@VID: STAT@VID: RET ENDIF IF ON@OFF ;set true if terminal has on/off DSEG $ APC_OFF DB ESC,'[5h',0 APC_ON DB ESC,'[5l',0 CSEG $ CUR@OFF: MOV SI,Offset APC_OFF JMP ILPRT CUR@ON: ;turn on cursor MOV SI,Offset APC_ON JMP ILPRT ENDIF ;ON@OFF IF NOT ON@OFF CUR@OFF: CUR@ON: RET ENDIF ;NOT ON@OFF ; ; END OF TERMINAL DEPENDENT ROUTINES ;****************************************************************** ; start of program FILER: MOV AX,DS MOV SS,AX MOV SP,(Offset STACK) ;start local stack MOV DATA_SEG,AX ;save data segment MOV Out_Device,DirCon CALL IDU ;set initial disk/user MOV BX,(Offset BUFENTRY) ;base address MOV BL,0 ; make it an even page INC BH MOV RING,BX ;beginning of ring MOV AL,MDISK ;get max disk number ADD AL,'A'-1 MOV MAXDR,AL ;set letter MOV AL,.FCB+1 ;check for initial help CMP AL,'/' JE FILERH MOV AL,.FCB2+1 ;check for wait CMP AL,'W' JNE FILER0 FILERSAK: MOV SI,Offset MSG1 CALL ILPRT DSEG $ MSG1 DB CR,LF,'Strike Any Key to Enter VFILER -- ',0 CSEG $ CALL DKEYIN JMPS FILER0 FILERH: CALL HELPMSG ;print help message FILER0: JMPS EMBARK ; set initial disk/user IDU: MOV BX,FCB+1 ;check for DU specification MOV AL,M CMP AL,'/' ;is there a help request? JZ IDU1 CMP AL,' ' ;=none JZ IDU1 CALL DEF@DU0 ;extrace drive/user MOV AL,CL ;get current user CALL IDU@USET ;set it MOV AL,CH ;get current disk CALL IDU@DSET ;set it JMP LOG1Z ;log it in IDU1: MOV DL,GET ;determine.. CALL GET@USR ;..user area then.. CALL IDU@USET ;set current user MOV CL,INQDISK ;determine current disk INT 224 CALL IDU@DSET ;set current disk JMP LOG1Z ;set current user and disk IDU@USET: MOV C@U@A,AL ;..store as current and.. MOV O@USR,AL ;..as original for exit. MOV R@U@A,AL ;..requested user area RET IDU@DSET: MOV C@DR,AL MOV R@DR,AL ;requested disk RET EMBARK: CALL FRESTOR ;get bytes remaining on drive (decode default) MOV BX,(Offset JOKER) ;..treat as '*.*' with 'joker'.. MOV DX,FCB+1 ;..loaded here. MOV CH,11 ; # of characters to move CALL MOVE ;set field to *.* ; build 'ring' with filename positioned in default 'fcb' area PLUNGE: MOV CL,SETDMA ;initialize dma address.. MOV DX,TBUF ;..to default buffer. INT 224 XOR AL,AL ;clear search 'fcb'.. MOV .FCBEXT,AL ;extent byte.. MOV .FCBRNO,AL ;..and record number. NOT AL MOV CANFLG,AL ;make cancel flag true MOV DX,FCB ;default 'fcb' for search.. MOV CL,SRCHF ;..of first occurrence. INT 224 INC AL ; 0ffh --> 00h if no file found JZ L_A4 JMP SETRING ;if found, branch and build ring. L_A4: MOV CANFLG,AL ;make log-cancel toggle false MOV SI,Offset MsgNoFile CALL ERMSG ;else say none found, fall thru to log. ; l o g ; select drive and user area (system reset for disk change on-the-fly) LOG: MOV SI,Offset MSG20 CALL CPRMPT ;prompt to get drive/user selection DSEG $ MSG20 DB 'Login DIR: ',0 CSEG $ CALL DEF@D@U LOG1: CALL LOG1Z ;set current and log in CALL CRLF ;new line JMPS EMBARK ;..restart ; set current user and disk LOG1X: MOV BX,(Offset LOG@DU@MSG) MOV AL,R@DR ;set prompt message ADD AL,'A' ;adjust to letter MOV M,AL INC BX MOV M,' ' ;prep for user < 10 MOV AL,R@U@A ;get user CMP AL,10 ;less than 10? JB LOG2 MOV CH,'1' ;set digits LOG1A: SUB AL,10 ;adjust user CMP AL,10 ;less? JB LOG1B INC CH ;incr 10's JMPS LOG1A LOG1B: MOV M,CH ;set 10's LOG2: INC BX ;pt to 1's ADD AL,'0' ;to ASCII MOV M,AL RET ; actually log into DU requested LOG1Y: MOV AL,R@U@A ;establish requested area.. MOV C@U@A,AL ;..as current area. CALL SET@USR CALL RESET ;reset disk system, make requested current. MOV BX,0 ;initialize tagged.. MOV TAG@TOT,BX ;..file size accumulator. RET ; set current DU and log into it LOG1Z: CALL LOG1X ;set current CALL LOG1Y ;actually log in RET ; routine to define current drive and user area with full error trapping. ; (check validity of user area entry first, then drive validity, then proceed ; with implementation.) DEF@D@U: MOV BX,(Offset CMDBUF)+2 MOV CH,20 ; # of blanks to.. CALL FILL ;..clear 'cmdbuf'. MOV DX,(Offset CMDBUF) ;get DU selection from.. MOV CL,RDBUF ;..console buffer read. INT 224 CALL CONVERT ;make sure alpha is upper case MOV BX,(Offset CMDBUF)+2 ;pt to possible drive DEF@DU0: CALL ZDNFIND ;look for DU form and return DU JZ ERRET ;error MOV R@DR,CH ; return disk MOV AL,CH INC AL ;set FCB MOV .FCB,AL MOV R@U@A,CL ; return user RET ; error return and recovery from command cancellation ERRET: MOV SI,Offset MSG41 CALL ERMSG DSEG $ MSG41 DB 'DIR Entry Error',0 CSEG $ JMP NEUTRAL COMCAN: MOV SP,(Offset STACK) ;reset stack.. CMP CANFLG,0 JNZ L_A5 JMP PLUNGE L_A5: CALL REFRESH ;refresh screen JMP LOOPFN ;..error/command abort. ; search for file pted to by DE; don't affect DE or HL; ret code in A SEARF: PUSH BX ;save regs PUSH DX MOV CL,SRCHF ;search for file INT 224 INC AL ;set flags POP DX ;get regs POP BX RET ; log in default directory DLOGIN: MOV AL,C@DR ;disk in B MOV CH,AL MOV AL,C@U@A ;user in C MOV CL,AL ;fall thru to SLOGIN ; log in DU in BC SLOGIN: PUSH BX ;save regs PUSH DX PUSH CX MOV AL,CL ;set user CALL SET@USR POP CX MOV AL,CH ;set disk CALL SET@DR POP DX ;restore regs POP BX RET QUIT: MOV SI,Offset MSG21 CALL CPRMPT DSEG $ MSG21 DB 'Confirm Quitting (Y/N)? ',0 CSEG $ CALL KEYIN CMP AL,'Y' JE CPM@CCP JMP NEUTRAL ; e x i t, return to cp/m ccp CPM@CCP: MOV AL,O@USR ;get and set original.. CALL SET@USR ;..user area and.. CALL CLS MOV CL,0 MOV DL,0 INT 224 ;warmboot ; establish ring (circular list) of filenames SETRING: MOV BX,RING ;initialize ring pointer MOV RINGPOS,BX ;start --> current position of ring ; put each found name in ring. a-reg --> offset into 'tbuf' name storage TO@RING: DEC AL ;un-do 'inr' from above and below MOV CL,5 SHL AL,CL ;times 32 --> position index MOV AH,0 ; make it a word ADD AX,TBUF ;add page offset and.. MOV BX,AX ;..put address into BX MOV AL,Byte Ptr .FCB ;get drive/user designator and.. MOV [BX],AL ;..put into 'fcb' buffer. MOV DX,RINGPOS ;pointer to current load point in ring MOV CH,12 ;move drive designator and name to ring CALL MOVE XCHG BX,DX ;de-pair contains next load point address MOV M,' ' ;space for potential.. INC BX ;..tagging of files for mass copy. ADD BX,RingEntSize-12-1 MOV RINGPOS,BX ;store and search.. MOV CL,SRCHN ;..for next occurrence. MOV DX,FCB ;filename address field INT 224 INC AL ;if all done, 0ffh --> 00h. JNZ TO@RING ;if not, put next name into ring. ; all filenames in ring -- setup ring size and copy-buffer start point MOV BX,RINGPOS ;next load point of ring is start of buffer MOV RINGEND,BX ;set ring end.. MOV BUFSTART,BX ;..and copy-buffer start. MOV DX,RING ADD DX,RingEntSize ;compare 'ringend' (tab base+RingEntSize) CMP DX,BX JNE SORT JMP CMDLOOP ;go to command loop, if no sort. ; sort ring of filenames SORT: MOV BX,RING ;initialize 'i' sort variable and.. MOV RINGI,BX ADD BX,RingEntSize ;..also 'j' variable. MOV RINGJ,BX SORTLP: MOV DX,RINGJ ;compare names 'i & j' MOV BX,RINGI MOV CX,RingEntSize ; # of characters to compare MOV SI,DX MOV DI,BX MOV ES,Data_Seg ; left to right compare of two strings. REPE CMPSB MOV CX,RingEntSize JNB NOSWAP ; swap if 'j' string larger than 'i' MOV CX,RingEntSize SWAP: MOV SI,DX MOV AL,[BX] ;get character from one string.. XCHG [SI],AL ; exchange with other string's char MOV [BX],AL ; store in first string INC BX ;bump swap pointers INC DX LOOP SWAP NOSWAP: MOV DX,RINGJ ;increment 'j' pointer ADD DX,RingEntSize MOV RINGJ,DX ;see if end of 'j' loop CMP DX,RINGEND JNE SORTLP ;no, so more 'j' looping. MOV DX,RINGI ;bump 'i' pointer ADD DX,RingEntSize MOV RINGI,DX ADD DX,RingEntSize ;set start over 'j' pointer MOV RINGJ,DX ; see if end of 'i' loop CMP DX,RINGEND JE sort_done JMP SORTLP ;must be more 'i' loop to do sort_done: ; sort done -- initialize tables for fast crc calculations IF CRC_Opt CALL INITCRC ENDIF ; calculate buffer maximum available record capacity B@SIZE: MOV CX,128 MOV REC@MAX,CX ;..record count. JMP CMDLOOP ; buffer size suitable -- process file/display loop LOOPFN: MOV BX,FNADR ;position cursor for file name print IF (ENH@VID AND (NOT HIDDEN)) DEC BX ;allow video attribute space ENDIF CALL GOTOXY MOV BX,RINGPOS ;pt to current file name INC BX CALL STAT@VID CALL PRFN ;print file name CALL STD@VID LOOP: CALL ATCMD ;position at command prompt CALL DKEYIN ;wait for character from keyboard PUSH AX ; save command CMP ERMFLG,0 ;error message? JE CPROC ; 0=no CALL ERCLR ;erase old error message CPROC: POP AX ; restore command CALL CTPROC ;process command or return if not found MOV SI,Offset MSG43 CALL ERMSG DSEG $ MSG43 DB 'Invalid Command: ',0 CSEG $ MOV AL,CH ;get char CMP AL,' ' ;expand if less than space JNB CPROC1 MOV AL,'^' ;control CALL TTYPE MOV AL,CH ;get byte ADD AL,'@' ;convert to letter CPROC1: CALL TTYPE NEUTRAL: JMPS LOOP ;..position. ; process command from table CTPROC: MOV BX,(Offset CTABLE) ;pt to table MOV CH,AL ;command in B CTPR1: CMP Byte Ptr [BX],0 ; end of table? JNE L_A8 ; no, continue RET ; done if so L_A8: CMP AL,[BX] ;match? JE CTPR2 ADD BX,3 ;skip to next entry JMPS CTPR1 CTPR2: INC BX ;pt to address MOV BX,[BX] MOV BP,SP ;address on stack XCHG BX,[BP] RET ;"jump" to routine DSEG $ ; Command Table CTABLE DB USER@UP ;user cursor positioning DW (Offset UP) DB USER@DOWN DW (Offset DOWN) DB USER@RIGHT DW (Offset FORWARD) DB USER@LEFT DW (Offset REVERSE) DB SCR@FOR DW (Offset JUMPF) DB SCR@BACK DW (Offset JUMPB) DB CTRLE ;system cursor positioning DW (Offset UP) DB CTRLX DW (Offset DOWN) DB CTRLD DW (Offset FORWARD) DB CTRLS DW (Offset REVERSE) DB '+' ;jump forward DW (Offset JUMPF) DB '-' ;jump backward DW (Offset JUMPB) DB ' ' ;go forward DW (Offset FORWARD) DB '.' ;go forward DW (Offset FORWARD) DB '>' ;go forward DW (Offset FORWARD) DB ',' ;back up? DW (Offset REVERSE) DB '<' ;back up? DW (Offset REVERSE) DB 'C' ;copy a file? DW (Offset COPY) DB 'D' ;delete a file? DW (Offset DELETE) DB 'E' ;enter a command? DW (Offset RUN@CMD) DB 'F' ;show file size? DW (Offset FIL@SIZ) DB 'G' ;goto a file? DW (Offset GOTO) DB 'L' ;log-in another drive? DW (Offset LOG) DB 'M' ;tagged multiple file copy? DW (Offset MASS@COPY) DB 'N' ;new screen DW (Offset SCREFRESH) DB 'P' ;output file to 'list' device? DW (Offset LSTFILE) DB 'Q' ;quit DW (Offset QUIT) DB 'R' ;if rename, get to work. DW (Offset RENAME) DB 'S' ;free bytes on.. DW (Offset R@DR@ST) ;..requested drive? DB 'T' ;if tag, put '*' in.. DW (Offset TAG@EM) ;..front of cursor. DB 'U' ;remove '*' from.. DW (Offset UNTAG) ;..in front of cursor? DB 'W' ;mass tag/untag? DW (Offset MASS@TU) DB 'V' ; 'view' file at console? DW (Offset VIEW) DB 'X' ;execute command file DW (Offset XQT@CMD) DB 'Y' ;mass delete? DW (Offset MASS@DEL) DB ESC ; 'esc' quits to cp/m ccp also. DW (Offset QUIT) DB '?' ;help DW (Offset HELP) DB '/' ;help also DW (Offset HELP) DB 0 ;end of table CSEG $ ; h e l p (menu) HELP: CALL HELPMSG ;print message CALL REFRESH ;refresh screen JMP LOOPFN HELPMSG: CALL CLS MOV SI,Offset MSG2 CALL ILPRT DSEG $ MSG2 DB '-- VFILER (APC)' DB VERS/10+'0','.',VERS MOD 10+'0' DB ': CPM-86 File Manipulation Program -- ' DB CR,LF,CR,LF DB '-- Tagging Commands -- -- File Operations --',CR,LF DB ' T - Tag File C - Copy File',CR,LF DB ' U - Untag File D - Delete File',CR,LF DB ' W - Mass Tag/Untag F - File Size',CR,LF DB ' M - Mass Copy',CR,LF DB '-- File Print & View -- R - Rename File',CR,LF DB 'P - Print V - View Y - Mass Delete',CR,LF DB CR,LF DB '-- Movement Commands -- -- Miscellaneous --',CR,LF DB ' - File Forward / - This Summary',CR,LF DB ' > - File Forward E - Enter Command',CR,LF DB ' - File Backward L - Login DIR',CR,LF DB ' < - File Backward N - reNew Screen',CR,LF DB ' G - Go To a File S - Status of Disk',CR,LF DB ' + - Screen Forward Q - Quit VFILER',CR,LF DB ' - - Screen Backward X - eXecute CMD file',CR,LF DB CR,LF DB ' -- Screen Movement --',CR,LF DB 'File: ^S - LEFT ^D - RIGHT ^E - UP ^X - DOWN',CR,LF DB 'Screen: ^A - LEFT ^F - RIGHT',CR,LF DB 0 CSEG $ CALL BOTTOM RET ; refresh screen SCREFRESH: CALL REFRESH ;do it JMP LOOPFN ;reprint name CHK@CMD: ;check if CMD file ; ENTRY: file in RINGPOS ; EXIT: zero set if CMD type ; PUSH BX MOV BX,RINGPOS ;get addr file location ADD BX,9 ;point to file type CMP Byte Ptr[BX],'C' ;test for CMD JNE CC_RET INC BX CMP Byte Ptr[BX],'M' JNE CC_RET INC BX CMP Byte Ptr[BX],'D' CC_RET: POP BX RET ;zero set if CMD type XQT@CMD: MOV SI,Offset MSG22 CALL CPRMPT DSEG $ MSG22 DB 'Execute Current CMD File (Y/N)? ',0 CSEG $ CALL KEYIN CMP AL,'Y' JE XQT1 JMP NEUTRAL XQT1: CALL CHK@CMD ;check if CMD filetype JZ XQT2 ;give error if not MOV SI,Offset MSG45 CALL ERMSG DSEG $ MSG45 DB 'Not a CMD file',0 CSEG $ JMP LOOPFN XQT2: CALL CLS MOV ES,Data_Seg MOV DI,TBUF ;put CMD in default DMA buffer MOV SI,RINGPOS ;get position in ring LODSB ;get drive number ADD AL,'A'-1 ;make into letter STOSB ;move it, SI -> filename MOV AL,':' STOSB ;DI -> TBUF+2 MOV CX,8 ;bytes in filename JMP CHAIN RUN@CMD: MOV SI,Offset MSG46 CALL ERMSG DSEG $ MSG46 DB 'Enter Command? ',0 CSEG $ MOV BX,TBUF MOV M,102 ;allow 100 length of line INC BX MOV M,0 ;store count MOV DX,TBUF MOV CL,RDBUF INT 224 MOV BX,TBUF+1 ;BX -> char count MOV CL,[BX] ;put in CL OR CL,CL ; anything? JNZ rcmd_ok ; yes, do it JMP NEUTRAL ; no, return rcmd_ok: INC BX ;point to first char XOR CH,CH ;CX = char count MOV SI,CX MOV Byte Ptr [BX+SI],0 ;store ending zero MOV SI,BX ;SI -> Command MOV DI,TBUF CALL UC_CMD ;make sure its upper CASE CALL CLS ; clear scrn and fall thru CHAIN: ; ENTRY: SI -> buffer containing command ; DI -> dest of command ; CX = length of command MOV ES,DATA_SEG CLD ;set forward direction REP MOVSB ;move it MOV Byte Ptr [DI],0 ;end with a zero MOV CL,47 ;Chain function MOV DX,0FFFFH ;chain flag INT 224 ; we don't return UC_CMD: ;make string ending in 0h upper case ; ENTRY: BX -> string ; UC_LOOP: MOV AL,[BX] OR AL,AL JZ UC_RET ;quit if zero CALL UCASE MOV [BX],AL INC BX ;point to next char JMPS UC_LOOP ;and process it UC_RET: RET ; mass tag or untag MASS@TU: MOV AL,TRUE ;update file totals MOV FS@FLG,AL ;of tagged/untagged files MOV SI,Offset MSG23 CALL CPRMPT DSEG $ MSG23 DB 'Mass Tag or Untag (T/U)? ',0 CSEG $ CALL KEYIN ;get response CMP AL,'T' JZ MASS@TAG CMP AL,'U' JZ L_A11 JMP NEUTRAL ;fall thru to MASS$UNTAG L_A11: ; mass u n t a g MASS@UNTAG: XOR AL,AL ;set tag/untag.. MOV T@UN@FG,AL ;..flag to untag MOV FSDFLG,AL ;no file size display CALL WORKMSG MUTLOOP: MOV BX,RINGPOS ;move to tag MOV DX,12 ADD BX,DX MOV AL,M ;get tag CMP AL,'*' ;check for tag MOV M,' ' ;clear tag JNZ L_A12 CALL FSIZ ;adjust sizes L_A12: MOV BX,RINGPOS ;advance to next MOV DX,RingEntSize ADD BX,DX MOV RINGPOS,BX XCHG BX,DX ;done? MOV BX,LOCEND CMP DX,BX JNZ MUTLOOP MOV BX,CURHOME ;reset cursor MOV CURAT,BX MOV BX,LOCBEG ;set ring position JMP JFW0 ; mass t a g MASS@TAG: XOR AL,AL MOV FSDFLG,AL ;no file size display MOV AL,TRUE ;set tag/untag.. MOV T@UN@FG,AL ;..flag to untag CALL WORKMSG MTLOOP: MOV BX,RINGPOS ;move to tag MOV DX,12 ADD BX,DX MOV AL,M ;get tag CMP AL,'*' ;check for tag MOV M,'*' ;clear tag JZ L_A13 CALL FSIZ ;adjust sizes L_A13: MOV BX,RINGPOS ;advance to next MOV DX,RingEntSize ADD BX,DX MOV RINGPOS,BX XCHG BX,DX ;done? MOV BX,LOCEND CMP DX,BX JNZ MTLOOP MOV BX,CURHOME ;reset cursor MOV CURAT,BX MOV BX,LOCBEG ;set ring position JMP JFW0 ; u n t a g UNTAG: XOR AL,AL ;set tag/untag.. MOV T@UN@FG,AL ;..flag to untag. NOT AL MOV FS@FLG,AL ;set flag to compute file size MOV BX,RINGPOS ;move back one.. MOV DX,12 ;..character position.. ADD BX,DX ;..and check tagging status. MOV AL,M ;if file previously tagged, remove.. CMP AL,'*' ;..size from.. LAHF ;save flag XCHG AL,AH PUSH AX MOV M,' ' ; (untag character, to next ring position.) CALL REFFN ;refresh file name POP AX ;get flag XCHG AL,AH SAHF JZ FS2 ;..summation. JMP FORWARD ; t a g TAG@EM: MOV AL,TRUE ;set.. MOV T@UN@FG,AL ;..tag/untag and.. MOV FS@FLG,AL ;..file size flags to tag. MOV BX,RINGPOS MOV DX,12 ;move back one.. ADD BX,DX ;..position.. MOV AL,M ; (if file CMP AL,'*' ; already tagged, skip JNZ L_A14 JMP FORWARD ; to next file.) L_A14: MOV M,'*' ;..and store a '*' tag character. CALL REFFN ;refresh file name JMPS FS2 ;get file size ; refresh file name with new tag REFFN: MOV BX,CURAT ;clear cursor IF ENH@VID ADD BX,4 ;advance 4 spaces CALL GOTOXY ENDIF IF NOT ENH@VID CALL GOTOXY MOV SI,Offset MSG4 CALL ILPRT DSEG $ MSG4 DB ' ',0 ;clear cursor CSEG $ ENDIF MOV BX,RINGPOS ;reprint file name INC BX CALL NC@PRFN ;print file name RET ; f i l e s i z e ; determine and display file size in kilobytes -- round up to next disk ; allocation block -- accumulate tagged file summation FIL@SIZ: XOR AL,AL ;set file size/tagged.. MOV FS@FLG,AL ;..file flag to file size. NOT AL MOV FSDFLG,AL ;display file size CALL FSIZ ;compute and print file size JMP LOOPFN FS2: MOV AL,TRUE MOV FSDFLG,AL ;display file size CALL FSIZ ;compute and print file size JMP FORWARD ; print file size FSIZ: CMP FSDFLG,0 ;display file size? JE L_A15 ;0=no CALL FSNOTE L_A15: CALL RINGFCB ;move name to 's$fcb' ; determine file record count and save in 'rcnt' MOV CL,COMPSZ MOV DX,(Offset S@FCB) INT 224 MOV BX,Word Ptr S@FCB+33 MOV RCNT,BX ;save record count and.. MOV BX,0 MOV Word Ptr S@FCB+33,BX ;..reset cp/m. ; round up to next disk allocation block MOV AL,B@MASK ;sectors/block - 1 PUSH AX ;save 'blm' MOV BL,AL XCHG BX,DX MOV BX,RCNT ;..use here. ADD BX,DX ;round up to next block MOV CL,3 ;convert from.. SHR BX,CL ;..records to kilobytes. POP AX ;retrieve 'blm' ROR AL,1 ;convert.. ROR AL,1 ;..to.. ROR AL,1 ;..kilobytes/block. AND AL,1FH NOT AL ;finish rounding AND AL,BL MOV BL,AL ;hl-pair contains # of kilobytes CMP FS@FLG,0 JE D@F@SIZ ;branch if 'f' function ; tagged file size summation XCHG BX,DX ;file size to de-pair CMP T@UN@FG,0 JE TAKE ;if untag, take size from total. MOV BX,TAG@TOT ;accumulate.. ADD BX,DX ;..sum of.. MOV TAG@TOT,BX ;..tagged file sizes. XCHG BX,DX ;file size to hl-pair JMPS D@F@SIZ ;branch to display sizes TAKE: MOV BX,TAG@TOT ;subtract.. SUB BX,DX ; file size from summation MOV TAG@TOT,BX ; (save total) XCHG BX,DX ;..file size in hl-pair. ; display file size in kilobytes -- right justify tagged file total D@F@SIZ: CMP FSDFLG,0 ;display file size? JNE L_A16 ;0=no RET L_A16: PUSH BX ;save value CALL ATFS ;position for file size print MOV BX,RINGPOS ;print file name of current file INC BX CALL PRFN MOV AL,':' CALL TTYPE POP BX ;get value CALL DECOUT ;print individual file size MOV AL,'K' CALL TTYPE ; determine # of digits in tagged summation MOV BX,TAG@TOT ;get present summation MOV SI,Offset MSG5 CALL ILPRT DSEG $ MSG5 DB ' Tagged:',0 CSEG $ CALL DECOUT ;print tagged file summation MOV AL,'K' JMP TTYPE ; j u m p backward JUMPB: CALL CUR@OFF ;turn off term. cursor MOV CURAT,CURHOME ;set cursor home MOV DX,RING ;at front? MOV BX,LOCBEG CMP DX,BX JZ JUMPBW ;back up and wrap around MOV LOCEND,BX ;set new end SUB BX,EPS*RingEntSize MOV LOCBEG,BX ;new beginning MOV RINGPOS,BX ;new position CALL REFRESH ;refresh screen CALL CUR@ON ;turn on term. cursor JMP LOOPFN JUMPBW: MOV BX,LOCBEG ;at first screen? XCHG BX,DX MOV BX,RING ;pt to first element of ring CMP DX,BX JZ JBW0 ;advance to end MOV BX,-EPS*RingEntSize ;back up ADD BX,DX JMPS JFW0 JBW0: MOV DX,EPS*RingEntSize ;pt to next screen ADD BX,DX XCHG BX,DX MOV BX,RINGEND CMP DX,BX XCHG BX,DX JZ JBW1 JB JBW0 JBW1: MOV DX,-EPS*RingEntSize ADD BX,DX ;pt to first element of local ring JMPS JFW0 JUMPF: CALL CUR@OFF ;tuen off term. cursor MOV CURAT,CURHOME ;set cursor to home MOV DX,LOCEND ;see if Local End <= Ring End MOV BX,RINGEND CMP DX,BX JZ CMDLOOP MOV BX,LOCEND ;new screen JMPS JFW0 CMDLOOP: CALL CUR@OFF ;turn off cursor MOV CURAT,CURHOME ;set cursor home MOV BX,RING ;set ring position JFW0: MOV RINGPOS,BX JFW0A: MOV LOCBEG,BX ;front of ring ADD BX,EPS*RingEntSize ; new end? MOV DX,RINGEND ;end of ring CMP DX,BX JB JFW1 XCHG BX,DX JFW1: XCHG BX,DX MOV LOCEND,BX CALL REFRESH CALL CUR@ON ;turn on term. cursor JMP LOOPFN ; f o r w a r d FORWARD: CALL CUR@OFF ;turn off term. cursor CALL CLRCUR ;clear cursor CALL FOR0 ;position on screen and in ring CALL SETCUR ;set cursor CALL CUR@ON ;turn on term. cursor JMP LOOPFN ; advance routine FOR0: MOV DX,RINGPOS ;at end of loop yet? ADD DX,RingEntSize CMP DX,LOCEND ;compare 'present' to 'end' JNZ FORW ;to next print position CALL CUR@FIRST ;position cursor MOV BX,LOCBEG ;set position pointer to beginning and.. MOV RINGPOS,BX RET FORW: ADD RINGPOS,RingEntSize ; advance position CALL CUR@NEXT ;position cursor RET ; r e v e r s e REVERSE: CALL CUR@OFF ;turn off term. cursor CALL CLRCUR ;clear cursor CALL REV0 ;position on screen and in ring CALL SETCUR ;set cursor CALL CUR@ON ;turn on term. cursor JMP LOOPFN ; Back Up Routine REV0: MOV BX,RINGPOS ;see if at beginning of ring CMP LOCBEG,BX JNZ REV1 ;skip position pointer reset if not.. CALL CUR@LAST ;end of local ring MOV BX,LOCEND ;set to end +1 to backup to end SUB BX,RingEntSize MOV RINGPOS,BX RET REV1: CALL CUR@BACK ;back up 1 REV2: SUB RINGPOS,RingEntSize RET ; u p UP: CALL CUR@OFF ;turn off term. cursor CALL CLRCUR ;clear cursor MOV DX,RINGPOS ;see if wrap around SUB DX,RingEntSize*4 ;4 entries CMP DX,LOCBEG ;beginning of local screen JB UP2 ;wrap around SUB RINGPOS,RingEntSize*4 ; back up 4 ring positions MOV BX,CURAT ; back cursor to prev line DEC BH MOV CURAT,BX JMPS DOWN1A UP2: MOV BX,RINGPOS ;advance to beyond end ADD BX,RingEntSize*4 CMP LOCEND,BX ;compare to local end JBE DOWN1A ;at/beyon end, so back up MOV RINGPOS,BX ;new ring position MOV BX,CURAT ;advance cursor INC BH ;next line MOV CURAT,BX JMPS UP2 ; d o w n DOWN: CALL CUR@OFF ;turn off term. cursor CALL CLRCUR ;clear cursor MOV BX,RINGPOS ;see if wrap around ADD BX,RingEntSize*4 ;4 entries CMP LOCEND,BX ; at end? JBE DOWN2 ;wrap around ADD RINGPOS,RingEntSize*4 ; advance 4 ring positions MOV BX,CURAT ; move cursor to next line INC BH MOV CURAT,BX DOWN1A: CALL SETCUR ;set cursor CALL CUR@ON ;turn on term. cursor JMP LOOPFN DOWN2: MOV BX,CURAT ;preserve column MOV CH,BL ;column number in B MOV CURAT,CURHOME ; set home position MOV BX,LOCBEG ;beginning of local ring MOV RINGPOS,BX ;new ring position DOWN3: MOV BX,CURAT ;check for at top of column CMP BL,CH ; are we at column? JZ DOWN1A ; yes, exit ADD RINGPOS,RingEntSize ;advance in ring,13 bytes/entry ADD CURAT,19 ;advance 19 bytes/screen entry JMPS DOWN3 ; s t a t, determine remaining storage on requested disk R@DR@ST: MOV SI,Offset MSG24 CALL CPRMPT DSEG $ MSG24 DB 'Status of Disk: ',0 CSEG $ CALL KEYIN ;get char PUSH AX CALL CRLF POP AX SUB AL,'A' ;convert to number JNB L_A17 JMP NEUTRAL L_A17: MOV CH,AL ;... in B MOV AL,MAXDR ;compare to max SUB AL,'A' CMP AL,CH JNB L_A18 MOV AL,MDRIVE DEC AL CMP AL,CH JE L_A18 JMP LOOPFN L_A18: MOV AL,CH ;get disk MOV R@DR,AL ;requested drive CALL RESET ;..login as current. CALL FRESTOR ;determine free space remaining CALL PRINT@FRE ;print value MOV AL,C@DR ;login original as.. CALL SET@DR ;..current drive. JMP LOOPFN ;done ; d e l e t e ; mass delete MASS@DEL: MOV SI,Offset MSG25 CALL CPRMPT DSEG $ MSG25 DB 'Mass Delete (Y/N/V=Verify Each)? ',0 CSEG $ CALL KEYIN ;get response CMP AL,'Y' JZ MD1 CMP AL,'V' JZ MD1 JMP NEUTRAL ;return to position MD1: MOV MDFLG,AL ;set flag MOV MFLAG,0 ;set for mass delete MOV BX,RING MOV RINGPOS,BX ;set ring position MD@LP: MOV BX,RINGPOS ;get current position CMP Byte Ptr 12[BX],'*' ;get tag JNE MD@LOOP CALL RINGFCB ;set up file name CMP MDFLG,'V' ;verify? JE MDEL1 ;delete with verify JMP DEL1 ;delete without verify MD@LOOP: ADD RINGPOS,RingEntSize ;advance to next MOV BX,RINGPOS ;re-entry point for next file mass-copy MD1@LOOP: CMP BX,RINGEND ;at ring end yet? (bx = present pos) JNZ MD@LP ;no, loop 'till thru ring list. MD@EXIT: MOV MFLAG,TRUE ;set no mass-delete request. JMP CMDLOOP ;jump to 'ring' beginning ; set up to delete filename at cursor position DELETE: MOV AL,TRUE ;set for no mass delete MOV MFLAG,AL MOV MDFLG,AL CALL RINGFCB ;move file name MDEL1: MOV SI,Offset MSG26 CALL CPRMPT DSEG $ MSG26 DB 'Delete ',0 CSEG $ CALL PRFNS ;print file name in S$FCB MOV SI,Offset MSG6 CALL ILPRT DSEG $ MSG6 DB ' (Y/N)? ',0 CSEG $ CALL KEYIN CMP AL,'Y' JE DEL1 CMP MFLAG,0 ;mass delete? JE MD@LOOP MDEL2: SUB LOCEND,RingEntSize MOV DX,LOCEND ;move in end CMP DX,RINGPOS ;position beyond end of ring? JNZ MDEL3 CALL CUR@BACK ;back up cursor MOV BX,LOCEND ;reset position SUB BX,RingEntSize MOV RINGPOS,BX MOV DX,LOCEND ;get end MDEL3: MOV BX,LOCBEG ; erased all local files? CMP DX,BX ; DX --> LOCEND. JNZ L_B3 ; any left? JMP CMDLOOP ;reset L_B3: JMP JFW0A ;rescreen ; delete file DEL1: CMP MDFLG,'Y' ;Y option on Mass Delete? JNZ DEL1A MOV SI,Offset MSG47 CALL ERMSG DSEG $ MSG47 DB 'Deleting File ',0 CSEG $ CALL PRFNS DEL1A: MOV BX,(Offset S@FCB) ;set file to R/W CALL ATTRIB MOV DX,(Offset S@FCB) ;point at delete 'fcb' MOV CL,ERASE ;erase function INT 224 INC AL JZ FNF@MSG ;print error message CALL MOVUP ;close up erased position CMP MFLAG,0 ;check for mass delete JE L_B4 JMP MDEL2 L_B4: MOV BX,RINGPOS ;no advance because of close up JMP MD1@LOOP FNF@MSG: MOV SI,Offset MsgNoFile CALL ERMSG ;show error message JMP LOOPFN ; reverse ring to close up erased position MOVUP: MOV ES,Data_Seg ;prepare move up pointers MOV DI,RINGPOS ; di --> dest, deleted entry LEA SI,RingEntSize[DI] ; si --> source + 1 entry MOV CX,RINGEND ; end of ring SUB CX,RINGPOS ; minus current position SUB CX,RingEntSize ; less 1 entry = # bytes to move SHR CX,1 ; div 2 = # words to move REP MOVSW ; move 'em MOV RINGEND,DI ; save new end of ring CMP DI,RING ;see if ring is empty JNE movup_ret CMP DI,RINGPOS JE L_B6 movup_ret: RET ;neither equal so not empty L_B6: MOV SP,(Offset STACK) ;reset stack MOV SI,Offset MSG49 CALL ERMSG DSEG $ MSG49 DB 'List Empty',0 CSEG $ JMP LOG ;go to drive/user area with files ; r e n a m e ; set-up to rename file at cursor position -- scan keyboard buffer and ; move filename to 'rename' destination 'fcb' (dfcb) RENAME: MOV BX,RINGPOS ;move name from ring to rename 'fcb' MOV DX,(Offset D@FCB) ;place to move name MOV CH,12 ;amount to move CALL MOVE MOV SI,Offset MSG27 CALL CPRMPT ;new name prompt DSEG $ MSG27 DB 'Rename File to: ',0 CSEG $ MOV DX,(Offset D@FCB)+16 ;pt to FCB to fill CALL FILENAME ;get file name MOV BX,(Offset D@FCB)+1 ;check for any wild cards -- none permitted MOV CH,11 ;11 bytes WILDCHK: MOV AL,M ;get char INC BX ;pt to next CMP AL,'?' ;wild? JZ WILDFND DEC CH JNZ WILDCHK ; copy old file status bit ($r/o or $sys) to new filename CPYBITS: MOV DX,(Offset D@FCB)+1 ;first character of old name.. MOV BX,(Offset D@FCB)+17 ;..and of new name. MOV CH,11 ; # of bytes with tag bits CBITS1: MOV SI,DX ;fetch bit of old name character MOV AL,[SI] AND AL,128 ;strip upper bit and.. MOV CL,AL ;..save in b-reg. MOV AL,7FH ;mask for character only AND AL,M ;put masked character into a-reg OR AL,CL ;add old bit MOV M,AL ;copy new byte back INC BX ;bump copy pointers INC DX DEC CH JNZ CBITS1 ; check if new filename already exists. if so, say so. then go ; to command loop without moving ring position MOV AL,Byte Ptr D@FCB ;copy new name to source 'fcb' MOV Byte Ptr S@FCB,AL MOV BX,(Offset D@FCB)+17 ;copy new name to.. MOV DX,(Offset S@FCB)+1 ;..source 'fcb' for existence check. MOV CH,11 CALL MOVE MOV BX,(Offset S@FCB)+12 ;clear cp/m 'fcb' system.. CALL INITFCB ;..fields. MOV DX,(Offset S@FCB) ;search to see if this file exists MOV CL,SRCHF ;search first function INT 224 INC AL ; 0ffh --> 00h if file not found JZ RENFILE ;to rename, if duplicate doesn't exists. MOV SI,Offset MSG50 CALL ERMSG ;announce the situation DSEG $ MSG50 DB 'File Already Exists',0 CSEG $ JMP COMCAN ;try again? ; wild char found in file name -- error WILDFND: MOV SI,Offset MSG51 CALL ERMSG DSEG $ MSG51 DB 'Wildcards NOT allowed',0 CSEG $ JMP COMCAN ; copy new name into ring position RENFILE: MOV BX,RINGPOS ;get ring position pointer INC BX ;pt to name PUSH BX ;save ptr XCHG BX,DX MOV BX,(Offset D@FCB)+17 ;point at new name and.. MOV CH,11 CALL MOVE ;..move. MOV BX,CURAT ;get current position on screen MOV DX,4 ;advance 4 chars ADD BX,DX CALL GOTOXY POP BX ;get ptr CALL AC@PRFN ;print file name MOV DX,(Offset D@FCB) ;rename 'fcb' location MOV CL,REN ;rename function INT 224 INC AL ; 0ffh --> 00h if rename error JZ L_B7 JMP NEUTRAL ;if okay, proceed, else.. L_B7: JMP FNF@MSG ;..show no-file msg. ; get file name from user and process into FCB pted to by DE FILENAME: PUSH DX ;save ptr MOV DX,(Offset CMDBUF) ;command line location MOV CL,RDBUF ;console read-buffer function INT 224 CALL CONVERT ;capitalize alpha POP BX ;set to null drive MOV M,0 ;..required by 'bdos'. INC BX ; initialize new filename field with spaces PUSH BX ;save start pointer MOV CH,11 ; # of spaces to 'blank' CALL FILL POP BX XCHG BX,DX MOV BX,(Offset CMDBUF)+1 ;put length.. MOV CL,M ;..in c-reg. INC BX XCHG BX,DX ;de-pair --> buffer pointer and hl-pair.. CALL UNSPACE ;..--> 'fcb' pointer. remove leading spaces. ; extend buffer to spaces beyond command length EXTEND: PUSH BX MOV BL,CL ;double-byte remaining length MOV BH,0 ADD BX,DX ;to buffer end +1 MOV M,' ' ;force illegal character end POP BX ; start filename scan SCAN: MOV CH,8 ; 8 characters in filename SCAN1: CALL CKLEGAL ;get and see if legal character JNB L_B8 JMP COMCAN ;all of command line? L_B8: CMP AL,' ' ;see if end of parameter field JNZ L_B9 RET ;rename file L_B9: CMP AL,'.' ;at end of filename JZ SCAN2 ;process filetype field CMP AL,'*' ;rest wild? JZ SCAN1B MOV M,AL ;put character into destination 'fcb' INC BX DEC CH JNZ SCAN1 ; entry if eight characters without a 'period' SCAN1A: CALL CKLEGAL ;scan buffer up to period or end JNB L_B10 RET ;no extent if not legal L_B10: CMP AL,' ' ;end of parameter field? JNZ L_B11 RET L_B11: CMP AL,'.' JNZ SCAN1A ;do till end or period JMPS SCAN2A ;continue at correct place ; make rest of entry wild SCAN1B: MOV M,'?' ;fill with ?'s INC BX DEC CH JNZ SCAN1B MOV SI,DX ;get next char MOV AL,[SI] INC DX ;pt to after dot CMP AL,'.' ;must be dot JZ L_B12 JMP COMCAN ;cancel if not L_B12: JMPS SCAN2A ; build filetype field SCAN2: INC BX ;advance ptr to file type field DEC CH JNZ SCAN2 SCAN2A: MOV CH,3 ;length of filetype field SCAN3: CALL CKLEGAL ;get and check character JB SCAN4 ;name done if illegal CMP AL,' ' ;end of parameter field? JZ SCAN4 CMP AL,'.' ;check if another period JZ SCAN4 CMP AL,'*' ;rest wild? JZ SCAN4B MOV M,AL INC BX DEC CH JNZ SCAN3 ;get next character JMPS SCAN4A SCAN4: INC BX ;advance to end of type field DEC CH JNZ SCAN4 SCAN4A: CALL INITFCB ;..and zero counter fields. RET SCAN4B: MOV M,'?' ;make wild INC BX DEC CH JNZ SCAN4B JMPS SCAN4A ;complete rest ; goto file GOTO: MOV SI,Offset MSG28 CALL CPRMPT DSEG $ MSG28 DB 'Goto Filename: ',0 CSEG $ MOV DX,(Offset D@FCB) ;pt to FCB CALL FILENAME ;get file name MOV BX,RING ;pt to first element of ring MOV RINGPOS,BX ;set position MOV LOCBEG,BX ;set local beginning MOV GO_CNT,EPS ;set local counter GOTOL: CALL GOTOCOMP ;compare JZ GOTOF ;we are there DEC GO_CNT ; bump count JNZ GOTOL1 ; done em all? MOV GO_CNT,EPS ; yes, reset count ADD LOCBEG,EPS*RingEntSize ;reset local beginning GOTOL1: ADD RINGPOS,RingEntSize ;advance to next entry MOV BX,RINGPOS ;new position CMP BX,RINGEND ;check current pos vs. end of ring JNE GOTOL MOV BX,RING ;pt to first element MOV RINGPOS,BX ;set position MOV SI,Offset MsgNoFile CALL ERMSG JMP CMDLOOP GOTOF: MOV DX,LOCBEG ;we have local beginning PUSH DX ; save ring location in DE MOV BX,CURHOME ;set cursor ptr MOV CURAT,BX CALL CUR@OFF ;turn off term. cursor GOTOF0A: MOV BX,RINGPOS ;at position? CMP DX,BX JZ GOTOF1 ADD DX,RingEntSize ;advance location CALL CUR@NEXT ;advance cursor JMPS GOTOF0A GOTOF1: CALL CUR@ON ;turn on term. cursor POP BX ;pt to local ring (from DX) JMP JFW0A ;process GOTOCOMP: MOV BX,RINGPOS ;pt to current entry INC BX ;pt to first char of file name MOV DX,(Offset D@FCB)+1 ;pt to first char of new file MOV CH,11 ;11 bytes MOV SI,DX ; set up si GOTOC1: LODSB ; get a char & pt to next CMP AL,'?' ;match? JZ GOTOC2 CMP AL,[BX] ;match? JZ GOTOC2 RET ;no match GOTOC2: INC BX DEC CH JNZ GOTOC1 RET ; v i e w ; type file to console with pagination set to 'lps' -- single-line scroll ; using bar , to cancel, any other key to page screen. VIEW: CALL CHK@CMD ;check if CMD filetype JNZ OK_VIEW ;give error if CMD type MOV SI,Offset MsgNoCmd CALL ERMSG JMP LOOPFN OK_VIEW: CALL CLS MOV SI,Offset MSG7 CALL ILPRT DSEG $ MSG7 DB CR,LF,' Quits, Turns Up One Line, ' DB 'Other Keys Page Screen',CR,LF,LF,0 CSEG $ MOV LPSCNT,1 ;..lines-per-screen counter. MOV AL,DirCon JMP CURRENT ;to common i/o processing ; p r i n t e r ; send file to logical list device -- any keypress cancels LSTFILE: MOV SI,Offset MSG29 CALL CPRMPT DSEG $ MSG29 DB 'Print current file (Y/N)? ',0 CSEG $ CALL KEYIN ;get response CMP AL,'Y' JE L_B14 JMP NEUTRAL L_B14: CALL CHK@CMD ;check if CMD filetype JNZ OK_LST ;give error if CMD type MOV SI,Offset MsgNoCmd CALL ERMSG JMP LOOPFN OK_LST: MOV AL,LTPP ;get lines to print per page MOV LTPP1,AL ;stash MOV HEADFLG,TRUE ;set flag defaults MOV PAGEFLG,TRUE MOV SI,Offset MSG55 CALL ERMSG DSEG $ MSG55 DB '*** Make Printer Ready ***',0 CSEG $ MOV SI,Offset MSG30 CALL CPRMPT DSEG $ MSG30 DB 'Page the printer output (Y/N)? ',0 CSEG $ CALL KEYIN CMP AL,'Y' JE L_B14A MOV PAGEFLG,FALSE JMPS L_B14B L_B14A: MOV SI,Offset MSG31 CALL CPRMPT DSEG $ MSG31 DB 'Print Header on every page (Y/N)? ',0 CSEG $ CALL KEYIN CMP AL,'Y' JE L_B14B MOV HEADFLG,FALSE ;set flag false L_B14B: MOV SI,Offset MSG70 CALL ERMSG DSEG $ MSG70 DB 'Printing ',0 CSEG $ MOV BX,RINGPOS ;pt to file name INC BX CALL PRFN ;print it MOV SI,Offset MSG32 CALL CPRMPT DSEG $ MSG32 DB 'Press ESC, or Q key to quit printing ',0 CSEG $ MOV LPSCNT,0 ;zero for lines-per-page counter MOV AL,LLIST ;out to 'list' device function and fall thru ; output character for console/list/punch processing CURRENT: MOV Out_Device,AL CALL RINGFCB ;position name to 'fcb' XCHG BX,DX ;HL pts to S$FCB CALL INITFCB ;set 'fcb' for use MOV DX,TBUF ;set to use default cp/m dma buffer MOV CL,SETDMA ;address set function INT 224 MOV DX,(Offset S@FCB) ;open file for reading MOV CL,OPEN ;file open function code INT 224 INC AL ; 0ffh --> 00h if open not okay JNZ ZEROCR ;if not okay, show error message. MOV SI,Offset MsgNoOpen CALL ERMSG JMP NEUTRAL ZEROCR: XOR AL,AL MOV Byte Ptr S@FCB+32,AL ;zero file 'current record' field MOV Byte Ptr CHARCNT,AL ;zero char count for tabbing CALL PHEAD ;print heading if output to LST device READMR: MOV DX,(Offset S@FCB) ;point at file 'fcb' for reading MOV CL,READ ;record read function INT 224 OR AL,AL ;check if read okay JZ L_B15 JMP CURDONE ;eof? L_B15: MOV BX,TBUF ;point at record just read MOV CX,128 ;set record character counter to output READLP: MOV AL,M ;get a character AND AL,7FH ;force to 'ascii' CMP AL,EOFCHAR ;see if end-of-file JNZ not_eof JMP CURDONE ;back to ring loop if 'eof' not_eof: PUSH CX PUSH BX CMP AL,TAB ;check char,tabulate? JNZ NOTAB MOV AL,' ' ;space over TABL: CALL TTYPE INC CHARCNT ;increment char count TEST CHARCNT,7 ;check for done at every 8 JNZ TABL JMPS TABDN NOTAB: CALL TTYPE INC CHARCNT TABDN: CMP AL,LF ; eoln? JNE not_lf ; nope CALL PAGER ; yes, see if we need to page not_lf: CALL PRN@CAN ; checks if prn AND cancel POP BX ; if not, restore pointer POP CX ; and count, INC BX ; bump buffer pointer. LOOP READLP ; buffer empty? JMP READMR ; yes, get next record. CURDONE: CMP Out_Device,DirCon JNE L_B20 CALL BOTTOM ;prompt for user L_B20: MOV Out_Device,DirCon CALL REFRESH ;refresh screen JMP LOOPFN PAGER: MOV CHARCNT,0 ;zero char count CMP Out_Device,LLIST ;printer or console? JE PAGEP INC LPSCNT ; bump lines/scrn counter MOV AL,LPSCNT CMP AL,CTPP ; at limit? JNB L_B22 ; yes, send prompt RET ;no, return. L_B22: MOV LPSCNT,0 ;yes, init for next screen full. MOV SI,Offset MSG8 CALL ILPRT DSEG $ MSG8 DB ' [View More...]',CR,0 ;show msg line CSEG $ CALL DKEYIN ;wait for keyboard input MOV SI,Offset MSG9 CALL ILPRT DSEG $ MSG9 DB ' ',CR,0 ;clear above msg line CSEG $ CMP AL,' ' ;see if bar.. JNE CHK@CAN ;..if not, see if cancel. MOV AL,CTPP ;set for single line DEC AL MOV LPSCNT,AL ;..scroll and.. RET ;..return for one more line. PAGEP: CALL PRN@CAN ; check if cancel CMP PAGEFLG,TRUE ;test paging flag JNE PAGE_RET ;if true then... MOV AL,LTPP1 ;get number of lines of text per page MOV CH,AL ;... in B MOV AL,LPSCNT ;is counter.. INC AL ;..at.. MOV LPSCNT,AL ;..limit.. CMP AL,CH ;..of lines-per-screen? JNB L_B23 RET ;no, return. L_B23: MOV LPSCNT,0 ;zero for lines-per-page counter MOV AL,LSPP ;number of lines to skip MOV CH,AL ;number of lines to skip PAGELST: CALL CRLF ;new line on LST DEC CH JNZ PAGELST CMP HEADFLG,TRUE ;test if print header true JNE PRN_HEAD ;if not true then... MOV AL,LTPP ;get lines to print per page ADD AL,2 ;add 2 lines MOV LTPP1,AL RET ;and return PRN_HEAD: CALL PHEAD ;...else print heading PAGE_RET: RET ;done PRN@CAN: ;check for list cancel CMP Out_Device,LLIST ; are we printing? JE pc_cont ; yes, check it out RET ; no, return pc_cont: CALL CST ;has key been hit OR AL,AL JNZ KEY_HIT RET ;if not, return KEY_HIT: CALL DKEYIN ;else get char and CHK@CAN: ; check for cancel CALL UCASE CMP AL,'Q' ;Q = quit JE L_B24 CMP AL,ESC ;so does ESC JE L_B24 CMP AL,CTRLC ;and ^C JE L_B24 RET ;return for another page L_B24: MOV AL,CR ;and send it a CALL TTYPE MOV Out_Device,DirCon ; restore the device JMP COMCAN ;cancel PHEAD: CMP Out_Device,LLIST ; printing to printer? JNE ph_ret MOV SI,Offset HEADMSG ;print heading CALL ILPRT MOV BX,(Offset S@FCB)+1 ;pt to file name CALL PRFN CALL CRLF ;new line CALL CRLF ;blank line ph_ret: RET ; m a s s c o p y ; copy files tagged using the 't' command. auto-erase if file exists ; on requested destination drive or in user area. MASS@COPY: MOV SI,Offset MSG33 CALL CPRMPT DSEG $ MSG33 DB 'Mass Copy (Y/N/V=Verify Overwrite)? ',0 CSEG $ CALL KEYIN CMP AL,'Y' ! JE MASC1 CMP AL,'V' ! JE MASC1 JMP NEUTRAL MASC1: MOV MCFLG,AL ;save answer MOV BX,RINGPOS ;save position MOV SRINGPOS,BX MOV BX,RING MOV RINGPOS,BX ;set position MASS@LP: MOV BX,RINGPOS ;get position ADD BX,12 ;get 1st possible tag location CMP Byte Ptr [BX],'*' ;get tag JE MCOPY ;copy filename with tag character (*) M@LP: MOV BX,RINGPOS ;re-entry point for next file mass-copy ADD BX,RingEntSize ;advance to next MOV RINGPOS,BX CMP BX,RINGEND ;at ring end yet? JNE MASS@LP ;loop 'till thru ring list. MF@EXIT: XOR AL,AL ;reset flags.. MOV FIRST@M,AL ;..for.. NOT AL ;..next.. MOV MFLAG,AL ;..mass-copy request. MOV BX,SRINGPOS ;reset ring position MOV RINGPOS,BX MOV BX,LOCBEG ;local ring JMP JFW0A ;rescreen ; c o p y ; copy source file at current 'ring' position to another drive. set-up ; fcb's and buffer area and check for correct keyboard inputs. contains ; auto-crc file copy verification. MCOPY: MOV MFLAG,0 ;zero flag to mass copy. JMPS COPY0M COPY: MOV MCFLG,'V' ;initialize verify flag COPY0M: IF CRC_Opt MOV CRCVAL,0 ;initialize 'crc' working value. ENDIF CALL RINGFCB ;move from 'ring' to 'sfcb' MOV BX,(Offset S@FCB)+12 ;set pointer to source extent field CALL INITFCB MOV Byte Ptr S@FCB+32,0 ;zero fcb 'cr' field MOV BX,(Offset S@FCB)+1 ;from point.. MOV DX,(Offset D@FCB)+1 ;..to point.. MOV CH,32 ;copy source 'fcb' to destination 'fcb' CALL MOVE ;..move across. MOV DX,(Offset S@FCB) ;open file for reading MOV CL,OPEN ;open function INT 224 INC AL ; 0ffh --> 00h if bad open JNZ COPY2 ;if okay, skip error message. MOV SI,Offset MsgNoOpen CALL ERMSG JMP NEUTRAL COPY2: MOV AL,FIRST@M ;by-pass prompt, drive/user compatibility.. OR AL,AL ;..test, and disk reset after.. JNZ COPY3M ;..1st time thru in mass-copy mode. MOV SI,Offset MSG34 CALL CPRMPT ;prompt for drive selection DSEG $ MSG34 DB 'Copy to DIR: ',0 CSEG $ CALL DEF@D@U ; either drives or user areas must be different MOV AL,Byte Ptr .FCB ;get requested drive from 'fcb' and.. CMP AL,Byte Ptr S@FCB JNE COPY3 ;branch if different MOV AL,R@U@A ;requested user area --> rua CMP AL,C@U@A ;current user area --> cua JNE COPY3 MOV SI,Offset MSG58 CALL ERMSG ;if not, show error condition: DSEG $ MSG58 DB 'Drives or User Areas must be different',0 CSEG $ JMP NEUTRAL ;try again? COPY3: CALL RESET ;make sure disk is read/write COPY3M: CALL ATCMD ;clear command line MOV SI,Offset MSG59 CALL ERMSG DSEG $ MSG59 DB 'Copying File ',0 CSEG $ MOV BX,(Offset D@FCB)+1 ;print file name CALL PRFNSX MOV AL,Byte Ptr .FCB ;put requested drive into.. MOV Byte Ptr D@FCB,AL ;..place in destination fcb. MOV AL,R@U@A ;toggle to.. CALL SET@USR ;..requested user area. MOV DX,(Offset D@FCB) ;search for duplicate MOV CL,SRCHF ; 'search first' function INT 224 INC AL ;if not found, 0ffh --> 00h. then.. JZ COPY5 ;go to 'make' function for new file. CMP MCFLG,'V' ;verify or auto erase JNE COPY4M ;..in mass-copy mode. MOV SI,Offset MSG35 CALL CPRMPT ;CPR2 - if found, ask to replace: DSEG $ MSG35 DB 'Overwrite Existing File (Y/N)? ',0 CSEG $ CALL KEYIN ;get answer CMP AL,'Y' ;if yes, then.. JZ COPY4M ;..delete and overlay. CMP MFLAG,0 ;zero is mass copy JNZ NOT_MASS MOV FIRST@M,0FFH ;set first pass flag JMP M@LP ;...and re-enter mass copy loop NOT_MASS: MOV AL,C@U@A ;reset to.. CALL SET@USR ;..current user area. JMP FORWARD ;if re-copy not wanted, to next position. COPY4M: MOV BX,(Offset D@FCB) ;pt to FCB CALL ATTRIB ;clear bytes in FCB and set attr of file MOV DX,(Offset D@FCB) ;delete file already existing MOV CL,ERASE ;erase function INT 224 COPY5: MOV DX,(Offset D@FCB) ;create new file and open for writing MOV CL,MAKE ;make function INT 224 INC AL ;if directory full, 0ffh --> 00h. JNZ COPY6 ;if not, branch. MOV SI,Offset MSG60 CALL ERMSG DSEG $ MSG60 DB 'Destination Directory Full',0 CSEG $ JMP LOOPFN ;if error, back to ring processor. COPY6: MOV BX,ERADR ADD BX,26 ;position cursor after file name CALL GOTOXY MOV EOFLAG,0 ;clear 'eof' flag. COPY6A: MOV AL,C@U@A ;reset user area.. CALL SET@USR ;..to current. MOV REC@CNT,0 ;clear current-record counter. MOV BX,BUFSTART ;set buffer start pointer.. MOV BUF@PT,BX ;..to begin pointer. ; read source file -- fill buffer memory or stop on 'eof' -- update 'crc' ; on-the-fly COPY7: MOV DX,BUF@PT ;set dma address to buffer pointer MOV CL,SETDMA INT 224 MOV DX,(Offset S@FCB) ;source 'fcb' for reading MOV CL,READ ;record read function INT 224 OR AL,AL ; 00h --> read okay JZ S@RD@OK DEC AL ;eof? JZ COPY8 ;yes, end-of-file, set 'eof' flag. MOV SI,Offset MsgBadRead CALL ERMSG JMP LOOPFN S@RD@OK: IF CRC_Opt MOV SI,BUF@PT MOV CX,128 COPY7A: LODSB ;get character and.. CALL UPDCRC ;..add to 'crc' value. LOOP COPY7A ;loop 'till record read finished ENDIF ADD BUF@PT,128 ;bump buffer pointer by record. MOV BX,REC@CNT ;bump buffer.. INC BX ;..record count and.. MOV REC@CNT,BX ;..store. CMP BX,REC@MAX ;compare to full-buffer. JNE COPY7 ;if not full, get next record. JMPS COPY9 ;full, start first write session. ; indicate end-of-file read COPY8: MOV EOFLAG,TRUE ;set 'eof' flag ; write 'read-file' from memory buffer to destination 'written-file' COPY9: MOV AL,R@U@A ;set user to requested.. CALL SET@USR ;..area. MOV BX,BUFSTART ;adjust buffer pointer.. MOV BUF@PT,BX ;..to start address. COPY10: CMP REC@CNT,0 ; buffer empty? JE COPY11 ;buffer empty, check 'eof' flag. DEC REC@CNT ;dec buffer record count for each write MOV DX,BUF@PT ;set up dma address MOV CL,SETDMA INT 224 ADD BUF@PT,128 ;bump pointer one record length MOV DX,(Offset D@FCB) ;destination file 'fcb' MOV CL,WRITE ;write record function INT 224 OR AL,AL ; 00h --> write okay JZ COPY10 ;okay, do next record. else.. MOV SI,Offset MSG63 CALL ERMSG ;..say disk write error. DSEG $ MSG63 DB 'Copy Disk Full',0 CSEG $ C@ERA: MOV DX,(Offset D@FCB) ;delete partial from directory. MOV CL,ERASE INT 224 ; reset 1st-time-thru tag flag.. MOV FIRST@M,0 ;..for continuation of mass copying. JMP LOOPFN ;back to ring COPY11: MOV AL,EOFLAG ;buffer all written, check for 'eof'. OR AL,AL JNZ L_C19 JMP COPY6A ;branch to read next buffer full L_C19: MOV DX,(Offset D@FCB) ;point at 'fcb' for file closure MOV CL,CLOSE INT 224 INC AL ;if no-close-error then.. IF CRC_Opt JNZ CRC@CMP ;..compare file crc's. ENDIF IF NOT CRC_Opt JZ close_error MOV AL,MFLAG ;if not mass-copy mode, return.. OR AL,AL ;..to next 'ring' position. JZ L_C22 JMP FORWARD ;else.. L_C22: NOT AL ;..set 1st-time-thru flag.. MOV FIRST@M,AL ;..and.. JMP M@LP ;..get next file to copy, if one. ENDIF close_error: MOV SI,Offset MSG64 CALL ERMSG DSEG $ MSG64 DB 'Copy Close Error',0 CSEG $ JMPS C@ERA ; read destination 'written-file' and compare crc's CRC@CMP: IF CRC_Opt MOV BX,CRCVAL ;transfer 'crc' value to.. MOV CRCVAL2,BX ;..new storage area. MOV CRCVAL,0 ;clear working storage to continue. MOV DX,TBUF MOV CL,SETDMA INT 224 MOV BX,(Offset D@FCB)+12 CALL INITFCB MOV DX,(Offset D@FCB) MOV CL,OPEN INT 224 INC AL ; 0ffh --> 00h if bad open JNZ L_C20 JMP BADCRC ;if bad open, just say 'bad-crc'. L_C20: XOR AL,AL ;zero 'fcb'.. MOV Byte Ptr D@FCB+32,AL ;..'cr' field. CRCWF1: MOV DX,(Offset D@FCB) MOV CL,READ INT 224 OR AL,AL ;read okay? JZ D@RD@OK ;yes, read more. DEC AL ;eof? JNZ L_C21 JMP FINCRC ;yes, finish up and make 'crc' comparison. L_C21: MOV SI,Offset MsgBadRead CALL ERMSG JMP NEUTRAL D@RD@OK: MOV SI,TBUF MOV CX,128 CRCWF2: LODSB ;get character to.. CALL UPDCRC ;..add to 'crc' value. LOOP CRCWF2 JMPS CRCWF1 ENDIF ; clear attributes of file (HL) and set attributes on disk ATTRIB: PUSH BX ;save ptr INC BX ;pt to first char MOV CX,11 ;11 Bytes ATTRIB1: AND Byte Ptr [BX],7FH ;mask byte INC BX ;pt to next LOOP ATTRIB1 ;count down POP DX ;pt to FCB MOV CL,ATTR INT 224 RET ; crc subroutines ;generator is x^16 + x^12 + x^5 + x^0 recommended by ccitt for asynchronous ;communications. produces the same results as public domain programs. ;check, comm7, mdm7, and modem7. ; initialize tables for fast crc calculations IF CRC_Opt INITCRC: MOV BX,(Offset CRCTBL) ; bx --> table MOV AL,0 ; al = table index GLOOP: MOV DX,0 ;initialize crc register pair XOR DH,AL MOV CX,8 LLOOP: SHL DX,1 JNB LSKIP XOR DX,(10H * 256) + 21H LSKIP: LOOP LLOOP MOV [BX],DH ;store high byte of crc.. INC BH MOV [BX],DL ;..and store low byte. DEC BH INC BX ;move to next table entry INC AL ;next index JNZ GLOOP RET UPDCRC: ;update 'crc' accumulator. PUSH BX MOV DX,CRCVAL ; put partial remainder in de MOV BH,0 XOR AL,DH MOV BL,AL ADD BX,(Offset CRCTBL) XOR DX,[BX] MOV CRCVAL,DX POP BX RET FINCRC: MOV AL,C@U@A ;reset user from 'requested'.. CALL SET@USR ;..to 'current' area. MOV BX,CRCVAL ;get written-file 'crc' CMP BX,CRCVAL2 ;..compare with read-file 'crc' JNE BADCRC ; if not equal, say copy-error. MOV SI,Offset MSG10 CALL ILPRT ; else say 'verified' DSEG $ MSG10 DB ' -- CRC Verified',0 CSEG $ MOV AL,MFLAG ;if not mass-copy mode, return.. OR AL,AL ;..to next 'ring' position. JZ L_C22 JMP FORWARD ;else.. L_C22: NOT AL ;..set 1st-time-thru flag.. MOV FIRST@M,AL ;..and.. JMP M@LP ;..get next file to copy, if one. BADCRC: MOV SI,Offset MSG66 CALL ERMSG DSEG $ MSG66 DB 'CRC ERROR',0 CSEG $ JMP FORWARD ;move to next 'ring' position ENDIF ; w o r k h o r s e r o u t i n e s ; inline print of message ILPRT: PUSH AX ilplp: LODSB AND AL,7FH JZ ilplp1 CALL TTYPE JMPS ilplp ILPLP1: POP AX RET ; output 'crlf' to console CRLF: MOV AL,CR CALL TTYPE MOV AL,LF ; conout routine TTYPE: PUSH AX ! PUSH CX ! PUSH DX ! PUSH BX MOV DL,AL MOV CL,Out_Device INT 224 POP BX ! POP DX ! POP CX ! POP AX RET ; direct I/O CST: ;Console status PUSH DX ! PUSH CX ! PUSH BX MOV DL,0FEH MOV CL,DIRCON INT 224 POP BX ! POP CX ! POP DX RET ; crt clear-line function CLR@L: MOV AL,CR CALL TTYPE MOV CX,30 ;blank # of characters on line MOV AL,' ' CL@LP: CALL TTYPE LOOP CL@LP RET ; conin routine (waits for response) KEYIN: MOV CL,RDCON INT 224 ; convert character in a-reg to upper case UCASE: CMP AL,'a' ;less than small 'a'? JB ucase_ok ;if so, no convert needed. CMP AL,'z' ; >small 'z'? JA ucase_ok ; no AND AL,5FH ; yes, convert ucase_ok: RET ; direct console input w/o echo (waits for input) DKEYIN: CALL CST OR AL,AL JZ DKEYIN PUSH BX ! PUSH CX ! PUSH DX MOV CL,DirCon MOV DL,0FFH INT 224 POP DX ! POP CX ! POP BX AND AL,7FH ; make ascii JMPS UCASE ; make upper ; convert keyboard input to upper case CONVERT: MOV BX,(Offset CMDBUF)+1 ; 'current keyboard buffer length'.. MOV CH,[BX] ;..to b-reg. OR CH,CH JNZ CONVLP JMP COMCAN ;if zero length, skip conversion. CONVLP: INC BX MOV AL,[BX] CALL UCASE MOV [BX],AL ;put back into buffer DEC CH JNZ CONVLP RET ; fill buffer with 'spaces' with count in b-reg FILL: MOV M,' ' ;put in space character INC BX DEC CH JNZ FILL ;no, branch. RET ; ignore leading spaces (ls) in buffer, length in c-reg. UNSPACE: MOV SI,DX ;get character MOV AL,[SI] CMP AL,' ' JZ L_C26 RET ;not blank, a file is entered. L_C26: INC DX ;to next character DEC CL JNZ L_C27 JMP COMCAN ;all spaces --> command recovery error L_C27: JMPS UNSPACE ; check for legal cp/m filename character -- return with carry set if illegal CKLEGAL: MOV SI,DX ;get character from de-pair MOV AL,[SI] INC DX ;point at next character CMP AL,' ' ;less than space? JNB L_C28 RET ;return carry if unpermitted character L_C28: PUSH BX PUSH CX CMP AL,'[' ;if greater than 'z', exit with.. JNB CKERR ;..carry set. MOV CH,Length CHR@TBL MOV BX,(Offset CHR@TBL) CHR@LP: CMP AL,M JZ CKERR INC BX DEC CH JNZ CHR@LP OR AL,AL ;clear carry for good character POP CX POP BX RET CKERR: POP CX POP BX STC ;error exit with carry set RET ; DSEG $ CHR@TBL DB ',',':',';','<','=','>' ;invalid character table CSEG $ ; print file name in S$FCB PRFNSX: PUSH BX ;save regs PUSH CX JMPS PRFNS0 PRFNS: PUSH BX ;affect only PSW PUSH CX MOV BX,(Offset S@FCB)+1 PRFNS0: CALL PRFN ;print file name POP CX ;restore POP BX RET ; print file name pted to by HL PRFN: MOV CX,8 ;8 chars PRFNS1: MOV AL,[BX] ;get char CALL TTYPE INC BX LOOP PRFNS1 MOV AL,'.' CALL TTYPE MOV CX,3 ;file type and fall thru PRFNS2: MOV AL,[BX] ;get char CALL TTYPE INC BX LOOP PRFNS2 RET ; print filename & tag in reverse video if at cursor AC@PRFN: IF ENH@VID CALL CUR@VID CALL PRFN ;print file name CMP M,'*' ;is it tagged? JNE AC@RET MOV AL,M ;print tag CALL TTYPE AC@RET: CALL STD@VID RET ENDIF ;ENH@VID IF NOT ENH@VID CALL PRFN MOV AL,M ;print tag JMP TTYPE ENDIF ;NOT ENH@VID ; print filename if not at cursor NC@PRFN: CMP Byte Ptr .11[BX],'*' ;is it tagged? JNE STD ;use std video if not tagged CALL TAG@VID JMPS NO@STD STD: CALL STD@VID NO@STD: CALL PRFN ;print file name MOV AL,[BX] CALL TTYPE JMP STD@VID ; filename from 'ring' to 'sfcb' RINGFCB: MOV BX,RINGPOS ;move name from ring to source 'fcb' MOV DX,(Offset S@FCB) ;place to move filename and.. MOV CH,12 ;..amount to move. ; move subroutine -- move b-reg # of bytes from hl-pair to de-pair MOVE: MOV AL,M ;get hl-pair referenced source byte AND AL,7FH ;strip cp/m 2.x attributes MOV SI,DX ;put to de-pair referenced destination MOV [SI],AL INC BX ;fix pointers for next search INC DX DEC CH JNZ MOVE RET ; initialize 'fcb' cp/m system fields (entry with hl-pair pointing to 'fcb') INITFCB: MOV CH,4 ;fill ex, s1, s2, rc counters with zeros. INITLP: MOV M,0 ;put zero (null) in memory INC BX DEC CH JNZ INITLP RET ; disk system reset -- login requested drive RESET: MOV CL,INQDISK ;determine and.. INT 224 ;..save.. MOV C@DR,AL ;..current drive. MOV CL,RESETDK ;reset system INT 224 MOV AL,R@DR ;make requested drive.. SET@DR: MOV DL,AL ;..current. MOV CL,LOGIN INT 224 ;return to caller RET ; set/reset (or get) user area (call with binary user area in a-reg) SET@USR: MOV DL,AL ; 0 --> 0, 1 --> 1, etc. GET@USR: MOV CL,SGUSER INT 224 ;return to caller RET ; decimal pretty print (h-reg contains msb; l-reg, the lsb.) DECOUT: MOV AL,5 ;set leading space count MOV LDSP,AL DECOU1: PUSH AX PUSH CX PUSH DX PUSH BX MOV AL,LDSP ;count down DEC AL MOV LDSP,AL MOV CX,-10 ;radix MOV DX,-1 DECOU2: ADD BX,CX ;sets.. INC DX JB DECOU2 ;..carry. MOV CX,10 ADD BX,CX XCHG BX,DX OR BX,BX JZ L_C33 CALL DECOU1 ; (recursive) L_C33: MOV AL,LDSP ; any spaces? OR AL,AL ; 0=none JZ DECOU4 MOV CH,AL ; count in B MOV AL,' ' DECOU3: CALL TTYPE DEC CH JNZ DECOU3 XOR AL,AL ;A=0 MOV LDSP,AL ;set flag DECOU4: MOV AL,DL ADD AL,'0' ;make ascii CALL TTYPE POP BX POP DX POP CX POP AX RET ; determine free storage remaining on selected drive FRESTOR: MOV CL,INQDISK ;determine current drive INT 224 ;returns 0 as a:, 1 as b:, etc. INC AL ;make 1 --> a:, 2 --> b:, etc. MOV Byte Ptr .FCB,AL MOV CL,GETPARM ;current disk parameter block INT 224 INC BX ;bump to.. INC BX MOV AL,ES:M ;..block shift factor. MOV BSHIFTF,AL ; 'bsh' INC BX ;bump to.. MOV AL,ES:M ;..block mask. MOV B@MASK,AL ; 'blm' INC BX ;bump to.. INC BX ;..get.. MOV DL,ES:M ;..maximum block number.. INC BX ;..double.. MOV DH,ES:M ;..byte. XCHG BX,DX MOV B@MAX,BX ; 'dsm' MOV CL,INQALC ;address of cp/m allocation vector INT 224 XCHG BX,DX ;get its length MOV BX,B@MAX INC BX MOV CX,0 ;initialize block count to zero GSPBYT: PUSH DX ;save allocation address MOV SI,DX MOV AL,ES:[SI] MOV DL,8 ;set to process 8 bits (blocks) GSPLUP: RCL AL,1 ;test bit JB NOT@FRE INC CX NOT@FRE: MOV DH,AL ;save bits DEC BX JZ END@ALC ;quit if out of blocks MOV AL,DH ;restore bits DEC DL ;count down 8 bits JNZ GSPLUP ;branch to do another bit POP DX ;bump to next count.. INC DX ;..of allocation vector. JMPS GSPBYT ;process it END@ALC: POP DX ;clear alloc vector pointer from stack MOV BL,CL ;copy # blocks to hl-pair MOV BH,CH MOV AL,BSHIFTF ;get block shift factor SUB AL,3 ;convert from sectors to thousands (k) JZ PRT@FRE ;skip shifts if 1k blocks FREK@LP: SHL BX,1 ;multiply blocks by k-bytes per block DEC AL ;multiply by 2, 4, 8, or 16. JNZ FREK@LP PRT@FRE: MOV DISKSP,BX ;save disk space RET ; ; Print free space on disk ; PRINT@FRE: MOV SI,Offset MSG67 CALL ERMSG ;position and set flags DSEG $ MSG67 DB 0 CSEG $ MOV BX,DISKSP CALL DECOUT ; # of free k-bytes in hl-pair MOV SI,Offset MSG11 CALL ILPRT DSEG $ MSG11 DB 'K Bytes on Disk',0 CSEG $ RET ; ZDNFIND: PUSH DX ; SAVE DE MOV DIRNAME,BX ; SAVE DIRECTORY NAME AWAY MOV CL,INQDISK ; SAVE CURRENT POSITION INT 224 MOV DISK,AL MOV DL,GET CALL GET@USR MOV USER,AL MOV BX,DIRNAME ; PT TO NAME JMPS SVDISK ; CHECK DU FORM FIRST ; ; LOOK AT START OF DU: FORM ; ON ENTRY, HL PTS TO FIRST CHAR OF DIRECTORY NAME ; SVDISK: MOV AL,[BX] ; GET DISK LETTER CMP AL,'A' ; DIGIT? JB USERCK ; IF NO DIGIT, MUST BE USER OR COLON SUB AL,'A' ; CONVERT TO NUMBER CMP AL,MDISK ; max drive limit? JNAE L_D3 MOV CL,MDRIVE DEC CL CMP CL,AL JE L_D3 JMP DIRNXX ; NAME IF OUT OF LIMIT L_D3: MOV DISK,AL ; SAVE DISK INC BX ; PT TO NEXT CHAR ; ; CHECK FOR USER ; USERCK: MOV AL,[BX] ; GET POSSIBLE USER NUMBER CMP AL,':' ; NO USER NUMBER JZ DIRNX ; EXIT IF SO CMP AL,' ' ; NO USER NUMBER JZ DIRNX OR AL,AL JZ DIRNX XOR AL,AL ; ZERO USER NUMBER MOV CH,AL ; B=ACCUMULATOR FOR USER NUMBER USRLOOP: MOV AL,[BX] ; GET DIGIT INC BX ; PT TO NEXT CMP AL,':' ; DONE? JZ USRDN CMP AL,' ' ; DONE? JZ USRDN SUB AL,'0' ; CONVERT TO BINARY JB DIRNXX ; NAME IF USER NUMBER ERROR CMP AL,10 JNB DIRNXX MOV CL,AL ; NEXT DIGIT IN C MOV AL,CH ; OLD NUMBER IN A ADD AL,AL ; *2 ADD AL,AL ; *4 ADD AL,CH ; *5 ADD AL,AL ; *10 ADD AL,CL ; *10+NEW DIGIT MOV CH,AL ; RESULT IN B JMPS USRLOOP USRDN: MOV AL,CH ; GET NEW USER NUMBER CMP AL,32 ; WITHIN RANGE? JNB DIRNXX ; NAME IF OUT OF RANGE MOV USER,AL ; SAVE IN FLAG ; ; VALID EXIT -- FOUND IT, SO LOAD BC AND EXIT FLAG; ON ENTRY, HL PTS TO : ; DIRNX: MOV CL,USER ; RETURN USER IN C, DISK IN B MOV CH,DISK MOV AL,0FFH ; SET NO ERROR OR AL,AL ; SET FLAGS POP DX ; RESTORE DE RET ; DIRNXX: POP DX XOR AL,AL RET ; message routines ; print VFILER banner BANNER: CALL CLS ;clear screen MOV BX,BANADR CALL GOTOXY MOV SI,Offset MSG12 CALL ILPRT ;print banner RET DSEG $ MSG12 DB ' VFILER (APC) CP/M-86 Ver ' DB VERS/10+'0','.',(VERS MOD 10)+'0' DB 0 CSEG $ ; home the cursor CUR@FIRST: MOV BX,CURHOME ; HOME ADDRESS MOV CURAT,BX ; SET CURSOR POSITION JMP GOTOXY ; last file position CUR@LAST: MOV BX,RINGPOS ; ADVANCE MOV LOCPOS,BX ; SET LOCAL POSITION CL0: ADD BX,RingEntSize CMP LOCEND,BX ; are we at end? JNE L_C34 ; no, keep going RET ; yes, done L_C34: MOV LOCPOS,BX ; update current position CALL CUR@NEXT ; move to next MOV BX,LOCPOS ; get current position back JMPS CL0 ; and test for end ; advance the cursor CUR@NEXT: MOV BX,CURAT ; COMPUTE NEW POSITION ADD BL,19 ; CHECK FOR NEW LINE CMP BL,70 ; SIZE OF EACH ENTRY JNB CN1 ; ADVANCE TO NEXT LINE MOV CURAT,BX ; NEW POSITION JMP GOTOXY CN1: MOV BL,Home_Col ; set home column MOV CURAT,BX ; SET NEW LINE AND FALL TO CUR$DOWN ; move cursor down one line CUR@DOWN: MOV BX,CURAT INC BH ; next line CMP BH,(EPS/4) + Home_Row ; beyond end of display? JNB CD1 ; yes, go to top MOV CURAT,BX JMP GOTOXY CD1: MOV BH,Home_Row MOV CURAT,BX JMP GOTOXY ; back up the cursor CUR@BACK: MOV BX,CURAT CMP BX,CURHOME ; are we at beginning? JE CUR@LAST ; yes, goto end of display CMP BL,Home_Col ; are we at first col? JE CB1 ; yes, go adjust new col SUB BL,19 ; no, back one entry MOV CURAT,BX ; and place it JMP GOTOXY CB1: ADD BL,19*3 ; back 3 entries DEC BH ; and one line MOV CURAT,BX ; place it JMP GOTOXY ; refresh screen REFRESH: MOV BX,CURAT ; SAVE CURSOR AND RING POSITIONS MOV SCURAT,BX MOV BX,RINGPOS MOV SRINGPOS,BX CALL CLS ; CLEAR SCREEN CALL CUR@OFF ; TURN OFF TERM. CURSOR CALL BANNER ; PRINT BANNER CALL NEWPOS ; DISPLAY FILES MOV BX,CPMADR ; COMMAND PROMPT MESSAGE CALL GOTOXY MOV SI,Offset LOG@DU@MSG CALL ILPRT ; PROMPT WITH DRIVE PREFIX MOV BX,FNADR ; PT TO WHERE FILE NAME IS PRINTED MOV BL,1 ; COL 1 FOR THIS MESSAGE CALL GOTOXY ; GO THERE MOV SI,Offset MSG15 CALL ILPRT DSEG $ MSG15 DB 'Current File:',0 CSEG $ MOV BX,SCURAT ; RESTORE CURSOR AND RING POSITIONS MOV CURAT,BX MOV BX,SRINGPOS MOV RINGPOS,BX CALL SETCUR ; RESTORE CURSOR ON SCREEN CALL CUR@ON ; TURN ON TERM. CURSOR RET ; refresh file display NEWPOS: CALL CUR@FIRST ; POSITION CURSOR AT FIRST POSITION MOV BX,LOCBEG ; PT TO FIRST FILE NAME NEWP1: MOV LOCPOS,BX ; SAVE LOCAL POSITION CMP BX,LOCEND ; AT END? JNE L_C35 JMP CUR@FIRST ; POSITION AT FIRST ENTRY AND RETURN L_C35: MOV CX,4 ; 4 SPACE MOV AL,' ' T4: CALL TTYPE LOOP T4 PUSH BX ; SAVE CURRENT LOCAL POSITION IN RING INC BX ; PT TO FILE NAME CALL NC@PRFN ; PRINT FILE NAME CALL CUR@NEXT ; ADVANCE CURSOR POP BX ; GET CURRENT LOCAL POSITION ADD BX,RingEntSize JMPS NEWP1 ; position cursor at CURAT SETCUR: MOV BX,CURAT IF ENH@VID ADD BX,4 ;advance 4 spaces CALL GOTOXY ENDIF IF NOT ENH@VID CALL GOTOXY MOV SI,Offset MSG16 CALL ILPRT DSEG $ MSG16 DB '--> ',0 CSEG $ ENDIF MOV BX,RINGPOS ;pt to current file name INC BX ;pt to first char CALL AC@PRFN RET ; clear cursor CLRCUR: MOV BX,CURAT IF ENH@VID ADD BX,4 ;advance 4 spaces CALL GOTOXY ENDIF IF NOT ENH@VID CALL GOTOXY MOV SI,Offset MSG17 CALL ILPRT DSEG $ MSG17 DB ' ',0 CSEG $ ENDIF MOV BX,RINGPOS ;pt to current file name INC BX ;pt to first char CALL NC@PRFN ;print file name RET ; command prompt CPRMPT: MOV BX,CPADR ; GET ADDRESS MPRINT: PUSH BX ; SAVE ADDRESS CALL GOTOXY CALL EREOL ; ERASE TO EOL POP BX ; GET ADDRESS CALL GOTOXY ; POSITION CURSOR JMP ILPRT ; PRINT MESSAGE AND RETURN ; working message WORKMSG: MOV SI,Offset MSG68 CALL ERMSG DSEG $ MSG68 DB 'Working ...',0 CSEG $ RET ; error message ERMSG: MOV AL,0FFH ; SET ERROR MESSAGE FLAG MOV ERMFLG,AL MOV BX,ERADR ; GET ADDRESS JMPS MPRINT ; print file size info FSNOTE: MOV SI,Offset MSG69 CALL ERMSG ; USE THIS ROUTINE DSEG $ MSG69 DB 'File Size of ',0 CSEG $ RET ; position for file size print ATFS: MOV BX,FSADR+RingEntSize ; POSITION FOR PRINT OF FILE SIZE JMP GOTOXY ; clear error message ERCLR: XOR AL,AL ; CLEAR FLAG MOV ERMFLG,AL MOV BX,ERADR ; POSITION CALL GOTOXY JMP EREOL ; ERASE TO EOL ; position at command prompt and clear it ATCMD: MOV BX,CPADR ; POSITION CALL GOTOXY CALL EREOL ; CLEAR MESSAGE MOV BX,CPADR ; REPOSITION JMP GOTOXY ; position at bottom of screen and prompt for continuation BOTTOM: MOV BX,BOTADR ; POSITION CALL GOTOXY MOV SI,Offset MSG18 CALL ILPRT DSEG $ MSG18 DB 'Strike Any Key to Continue -- ',0 CSEG $ JMP KEYIN IF (Offset $ - Offset Code_Start) MOD 10H EQ 1 RS 1 ENDIF DSEG $ ; s t o r a g e: initialized MsgNoOpen DB 'Can''t Open source file',0 MsgNoFile DB 'No File Found',0 MsgNoCmd DB 'Can''t Print/View CMD files',0 MsgBadRead DB 'File Read Error',0 LOG@DU@MSG DB ' : ' DB 'Command (? for Help)?',0 HEADMSG DB 'File: ',0 JOKER DB '???????????' ; *.* equivalent FIRST@M DB FALSE ; 1st time thru in mass-copy mode MFLAG DB TRUE ;multiple file copy flag --> 0 for mass copy TAG@TOT DW 0 ;summation of tagged file sizes CMDBUF DB 32 ;command buffer maximum length RS 33 ; uninitialized B@MASK RB 1 ;sec/blk - 1 BSHIFTF RB 1 ; # of shifts to multiply by sec/blk CANFLG RB 1 ;no-file-found cancel flag C@DR RB 1 ; 'current drive' CHARCNT RB 1 ;character count for tab expansion C@U@A RB 1 ; 'current user area' D@FCB RS 33 ;fcb for dest file/new name if rename DISK RB 1 ;selected disk for ZDNAME EOFLAG RB 1 ;file copy loop 'eof' flag ERMFLG RB 1 ;error message present flag FSDFLG RB 1 ;display file size flag (yes/no) FS@FLG RB 1 ;tag total versus file size flag GO_CNT RB 1 ; counter for goto cmd. LDSP RB 1 ;leading space count for DECOUT LPSCNT RB 1 ;lines-per-screen for 'view' MAXDR RB 1 ;max driver letter MDFLG RB 1 ;mass delete verify flag O@USR RB 1 ;store initial user area for exit Out_Device RB 1 ; used for TTYPE R@DR RB 1 ; 'requested drive' R@U@A RB 1 ; 'requested user area' S@FCB RS 36 ;fcb for source (random record) file TEST@RT RB 1 ;intermediate right-justify data T@UN@FG RB 1 ;tag/untag file summation switch USER RB 1 ;temp user buffer ; PAGEFLG RB 1 ;true for printing pages HEADFLG RB 1 ;true for printing header LTPP1 RB 1 ;modified lines per page MCFLG RB 1 ;mass copy verify flag ; IF (Offset $ - Offset Data_Start) MOD 2 NE 0 RS 1 ENDIF IF CRC_Opt CRCTBL RS 512 ;tables for 'crc' calculations ENDIF RS 128 ;..storage for buffer and local stack. STACK EQU $ B@MAX RW 1 ;highest block number on drive BUF@PT RW 1 ;copy buffer current pointer.. BUFSTART RW 1 ;..and begin pointer. IF CRC_Opt CRCVAL RW 1 ; 2-byte 'crc' value of working file and.. CRCVAL2 RW 1 ;..of finished source read-file. ENDIF CURAT RW 1 ;current cursor position DIRNAME RW 1 ;ptr to DIR prefix DISKSP RW 1 ;space remaining on disk LOCBEG RW 1 ;local beginning of ring LOCEND RW 1 ;local end of ring LOCPOS RW 1 ;local ring position (temp) RCNT RW 1 ; # of records in file and.. REC@CNT RW 1 ;..currently in ram buffer. REC@MAX RW 1 ;max record capacity of buffer RING RW 1 ;ptr to beginning of ring RINGI RW 1 ;ring sort pointer RINGJ RW 1 ;another ring sort pointer RINGEND RW 1 ;current ring end pointer RINGPOS RW 1 ;current ring position in scan SCURAT RW 1 ;save cursor position SRINGPOS RW 1 ;save ring position DATA_SEG RW 1 ;program data segment BUFENTRY EQU $ ; END ; DATE 10/10/83 11:21 last revision ; ENH@VID,HIDDEN,ON@OFF,CLOCK set to FALSE MDRIVE set to 0FF (no Mdrive) TITLE 'VFILER CP/M-86 VER 1.1' ; DATE 10/06/83 17:13 ; by:H.M. Van Tassell 120 Hill Hollow Rd, Watchung NJ 07060 (201)755-5372 ; ; This is a direct knock-off of Rich Conn's ZCPR2 utility VFILER ver 1.7 ; Please see SIG/M vol 145 for the original release and author credits. ; ; The original program was translated to 8086 code using XLT86. ; The unique ZCPR2 features have been mostly removed. More than 1000 ; lines of code were removed and/or changed to enable the translation. ; Some of the ZCPR2 code and all of the data storage area are intact. ; ; REVIEW! the equates, parameters, and routines at the start of the program. ; ; Additions to VFILER ver 1.7 in this CP/M-86 version include: ; 1. Enhanced video mode if your terminal has reverse, underline, and ; dim modes,either hidden or non-hidden video attributes. ; Terminal cursor on/off is also supported - stops screen flashing. ; 2. MDRIVE code was added to allow a gap in drive numbers. ; 3. Status request now only shows free space on disk ; 4. Command structure and names changed to suit my preferences. ; 5. New X command added to eXecute current CMD file. ; 6. CP/M-86 ver 1.1 supports chaining but not mult. commands so ; you can run a CMD file but will not return to VFILER. The new ; CP/M-86 Plus will support mult. commands-I'll do new version. ; 7. External HELP if you modify the HELP.HLP file to support VFILER ; and set HLP@FIL equate true. Note VILERr will search along ; the specified internal search path for HELP.CMD. ; 8. Printer output features: ; a. Quit allowed on ESC, Q ,or ^C key press ; b. Ask for paging and header options ; c. Date in header, you must supply your clock read routine ; d. Dont allow Printing (Viewing) of CMD files. ; 9. Verify Destination Copy Erase option added to mass copy ; ; ; TO GENERATE PROGRAM ; ASM86 VFILER $SZPZ ; GENCMD VFILER 8080 CODE[M3FF,XF00] ; ; Memory allowed in GENCMD is in paragraphs. The XF00 allows program to use ; memory up to 0F000h if available at program startup. ; ; If you must limit memory, then dont use ',XF00' in GENCMD tail, the 3FF ; allows room for most any number of directory entrys and a smaller size ; copy buffer. Increase if not large enough for big hard disk directorys. ; ..U= [~0yKtZ TNþGA؎мn  1 lj @ ] u@2SRZ[à 蠒 SRQ!YZ[þ` tXy< s ^ @ ѻ?u:tC^p S ?Cu C?MuC?D[þ+ t #    P؇ڋ ڱX$"Ê؀> t#ڀ> ti ډi i +ډi ڀ> uS2  C :, [o K# i  ] K t  z ;t| z   z ڋ ;tBڇڋ ;Ӈtr(Pt |  ;t| 5t   z  ;rڇډ| q  _ ;| u z  Ã  + 9z u |   .   @;z r. @t ωt ? @9| v2 t ljt Zu  @9| v @t ljt C ;t t z  t :tۃ t 5 PWX,As蠼 ,A:s :tIŢ b1 d2 M Vt%n  ; uh =h  v'h t.| | ; u |  | z ;u> Yu 0Z # D t>h t f , K > u + > ;> u;> tün ? q J C u * > t/ :s  < u]Ȣ >> u6 蠻 :s u> u  1À> t u uU ) -*þU Vu% dh ug & ] ຓ u 0P % r p p   t t ) p  C ; u r p > t2 p p  tܾKK g ^ u_ th tТg 0ZSC 'CZP$t Xð  PQRSЊ [ZYXRQS[YZð  ñût  ~ 9| uÉ~ ~ t Fst ut t ǀst ]t Tt tt t ;9ωt /t    XU1 9  t   0(.z ~ ;| u fSCN4[ۋt  CËt  C ûS[ ð ᾼû.a2 VkMbD>; Strike Any Key to Enter VFILER -- Login DIR: DIR Entry ErrorConfirm Quitting (Y/N)? Invalid Command:   FzFz+- F.F>F,z - File Forward / - This Summary > - File Forward E - Enter Command - File Backward L - Login DIR < - File Backward N - reNew Screen G - Go To a File S - Status of Disk + - Screen Forward Q - Quit VFILER - - Screen Backward X - eXecute CMD file -- Screen Movement -- File: ^S - LEFT ^D - RIGHT ^E - UP ^X - DOWN Screen: ^A - LEFT ^F - RIGHT Execute Current CMD File (Y/N)? Not a CMD fileEnter Command? Mass Tag or Untag (T/U)? Tagged:Status of Disk: Mass Delete (Y/N/V=Verify Each)? Delete (Y/N)? Deleting File List EmptyRename File to: File Already ExistsWildcards NOT allowedGoto Filename: Quits, Turns Up One Line, Other Keys Page Screen Print current file (Y/N)? *** Make Printer Ready ***Page the printer output (Y/N)? Print Header on every page (Y/N)? Printing Press ESC, or Q key to quit printing [View More...] Mass Copy (Y/N/V=Verify Overwrite)? Copy to DIR: Drives or User Areas must be differentCopying File Overwrite Existing File (Y/N)? Destination Directory FullCopy Disk FullCopy Close Error,:;<=>K Bytes on Disk VFILER (APC) CP/M-86 Ver 2.0Current File:Working ...File Size of Strike Any Key to Continue -- Can't Open source fileNo File FoundCan't Print/View CMD filesFile Read Error : Command (? for Help)?File: ???????????