; Program: VALIAS0 ; Author: Jay Sage ; Version: 1.1 ; Date: 21 August 85 ; Previous Versions: ALIAS0, Version 1.1 version equ 11 ; REVISION HISTORY ; ; Version 1.1, 21 Aug. 1985, Jay Sage ; Fixed bug in handling of user area when a file is specified on ; the command line (always got current user rather than specified ; user). ; ; Version 1.0, 12 Aug. 1985, Jay Sage ; The purpose of VALIAS is to create and edit aliases using the ALIAS1 ; model program. The editor allows deleting, inserting, and replacing ; command lines. As configured here, the program requires that the user ; have wheel status and that the TCAP support both clear-screen and ; clear-to-end-of-line functions. The screen displays are designed to ; work correctly with reverse video highlighting (extra spacing is provided ; to enhance the appearance). The command lines can be read in from an ; existing alias and written out to new alias files. ; ; To create VALIAS.COM, assemble and link VALIAS0 to make VALIAS0.COM and ; VALIAS1 to make VALIAS1.COM. Then use PIP to combine the two as ; follows: ; ; PIP VALIAS.COM=VALIAS0.COM,VALIAS1.COM ; ; Some possible extensions to VALIAS that others might wish to add to this ; program are as follows (please sign the program out of Z-Node Central ; before making any changes that you would consider releasing): ; ; 1. Put in macros for optional Z80 code, especially for relative jumps. ; If this is done, be sure to use a correct form of the @GENDD macro ; used in other ZCPR3 utilities (i.e., with same number of bytes in ; each clause of the IF-ELSE-ENDIF expression). Also, be sure to use ; names for the macros that are not Z80 opcode names as was unfortunately ; done in a number of other ZCPR3 programs (conversion to Z80 opcodes ; cannot be done). ; 2. Allow real full-screen editing of a line with character insertion, ; replacement, and deletion. (Cursor keys from WordStar and TCAP ; would be used for movement, but what characters would be used to ; select insertion, overtype, etc.? Is this worth the code space?) ; 3. Use Z3ENV to get width and height of console screen. The width is ; probably less significant than the height, since a person with more ; screen lines could then handle aliases with more commands. ; ; Jay Sage, sysop, Z-Node #3 ; Newton Centre, MA, 617-965-7259 (300/1200/2400 baud) ;============================================================================= ; E Q U A T E S no equ 0 yes equ not no hcmdfl equ no ;include help command? modecol equ 21 ;column where mode message is put fncol equ 45 ;column where file name message is put alsect equ 8 ;number of sectors in alias file columns equ 80 ;columns on screen rows equ 24 ;rows on screen cmdlen equ columns-4 ;max length of each command maxcmds equ rows-4 ;max number of commands buffer equ 4000h ;1K buffer for reading in existing alias file cmdlist equ buffer + 1024 ;place to keep commands as they are edited lastcmd equ cmdlist + ((maxcmds-1)*cmdlen) cmdend equ cmdlist + (maxcmds*cmdlen) tbuff equ 80h fcb equ 5ch cr equ 0dh lf equ 0ah tab equ 09h bell equ 07h envdefn equ 103H ;beginning of environment definition envclas equ 108H ;address of environment descriptor class ; ;============================================================================= ; E X T E R N A L R E F E R E N C E S ext cout,pstr,print,pafdc,crlf ext capin,bbline ext z3vinit,getwhl,getcl1 ext retud,logud,putud,getud,sua ext sfa,zfname ext f$open,f$read,f$close,f$make,f$delete,f$write,f$exist,initfcb ext fillbc,sksp,hmovb,$memry ext tinit,cls,ereol,gotoxy,at,stndout,stndend ;============================================================================= ; Z C P R I N I T I A L I Z A T I O N ; Use Z3BASE to get address and type of environment MACLIB Z3BASE.LIB ; 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 SYSENV.LIB z3eadr: jmp start SYSENV start: lxi h,z3eadr ;pt to ZCPR3 environment endif ; ;============================================================================= ; M A I N P R O G R A M C O D E ;save CP/M stack pointer xchg ;save pointer to ENV in DE lxi h,0 dad sp shld oldstack lxi sp,stack ;set up new stack pointer xchg ;HL = ENV address again ;perform initialization call z3vinit ;initialize the zcpr3 env and the vlib env call tinit ;initialize terminal call putud ;remember current DU: lda fcb+13 ;get user area specified on command line or call sua ;..current user if none specified call zerocmds ;zero out the command list buffer xra a ;set mode to normal sta modeflag ;check for help request lda fcb+1 ;get first character of file name cpi '/' ;help? jz help ;make sure minimal TCAP support is available call cls ;try clearing screen jz badtcap ;if it failed, abort with message call ereol ;try clearing to end of line jz badtcap ;if it failed, abort with message ;sign on call signon ;check on wheel status call getwhl jz nowheel ;if no wheel, abort with message ;display default mode call dispmode ;see if alias file name specified on command line lda fcb+1 cpi ' '+1 ;if no name given jc newalias ;..go to entry of new alias ;process file named on command line or by load command valias1: call loadfile ;try loading file jc newalias ;if load failed, go to entry of new alias ;ALIAS EDITING COMMAND LOOP command: call prompt ;put up command prompt db 'CMD LETTER ' db '(Clear Delete Format ' if hcmdfl db 'Help ' endif db 'Insert Load Mode Replace Save eXit):',0 command1: call capin ;get answer with no echo cpi 'C' ;clear alias? jz newalias cpi 'D' ;delete a line in alias? jz delete cpi 'F' ;reformat commands? jz format if hcmdfl cpi 'H' ;help with commands? jz cmdhelp endif cpi 'I' ;insert line into alias? jz insert cpi 'L' ;load new alias jz loadalias cpi 'M' ;mode selection jz modeset cpi 'R' ;replace a line in alias? jz replace cpi 'S' ;save the alias to disk? jz savalias cpi 'X' ;exit? jz exit cpi 'C'-'@' ;abort? jnz command1 ;if none of above, ask again exit: call cls ;if exit, clear screen and quit jmp quit ; ;============================================================================= ; E D I T C O M M A N D P R O C E S S I N G ;----------------------------------------------------------------------------- ; DISPLAY INTERNAL HELP ; This routine displays a help screen on the use of the editing commands using ; a window at the lower right part of the screen. It is included only if the ; equate for HCMDFL is set to YES. if hcmdfl cmdhelp: lxi h,13*100h+16 ;start window at line 13, column 16 call gotoxy call ereol ;clear line above window call nextline call print db tab,'C clear all commands and start over',0 call nextline call print db tab,'D delete specified line',0 call nextline call print db tab,'F reformat commands (one per line, no leading spaces)',0 call nextline call print db tab,'I insert commands before specified line',0 call nextline call print db tab,'L load new alias file or name',0 call nextline call print db tab,'M set normal or recursive mode',0 call nextline call print db tab,'R replace specified line with new line',0 call nextline call print db tab,'S save commands in an alias file',0 call nextline call print db tab,'X exit to ZCPR3',0 call nextline ;clear line below help screen jmp command ;back for another command ;local subroutine to go to next line and clear ;space for the window nextline: inr h call gotoxy call ereol ret endif ;hcmdfl ;----------------------------------------------------------------------------- ; MODE SELECTION modeset: call prompt db 'Alias Mode (N=normal R=recursive):',0 modeset1: call capin ;get user response mvi b,0 ;flag value for normal mode cpi 'N' ;normal mode? jz modeset2 mvi b,0ffh ;flag value for recursive mode cpi 'R' ;recursive mode? jz modeset2 cpi cr ;abort: jz command cpi 'C'-'@' ;control-c abort jz command jmp modeset1 ;otherwise, get another response modeset2: mov a,b ;get flag value sta modeflag ;..and store it call dispmode ;display the mode on the screen jmp command ;back for another command ;----------------------------------------------------------------------------- ; ENTER NEW ALIAS ; This code clears the command list editing space, brings up an empty screen, ; sets the working command to number 0, and then continues with the code for ; the insertion command. newalias: call zerocmds ;clear command line buffer call listall ;redisplay all the commands xra a ;start work at command 0 sta workcmd jmp insert1 ;use code for insert mode ;----------------------------------------------------------------------------- ; INSERT COMMAND LINE ; This code handles insertion of new command lines. It prompts the user for ; the letter designating the command line at which the insertion is to be made. ; If that line is currently empty, then the cursor is placed there ready for ; the insertion to be made. If there is a command on that line already, then ; it and any commands after it are moved up by one line. When the user ; completes the new command, it is entered into the command line. If the ; command was a null line, then any space opened up for the insertion is ; closed up again. If a non-null line was entered, then the code automatically ; goes on to the next line. If the next line is the last line and it is not ; empty, then the code returns to the command prompt so that the last line will ; not be forced off the top. When space is opened up, any commands on the ; last line are combined with commands on the next to last line. In this way ; commands are not pushed off the top by inserts to lines other than the top ; line. insert: call prompt ;prompt for line to insert db 'Line Before Which to Insert (cr to cancel)?',0 call getworkcmd ;get the line to work on jz command ;if cr entered, return to prompt insert1: call prompt db 'Enter Commands (end with empty line):',0 ;command line insertion loop insert2: call inscmd ;open up space for command and initialize call readcmd ;get new command ora a ;check for null line jz insert3 ;if so, end insertion mode ;store command and advance to next line call storecmd ;put command into line lxi h,workcmd ;point to the number of the working command inr m ;increment it mov a,m cpi maxcmds ;check for past last available line jnc command ;if so, return for another command cpi maxcmds-1 ;now check for last line jnz insert2 ;if not, continue with insertions ;before inserting on last line, make sure that ;an existing line will not be lost over the top lxi h,lastcmd ;point to beginning of last command call sksp ;skip to first non-blank character mov a,m ;see if last line is empty ora a jz insert2 ;if so, go on with insertions jmp command ;otherwise, go back to edit command prompt ;terminate insertions, delete any line that was ;opened up for the last (blank) line insert3: lda insflag ;check insertion flag ora a cnz delcmd ;if line was opened, delete it jmp command ;back to edit command prompt ;----------------------------------------------------------------------------- ; DELETE COMMAND LINE ; This code asks for the command line to be deleted, deletes it, and closes ; up the space. delete: call prompt ;prompt for line to delete db 'Line to Delete ( cr to cancel )?',0 delete1: call getworkcmd ;get selection from user jz command ;return to prompt call delcmd ;delete the command and refresh display jmp command ;----------------------------------------------------------------------------- ; REPLACE A COMMAND ; This code deletes an existing command line and allows the user to enter a ; new command on that line. replace: call prompt ;prompt for line to replace db 'Line to Replace (cr to cancel)?',0 replace1: call getworkcmd ;query user for line to work on jz command ;if cr or control-c, return to prompt replace2: call prompt ;put message in prompt area db 'Enter New Line at Cursor',0 call readcmd ;get new command line at working position call storecmd jmp command ;go back for another command ;----------------------------------------------------------------------------- ; FORMAT ; This code reformats the commands in the command list. Blank lines are ; eliminated, and leading spaces are deleted. format: call makecl ;make multiple command line in buffer call zerocmds ;clear the command list buffer lxi h,buffer ;copy the cmd line in buffer call copycmds ;..back into CMDLIST call listall ;display all of the commands jmp command ;back for another command ;----------------------------------------------------------------------------- ; LOAD NEW ALIAS FILE ; This code prompts for the name of a file. If the name entered begins with ; control-A, then the code returns to the command prompt. Otherwise it ; branches to the same code that was used for file names specified on the ; command line when VALIAS was invoked. loadalias: call gotoprmt ;request name of file call print db 'LOAD: ',0 call getfn ;get and check name of file jz command ;if aborted, go back for another command call zerocmds ;otherwise, clear out command list jmp valias1 ;..and try to load new file ;----------------------------------------------------------------------------- ; SAVE ALIAS TO DISK ; This code writes a new alias file to disk. First it configures the model ; alias file ALIAS1.COM that has been appended to this code. The environment ; information is copied into the prototype alias. Then the command line ; from the command list buffer is converted into a single-string command line ; and installed in the alias. savalias: call setenv ;set up environment header in model alias call makecl ;form multiple command line in BUFFER call codend ;pt to beginning of new alias file push h ;save address for later inx h ;point to address word in initial jump mov e,m ;get address of START inx h mov d,m lxi h,-100h ;adjust for 100h offset to get offset from dad d ;..beginning in file pop d ;get back address where new alias file starts dad d ;HL pts to absolute address of START dcx h ;point to mode flag byte lda modeflag ;get current mode mov m,a ;store it in prototype alias lxi d,17+1 ;offset to START+17, where command line goes dad d lxi d,buffer ;point to new command line to install xchg ;HL = source, DE = destination call hmovnul ;copy HL to DE through first null byte ;get name for new alias save1: call gotoprmt ;prompt for name of file call print ;display SAVE header db 'SAVE: ',0 call getfn ;get and check the name of save file jz command ;if abort, go back for another command ;write file whose name is in FCB lxi d,fcb ;check for existing file call f$exist jz write1 call gotoprmt call print db 'File ',0 call prtname call print db '.COM Exists - Overwrite (Y/N)?',0 call endprmt call capin cpi 'Y' jnz save1 ;back to asking for name call prompt db 'Erasing Old File',0 lxi d,fcb ;clear file attributes xra a call sfa ;set file attributes to R/W DIR call f$delete ;delete file ;create new alias file write1: call gotoprmt call print db 'Saving Alias ',0 call prtname call print db ' to Disk',0 call endprmt ;end hilite and put in a space lxi d,fcb ;pt to FCB call initfcb ;init it call f$make ;create file mvi c,alsect ;number of sectors to save call codend ;pt to file write2: lxi d,tbuff ;copy sector into buffer mvi b,128 ;128 bytes call hmovb lxi d,fcb ;write block call f$write jnz werr dcr c ;count down jnz write2 call f$close ;close file jmp command ;back for another command werr: call print db cr,lf,lf db ' Error in Creating File',0 jmp quit ; ;============================================================================= ; S U B R O U T I N E S ;----------------------------------------------------------------------------- ; APNDCMD -- Append Command ; This routine processes a single command in the command list. It first skips ; over leading blank spaces. If the command is then found to be null, the ; routine terminates. Otherwise, it checks to see if this is the first ; character of the new multiple command line. If not, it first puts in the ; semicolon command separator. It then copies the characters in the command ; to the multiple command line. Whenever a character is added to the multiple ; command line, the count in B is incremented, and the value is checked against ; the size of the Z3 command line. If too many characters have been entered, ; the routine terminates with the carry flag set. Otherwise the carry flag ; is reset when APNDCMD returns. apndcmd: call sksp ;skip over blank space mov a,m ;check for end of line ora a rz ;if end, return now (carry is reset) mov a,b ;see if any chars on cmd line so far ora a jz apndcmd1 ;if not, skip insertion of separator mvi a,';' ;put in command separator stax d inx d inr b ;increment the character count apndcmd1: lda z3cllen ;get allowed command line length cmp b ;see if we are over the limit rc ;if so, return with carry set mov a,m ;get character from command ora a ;see if end rz ;if so, return (carry reset) inx h ;point to next character cpi ';' ;see if at command separator jz apndcmd ;if so, start over with space skipping stax d ;add char to multiple command line inx d ;increment pointers inr b ;..and character count jmp apndcmd1 ;----------------------------------------------------------------------------- ; BADTCAP ; This routine is called if the TCAP is not defined or does not support the ; necessary functions of clear-screen and clear-to-end-of-line. badtcap: call signon call print db bell,cr,lf,lf db ' No TCAP or TCAP lacks required functions' db 0 jmp quit ;abort ;----------------------------------------------------------------------------- ; CALCBLK ; This code calculates the size of the memory block above the working command. ; If the working command is the highest numbered one allowed, then CALCBLK ; returns with the zero flag set. The result is returned in BC. calcblk: mvi a,maxcmds-1 ;A = highest numbered command lxi h,workcmd sub m ;A = number of commands above workcmd rz ;if at last cmd, return with zero flag lxi h,0 ;preset HL to zero lxi d,cmdlen ;DE = length of each command string calcblk1: dad d ;add command length to HL dcr a ;count down commands jnz calcblk1 ;loop until A = 0 dcr a ;once more to reset zero flag mov b,h ;move result into BC mov c,l ret ;----------------------------------------------------------------------------- ; CODEND ; This routine finds the next record boundary after the end of the program. ; This is where PIP will append the prototype alias program ALIAS1.COM. Do ; not try using the routine CODEND in SYSLIB. It finds the nearest page ; boundary. codend: push d lhld $memry ;get next available byte mov a,l ;get low ani 80h ;set MSB mov l,a lxi d,128 ;next 128 bytes dad d pop d ret ;----------------------------------------------------------------------------- ; COPYCMDS ; This subroutine takes a command line pointed to by HL and copies the ; individual commands into the command list buffer. Semicolons are deleted ; and nulls are placed at the end of each line. copycmds: dcx h ;compensate for pre-increment below xra a ;initialize command count mov b,a ;..in B register lxi d,cmdlist-cmdlen xchg ;HL=dest, DE=source push h ;save begining of each line copycmd1: ;advance pointer to next command line in command line buffer pop h ;get beginning of previous line push d ;save source address lxi d,cmdlen ;increment by line length dad d pop d ;restore source address inx d ;point to start of next command in old alias push h ;save addr of beginning of line again ;check for end of command line in old alias ldax d ora a jz endcopy ;increment the command count inr b ;increment command count mov a,b ;save number of commands cpi maxcmds ;see if we are at last command jnc toomany ;if so, copy rest of line to last position ;copy the next command copycmd2: ldax d ;get char from command line ora a ;check for end of commands jz endcopy cpi ';' ;check for end of this command jz copycmd1 ;if so, set up for next command mov m,a ;save it in command buffer inx d ;increment pointers inx h jmp copycmd2 endcopy: ;clean up stack and return pop h ret toomany: ;if too many commands in alias file, put several commands ;on the last line of screen ldax d ;get char from command line ora a ;check for end of entire command line jz endcopy mov m,a ;save it in command buffer inx d ;increment pointers inx h jmp toomany ;----------------------------------------------------------------------------- ; DELCMD ; This code deletes the working command by moving down the block of memory ; containing the commands that follow it and by putting a null command at the ; top position. The block move begins at low memory and works upward. delcmd: call calcblk ;calculate size of block to move jz delcmd2 ;if zero, skip the block move lda workcmd ;set pointer to current command call setcmdptr ;HL = current command push h ;save it lxi d,cmdlen dad d ;source: HL = next command pop d ;destination: DE = current command delcmd1: mov a,m stax d inx h inx d dcx b mov a,b ora c jnz delcmd1 ;put null command at top of memory delcmd2: xra a sta lastcmd call listwork ;refresh the screen display ret ;----------------------------------------------------------------------------- ; DISPFN ; This routine displays the name of the alias file at the top right side ; of the screen. dispfn: call gotofn ;put cursor in file name postiion call print db 'Alias Name: ',0 call prtname ;display the file name call endprmt ret ;----------------------------------------------------------------------------- ; DISPLAY MODE ; This code displays the alias mode (normal or recursive) at the top of ; the screen. dispmode: call at db 1,modecol ;column 21 at top of screen call stndout ;start highlighting call print db ' Mode: ',0 lda modeflag ;see which mode is in effect ora a lxi h,normmsg ;point to normal mode message jz dispmode1 lxi h,recursmsg ;..or recursive mode message dispmode1: call pstr call endprmt ;end this part of display call dispfn ;then update file name display ret normmsg: db 'Normal',0 recursmsg: db 'Recursive',0 ;----------------------------------------------------------------------------- ; ENDPRMT ; This routine ends highlighting, outputs a space to the console, and clears ; the rest of the line. The extra space improves the appearance with ; reverse-video highlighting. endprmt: call space call stndend call space call ereol ret ;----------------------------------------------------------------------------- ; GETFN ; This routine prompts the user for the name of a file to save or load. If ; the answer is control-a, then the routine returns with the zero flag set. ; Once an answer has been given, the input is parsed, and a proper FCB is ; built. The routine will not accept an ambiguous name (it rings the bell ; and returns to the name prompt). getfn: call at db 24,8 call stndout call print ;complete the prompt db 'Name of ALIAS Command ' db '( ^A = abort',0 lda fcb+1 ;see if file name is in FCB cpi ' '+1 ;force carry set if not jc getfn1 ;if not, done with prompt call print db ' | CR = ',0 call prtname getfn1: call print db ' )?',0 call endprmt mvi a,0ffh ;read and capitalize input from user call bbline call sksp ;skip to non-blank mov a,m ;get first character entered ora a ;check for null entry jz getfn2 ;if no name entered, leave name from before cpi 'A'-'@' ;if control-a rz ;..return with zero flag set lxi d,fcb ;pt to FCB call zfname ;convert user's answer and place in FCB call setcom ;set file type to COM call chkambig ;check for ambiguous name (nulls out bad name) getfn2: call getud ;return to original DU call retud ;set bc to reflect that area lda fcb+1 ;get first char of file name in FCB cpi ' '+1 jc getfn ;if so, back to asking for name lda fcb ;get disk ora a ;default? jz getfn3 dcr a ;shift to range 0 - 15 mov b,a getfn3: lxi h,fcb+13 ;point to user number mov c,m ;get it into C call logud ;log into specified area lxi d,fcb ;initialize the FCB call initfcb call dispfn ;display file name and set user # in fcb xra a ;set the zero flag dcr a ret ; local subroutine CHKAMBIG ; This code checks the file name in the default FCB to make sure that it is ; not ambiguous. If it is, the name is set to empty and the bell is rung. chkambig: lxi h,fcb+1 ;point to beginning of name mvi b,8 ;check 8 characters mvi a,'?' ;character to check for chkamb1: cmp m inx h jz chkamb2 ;jump if bad character found dcr b rz ;file name is OK jmp chkamb1 chkamb2: mvi a,' ' ;show no name entered sta fcb+1 mvi a,bell ;ring the bell call cout ret ;return with zero flag set ;----------------------------------------------------------------------------- ; GETWORKCMD ; This routine gets the user's selection of a command line to work on. The ; routine does not return until a carriage return, control-c, or valid line ; ID is entered. If a valid ID is given, it is stored in WORKCMD. If carriage ; return or control-c is entered, the routine returns with the zero flag set; ; otherwise the zero flag is reset. getworkcmd: call capin ;get answer from user cpi cr ;return if carriage return rz cpi 'C'-'@' ;return if control-c rz sui 'A' ;convert to command number jc getworkcmd ;if carry, less than 'A', ask again cpi maxcmds ;beyond last allowed command? jnc getworkcmd ;if so, ask again sta workcmd ;save working command number inr a ;force resetting of zero flag ret ;----------------------------------------------------------------------------- ; GOTOFN ; This routine positions the cursor to where the file name or error message ; goes in the upper left hand corner of the screen and clears the rest of ; the line. gotofn: call at db 1,fncol call stndout ;start highlighting call space ;put in leading space ret ;----------------------------------------------------------------------------- ; GOTOPRMT ; This routine goes to the last line on the screen, turns on highlighting, ; and puts in a leading space. gotoprmt: call at db 24,1 call stndout call space ret ;----------------------------------------------------------------------------- ; GOTOWORK ; This routine positions the cursor to the working command on the screen and ; clears the rest of the line. gotowork: lda workcmd ;get letter for working command line adi 3 ;calculate line number on screen mov h,a mvi l,5 ;column 5 is where command text starts call gotoxy ;put cursor there call ereol ;clear the command shown there ret ;----------------------------------------------------------------------------- ; HELP ; This routine displays the built-in help screen invoked by // on the command ; line and then terminates the program. help: call signon call print db cr,lf,lf,lf db 'SYNTAX: VALIAS [ [DIR:]ALIASNAME ] ' db cr,lf,lf,lf db 'If the optionally specified alias file exists, it is opened' db cr,lf db 'for editing. Otherwise it is used as the default name for' db cr,lf db 'a new alias. Editing commands allow insertion, deletion,' db cr,lf db 'or replacement of command lines. Wheel status is required.' db 0 jmp quit ;terminate program ;----------------------------------------------------------------------------- ; HMOVNUL ; This routine copies bytes from HL to DE until and including the first null ; byte. hmovnul: mov a,m ;get source byte stax d ;store at destination inx h ;increment pointers inx d ora a ;test for null jnz hmovnul ;if not, keep looping ret ;----------------------------------------------------------------------------- ; INSCMD ; If the line in which a command is to be inserted is presently empty, then ; this code moves the commands in the command list buffer one command up to ; allow for the insertion of a new command. The place where the new command ; is to go is initialized to a null command. This routine works by computing ; how many bytes need to be moved. Then the move is performed, starting at ; high memory and working down so the commands do not owerwrite one another. inscmd: ;see if current line is empty xra a ;preset insertion flag to false sta insflag lda workcmd ;point to beginning of working cmd call setcmdptr call sksp ;skip to first significant char mov a,m ;see if it is null ora a jz inscmd4 ;if so, skip the moving around ;check for case of insertion on last line lda workcmd cpi maxcmds-1 ;if last command line jz inscmd4 ;..then skip all the moving around ;move command lines up one mvi a,0ffh ;set insertion flag sta insflag ;make HL point to beginning of last command text lxi h,lastcmd ;point to beginning of last cmd call sksp ;skip over any spaces mov a,m ;get first character ora a ;if nothing there jz inscmd2 ;go on with block move ;make DE point to end of next to last command lxi d,lastcmd-cmdlen-1 ;point to char before next to last cmd inscmd1: inx d ;point to next character ldax d ;test for end of line ora a jnz inscmd1 mvi a,';' ;put in semicolon stax d inx d call hmovnul ;copy last cmd to end of previous ;move block upward starting in high memory inscmd2: call calcblk ;calculate length of block lxi h,lastcmd-1 ;source = end of next to last command lxi d,cmdend-1 ;dest = end of last command in list inscmd3: mov a,m stax d dcx h dcx d dcx b mov a,b ora c jnz inscmd3 ;put null command at insert location inscmd4: lda workcmd call setcmdptr mvi m,0 call listwork ;update display of command lines ret ;----------------------------------------------------------------------------- ; LISTCMDS ; This subroutine displays on the screen the commands stored in the command ; buffer. At entry point LISTALL, it displays all of the commands in the list. ; At entry point LISTWORK, it displays only the commands from the working ; command on down. listall: xra a ;start at command 0 jmp listcmd1 listwork: lda workcmd ;start with working command ;display commands starting at value in A listcmd1: ;get starting line letter into B mov c,a ;save command number in C adi 'A' ;convert to ascii line letter mov b,a ;save line letter in B ;set initial position of cursor mov a,c ;get command number back adi 3 ;compute screen line number mov h,a ;put value into H mvi l,1 ;start in column 1 call gotoxy ;set cursor to starting position ;set HL to first command in list to display lxi h,cmdlist ;point to beginning of command list lxi d,cmdlen ;length of space for each command in list push b ;save B and C inr c ;set up for loop with zero possibility listcmd2: dcr c jz listcmd3 dad d jmp listcmd2 ;set C to number of commands to display listcmd3: pop b ;get B and C back mvi a,maxcmds ;calculate number of sub c ;..command lines to display mov c,a ;save that in C ;loop through printing of commands listcmd4: push h ;save pointer to start of command mov a,b ;print line label call cout inr b ;increment line label call print ;print pointer mark db '-->',0 call pstr ;print the command (even if none) call ereol ;clear the rest of the line call crlf ;to next line pop h ;get pointer to start of command back dad d ;advance pointer to next line dcr c ;check line count jnz listcmd4 ;if more, continue ret ;----------------------------------------------------------------------------- ; LOADFILE ; This routine logs into the disk and user area specified with the file name. ; Then it tries to open the file. If it fails, the routine takes the file name ; as the name of a new alias. If the file is opened but is found not to be an ; alias, then a message to this effect is displayed and the program proceeds to ; define a new alias. The FCB is cleared of this name. If the program named is ; a proper alias file, then it is loaded into the area BUFFER and the routine ; returns with the carry flag clear; otherwise the carry flag is set to ; indicate that a new alias should be created. The user number of any named ; file is restored after file operations so that the FCB can be used later. loadfile: call setcom ;set file type to COM call retud ;get current DU in BC lxi h,fcb ;point to drive in FCB mov a,m ;get it ora a ;test for default specification jz loadf1 ;if so, use current disk dcr a ;else convert to range 0-F mov b,a ;..and put in b loadf1: mov a,b ;set FCB to specific drive inr a ;..using range 1..10h mov m,a lxi d,13 ;pt to user number in FCB push h ;save ptr to FCB dad d ;pt to user mov c,m ;get user pop d ;pt to FCB again call logud ;log into dir in BC call f$open ;open alias file for input jz loadf2 ;if found, load the file ;file not found mov a,c ;restore user number sta fcb+13 call gotofn ;put cursor where file name msg would go call print db 'New Alias File: ',0 call prtname ;print it call endprmt ;end highlight and add a space stc ;set carry to show error ret ;load the alias file loadf2: lxi h,buffer ;pt to load buffer mvi c,alsect+1 ;set block count loadf3: lxi d,fcb ;pt to FCB call f$read ;read next block jnz aliaschk ;done loading, check for alias id lxi d,tbuff ;pt to DMA buffer xchg mvi b,128 ;copy 128 bytes to buffer call hmovb xchg ;DE pts to next block dcr c ;count down blocks jnz loadf3 ;if file not too long, read some more ; error - not an alias file noalias: call gotofn call print db bell db 'File ',0 call prtname call print db '.COM is Not an Alias',0 call endprmt mvi a,' ' ;blank out the FCB sta fcb+1 stc ;show that load failed ret ; load complete - check for alias file structure aliaschk: call f$close ;close input file call retud ;restore user number to FCB lxi h,fcb+13 mov m,c lhld buffer+1 ;get address where loaded alias starts lxi d,buffer-100H+9 ;calc address in buffer where alias id dad d ; should be lxi d,aliasid ;compare to model in this code mvi b,8 ;8 chars acheck: ldax d ;get char cmp m ;compare jnz noalias inx h ;pt to next inx d dcr b ;count down jnz acheck push h ;save ptr command line in loaded alias ;determine mode of file if new type alias lhld buffer+1 ;get address of START in alias lxi b,buffer-2-100h ;offset to where 'F' marker byte would be dad b ;..2 bytes before START address mvi b,0 ;default flag value mov a,m ;is it an 'F'? cpi 'F' jnz acheck1 ;if not, use default flag value inx h ;advance to mode flag value mov b,m ;get flag into B acheck1: lxi h,modeflag ;store the mode flag value mov m,b call dispmode ;display mode and file name on screen pop h call copycmds ;copy cmds to command list buffer call listall ;list commands to screen xra a ;clear carry flag to show success ret ;----------------------------------------------------------------------------- ; MAKECL -- Make Command Line ; This code reads through the commands in CMDLIST and builds a single command ; line from them. HL points to the commands in CMDLIST and DE points to the ; command line in BUFFER. C is used to count count through the commands in ; CMDLIST, and B is used to count the number of characters in the command line ; that is being built. If the number of characters in the line exceeds the ; number allowed in ZCPR3's multiple command line buffer, an error is reported. ; (Because of parameter expansion and the fact that aliases may be combined ; with other commands on a line, this is no guarantee that the line is short ; enough. However, a line longer than this will certainly fail.) makecl: ;initialization call getcl1 ;get length of Z3 command line into A sta z3cllen ;save value lxi h,cmdlist lxi d,buffer lxi b,0+maxcmds ;B = 0 and C = number of commands in list makecl1: ;build command line command by command push h ;save pointer to beginning of command call apndcmd ;append this command to command line jc makecl3 ;carry set if command line too long pop h ;get back address of beginning of cmd push d ;save command line pointer lxi d,cmdlen ;advance HL to next line in CMDLIST dad d pop d ;restore command line pointer dcr c ;see if all commands processed jnz makecl1 makecl2: mvi a,0 ;put null at end of command line stax d ret makecl3: ;command line is too long pop h ;clean up stack call prompt db bell db 'Command Line Too Long - Truncated',0 call print db ' strike any key',0 call capin jmp makecl2 z3cllen: db 0 ;space to keep ZCPR3 multiple cmd line length ;----------------------------------------------------------------------------- ; NOWHEEL ; This routine is called if the user does not have wheel status. nowheel: call print ;print warning message db bell,cr,lf,lf db ' Access Denied -- Not Wheel',0 jmp quit ;and abort ;----------------------------------------------------------------------------- ; PRTNAME ; This subroutine prints a string of up to eight characters. It prints the ; name but not the type of the file in the default FCB. prtname: call retud ;set bc to current drive/user lxi h,fcb ;point to FCB mov a,m ;get drive ora a ;test for default specification jnz prtname1 ;if explicit, skip getting default mov a,b ;get current drive value into A inr a ;use range 1 - 16 sta fcb ;make fcb have explicit drive prtname1: adi 'A'-1 ;convert to ascii call cout ;..and display drive letter mov a,c ;get user number of current area sta fcb+13 ;put it into fcb call pafdc ;print it mvi a,':' ;put in colon call cout inx h ;point to name of file mvi b,8 ;8 chars prtname2: mov a,m ;get character cpi ' ' ;if space rz ;return immediately call cout ;else display it inx h ;pt to next char dcr b ;count down jnz prtname2 ret ;----------------------------------------------------------------------------- ; PROMPT ; This routine moves the cursor to the place where the prompt is to be ; put, turns on highlighting, puts in a space, prints the string following ; the call to PROMPT, puts in another space, terminates highlighting, and ; puts in one more space. prompt: call gotoprmt ;position for the prompt pop h ;get address of string call pstr ;print the string push h ;put return address onto stack call endprmt ;termination the prompt ret ;----------------------------------------------------------------------------- ; QUIT ; This code restores the original CP/M stack and returns. quit: call getud ;restore original drive/user area call print db cr,lf,lf,0 lhld oldstack sphl ret ;----------------------------------------------------------------------------- ; READCMD ; This code reads in a new command and capitalizes it. On return HL points ; to the command entered, and A has the length. If the length exceeds ; the allowd length, then a message is placed at the bottom of the screen ; until a key is struck. Then the screen is redrawn and new input is ; requested. readcmd: call gotowork ;position cursor to working command mvi a,0ffh ;capitalize the input line call bbline cpi cmdlen ;check length of command entered rc ;length is OK, so return call prompt db 'ERROR -- line to long -- strike any key and reenter:' db 0 call capin jmp readcmd ;----------------------------------------------------------------------------- ; SETCMDPTR ; This routine sets HL to the address where the command specified by the ; number in A is stored. No registers are changed except for HL. setcmdptr: push d push psw lxi h,cmdlist ;point to start of buffer lxi d,cmdlen ;spacing between commands inr a ;increment to handle zero case setptr1: dcr a ;see if done jz setptr2 dad d jmp setptr1 setptr2: pop psw pop d ret ;----------------------------------------------------------------------------- ; SETCOM ; set file type of file in FCB to COM setcom: push h lxi h,fcb+9 mvi m,'C' inx h mvi m,'O' inx h mvi m,'M' pop h ret ;----------------------------------------------------------------------------- ; SETENV ; This routine copies the environment information put into VALIAS0 by ; Z3INS to the model alias appended to VALIAS0. This is required so ; that the alias file produced by VALIAS does not have to be installed ; manually by Z3INS. setenv: call codend ;point to model alias at end of VALIAS0 inx h ;pt to start of environment info inx h ;..in ALIAS1 model inx h lxi d,envdefn ;pt to environment definition in VALIAS0 mvi b,8 ;prepare to copy 8 bytes for class 1 ; bytes are: DB 'Z3ENV',1 ; DW envaddr lda envclas ;get code for class of alias cpi 1 ;class 1 is address of Env Desc only jz setenv1 mvi b,100H-3 ;prepare to copy an entire env desc ;copy the buffers over setenv1: ldax d ;copy environment definition into new alias mov m,a inx h ;advance inx d dcr b ;count down jnz setenv1 ret ;----------------------------------------------------------------------------- ; SIGNON ; This subroutine clears the screen and prints the signon message. signon: call cls ;clear the screen call stndout ;highlight on call print db ' VALIAS ' db (version/10)+'0','.',(version mod 10)+'0' db 0 call endprmt ret ;----------------------------------------------------------------------------- ; SPACE ; This code inserts a single space in text sent to the console. space: mvi a,' ' ;put in leading space call cout ret ;----------------------------------------------------------------------------- ; STORECMD ; This routine stores the newly entered command into the command list. It ; assumes that readcmd was called before this and that HL points to the input ; buffer and that the length of the entered command is in A. It then displays ; the new command on the screen. storecmd: ;get pointer into command list push h ;save pointer to input buffer push psw ;save length of command lda workcmd ;get working command number call setcmdptr ;set up pointer to command pop psw ;get command line length back ;copy command in input buffer to command list xchg ;destination in de pop h ;get source address back push d ;save address of command in list mov b,a ;put input line length in B ora a ;check for zero length cnz hmovb ;copy the command line if not null xra a ;put null at end of command stax d ;refresh the single line of the display lda workcmd ;get working command number again adi 3 ;compute screen line number mov h,a mvi l,5 ;point to screen column 5 call gotoxy ;position cursur pop h ;HL points to new command in list call pstr ;print the command call ereol ret ;----------------------------------------------------------------------------- ; ZEROCMDS ; This subroutine clears the buffer used to hold the individual commands ; for the alias. It fills the space required for MAXCMDS commands of max ; length LINELEN. zerocmds: lxi h,cmdlist lxi b,maxcmds*cmdlen+1 xra a call fillbc ret ;============================================================================= ; D A T A A R E A ; The data in this area must be included in the actual code in order for ; codeend to find the end of the code correctly and not produce a memory ; conflict with this data. Therefore, make sure the list ends with a DB or DW. aliasid: db 'Z3 ALIAS' ;ALIAS File ID workcmd: db 0 ;number of working command insflag: db 0 ;flag to show whether space was opened for modeflag: db 0 ;flag to show mode (0 = normal, FF = recursive) ;insertion of new command oldstack: dw 0000h ;address of stack pointer on entry rept 25 dw 0 ;space for 25 stack entries endm stack: end