home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
cpm3
/
chn31.lbr
/
CHN31.MZC
/
CHN31.MAC
Wrap
Text File
|
1988-01-06
|
15KB
|
510 lines
;
; CHN.MAC -- Version 3.1 -- For CP/M Plus (3.0) Only
;
; Creates a command file (alias) for a group of chained
; commands.
;
; Note: This program requires CP/M 3.0 and a Z80 CPU.
;
; Usage: CHN {{d:}fn {[command{\command{...}}}}
;
; The filename is name of the output (command) file for CHN to
; create or edit. If a filename is not given, it will be requested:
;
; Name of Command File: {d:}fn
;
; Enter the name. If a drive specification is included, the new
; file will be created on that drive, otherwise the default drive
; will be used. The file created will be a .COM file, so it is
; not necessary to enter the filetype (any filetype entered will
; be ignored).
;
; If an output filename is included in the command tail then a
; command line for inclusion in the command file may also be
; included in the tail following a left bracket ([). You have
; slightly less command line space for your command file this way
; because the CCP will not accept more than 128 characters from
; the system prompt, including "CHN", the output filename, and the
; necessary delimiting spaces. In addition, exclamation points
; cannot be included in a CP/M Plus command tail, so a backslash
; (\) should be used to separate multiple commands. These will
; be converted by CHN to exclamation points. Backslashes are
; seldom used in commands, but if you need to enter one then omit
; the command line from the command tail.
;
; CHN will then request the command line from you:
;
; COMMAND LINE:
;
; >
;
; Enter the command line. It may include parameters like SUBMIT
; files of the form $n where n is a single digit 1-9. Parameter
; 0 cannot be used (it becomes the command name). Entering two
; $$ in the command line enters a real $ (like SUBMIT). Parameters
; may be up to 14 characters each. The command line is limited
; to 128 characters total, including space for entering parameters.
;*Multiple chained commands separated by ! are permitted, as are
; conditional commands using a colon (:).
;
; CHN's .COM files do not support program input. (SUBMIT allows
; that using the "<" marker.)
;
; If a .COM with the same name exists, you will be asked if you want
; to modify it. If you answer "Y" and you enter a command line in
; the command tail, the old file will immediately be overwritten. If
; you didn't enter a command tail, CHN will attempt to read the file.
; (If it is not a CHN file, CHN will complain and abort.)
;
; After the old file is read, the old command line will be displayed
; for editing. You may use all the CP/M Plus line editing facilities,
; some of which will be displayed on the screen to remind you. Once
; you press <return>, a new file containing the edited line will be
; created.
;
; VERSIONS:
; 0.1 Gordon Wilk -- original version.
; 1.0 Gordon Wilk -- first public domain release.
; 2.0 Gordon Wilk, 9/86 -- FOG release -- Osborne
; Executive specific; program named SYN for
; SYNonym.
; 3.0 Gene Pizzetta, 5/20/87 -- Machine specific code
; (which was unnecessary) changed; command
; line filename and drive specification added
; for output file; changed parameter marker
; to '$' (was '&') to be consistent with SUBMIT
; (nothing new to remember); changed program
; name to CHN from SYN; now sends "failed"
; code to BDOS if aborted (to work with
; conditional CHN and SUBMIT files); code
; cleaned up; Z80 macros removed, Z80.LIB now
; required. Should now run on all CP/M Plus
; machines.
; 3.1 Gene Pizzetta, 6/15/87 -- Added ability to read
; command line contents from command tail;
; fixed bug that caused program not to abort
; after command line editing mode if ^X was
; used to erase the entire command line (an
; empty command line was written to disk).
;
; COPYRIGHT: Original code copyright 1986 by Gordon Wilk
; 6707 Springpark Ave.
; Los Angeles CA 90056
;
; Released for private non-commercial uses without fee.
;
; Please report any bugs or suggestions concerning this version to:
; Gene Pizzetta CompuServe 72060,505
; 481 Revere Street FOG #29 (617) 288-4667
; Revere, MA 02151 Voice (617) 284-0891
;
; Developed with SLRMAC. May be assembled with MAC by changing the
; filetype to .ASM. Z80.LIB is required. Note: the line above
; marked with an * will generate an error, but it is harmless.
; The code is not affected.
;
;
WBoot equ 00h ; warm boot
Bdos equ 05h ; BDOS entry
MemTop equ Bdos+1 ; top of memory
Fail equ 0FF00h ; failure code
CpmFcb equ 05Ch ; default FCB
FcbExt equ CpmFcb+9 ; default filetype
FcbCr equ CpmFcb+32
DBuff equ 080h ; default DMA buffer
;
; BDOS functions
;
ConIn equ 01h
FOpen equ 0Fh
FClose equ 10h
FRead equ 14h
FWrite equ 15h
FMake equ 16h
MultSec equ 2Ch
Chain equ 2Fh
BdosRet equ 6Ch
FParse equ 98h
;
; character codes
;
LF equ 0Ah ; linefeed
CR equ 0Dh ; carriage return
BELL equ 07h ; BEL
ESC equ 1Bh ; escape
;
; The following equates may be changed and the program re-assembled
;
ArgMark equ '$' ; parameter argument marking character
CmdDelm equ '\' ; command tail multiple command delimiter
;
MACLIB Z80
;
PRINT MACRO MSG ; print the string at MSG
lxi d,MSG
call PSTR
ENDM
;
REPLY MACRO BUFFR,LENGTH ; get string from console
lxi h,BUFFR
mvi m,LENGTH
xchg
call GETS
ENDM
;
FILE MACRO FUNC,POINTER ; BDOS file related calls
IF NOT NUL POINTER
lxi d,POINTER
ENDIF
mvi c,FUNC
call Bdos
ENDM
;
SETSEC MACRO NUMBER ; set multi-sector count
push b
push d
push h
mvi c,MultSec
mvi e,NUMBER
call Bdos
pop h
pop d
pop b
ENDM
;
BLKMOVE MACRO FROM,TO,LENGTH ; move a block of memory
lxi h,FROM
lxi d,TO
lxi b,LENGTH
LDIR
ENDM
;
org 100h
jmp MAIN
;
; strings for dim and normal video must end with $
;
DIM: db '$',0,0,0,0,0,0,0 ; string for dim video
NORMAL: db '$',0,0,0,0,0,0,0 ; string for normal video
;
; messages ...
;
SIGNON: db CR,LF,'CHN for CP/M Plus Version 3.1$'
ASKFIL: db 'Name of Command File: $'
EDHLP: db '<-- --> DEL Del/BS BOL/EOL Redsply DONE ',CR,LF
db '^A ^F ^G ^H ^B ^R <CR> $'
SHWOLD: db 'EDITING COMMAND LINE:$'
CRLF: db CR,LF,LF,'$'
ASKCOM: db 'COMMAND LINE:$'
PROMPT: db '>$'
ASKMOD: db 'This Command File Exists. Modify it? (Y/N): $'
NOTCHN: db ' * * Not a Command File * *$'
ABORT: db 'ABORTED',BELL,'$'
DONE: db 'DONE$'
QCOM: db '.COM',0
QCHN: db 'CHN',0
PFCB: dw DBuff+2 ; parse block: name starts at 2nd byte
dw CpmFcb
;
MAIN: lhld MemTop ; stack at top of memory
dcx H
sphl
PRINT SIGNON ; sign on
lda CpmFcb+1 ; check for command tail
cpi '#'
cc GETFN ; (no tail, ask)
BLKMOVE QCOM+1,FcbExt,3 ; move .COM to FCB
;
lxi h,DBuff+1
lxi d,COMNC
call BRACKET ; check for command line in tail
;
ISFILE: BLKMOVE CpmFcb+1,PARMS,8 ; and place in parameter 0
FILE FOpen,CpmFcb ; see if file already exists
inr a ; if it does then ask
JRNZ FILEX ; ..about modification
lda COMNC ; see if command line already exists
cpi 0
JRNZ FLMAKE ; (yes, don't ask for one)
PRINT CRLF
PRINT ASKCOM ; otherwise, ask for command line and
PRINT CRLF
PRINT PROMPT
REPLY COMMX,128 ; ..put into buffer space of new program
jz EREXIT ; (no command line: abort)
FLMAKE: FILE FMake,CpmFcb ; ..create it and
jmp DO$WR ; ..write the new file
;
; FILEX -- the command file exists; do you want to modify it?
;
FILEX: PRINT CRLF
PRINT ASKMOD ; Modify it?
call YESNO
jrz YESMOD
call GETFN ; (no, get new filename)
jr ISFILE
;
YESMOD: lda COMNC ; see if a new cmd line already exists
cpi 0
jnz DO$WR ; if so just write it
call RD$COM ; get command line from file,
sub a ; ..set cr to first
sta FcbCr ; ..record for re-write
;
; show the old line and accept edit to COMLIN
;
PRINT CRLF
PRINT DIM ; dim video
PRINT EDHLP ; editing help message
PRINT NORMAL ; normal video
PRINT CRLF
PRINT SHWOLD ; editing message
PRINT CRLF
PRINT PROMPT
lxi D,COMMX
call GETEDIT ; edit command line
;
; DO$WR -- write program code and command line data to new file
; (512 bytes, 4 logical sectors)
;
DO$WR: lda COMNC ; is command line null?
cpi 0
JRZ EREXIT ; (yes, abort)
lxi d,NEWPRO ; set buffer to new program area
call SETBUFF
SETSEC 4 ; set multi-sector count
FILE FWrite,CpmFcb ; ..write
FILE FClose,CpmFcb ; ..close
;
; FINISH -- normal end of program
;
FINISH: PRINT CRLF
PRINT DONE ; say we're through
jmp WBoot ; ..and terminate
;
; EREXIT -- aborted program exit
;
EREXIT: PRINT CRLF
PRINT ABORT ; let us know
lxi d,Fail ; kill any conditional
mvi c,BdosRet ; ..batch file
call Bdos
jmp WBoot ; ..and terminate
;
;================================================================
; SUBROUTINES
;================================================================
;
BRACKET:
mvi b,'[' ; look for [ in command tail
mvi c,0 ; ..or a null
call SCAN
cmp b ; was it a [
rnz ; (no, return)
mvi a,0 ; yes, move it
sta COMNC ; initialize buffer to 0
LOOP: inx d
inx h ; increment pointers
mov a,m ; get byte from command tail
cpi CmdDelm ; is it a backslash?
JRNZ NOSLSH ; (no, skip conversion)
mvi a,'!' ; make it an exclamation
NOSLSH: stax d ; store in command line
cpi 0 ; was it a null?
rz ; (yes, end of tail)
lda COMNC ; no, increment command length
inr a
sta COMNC
jr LOOP
;
SCAN: mov a,m ; get byte
cmp b ; is it a [
rz ; (yes, return)
cmp c ; a null then?
rz ; (yes, return)
inx h ; increment pointer
jr SCAN ; ..and keep looking
;
GETFN: PRINT CRLF
PRINT ASKFIL ; ask for filename
REPLY DBuff,10 ; get reply, put in DMA buffer
jz EREXIT ; (no entry: abort)
lxi b,5 ; move 5 chars from ".COM"
xchg ; ..to 1st byte after name
lxi h,QCOM
LDIR
FILE FParse,PFCB ; parse filename into CpmFcb
ret
;
; RD$COM -- Read an existing file and verify it is a CHN file
;
RD$COM: lxi d,NEWPRO ; overlay the NEWPRO code
call SETBUFF ; with a file read
SETSEC 4 ; set multi-sector count
FILE FRead,CpmFcb ; ..read it
;
; parmeter 0 must be filename, but only the first char is checked
;
lda PARMS ; 1st char of parm0
lxi h,CpmFcb+1 ; --> 1st char of filename
cmp m
rz ; if it matches, return
PRINT CRLF
PRINT NOTCHN ; otherwise, complain
jmp EREXIT ; ..and abort
;
; GETEDIT -- edits string at (DE)
; return: DE = A = length and flags set
; HL -> EOS null termination
;
GETEDIT:
push d ; save buffer address
call SETBUFF ; set DMA address there
mov d,a ; set DE=0 for edit
mov e,a
jmp GETS$2
;
; GETS -- gets string to (DE)
;
GETS: push d ; save buffer address
GETS$2: mvi c,10 ; get string (DE)
call Bdos
pop h ; HL --> buffer
inx h ; HL --> count
mov a,m ; A = length
mov e,a
mvi d,0 ; DE = length
dad d ; HL --> last char in string
inx h ; HL --> EOS
mov m,d ; NULL terminate
ora a ; and set flags
ret
;
; YESNO -- return with Z flag set if reply = Y ; reset otherwise
;
YESNO: mvi C,ConIn
call Bdos
ani 05Fh ;upper case
cpi 'Y'
ret
;
; * * The routines below return directly from BDOS * *
;
; PSTR -- Console display string
;
PSTR: mvi c,09 ; display string pointed
jmp Bdos ; ..to by DE
;
; SETBUFF -- set buffer address
;
SETBUFF:
mvi c,26 ; set DMA buffer
jmp Bdos ; ..to (DE)
;
;
; * * below is the new command file to be created * *
;
; Move the command line data from COMLIN to the default DMA buffer
; and chain to it. OFFSET adjusts addresses to their runtime
; locations because MAC does not have .phase/.dephase
;
NEWPRO equ $
OFFSET equ $-100H
lhld MemTop ; set up stack
dcx h
sphl
;
call GETARG ; get args into parm list
lxi h,COMLIN-OFFSET ; move the command line
lxi d,DBuff ; ..to DMA buffer
call MOVE
stax d ; terminate with 0
mvi c,Chain ; chain to command line
jmp Bdos
;
; * * SUBROUTINES * *
;
; GETARG -- moves arguments from the command line to the
; appropriate PARM slots
;
GETARG equ $-OFFSET
lxi d,DBuff+1 ; source
lxi h,PARMS-OFFSET+16 ; destination step over parm0
lxi b,16 ; parm increment
FNDARG equ $-OFFSET ; find an argument
ldax d
inx d
cpi ' ' ; if it's a space
jz FNDARG ; ..keep looking
rc ; (if < space, quit; otherwise
; ..we've found an argument
push h ; save address of parm slot
ARGLOOP equ $-OFFSET ; move chars until end of argument
mov m,a ; move char to parms
inx h ; increment destination
ldax d ; get next char
inx d ; increment source
cpi ' '+1 ; (if it's > space then
jnc ARGLOOP ; ..there's more to copy)
pop h ; else restore HL --> parm slot
ora a ; (if it's null
rz ; ..then quit)
dad b ; otherwise HL = HL+16, next slot
jmp FNDARG
;
; MOVE -- a recursive macro processor
; HL --> source string
; DE --> destination in the command line buffer
; Characters are moved (HL) to (DE). If an ArgMark is encountered,
; HL is saved, the address of the stored argument placed in HL
; and MOVE is called recursively to move from the stored argument.
; Stops at a NULL byte in source.
; Return: A = 0
; DE --> EOS
;
MOVE equ $-OFFSET
mov a,m ; A = char
inx h ; point to next char
ora a ; if 0 then
rz ; ..end of string
cpi ArgMark ; if not an argument marker then
jnz MOVE2 ; ..move the character
mov a,m ; otherwise get next char
inx h ; ..and point to one after that
cpi '0' ; if it's < '0' it's not an arg number
jc MOVE2 ; ..so move it
cpi '9'+1 ; if it's > '9' it's not an arg number
jnc MOVE2 ; ..so move it
; otherwise its an ASCII digit
sui '0' ; ..so make it binary
;
; A = argument number which, multiplied by 16, is list index.
; Save HL and replace it with the argument address.
;
add a
add a
add a
add a ; times 16 for length of arg
push h ; save address of next char
mvi b,0
mov c,a ; BC = address of list offset
lxi h,PARMS-OFFSET ; HL = base of arg list
dad b ; HL = address in arg list
call MOVE ; move recursively from arg list
pop h ; restore source address
jmp MOVE ; ..and start over
;
MOVE2 equ $-OFFSET
stax d ; move to destination
inx d ; point to next char in dest
jmp MOVE ; get next char
;
; data for NEWPRO
;
PARMS: ds 10*16 ; parameter space
COMMX: db 128 ; maximum chars accepted
COMNC: db 0 ; number of chars entered
COMLIN: ds 128 ; command line buffer
;
end 100h