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
/
ZSYS
/
SIMTEL20
/
ZCPR3
/
VMENU.MAC
< prev
next >
Wrap
Text File
|
2000-06-30
|
54KB
|
2,655 lines
; PROGRAM: VMENU
; VERSION: 1.0
; DATE: 26 June 84
; AUTHOR: Richard Conn
; PREVIOUS VERSIONS: None
;
z3env equ 0f400h
VERS EQU 10 ;version number
; VMENU is copyright (c) 1984 by Richard Conn
; All Rights Reserved
; VMENU may be used freely by the ZCPR3 Community
; VMENU is a screen-oriented, ZCPR3-specific file utility. It can not be
; installed to run under conventional CP/M. VMENU
; extensively employs cursor addressing to position a pointer on the
; screen, allow the user to manipulate the pointer (up, down, right, left,
; next screen, previous screen, GOTO file). The pointer points to files
; in the current user directory and displays the user's position dynamically
; on the screen. Once pointing to a file, user commands can be used to
; manipulate the file according to options presented in the menu displayed to
; the user. MENU and VMENU are compatible. In the way of being ZCPR3-
; specific, VMENU can chain to external programs via the Command Line Buffer
; and then return, and it recognizes Named Directories (so the user can log
; into B:, B4:, and MYDIR:, for example).
; VMENU is installed by Z3INS.
; VMENU works with ZCPR3 only, with 32k or more of RAM.
; VMENU can be assembled for use with a Z80 or 8080 microprocessor.
;
; SYSLIB, Z3LIB, and VLIB References
;
ext z3vinit,cls,gotoxy,ereol,vprint,envptr,stndout,stndend
ext pafdc,dutdir
ext qshell,getefcb,shpush,shpop,getcrt,getfn2,zprsfn
ext putshm,getshm,getsh,getzrun,getcl1,putzex,putcst
ext cin,cout,caps,crlf,bline,sksp
ext f$open,f$read,f$close,initfcb
ext retud
ext codend
;
; Basic Definitions
;
TRUE EQU 0FFH ;define true and..
FALSE EQU 0 ;..false.
;
DIM EQU 1 ;GOTO DIM
BRIGHT EQU 2 ;GOTO BRIGHT
ELTSIZ EQU 11 ;size of file name and type element
;
; User-Customized Definition
;
VMNAME MACRO ;;Name of VMENU
DB 'VMENU'
ENDM
VMNFILL MACRO ;;Spaces to fill out name to 8 chars
DB ' '
ENDM
;
Z80 EQU TRUE ;TRUE to use Z80 Instructions
WARMBOOT EQU FALSE ;set TRUE to warmboot on exit
EPS EQU 4*4 ;N lines x 4 cols per screen
; EPS = Entries Per Screen
;
; Command Line Builder Constants
;
FPESC EQU '%' ;escape char
FPDISK EQU 'D' ;disk only (D)
FPUSER EQU 'U' ;user only (U)
FPFILE EQU 'F' ;filename.typ
FPNAME EQU 'N' ;file name only
FPTYPE EQU 'T' ;file type only
FPPTR EQU 'P' ;file entry being pointed to
MNOTE EQU '#' ;denotes comment area in macro file
UIN1 EQU 27H ;single quote for user input
UIN2 EQU 22H ;double quote for user input
;
; Menu Constants
;
; 1 Special Menu Command Chars
RNM EQU '>' ;NEXT MENU
RNMP EQU '.' ;NEXT MENU PRIME (ALTERNATE)
RLM EQU '<' ;LAST MENU
RLMP EQU ',' ;LAST MENU PRIME (ALTERNATE)
RFM EQU '*' ;FIRST MENU
; 2 Internal Menu Control Chars
MCMD EQU ':' ;COMMAND TO JUMP TO ANOTHER MENU
PCHAR EQU '"' ;INDICATES AUTO PROMPT FOR SPECIFIC CMD
MINDIC EQU '#' ;MENU SECTION INDICATOR
MFIRST EQU '%' ;FIRST MENU INDICATOR
GOPTION EQU '-' ;GLOBAL OPTION INDICATOR
WOPTION EQU '!' ;ACTIVATES WAIT UPON RETURN
; 3 Menu Option Chars
XOPTION EQU 'X' ;DISABLE ZCPR3 RETURN
; 4 Miscellaneous
IBUFSZ EQU 254 ;SIZE OF INPUT LINE BUFFER
VARFLAG EQU '$' ;VARIABLE FLAG
;(FOLLOWED BY D,U,Fn,Nn,Tn)
CMDSEP EQU ';' ;ZCPR3 COMMAND SEPARATOR
;
; Cursor Positioning Addresses
;
EPSLINE EQU (EPS/4)+3 ;position of last line of EPS + 1
BANADR EQU 1*256+24 ;banner address
CURHOME EQU 3*256+1 ;home address of cursor
BOTADR EQU 23*256+1 ;bottom of screen
CPMADR EQU 22*256+1 ;command prompt message
CPADR EQU CPMADR+27 ;command prompt address (cursor position)
ERADR EQU CPMADR+256+15 ;error message
FNADR EQU 1*256+62 ;address of current file name
MOREADR EQU FNADR+1*256 ;address of more files message
DUADR EQU 1*256+4 ;address of current DU
;
; System Functions
;
RDCON EQU 1
WRCON EQU 2
PUNCH EQU 4
LIST EQU 5
DIRCON EQU 6
RDBUF EQU 10
CONST EQU 11
LOGIN EQU 14
OPEN EQU 15
CLOSE EQU 16
SRCHF EQU 17
SRCHN EQU 18
ERASE EQU 19
READ EQU 20
WRITE EQU 21
MAKE EQU 22
REN EQU 23
INQDISK EQU 25
SETDMA EQU 26
INQALC EQU 27
ATTR EQU 30
GETPARM EQU 31
SGUSER EQU 32
COMPSZ EQU 35
;
; System Addresses
;
OS$BASE EQU 000H ;system base..
CCP EQU 800H ;..and 'ccp' length in bytes.
GET EQU 0FFH ;get user area e-reg value
BDOS EQU OS$BASE+05H
FCB EQU OS$BASE+5CH
FCBEXT EQU FCB+12
FCBRNO EQU FCB+32
FCB2 EQU OS$BASE+6CH
TBUFF EQU OS$BASE+80H
TPA EQU OS$BASE+100H
;
; ASCII Definitions
;
CTRLC EQU 'C'-'@' ;..control-C..
CTRLD EQU 'D'-'@'
CTRLE EQU 'E'-'@'
CTRLR EQU 'R'-'@'
CTRLS EQU 'S'-'@' ;..XOFF..
CTRLX EQU 'X'-'@'
BEL EQU 07H ;..bell..
BS EQU 08H ;..backspace..
TAB EQU 09H ;..tab..
LF EQU 0AH ;..linefeed..
FF EQU 0CH ;..formfeed..
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.
;
; MACROS TO PROVIDE Z80 EXTENSIONS
; MACROS INCLUDE:
;
; BR - JUMP RELATIVE
; BRC - JUMP RELATIVE IF CARRY
; BRNC - JUMP RELATIVE IF NO CARRY
; BRZ - JUMP RELATIVE IF ZERO
; BRNZ - JUMP RELATIVE IF NO ZERO
; BJNZ - DECREMENT B AND JUMP RELATIVE IF NO ZERO
;
BR MACRO ?N ;;JUMP RELATIVE
IF Z80
.z80
jr ?N
.8080
ELSE
jmp ?N
ENDIF
ENDM
;
BRC MACRO ?N ;;JUMP RELATIVE ON CARRY
IF Z80
.z80
jr c,?N
.8080
ELSE
jc ?N
ENDIF
ENDM
;
BRNC MACRO ?N ;;JUMP RELATIVE ON NO CARRY
IF Z80
.z80
jr nc,?N
.8080
ELSE
jnc ?N
ENDIF
ENDM
;
BRZ MACRO ?N ;;JUMP RELATIVE ON ZERO
IF Z80
.z80
jr z,?N
.8080
ELSE
jz ?N
ENDIF
ENDM
;
BRNZ MACRO ?N ;;JUMP RELATIVE ON NO ZERO
IF Z80
.z80
jr nz,?N
.8080
ELSE
jnz ?N
ENDIF
ENDM
;
BJNZ MACRO ?N ;;DECREMENT B AND JUMP RELATIVE ON NO ZERO
IF Z80
.z80
djnz ?N
.8080
ELSE
dcr b
jnz ?N
ENDIF
ENDM
;
; END OF Z80 MACRO EXTENSIONS
;
;
; Environment Definition
;
if z3env ne 0
;
; External ZCPR3 Environment Descriptor
;
jmp start
db 'Z3ENV' ;This is a ZCPR3 Utility
db 1 ;External Environment Descriptor
z3eadr:
dw z3env
start:
lhld z3eadr ;pt to ZCPR3 environment
;
else
;
; Internal ZCPR3 Environment Descriptor
;
MACLIB Z3BASE.LIB
MACLIB SYSENV.LIB
z3eadr:
jmp start
SYSENV
start:
lxi h,z3eadr ;pt to ZCPR3 environment
endif
;
; Start of Program -- Initialize ZCPR3 Environment
; Once Environment is Initialized, One of Three Major Functions
; will be Performed:
; 1. VMENU will be installed as a Shell if invoked explicitly
; by user command
; 2. The VMENU Function will be performed if VMENU is invoked
; by ZCPR3 as a Shell and ZEX is not Running
; 3. A Command Line will be Input by VMENU from ZEX and Passed
; on to ZCPR3 without Processing
;
call z3vinit ;initialize the ZCPR3 Env and the VLIB Env
;
; Set Opsys Stack Pointer
;
if not WARMBOOT
lxi h,0 ;clear hl-pair then..
dad sp ;..add stack address.
shld stack
endif ;not warmboot
;
; Check to see if VMENU was executed as a shell
;
call qshell ;get and test message from ZCPR3
jz runsh ;execute shell procedures
;
; Initialize VMENU as a Shell
;
call shtest1 ;there must be a shell stack
call shtest2 ;there must be a command line buffer
;
; FUNCTION 1: Set Up VMENU as a Shell
; Run Shell Via Exit to Opsys
;
call getefcb ;determine name of program
brz shgo1 ;name not given, so use default
inx h ;pt to name
lxi d,filercmd ;define name of program
mvi b,8
call moveb ;copy name
shgo1:
lxi h,filercmd ;establish shell
call shpush ;push onto shell stack
brnz shgo2 ;error?
;
; Establish File Selection
; 3rd System File = Name of Menu File (2nd token)
; 4th System File = Name of AFN to Select Files (1st token)
;
call getfn2 ;setup file name
lxi d,11 ;use 2nd system file
dad d
xchg ;destination in DE
lxi h,joker ;pt to joker
mvi b,11 ;copy joker into 2nd system file
call move ;... so selection is on joker
xchg ;HL now pts to 3rd system file
push h ;save ptr to name of Menu File
lxi d,fcb2+1 ;pt to FCB
xchg
mvi b,11 ;copy 11 chars
call move
push d ;save ptr to file spec
lxi h,fcb+1 ;pt to FCB (use 4th system file name)
mvi b,11 ;copy 11 chars
call move
pop d ;get ptr to file spec
lxi h,joker ;make wild if none
mvi b,11 ;11 chars
ldax d ;get first char
cpi ' ' ;wild if space
cz moveb ;copy
ldax d
cpi '/' ;wild if option
cz moveb
pop d ;get ptr to name of menu file
lxi h,menufile ;pt to menu file name (default)
ldax d ;check for no file name given
mvi b,11 ;11 chars
cpi ' ' ;if none, set default
cz moveb
lxi b,8 ;check file type
dad b
xchg
dad b
xchg
ldax d ;check for file type
mvi b,3 ;3 chars
cpi ' ' ;if none, set default
cz move
;
; Print Done Message
;
simsg:
mvi a,0 ;default to menu 0
mvi b,1 ;shell message 1 contains menu number
call putshm
;
mvi b,0 ;shell message 0
mvi a,0 ;no wait
call putshm ;set shell message
;
call vprint
db ' Shell Installed',0
;
jmp os$ccp1 ;return to opsys
;
; Error in Shell Stack Installation
;
shgo2:
cpi 2 ;shell stack full
brnz shgo3
call vprint
db ' Shell Stack Full',0
ret
shgo3:
call vprint
db ' Shell Entry Size',0
ret
;
; VMENU was invoked as a Shell
; Check for ZEX Input in Progress
;
runsh:
call getzrun ;check ZEX message byte
jnz zexrun ;process ZEX command line if ZEX running
;
; Check for Delay Before Resuming VMENU and Delay if Set
;
mvi b,0
call getshm ;get shell message 0
ani 80h ;check MSB
cnz sak ;pause for input
mvi a,0 ;set normal command status
call putcst
;
; FUNCTION 2: Run VMENU and Perform Main Function
;
call setup ;init buffers and pointers
call stackset ;setup stack
;
; Begin VMENU Processing
;
runsh2:
call stackset ;reset stack
call fileload ;load files
call setscr ;set up screen display variables
call findcfile ;locate current file
call menuload ;load menu file
;
; Entry Point for Command Processing
; Display Screen and Input/Process Command
;
runsh3:
call stackset ;reset stack
call refresh ;refresh screen display
;
; Display Current File and Input/Process Command
;
loopfn:
call prcfn1 ;print current file name
;
; Input/Process Command
;
loop:
call stackset ;reset stack
call prompt ;get command from user
call cmdproc ;process command in A
call icmsg ;print invalid command msg
br loop ;continue
;
; Set Stack Pointer
;
stackset:
pop d ;get return address
lhld ibuf ;top of stack
sphl ;start local stack
push d ;return address on new stack
ret
;
; Check for Presence of Shell Stack
;
shtest1:
call getsh ;get shell stack data
rnz
pop psw ;clear stack
call vprint
db 'No Shell Stack',0
ret
;
; Check for Command Line
;
shtest2:
call getcl1 ;get command line data
rnz
pop psw ;clear stack
call vprint
db 'No Cmd Line',0
ret
;
; FUNCTION 3: Run ZEX on Top of VMENU
; Accept Command Line and Pass it to ZCPR3
;
zexrun:
call vprint ;print prompt
db 'VMENU> ',0
mvi a,1 ;tell ZEX that it is prompted
call putzex
call getcl1 ;pt to command line buffer
mov a,l ;set ptr to first char
adi 4
mov c,a
mov a,h
aci 0
mov b,a ;BC pts to first char
mov m,c ;store low
inx h
mov m,b ;store high
inx h ;pt to char count
xchg ;... in DE
mvi c,rdbuf ;input line via BDOS
push d ;save ptr
call bdos
pop h ;pt to char count
inx h
mov e,m ;get char count
inx h ;pt to first char
push h ;save ptr
mvi d,0 ;DE=char count
dad d
xra a ;A=0
mov m,a ;store ending 0
pop h ;pt to first char
call sksp ;skip to first non-blank character
mov a,m ;get it
cpi ';' ;comment line?
jz zexrun1 ;process comment line
call putzex ;resume ZEX (A=0)
call putcst ;set command status to normal (A=0)
ret ;return to opsys
zexrun1:
call crlf ;new line
jmp zexrun
;
;**************************************************
;
; CRT Routine for VMENU
;
VCLS:
CALL CLS ;try to clear the screen
RNZ ;OK if done
PUSH H ;save regs
PUSH B
CALL GETCRT ;get CRT Data
INX H ;get number of lines on screen
MOV B,M ;B=number of lines
VCLS1:
CALL CRLF ;new line
BJNZ VCLS1
POP B ;restore regs
POP H
RET
;
; EREOL Routine for VMENU
;
VEREOL:
CALL EREOL ;try to erase to EOL
RNZ ;OK if done
PUSH B ;save count
MVI A,' ' ;space out
CALL VEREOL1 ;send B spaces
POP B ;get count
MVI A,BS ;backspace in
VEREOL1:
CALL COUT ;send char
BJNZ VEREOL1 ;count down
RET
;
; Setup Screen Display Variables
;
SETSCR:
LXI H,CURHOME ;set cursor home
SHLD CURAT
LHLD RING ;set ring position
CALL SETMORE ;set more flag if more files on screen
;
; Entry to Reset Ring Position at HL
;
SETSCR1:
SHLD RINGPOS ;set current file to first file in ring
;
; Entry to Reset Local Ring Position at HL
;
SETSCR2:
SHLD LOCBEG ;front of ring
LXI D,EPS*ELTSIZ ;new end?
DAD D
XCHG
LHLD RINGEND ;end of ring
XCHG
CALL CMPDEHL
BRC SETSCR3
XCHG
SETSCR3:
XCHG
SHLD LOCEND
RET
;
; Set More Flag - Count Files on Screen and See if Display Exceeded
;
SETMORE:
PUSH H ;SAVE REGS
PUSH D
PUSH B
XRA A ;CLEAR FLAG
STA MORE
MVI B,EPS ;COUNT DOWN
LXI D,ELTSIZ ;SIZE OF ELEMENT
SETMORE1:
MOV A,M ;GET CHAR
ORA A ;DONE IF ZERO
JZ SETMDONE
DAD D ;PT TO NEXT
DCR B ;COUNT DOWN
JNZ SETMORE1
MOV A,M ;GET CHAR
ORA A ;DONE IF ZERO
JZ SETMDONE
MVI A,0FFH ;SET FLAG
STA MORE
SETMDONE:
POP B ;RESTORE REGS
POP D
POP H
RET
;
; Search for Current File starting at position in HL
;
FINDCFILE:
CALL GETFN2 ;get ptr to current file
LXI D,11
DAD D ;... which is 2nd System File
XCHG ;... ptr in DE
;
; Next group of EPS files for file display
;
FINDCF1:
LXI H,CURHOME ;set cursor
SHLD CURAT
LHLD LOCBEG ;pt to first file in list
MVI B,EPS ;number of files in display
;
; Check current file
;
FINDCF2:
SHLD RINGPOS ;set position of current ring element
;
; Check for end of file ring
;
MOV A,M ;end of list?
ORA A ;done if so
BRZ FINDCF4
;
; Compare candidate file against file in ring
;
PUSH H ;save ptr to file
PUSH D ;save ptr to System File
PUSH B ;save count
MVI B,ELTSIZ ;compare
CALL CMPSTR
POP B ;get count
POP D ;get ptr to System File
POP H ;get ptr to file
BRZ FINDCF5 ;we found it
BRC FINDCF5 ;we found following file
;
; Advance to next file in ring
;
PUSH B ;save count
LXI B,ELTSIZ ;pt to next element
DAD B
;
; Advance to next file on screen
;
PUSH H
LHLD CURAT ;get cursor position
MOV A,L
ADI 19 ;advance cursor
MOV L,A
CPI 70
BRC FINDCF3
MOV A,H ;get current line
LXI H,CURHOME ;get home row
MOV H,A ;set current line
INR H ;next line
FINDCF3:
SHLD CURAT ;set cursor
POP H
POP B ;get count
;
; Count down files in current display
;
BJNZ FINDCF2 ;count down
MOV A,M ;any following elements in ring?
ORA A ;0=no
BRZ FINDCF4
;
; End of current display - set new display
;
SHLD LOCBEG ;new local beginning
BR FINDCF1 ;continue search
;
; File beyond end of file display - set pointers to first file
;
FINDCF4:
LXI H,CURHOME ;set cursor to first file
SHLD CURAT
LHLD RING ;pt to first file
SHLD RINGPOS
SHLD LOCBEG ;set local beginning
;
; Done - Set Local Ring
;
FINDCF5:
LHLD LOCBEG ;pt to local ring
JMP SETSCR2
;
; Display file name of current file
; Side Effect: Change Name of 2nd System File to Current File
;
PRCFN1:
LXI H,FNADR ;position cursor for file name print
CALL GOTOXY
CALL GETFN2 ;pt to system file name
LXI D,11 ;pt to 2nd System File Name
DAD D
XCHG ;... in DE
LHLD RINGPOS ;pt to current file name
MVI B,11 ;copy into 2nd System File Name
CALL MOVEB
JMP PRFN ;print file name
;
; Process Command
;
ICMSG:
CALL ERMSG
DB 'Invld Cmd: ',0
MOV A,B ;get char
CPI ' ' ;expand if less than space
JNC COUT
MVI A,'^' ;control
CALL COUT
MOV A,B ;get byte
ADI '@' ;convert to letter
JMP COUT ;return for loop processing
;
; SET UP BUFFERS
;
SETUP:
CALL RETUD ;get home DU
MOV A,B
STA H$DR ;home drive
MOV A,C
STA H$U$A ;home user area
CALL CODEND ;start of free space
LXI D,256 ;256 bytes/unit
DAD D
SHLD IBUF ;input line buffer and top of stack
MVI M,IBUFSZ ;number of bytes in line
DAD D
SHLD EXPLINE ;expansion line
DAD D
SHLD MENUFCB ;dummy FCB
DAD D ;next page
SHLD BUFFER ;free space to end of TPA
;
; Begin Further Inits
;
LHLD ENVPTR ;pt to ZCPR3 Env Desc
LXI D,80H+10H ;pt to cursor commands
DAD D
LXI D,CTABLE ;pt to area
MVI B,4 ;4 commands
CURINIT:
MOV A,M ;get command
STAX D ;put it
INX H ;pt to next
INX D
INX D
INX D
BJNZ CURINIT
;
LHLD BUFFER ;base address
SHLD RING ;beginning of ring
;
XRA A ;clear error message flag
STA ERMFLG
;
RET
; e x i t
; return to ccp
;
; Entry point for VMENU exit
;
OS$CCP:
CALL SHPOP ;clear shell stack
;
; Entry point for command line exec
;
OS$CCP1:
LXI D,TBUFF ;..tidy up..
MVI C,SETDMA ;..before going home.
CALL BDOS
IF WARMBOOT
JMP OS$BASE
ENDIF ;warmboot
IF NOT WARMBOOT
LHLD STACK ;put pointer..
SPHL ;..back to 'sp'.
RET ;return to ccp
ENDIF ;not warmboot
;
; FLOAD loads the files into the buffer, setting up the ring
; Return with NZ if load OK, Z if no files loaded
;
FILELOAD:
;
; Set up file name from System File 4
; Select all files if no entry in System File 4
;
CALL GETFN2 ;pt to first system file name
LXI D,11*3 ;pt to 4th file name
DAD D
LXI D,JOKER ;setup Joker if none
XCHG
LDAX D ;any chars?
MVI B,11 ;11 bytes
CPI ' '
CZ MOVEB
XCHG ;HL pts to system file name
LXI D,FCB+1 ;pt to FCB
MVI B,11 ;11 bytes
CALL MOVEB
;
; Build ring with filename positioned in default FCB area
;
LHLD RING ;pt to ring
MVI B,ELTSIZ ;set first element to 'noname'
FILEL1:
MVI M,1 ;store ^A's
INX H ;pt to next
BJNZ FILEL1
SHLD RINGPOS ;set ring position
SHLD RINGEND ;set ring end in case this is the only one
MVI M,0 ;store ending 0
MVI C,SETDMA ;initialize dma address..
LXI D,TBUFF ;..to default buffer.
CALL BDOS
XRA A ;clear search 'fcb'..
STA FCBEXT ;extent byte..
STA FCBRNO ;..and record number.
LXI D,FCB ;default FCB for search
CMA
MVI C,SRCHF ;..of first occurrence.
CALL BDOS
INR A ; 0ffh --> 00h if no file found
RZ
; put each found name in ring. a-reg --> offset into 'tbuf' name storage
SETRING:
DCR A ;un-do 'inr' from above and below
ADD A ;times 32 --> position index
ADD A
ADD A
ADD A
ADD A
ADI TBUFF+1 ;add page offset and..
MOV L,A ;..put address into..
MVI H,0 ;..hl-pair.
XCHG
LHLD RINGPOS ;pointer to current load point in ring
XCHG
MVI B,ELTSIZ ;move name to ring
CALL MOVE
XCHG ;de-pair contains next load point address
SHLD RINGPOS ;store and search..
MVI C,SRCHN ;..for next occurrence.
LXI D,FCB ;filename address field
CALL BDOS
INR A ;if all done, 0ffh --> 00h.
BRNZ SETRING ;if not, put next name into ring.
;
; All filenames in ring -- setup ring size and copy-buffer start point
;
LHLD RINGPOS ;next load point of ring is start of buffer
SHLD RINGEND ;set ring end..
MVI M,0 ;store ending 0
;
; Sort ring of filenames
;
SORT:
LHLD RING ;initialize 'i' sort variable and..
SHLD RINGI
LXI D,ELTSIZ ;..also 'j' variable.
DAD D
SHLD RINGJ
;
; Main Sort Loop
;
SORTLP:
LHLD RINGJ ;compare names 'i & j'
XCHG
LHLD RINGI
PUSH H ;save position pointers..
PUSH D ;..for potential swap.
; sort by file name and type
MVI B,ELTSIZ ; # of characters to compare
CALL CMPSTR ;do comparison
; final test for swapping purposes
NOCMP:
POP D
POP H
MVI B,ELTSIZ
BRNC NOSWAP
;
; Swap if 'j' string larger than 'i'
;
SWAP:
MOV C,M ;get character from one string..
LDAX D ;..and one from other string.
MOV M,A ;second into first
MOV A,C ;first into second
STAX D
INX H ;bump swap pointers
INX D
BJNZ SWAP
NOSWAP:
LHLD RINGJ ;increment 'j' pointer
LXI D,ELTSIZ
DAD D
SHLD RINGJ
XCHG ;see if end of 'j' loop
LHLD RINGEND
CALL CMPDEHL
BRNZ SORTLP ;no, so more 'j' looping.
LHLD RINGI ;bump 'i' pointer
LXI D,ELTSIZ
DAD D
SHLD RINGI
DAD D ;set start over 'j' pointer
SHLD RINGJ
XCHG ;see if end of 'i' loop
LHLD RINGEND
CALL CMPDEHL
BRNZ SORTLP ;must be more 'i' loop to do
RET
;
; left to right compare of two strings (de-pair points to 'a' string;
; hl-pair, to 'b'; b-reg contains string length.)
;
CMPSTR:
LDAX D ;get an 'a' string character and..
CMP M ;..check against 'b' string character.
RNZ ;if not equal, set flag.
INX H ;bump compare..
INX D ;..pointers and..
BJNZ CMPSTR ;..do next character.
RET
;
; Process command from table
;
CTPROC:
MOV B,A ;command in B
LXI H,CTABLE ;pt to table
MOV A,M ;any cursor commands?
ORA A
JNZ CTPR1
LXI H,CTAB1
;
; Command table scanner
; HL = Table
; B = Command Letter
;
CTPR1:
MOV A,M ;get table command char
ORA A ;end of table?
RZ ;done if so
CMP B ;match?
BRZ CTPR2
INX H ;skip to next entry
INX H
INX H
BR CTPR1
CTPR2:
INX H ;pt to address
MOV A,M ;get low
INX H
MOV H,M ;get high
MOV L,A
XTHL ;address on stack
RET ;"jump" to routine
; Command Table
CTABLE:
DB 0 ;user cursor positioning
DW UP
DB 0
DW DOWN
DB 0
DW FORWARD
DB 0
DW REVERSE
CTAB1:
DB CTRLC ;if exit, then to opsys
DW OS$CCP
DB CTRLR ;screen refresh?
DW RUNSH3
DB CTRLE ;system cursor positioning
DW UP
DB CTRLX
DW DOWN
DB CTRLD
DW FORWARD
DB CTRLS
DW REVERSE
DB CR ;nop
DW LOOP
DB '+' ;jump forward
DW JUMPF
DB '-' ;jump backward
DW JUMPB
DB ' ' ;go forward
DW FORWARD
DB BS ;back up?
DW REVERSE
;
DB 0 ;end of table
;
; COMMAND: - (Previous Screen)
;
JUMPB:
LXI H,CURHOME ;set cursor home
SHLD CURAT
LHLD RING ;at front?
XCHG
LHLD LOCBEG
CALL CMPDEHL
BRZ JUMPBW ;back up and wrap around
SHLD LOCEND ;set new end
LXI D,-EPS*ELTSIZ ;back up
DAD D
SHLD LOCBEG ;new beginning
SHLD RINGPOS ;new position
JMP RUNSH3
JUMPBW:
LHLD LOCBEG ;at first screen?
XCHG
LHLD RING ;pt to first element of ring
CALL CMPDEHL
BRZ JBW0 ;advance to end
LXI H,-EPS*ELTSIZ ;back up
DAD D ;first element of new local ring
BR JFW0
JBW0:
LXI D,EPS*ELTSIZ ;pt to next screen
DAD D
XCHG
LHLD RINGEND
CALL CMPDEHL
XCHG
BRZ JBW1
BRC JBW0
JBW1:
LXI D,-EPS*ELTSIZ
DAD D ;pt to first element of new local ring
BR JFW0
;
; COMMAND: + (Next Screen)
;
JUMPF:
LXI H,CURHOME ;set cursor to home
SHLD CURAT
LHLD LOCEND ;see if Local End <= Ring End
XCHG
LHLD RINGEND
CALL CMPDEHL
BRZ CMDLOOP
LHLD LOCEND ;new screen starting at LOCEND
BR JFW0
;
; Reset to Beginning of RING and Resume Command Looping
;
CMDLOOP:
CALL SETSCR ;reset all screen pointers
CMDLRET:
JMP RUNSH3
;
; Reset RING Position to HL
;
JFW0:
CALL SETSCR1 ;reset RINGPOS on ...
BR CMDLRET
;
; Reset Local Ring to HL
;
JFW0A:
CALL SETSCR2 ;reset LOCBEG on ...
BR CMDLRET
;
; COMMAND: ' ', Left-Arrow
;
FORWARD:
CALL CLRCUR ;clear cursor
CALL FOR0 ;position on screen and in ring
CALL SETCUR ;set cursor
JMP LOOPFN
; advance routine
FOR0:
LHLD RINGPOS ;at end of loop yet?
LXI D,ELTSIZ ;i.e., will we be at end of loop?
DAD D
XCHG
LHLD LOCEND
CALL CMPDEHL ;compare 'present' to 'end'
BRNZ FORW ;to next print position
CALL CUR$FIRST ;position cursor
LHLD LOCBEG ;set position pointer to beginning and..
SHLD RINGPOS
RET
FORW:
LHLD RINGPOS ;advance in ring
LXI D,ELTSIZ
DAD D
SHLD RINGPOS ;new position
CALL CUR$NEXT ;position cursor
RET
;
; COMMAND: BS, Right-Arrow
;
REVERSE:
CALL CLRCUR ;clear cursor
CALL REV0 ;position on screen and in ring
CALL SETCUR ;set cursor
JMP LOOPFN
; Back Up Routine
REV0:
LHLD LOCBEG
XCHG
LHLD RINGPOS ;see if at beginning of ring
CALL CMPDEHL
BRNZ REV1 ;skip position pointer reset if not..
CALL CUR$LAST ;end of local ring
LHLD LOCEND ;set to end +1 to backup to end
LXI D,-ELTSIZ
DAD D
SHLD RINGPOS
RET
REV1:
CALL CUR$BACK ;back up 1
REV2:
LHLD RINGPOS
LXI D,-ELTSIZ ;one ring position..
DAD D ;..backwards.
SHLD RINGPOS
RET
;
; COMMAND: Up-Arrow
;
UP:
CALL CLRCUR ;clear cursor
LHLD RINGPOS ;see if wrap around
LXI D,-ELTSIZ*4 ;4 entries
DAD D
XCHG
LHLD LOCBEG ;beginning of local screen
CALL CMPDEHL
BRC UP2 ;wrap around
MVI B,4 ;back up 4 entries
UP1:
PUSH B ;save count
CALL REV0 ;back up in ring and on screen (no print)
POP B ;get count
BJNZ UP1
BR DOWN1A
UP2:
LHLD RINGPOS ;advance to beyond end
LXI D,ELTSIZ*4
DAD D
XCHG
LHLD LOCEND ;compare to local end
XCHG
CALL CMPDEHL
BRZ DOWN1A ;at end, so too far
BRC DOWN1A ;beyond end, so back up
SHLD RINGPOS ;new ring position
LHLD CURAT ;advance cursor
INR H ;next line
SHLD CURAT
BR UP2
;
; COMMAND: Down-Arrow
;
DOWN:
CALL CLRCUR ;clear cursor
LHLD RINGPOS ;see if wrap around
LXI D,ELTSIZ*4 ;4 entries
DAD D
XCHG
LHLD LOCEND ;end of local screen
XCHG
CALL CMPDEHL
BRZ DOWN2 ;wrap around
BRC DOWN2 ;wrap around
MVI B,4 ;forward 4 entries
DOWN1:
PUSH B ;save count
CALL FOR0 ;advance in ring and on screen (no print)
POP B ;get count
BJNZ DOWN1
DOWN1A:
CALL SETCUR ;set cursor
JMP LOOPFN
DOWN2:
LHLD CURAT ;preserve column
MOV B,L ;column number in B
LXI H,CURHOME ;home position
SHLD CURAT ;set new position
LHLD LOCBEG ;beginning of local ring
SHLD RINGPOS ;new ring position
DOWN3:
LHLD CURAT ;check for at top of column
MOV A,L ;get col
CMP B ;there?
BRZ DOWN1A
LHLD RINGPOS ;advance in ring
LXI D,ELTSIZ ;ELTSIZ bytes/entry
DAD D
SHLD RINGPOS
LHLD CURAT ;get cursor position
LXI D,19 ;advance 19 bytes/screen entry
DAD D
SHLD CURAT
BR DOWN3
;
;**************************************************
;
; WORKHORSE Routines
;
; conin routine (waits for response)
;
KEYIN:
CALL CIN ;get input
JMP CAPS ;capitalize
;
; Fill buffer with 'spaces' with count in b-reg
;
FILL:
MVI M,' ' ;put in space character
INX H
BJNZ FILL ;no, branch.
RET
;
; Check for legal filename character -- return with carry set if illegal
;
CKLEGAL:
LDAX D ;get character from de-pair
INX D ;point at next character
CPI ' ' ;less than space?
RC ;return carry if unpermitted character
PUSH H
PUSH B
CPI '[' ;if greater than 'z', exit with..
BRNC CKERR ;..carry set.
MVI B,CHR$TEND-CHR$TBL
LXI H,CHR$TBL
CHR$LP:
CMP M
BRZ CKERR
INX H
BJNZ CHR$LP
ORA A ;clear carry for good character
POP B
POP H
RET
CKERR:
POP B
POP H
STC ;error exit with carry set
RET
CHR$TBL:
DB ',',':',';','<','=','>' ;invalid character table
CHR$TEND:
DS 0
;
; Print file name pted to by HL
; Advance HL 11 bytes
;
PRFN:
MOV A,M ;check for 'noname'
CPI 1 ;no name?
BRZ PRFN1
MVI B,8 ;8 chars
CALL PRFNS1
MVI A,'.'
CALL COUT
MVI B,3 ;file type and fall thru
PRFNS1:
MOV A,M ;get char
CALL COUT
INX H ;pt to next
BJNZ PRFNS1
RET
PRFN1:
CALL VPRINT
DB ' No File'
DB ' '
DB ' ',0
MVI B,11 ;advance 11 chars
PRFN2:
INX H ;pt to next
BJNZ PRFN2
RET
;
; move subroutine -- move b-reg # of bytes from hl-pair to de-pair
;
MOVE:
MOV A,M ;get hl-pair referenced source byte
ANI 7FH ;strip attributes
STAX D ;put to de-pair referenced destination
INX H ;fix pointers for next search
INX D
BJNZ MOVE
RET
MOVEB:
PUSH H ;SAVE HL, DE
PUSH D
CALL MOVE
POP D ;RESTORE DE, HL
POP H
RET
;
; Compare de-pair to hl-pair and set flags accordingly
;
CMPDEHL:
MOV A,D ;see if high bytes set flags
CMP H
RNZ ;return if not equal
MOV A,E
CMP L ;low bytes set flags instead
RET
;
; Shift hl-pair b-reg bits (-1) to right (divider routine)
;
SHIFTLP:
DCR B
RZ
MOV A,H
ORA A
RAR
MOV H,A
MOV A,L
RAR
MOV L,A
BR SHIFTLP
;
;**************************************************
;
; MESSAGE Routines
;
; Print VMENU Banner
;
BANNER:
CALL VCLS ;clear screen
LXI H,BANADR
CALL GOTOXY
CALL VPRINT ;print banner
DB 'VMENU, Version '
DB VERS/10+'0','.',(VERS MOD 10)+'0'
IF Z80
DB ' ',DIM,'[Z80 Code]',BRIGHT
ELSE
DB ' ',DIM,'[8080 Code]',BRIGHT
ENDIF
DB 0
RET
;
; Print DU:DIR and MORE Message
;
DIRMORE:
LXI H,DUADR ; POSITION CURSOR
CALL GOTOXY
CALL RETUD ; GET CURRENT DISK AND USER
MOV A,B ; PRINT DISK
ADI 'A'
CALL COUT
MOV A,C ; PRINT USER
CALL PAFDC ; FLOADING DECIMAL
MVI A,':'
CALL COUT
CALL DUTDIR ; GET DIR NAME
BRZ NODIR
MVI B,8 ; 8 CHARS IN NAME
PRNAME:
MOV A,M ; GET CHAR
CPI ' '+1 ; CHECK FOR DONE
BRC PRMORE
CALL COUT ; PRINT CHAR
INX H
BJNZ PRNAME
BR PRMORE
NODIR:
CALL VPRINT
DB 'Noname',0
PRMORE:
LDA MORE ; CHECK FLAG
ORA A ; 0=NO MORE
RZ
LXI H,MOREADR
CALL GOTOXY ; POSITION CURSOR
CALL VPRINT
DB DIM,'[More Files]',BRIGHT,0
RET
;
; Home the Cursor
;
CUR$FIRST:
LXI H,CURHOME ; HOME ADDRESS
SHLD CURAT ; SET CURSOR POSITION
JMP GOTOXY
;
; Last File Position
;
CUR$LAST:
LHLD RINGPOS ; ADVANCE
SHLD LOCPOS ; SET LOCAL POSITION
CL0:
LXI D,ELTSIZ
DAD D
XCHG
LHLD LOCEND ; END OF LOCAL RING?
CALL CMPDEHL
RZ
XCHG ; NEW POSITION
SHLD LOCPOS
PUSH H ; SAVE POSITION
CALL CUR$NEXT ; ADVANCE CURSOR
POP H ; GET POSITION
BR CL0
;
; Advance the Cursor
;
CUR$NEXT:
LHLD CURAT ; COMPUTE NEW POSITION
MOV A,L ; CHECK FOR NEW LINE
ADI 19 ; SIZE OF EACH ENTRY
CPI 70
BRNC CN1 ; ADVANCE TO NEXT LINE
MOV L,A ; NEW POSITION
SHLD CURAT
JMP GOTOXY
CN1:
MOV A,H ; GET LINE
LXI H,CURHOME ; GET COL
MOV H,A ; SET LINE AND FALL GO TO CUR$DOWN
SHLD CURAT
BR CUR$DOWN
;
; Back Up the Cursor
;
CUR$BACK:
LXI H,CURHOME ; GET HOME
XCHG ; ... IN DE
LHLD CURAT
CALL CMPDEHL ; COMPARE
BRZ CUR$LAST ; GOTO END IF LAST
MOV A,L ; CHECK FOR FIRST COL
CMP E
BRZ CB1
SUI 19 ; BACK UP ONE COL
MOV L,A
SHLD CURAT ; NEW POS
JMP GOTOXY
CB1:
MOV A,E ; GET HOME COL
ADI 19*3 ; GET LAST COL
MOV L,A
DCR H ; PREV LINE
SHLD CURAT
JMP GOTOXY
;
; Move Cursor Down One Line
;
CUR$DOWN:
LXI H,CURHOME ; GET HOME ADDRESS
MOV B,H ; LINE IN B
LHLD CURAT ; GET CURRENT ADDRESS
INR H ; MOVE DOWN
MOV A,H ; CHECK FOR TOO FAR
SUB B
CPI EPS/4
BRNC CD1
SHLD CURAT ; OK, SO SET POSITION
JMP GOTOXY
CD1:
MOV A,L ; GET COL
LXI H,CURHOME
MOV L,A
SHLD CURAT
JMP GOTOXY
;
; Refresh Screen
;
REFRESH:
LHLD CURAT ; SAVE CURSOR AND RING POSITIONS
SHLD SCURAT
LHLD RINGPOS
SHLD SRINGPOS
CALL BANNER ; PRINT BANNER
CALL DIRMORE ; PRINT CURRENT DIRECTORY AND MORE MESSAGE
CALL DISPFILES ; DISPLAY FILES
CALL DISPMENU ; DISPLAY MENU
LHLD SCURAT ; RESTORE CURSOR AND RING POSITIONS
SHLD CURAT
LHLD SRINGPOS
SHLD RINGPOS
CALL SETCUR ; RESTORE CURSOR ON SCREEN
call atcmd
call vprint
db DIM,'Command (CR=Menu',0
lda cpmok ;OK to return to ZCPR3?
ora a ;0=No
cnz prmptc
lhld cstart ;pt to first char
mov a,m ;get it
ani 7FH ;mask
cpi MFIRST
cnz prmptf ;print previous menu prompt if not first menu
lda nmenfl ;next menu available?
ora a ;0=No
cnz prmptn ;print next menu prompt
call vprint
db ') - ',BRIGHT,0
RET
;
; Print ZCPR3 Return Prompt
;
prmptc:
call vprint
db ', ^C=Z3',0
ret
;
; Print First/Last Menu Chars
;
prmptf:
call vprint
db ', ',RFM,'=1st Menu, ',RLM,'=Prev Menu',0
ret
;
; Print next menu message
;
prmptn:
call vprint
db ', ',RNM,'=Next Menu',0
ret
;
; Refresh File Display
;
DISPFILES:
CALL CUR$FIRST ; POSITION CURSOR AT FIRST POSITION
LHLD LOCBEG ; PT TO FIRST FILE NAME
SHLD LOCPOS ; SAVE LOCAL POSITION
DSPF1:
LHLD LOCEND ; AT END?
XCHG
LHLD LOCPOS
CALL CMPDEHL
JZ CUR$FIRST ; POSITION AT FIRST ENTRY AND RETURN
MVI B,4 ; 4 SPACES
MVI A,' '
DSPF2:
CALL COUT
BJNZ DSPF2
CALL PRFN ; PRINT FILE NAME (HL IS ADVANCED)
SHLD LOCPOS
CALL CUR$NEXT ; ADVANCE CURSOR
BR DSPF1
;
; Position Cursor at CURAT
;
SETCUR:
LHLD CURAT
CALL GOTOXY
CALL VPRINT
DB '-->',0
RET
;
; Clear Cursor
;
CLRCUR:
LHLD CURAT
CALL GOTOXY
CALL VPRINT
DB ' ',0
RET
;
; Working Message
;
WORKMSG:
CALL ERMSG
DB DIM,'Working ...',BRIGHT,0
RET
;
; Error Message
;
ERMSG:
MVI A,0FFH ; SET ERROR MESSAGE FLAG
STA ERMFLG
LXI H,ERADR ; GET ADDRESS
CALL GOTOXY
JMP VPRINT
;
; Clear Error Message
;
ERCLR:
XRA A ; CLEAR FLAG
STA ERMFLG
LXI H,ERADR ; POSITION
CALL GOTOXY
PUSH B
MVI B,76-(ERADR MOD 255)
CALL VEREOL ; ERASE TO EOL
POP B
RET
;
; Position at Command Prompt and Clear It
;
ATCMD:
LXI H,CPMADR ; POSITION
CALL GOTOXY
PUSH B
MVI B,76-(CPMADR MOD 255)
CALL VEREOL ; CLEAR MESSAGE
POP B
LXI H,CPMADR ; REPOSITION
JMP GOTOXY
;
; Position at Bottom of Screen and Prompt for Continuation
;
BOTTOM:
LXI H,BOTADR ; POSITION
CALL GOTOXY
;
; Prompt for Continuation
;
SAK:
CALL VPRINT
DB DIM,'Strike Any Key -- ',BRIGHT,0
JMP KEYIN
;
; Open Menu File
;
menuload:
lhld menufcb ;pt to menu fcb
inx h
push h
call getfn2 ;copy FCB into MENU FCB
lxi d,11*2 ;pt to 3rd system file name
dad d
pop d ;DE pts to first char of MENU FCB file name
mvi b,11 ;11 bytes
call moveb
dcx d ;pt to fcb
call initfcb ;init fcb
call f$open ;open file
brz menu1 ;abort if no menu
call vprint
db CR,LF,' File ',0
lhld menufcb ;pt to file name
inx h
call prfn
call vprint
db ' Not Found',0
jmp os$ccp ;abort
;
; Load Menu File from disk
;
menu1:
call menustrt ;get address of buffer for menu load
xchg ;... in DE
;
; Load next block from Menu File -- DE pts to Load Address
;
mload:
lhld menufcb ;pt to FCB
xchg ;... in DE, HL = load address
call f$read ;read in next block
ora a ;error?
brnz mloaddn ;load done if error
lxi d,tbuff ;copy from TBUFF into memory pted to by HL
xchg ;HL is source, DE is dest
mvi b,128 ;128 bytes
call move
lhld bdos+1 ;get address of top of TPA
mov a,h ;set to bottom of ZCPR3
sui 10
cmp d ;about to overflow ZCPR3?
brnc mload ;continue if not
call vprint
db CR,LF,' TPA Full',0
jmp os$ccp
;
; Init Flags and Clear MSB of all bytes in Menu File
;
mloaddn:
call f$close ;close input file
mvi m,CTRLZ ;ensure EOF mark
xra a ;A=0
sta cpmok ;turn off ZCPR3 return flag
call menustrt ;pt to first menu char
push h ;save ptr
menul1:
mov a,m ;get byte
ani 7FH ;mask out MSB
mov m,a ;put byte
inx h ;pt to next
cpi CTRLZ ;EOF?
brnz menul1 ;continue if not
;
; Mark all Menu Sections
;
pop h ;HL pts to first byte of menu
mvi b,0FFH ;set menu counter
;
; Skip to Next Menu
;
menul2:
mov a,m ;get byte
cpi CTRLZ ;error?
jz mstrerr ;structure error if so
cpi MINDIC ;menu indicator (start of menu?)
brnz menul4
ori 80H ;beginning of menu found -- set MSB
mov m,a ;put byte
inr b ;increment menu count
inx h ;pt to next
mov a,m ;get byte
cpi MINDIC ;menu indicator (end of menu?)
brz menul5 ;done if so
cpi CTRLZ ;error?
jz mstrerr
;
; Skip out Menu Display
;
menul3:
call lskipt ;skip to beginning of next line
brz menul4 ;found menu indicator
cpi CTRLZ ;error?
jz mstrerr
br menul3 ;continue if not
;
; Skip to Next Menu
;
menul4:
call lskipt ;skip to beginning of next menu
brz menul2 ;resume if at beginning of next menu
cpi CTRLZ ;error?
jz mstrerr
br menul4
;
; Check Menu Options
;
menul5:
call menustrt ;pt to first menu char
mov a,m ;check for option
cpi GOPTION ;global option char?
jnz mfile ;if no global option, scan for menu files
inx h ;pt to option char
option:
mov a,m ;get option char
call caps ;capitalize
inx h ;pt to next
cpi CR ;done?
brz optdn
cpi XOPTION ;exit OK?
jnz mstrerr ;option error if not
;
; Disable Exit to ZCPR3
;
mvi a,0FFH ;turn flag off
sta cpmok
br option
;
; Option Processing Done
;
optdn:
inx h ;skip LF
;
; Check for Menu Display
;
mfile:
mov a,m ;get first byte
ani 7FH ;mask
cpi MINDIC ;start of menu?
jnz mstrerr
;
; Check and Set First Menu
;
shld mstart ;save start address of first menu item
mvi m,MFIRST+80H ;set first char of first menu
ret
;
; Entry Point for Menu Display
;
dispmenu:
mvi h,epsline ;pt to first line of menu
mvi l,1 ;col 1
call gotoxy ;position there
lhld mstart ;pt to first byte of current menu
mvi b,1 ;shell message 1 contains menu number
call getshm ;get menu number flag
cnz mchc0 ;skip to proper menu
shld cstart ;save start address of current menu
inx h ;pt to first char after menu indicator char
dispm1:
mov a,m ;get char
call caps ;capitalize
inx h ;pt to next
cpi CR ;end of options?
brz dispm2
cpi XOPTION ;ZCPR3 return?
jnz mstrerr ;error if not
;
; Toggle ZCPR3 Return Option
;
lda cpmok ;get flag
cma ;toggle
sta cpmok
br dispm1
;
; Done with Menu-Specific Option Processing
;
dispm2:
call lskip ;skip to LF
call getnlines ;get line count in A
sta pagcnt ;set count
;
; Print Next Line of Menu if not Starting with ESCAPE Char (MINDIC)
;
dispm3:
mov a,m ;get first char of line
ani 7FH ;mask
cpi MINDIC ;done?
brz dispm4
call expand ;expand line pted to by HL
push h ;save ptr to next line
xchg ;HL pts to expanded line
call lprintx ;print line pted to by HL ending in <CR>
pop h ;pt to next line
br dispm3
;
; Done with Menu Display
;
dispm4:
call lskip ;skip to first char of next line (option char)
shld optstrt ;set start address of options
;
; Determine if Another Menu Follows
;
xra a ;A=0
sta nmenfl ;set for no next menu
dispm5:
mov a,m ;ok?
ani 7FH ;mask
cpi CTRLZ ;error if EOF
jz mstrerr
cpi MINDIC ;next menu?
brnz dispm6
inx h ;double indicator if end
mov a,m
cpi MINDIC ;end?
rz
mvi a,0FFH ;set next menu
sta nmenfl
ret
dispm6:
call lskip ;skip to next line
br dispm5
;
; Ready for Option Input
; The following Flags/Values are now set:
; OPTSTRT -- Address of First Menu Option
; NMENFL -- 0 if no next menu, 0FFH if next menu
; CSTART -- Address of First Char of Current Menu
; MSTART -- Start Address of MINDIC Before Menu Display
; (MSTART)=MFIRST with MSB Set
prompt:
lxi h,cpadr ;position for input
call gotoxy
mvi a,0ffh
sta pagcnt ;turn off paging
call keyin ;get user input
PUSH PSW ;save command
LDA ERMFLG ;error message?
ORA A ;0=no
CNZ ERCLR ;erase old error message
POP PSW ;get command
ret
;
; Process Command
;
cmdproc:
call ctproc ;process movement or exit command
;
; Check for Command to Return to First Menu
;
lhld cstart ;pt to first char of menu
mov a,m ;get it
ani 7FH ;mask
cpi MFIRST
brz prmpt1
mov a,b ;get command
cpi RFM ;return to first menu?
brnz prmpt1
lhld mstart ;pt to first menu
mvi b,1 ;shell message 1 is menu number
xra a ;A=0=menu 0
jmp putshm ;reenter shell at first menu
;
; Check for Command to go to Next Menu
;
prmpt1:
lda nmenfl ;next menu available?
ora a ;0=No
brz prmpt2
mov a,b ;get command
cpi RNMP ;goto next menu?
brz rnmx
cpi RNM ;goto next menu?
brnz prmpt2
rnmx:
mvi b,1 ;shell message 1 is menu number
call getshm ;increment menu number
inr a
call putshm ;reenter menu system at new menu
jmp os$ccp1
;
; Check for Command to go to Last Menu
;
prmpt2:
mov a,m ;get menu char
ani 7FH ;at first menu?
cpi MFIRST
brz prmpt3 ;skip if at first menu
mov a,b ;get command
cpi RLMP ;goto last menu?
brz lstmnu
cpi RLM ;goto last menu?
brnz prmpt3
lstmnu:
mvi b,1 ;shell message 1 is menu number
call getshm ;decrement menu number
dcr a
call putshm ;reenter shell at last menu
jmp os$ccp1
;
; This is where additional functions may be added
;
prmpt3:
;
; Check for Option Letter
;
lhld optstrt ;pt to first option char
prmptx:
mov a,m ;get it
ani 7FH ;mask MSB
call caps ;capitalize
cpi MINDIC ;at next menu?
rz
cmp b ;match user selection?
brz prmptd
call lskip ;skip to next line
br prmptx
;
; Process Option
;
prmptd:
mvi b,0 ;shell message 0, bit 7 = wait flag
call getshm
ani 7FH ;set no wait
call putshm
inx h ;pt to first letter of command
mov a,m ;get it
cpi MCMD ;invoke other menu?
jz mchcmd ;menu change command
cpi WOPTION ;turn on wait?
brnz prmptg
mvi b,0 ;shell message 0, bit 7 = wait flag
call getshm
ori 80h ;set wait flag
call putshm ;set shell message
inx h ;skip option char
prmptg:
call expand ;expand line, DE pts to result
;
; Run Command Pted to by DE
;
runcmnd:
call getcl1 ;get address of command buffer
mov b,h ;... in BC also
mov c,l
mvi a,4 ;HL=HL+4 for address of first char
add l
mov l,a
mov a,h
aci 0
mov h,a
mov a,l ;store address
stax b
inx b
mov a,h
stax b
;
; Copy Command Line in DE into Buffer in HL
;
cmdcpy:
ldax d ;get command letter
call caps ;capitalize it
ora a ;done?
brz ccpyd
cpi CR ;done?
brz ccpyd
cpi PCHAR ;prompt?
brz ccpyp
mov m,a ;store it
inx h ;pt to next
inx d
br cmdcpy
ccpyd:
mvi m,0 ;store ending 0
jmp os$ccp1 ;optionally display command
;
; Prompt User for Input and Accept It
;
ccpyp:
inx d ;pt to first char of prompt
call crlf ;new line
ccpyp1:
ldax d ;get char
cpi PCHAR ;end of prompt?
brz ccpyp2
cpi CR ;new line?
brz ccpyp3
call cout ;echo char
inx d ;pt to next char
br ccpyp1 ;continue looping
ccpyp2:
inx d ;pt to char after closing PCHAR
ccpyp3:
push d ;save ptr to next char
xchg ;DE pts to buffer
mvi a,0FFH ;capitalize input from user
lhld ibuf ;input line buffer
call bline ;get input from user
xchg ;HL pts to buffer, DE pts to user input
cmdlp:
ldax d ;get char from user
ora a ;end of input?
brz cmdlp1 ;store rest of line
mov m,a ;store char
inx h ;pt to next
inx d
br cmdlp
cmdlp1:
pop d ;DE pts to next char, HL pts to buffer
br cmdcpy ;resume copying
;
; Menu Change Command -- Jump to Specified Menu
;
mchcmd:
inx h ;pt to menu number
call eval ;convert to decimal number in A
sta menuno ;save menu number
call mchc0 ;skip to desired menu to check for it
lda menuno ;get menu number
mvi b,1 ;menu number is shell message 1
jmp putshm ;set message and reenter shell
;
; Entry Point if MENU is Reinvoked
;
mchc0:
mov b,a ;menu number in B
inr b ;increment for following decrement
lhld mstart ;pt to start of menu
mchc1:
dcr b ;count down
rz ;done if found
mchc2:
call lskipt ;skip to next line
brnz mchc2 ;continue if not end of menu display
cpi CTRLZ ;EOF?
jz mstrerr
mchc3:
call lskipt ;skip to next line
brnz mchc3 ;continue if not at end of menu commands
cpi CTRLZ ;EOF?
jz mstrerr
inx h ;end of MENU.MNU?
mov a,m ;yes if double MINDIC
ani 7FH ;mask
cpi MINDIC
jz mstrerr ;error if so
dcx h ;pt to first char
br mchc1 ;continue
;
; Print Line pted to by HL Ending in <CR>
; Decrement PAGCNT
;
lprintx:
call lprint ;print without <CR>
jmp crlf ;do <CR> <LF>
;
; Print Line Pted to by HL; Decrement PAGCNT
;
lprint:
lda pagcnt ;check for page overflow
ora a ;do nothing
brz lskip ;... except skip out line
mvi b,0 ;set tab counter
lprnt0:
mov a,m ;get char
inx h ;pt to next
ani 7FH ;mask MSB
cpi DIM ;goto standout mode?
brz lprnt3
cpi BRIGHT ;end standout mode?
brz lprnt4
cpi TAB ;tabulate?
brz lprnt2
cpi CR ;done?
brz lprnt1
call cout ;print
inr b ;incr tab counter
br lprnt0
lprnt1:
inx h ;pt to first char of next line
lda pagcnt ;count down pages
dcr a
sta pagcnt
ret
lprnt2:
mvi a,' ' ;print <SP>
call cout
inr b ;incr tab counter
mov a,b ;done?
ani 7 ;every 8
brnz lprnt2
br lprnt0
lprnt3:
call stndout ;enter standout mode
br lprnt0
lprnt4:
call stndend ;end standout mode
br lprnt0
;
; Skip to Beginning of Next Line and Test First Char for Menu Indicator
;
lskipt:
call lskip ;skip
mov a,m ;get char
ani 7FH ;mask
cpi MINDIC ;test
ret
;
; Skip to Beginning of Next Line
;
lskip:
mov a,m ;get char
ani 7FH ;mask out MSB
cpi CTRLZ ;EOF?
rz
inx h ;pt to next
cpi LF ;EOL?
brnz lskip
ret
;
; Menu Structure Error -- FATAL
; This message is printed to indicate an error in the structure of
; the MENU.MNU file.
;
mstrerr:
call vprint
db CR,LF,' Structure Error',0
jmp os$ccp
;
; Expand Line Pted to by HL into Scratch Area
; Return with HL pting to next line, DE pting to current line
;
expand:
xchg
lxi h,noname ;init no name file
mvi m,1 ;set no entry
lhld expline ;pt to buffer
xchg
exp1:
mov a,m ;get next char
ani 7fh ;mask MSB
stax d ;store char
cpi CR ;end of line?
jz expx
inx h ;pt to next
inx d
cpi VARFLAG ;variable follows?
brnz exp1
;
; Variable Identified - Process it
;
mov a,m ;get next char
inx h ;pt to next
cpi VARFLAG ;one variable char?
brz exp1 ;resume if double VARFLAG
dcx d ;pt to variable position
ani 7FH ;mask
call caps ;capitalize variable
cpi FPDISK ;current disk?
brz expdisk
cpi FPUSER ;current user?
brz expuser
cpi FPFILE ;filename.typ?
brz expfile
cpi FPNAME ;filename?
brz expname
cpi FPPTR ;file being pointed to?
brz exppfile
cpi FPTYPE ;filetype?
brz exptype
br exp1 ;resume expansion
;
; Expand Exit
;
expx:
inx h ;pt to line feed
mov a,m ;get it
cpi LF ;line feed?
brnz expx1
inx h ;pt to char after line feed
expx1:
xchg ;DE pts to next line
lhld expline ;pt to expanded line
xchg ;HL pts to next line, DE pts to expanded line
ret
;
; Expand Disk
;
expdisk:
call retud ;get disk in B
mov a,b ;get disk number (A=0)
adi 'A' ;convert to ASCII
stax d ;store letter
inx d ;pt to next
br exp1 ;resume expansion
;
; Expand User
;
expuser:
call retud ;get user in C
mov a,c ;get user number
mvi b,10 ;subtract 10's
mvi c,'0' ;set char
expu1:
sub b ;-10
brc expu2
inr c ;increment digit
br expu1
expu2:
add b ;+10
adi '0' ;convert 1's to ASCII
mov b,a ;B=1's
mov a,c ;get 10's
stax d ;store 10's
inx d
mov a,b ;get 1's
stax d ;store 1's
inx d ;pt to next
br exp1 ;resume
;
; Expand File
;
expfile:
call getfnum ;get file number
jz exp1 ;resume if error
push h ;save ptr to next char
call ptfn ;set ptr to file name
call putn ;put file name
mvi a,'.'
stax d ;store dot
inx d ;pt to next
call putt ;put file type
pop h ;restore ptr
jmp exp1 ;resume
;
; Expand Name
;
expname:
call getfnum ;get file number
jz exp1 ;resume if error
push h ;save ptr to next char
call ptfn ;set ptr to file name
call putn ;put file name
pop h ;restore ptr
jmp exp1 ;resume
;
; Expand Type
;
exptype:
call getfnum ;get file number
jz exp1 ;resume if error
push h ;save ptr to next char
call ptfn ;set ptr to file name
mvi a,8 ;add 8
add l
mov l,a
mov a,h
aci 0
mov h,a
call putt ;put file type
pop h
jmp exp1 ;resume
;
; Expand File at Pointer
;
exppfile:
mov a,m ;get option char
ani 7FH ;mask
call caps ;capitalize
cpi FPFILE ;filename.typ?
brz exppf
cpi FPNAME ;filename only?
brz exppn
cpi FPTYPE ;filetype only?
brz exppt
jmp exp1 ;abort if error
;
; Extract full filename.typ of file being pointed to
;
exppf:
inx h ;pt to next char
push h ;save ptr to next char
lhld ringpos ;set ring position
call cknoname ;check and substitute no file
call putn ;put name pted to by HL
mvi a,'.' ;store dot
stax d
inx d
call putt ;put type pted to by HL
pop h
jmp exp1 ;continue
;
; Expand file name of file being pointed to
;
exppn:
inx h ;pt to next char
push h ;save ptr to next char
lhld ringpos ;set ring position
call cknoname ;check and substitute no file
call putn ;put name
pop h
jmp exp1
;
; Expand file type of file being pointed to
;
exppt:
inx h ;pt to next char
push h ;save ptr to next char
push d ;save DE
lhld ringpos ;pt to ring entry
call cknoname ;check and substitute no file
lxi d,8 ;pt to file type
dad d
pop d ;get DE
call putt ;put type
pop h
jmp exp1
;
; Check to see if HL pts to 'noname' and, if so, substitute name
;
cknoname:
push d ;save DE
push b ;save BC
call ckno ;do check
pop b ;get BC
pop d ;restore DE
ret
ckno:
mov a,m ;get char
cpi 1 ;no name?
rnz
lxi h,noname ;pt to no name
mov a,m ;check for definition
cpi 1 ;no name?
rnz
xchg ;HL pts to file name
call ermsg
db 'File Name? ',0
lhld ibuf ;pt to input buffer
mvi a,0ffh ;capitalize input
call bline ;get line from user
call sksp ;skip spaces
xchg
lhld menufcb ;pt to dummy FCB
xchg
call zprsfn ;parse file name into FCB
inx d ;pt to first char
lxi h,noname ;pt to name buffer
xchg
mvi b,11 ;copy into buffer
call moveb
ret ;HL pts to name
;
; Pt to File Name whose Number (1-4) is in A
;
ptfn:
mov b,a ;get number in B
call getfn2 ;pt to file name 2
push d ;save DE
mov a,b ;file 0?
ora a
brz ptfnx
lxi d,11 ;size of file name and type
ptfn1:
dad d ;pt to next
bjnz ptfn1
ptfnx:
pop d ;restore DE
ret
;
; Put File Name pted to by HL
;
putn:
mvi b,8 ;8 chars
br putc
;
; Put File Type pted to by HL
;
putt:
mvi b,3 ;3 chars
;
; Copy Chars from HL to DE for up to B bytes -- flush if space
;
putc:
mov a,m ;get next char
cpi ' ' ;skip spaces
brz putc1
stax d ;put next char
inx d ;pt to next
putc1:
inx h ;pt to next
bjnz putc
ret
;
; Get File Number (1 to 4)
; If valid number, return with value in A and HL pting to next char
; If not valid, return with Z and HL pting to last char (F, N, T)
;
getfnum:
mov a,m ;get char
sui '1' ;convert
brc getfne ;error
cpi 4 ;range?
brnc getfne
inx h ;pt to next char
ret ;NZ from CPI 4
getfne:
dcx h ;error return
xra a
ret
;
; Return Number of Lines on CRT in A
;
getnlines:
push h ;save HL
call getcrt ;get CRT info
inx h ;pt to number of lines
mov a,m ;get count
pop h ;restore HL
sui EPSLINE+1 ;subtract number of lines in file display
; ... + 1 for footer
ret
;
; Convert char string pted to by HL into decimal number in A
; On Entry, HL pts to first digit char
; On Exit, HL pts to after last digit char and A=number
;
eval:
push b ;save BC
mvi b,0 ;set value
eval1:
mov a,m ;get digit
sui '0' ;convert to binary
brc eval2
cpi 10 ;range?
brnc eval2
inx h ;pt to next digit
mov c,a ;new digit in C
mov a,b ;multiply B by 10
add a ;*2
add a ;*4
add b ;*5
add a ;*10
add c ;add in new digit
mov b,a ;result in B
br eval1
eval2:
mov a,b ;result in A
pop b ;restore ptr
ret
;
; Compute Address of Buffer for Menu Load
;
menustrt:
lhld ringend ;get address of buffer for menu load
inr h ;next page
mvi l,0
ret
;
; S T O R A G E
;
; Initialized
;
FILERCMD:
VMNAME ;VMENU Name
VMNFILL ;Filler
DB ' ' ;one space
DB 0 ;end of shell command
JOKER:
DB '???????????' ;*.* equivalent
MENUFILE:
db 'MENU '
db 'VMN'
;
; Uninitialized
;
STACK:
DS 2
BUFFER:
DS 2 ;buffer start
CURAT:
DS 2 ;current cursor position
ERMFLG:
DS 1 ;error message flag
EXPLINE:
DS 2 ;buffer to expand line in
H$DR:
DS 1 ;home drive
H$U$A:
DS 1 ;home user area (must follow H$DR)
IBUF:
DS 2 ;input line buffer
LOCBEG:
DS 2 ;local beginning of ring
LOCEND:
DS 2 ;local end of ring
LOCPOS:
DS 2 ;local ring position (temp)
MENUFCB:
DS 2 ;FCB for Menu File
NONAME:
DS 11 ;dummy user-defined file name
RING:
DS 2 ;ptr to beginning of ring
RINGI:
DS 2 ;ring sort pointer
RINGJ:
DS 2 ;another ring sort pointer
RINGEND:
DS 2 ;current ring end pointer
RINGPOS:
DS 2 ;current ring position in scan
SCURAT:
DS 2 ;save cursor position
SRINGPOS:
DS 2 ;save ring position
;
; Menu Buffers
;
more:
ds 1 ;More Files Flag
optstrt:
ds 2 ;Address of First Option in Current Menu
mstart:
ds 2 ;Address of First Menu
cstart:
ds 2 ;Address of Current Menu
nmenfl:
ds 1 ;Next Menu Available Flag (0=No)
menuno:
ds 1 ;Number of Menu
pagcnt:
ds 1 ;Paging Counter
cpmok:
ds 1 ;OK to Return to ZCPR3 (0=No)
END