NAM HDOS09 TTL COMMAND INTERFACE WITH HISTORY ********************************************************** * HDOS09 is a command line interface with some improved * * editing capabilities. It runs as an application that * * run commands via the DOCMND flex function. * * The program itself consist of a launcher that use the * * Flex MEMEND variable to put itself just before MEMEND * * address and move MEMEND from BFFF to BBFF-B7FF, given * * the size (175 to 1199 bytes) needed for the history. * * HSIZE allows to select the amount of memory used * * Prompt is modified to '$ ' (show you are using Hdos09) * * -- New functions with control characters : * * ^B and ^F are used to move the cursor in the command * * line (Backward, Forward) * * ^A and ^E move the cursor to start and end of line * * ^P (previous) and ^N (next) let you navigate history * * ^H (backspace) delete the character before the cursor * * ^X delete the character under the cursor * * Entering a printable character insert it before cursor * * CR (Return) run the command, wherever the cursor is * * -- New commands : * * h (or H) display history * * q (or Q) leave Hdos09, end restore MEMEND * * ! runs the th command in history * * * * (C) 2022 Michel J. Wurtz under GPL2 licence : * * https://opensource.org/licenses/GPL-2.0 * ********************************************************** * Flex memory fields used LINBUF EQU $C080 Line buffer start TTYBS EQU $CC00 Backspace character TTYDEL EQU $CC01 Delete caracter TTYEOL EQU $CC02 End of line character TTYBE EQU $CC07 Backspace echo charater TTYESC EQU $CC0A Escape character LINPTR EQU $CC14 Line buffer pointer MEMEND EQU $CC2B End of user memory SCRTCH EQU $CC2A System scratch BUFLEN EQU $CC2A = SCRTCH : length of current line SCRTC3 EQU $CC30 System scratch (3 bytes) * Flex entry points used WARMS EQU $CD03 Warm entry point PSTRNG EQU $CD1E Print string INCHNE EQU $D3E5 Get char w/o echo (indirect) PUTCHR EQU $CD18 print char in A PCRLF EQU $CD24 print CR/LF OUTDEC EQU $CD39 Output reg D in decimal INDEC EQU $CD48 Input décimal number DOCMND EQU $CD4B run command in BUFLIN * Constant used CR EQU $0D Cariage Return - terminate entry LF EQU $0A Line Feed BK EQU $02 ^B move cursor backward FW EQU $06 ^F move cursor forward BL EQU $01 ^A move cursor to 1st character EL EQU $05 ^E move cursor to end of line PR EQU $10 ^P Previous command NX EQU $0E ^N Next command BS EQU $08 ^H (Backspace) erase prev. char DEL EQU $18 ^X erase current character * Size of history + this utility (from $400 to $800) HSIZE EQU $600 687 bytes for history * Loader : only used for moving program under MEMEND ORG $A000 HSTART LDX MEMEND Search start of hdos STX HEND Save it for futur use LEAX -HSIZE,X New value of MEMEND STX MEMEND LEAX 1,X LDY #HINIT code to move HLOAD LDA ,Y+ STA ,X+ CMPY #HIST+2 BNE HLOAD LDX MEMEND JMP 1,X Jump to HINIT (moved to HEND+1) * * Relocatable part : goes to $B800 if HSIZE = $800 * This suppose a non modified system with MEMEND = $BFFF * * ORG $BFFF-HSIZE+1 uncomment for debug only ! HINIT LEAU HEND,PC LEAX 8,U Clean history STX 2,U Initialise pointers STX 4,U STX 6,U CLRA CLEAN STA ,X+ CMPX ,U HEND BNE CLEAN * * Main DOS routine : prompt + read/edit a line * RDLINE LEAU HEND,PC init pointer to hist data JSR PCRLF Output prompt LDA #'$' JSR PUTCHR LDA #$20 JSR PUTCHR LDX #LINBUF STX LINPTR CLR LINBUF CLR LINBUF+1 CLR BUFLEN start with emplty command * * Get a new char from keybord and manage it * GETC JSR [INCHNE] Main loop for input data CMPA #CR Carriage Return ? LBEQ LAUNCH Add to history and run command * * CTRL_B - Move cursor left (Backward) * CMPA #BK ^B : move cursor left BNE CTRL_F LDX LINPTR CMPX #LINBUF if start of line do nothing BEQ GETC LEAX -1,X STX LINPTR LDA #BS GETCE JSR PUTCHR BRA GETC * * CTRL_F - Move cursor right (Forward) * CTRL_F CMPA #FW ^F : move cursor right BNE CTRL_A LDX LINPTR LDA ,X BEQ GETC If end of line do nothing LDA ,X+ increment pointer and STX LINPTR BRA GETCE print char in place * * CTRL_A - go to beginning of line * CTRL_A CMPA #BL ^A move cursor to line start BNE CTRL_E LDD LINPTR SUBD #LINBUF calc length of move LDA #BS TSTB CTRA1 BEQ CTRA2 JSR PUTCHR move cursor DECB BRA CTRA1 CTRA2 LDX #LINBUF adjust pointer STX LINPTR BRA GETC * * CTRL_E - go to end of line * CTRL_E CMPA #EL ^E : move cursor to end of line BNE TST_BS LDX LINPTR CTRE1 LDA ,X+ reprint to end of line BEQ CTRE2 JSR PUTCHR BRA CTRE1 CTRE2 LEAX -1,X restore cursor position STX LINPTR BRA GETCE * * CTRL_H (BACKSPACE) - Erase previous character * TST_BS CMPA #BS Backspace : erase previous char BNE TSTDEL LDX LINPTR CMPX #LINBUF if start of line do nothing BEQ GETC LEAX -1,X STX LINPTR update pointer LDA #BS move on screen JSR PUTCHR BRA MVLINE * * CTRL_X (DELETE) - Erase current character * TSTDEL CMPA #DEL ^X : erase current char BNE CTRL_P LDX LINPTR LDA ,X LBEQ GETC If end of line do nothing MVLINE DEC BUFLEN One char less CLRB NXTC LDA 1,X STA ,X+ BEQ MVCUR JSR PUTCHR and reprint end of line INCB BRA NXTC MVCUR STA ,X LDA #$20 erase last char with a space JSR PUTCHR LDA #BS move cursor back INCB MVCUR2 JSR PUTCHR DECB BNE MVCUR2 LBRA GETC * * CTRL_P - recall previous command * CTRL_P CMPA #PR ^P : Previous command in history BNE CTRL_N LDB [6,U] Current Command is the first ? LBEQ GETC Yes, do nothing NEGB SEX BMI EXT LDA #$FF EXT LDX 6,U Calc. pos. of previous command LEAX D,X LEAY 8,U STY SCRTC3 CMPX SCRTC3 Wrap around end of hist. space ? BHS NOWRAP TFR X,D ADDD ,U SUBD SCRTC3 TFR D,X LEAX 1,X correct displacement... LDB 1,X NOWRAP STX 6,U BRA PUTCMD go rewrite command line * * CTRL_N - recall next command * CTRL_N CMPA #NX ^N - Next command in history BNE NOCTRL LDX 6,U CMPX 4,U LBEQ GETC last command : do nothing LDA ,X+ LBSR TSTWRP history wrap around ? LDB ,X+ STB BUFLEN new command length ABX CMPX ,U BLE PUTCMD go rewrite command line TFR X,D SUBD ,U LEAX 8,U LEAX D,X LEAX -1,X correct displacement... PUTCMD STX 6,U modify current command index LBSR REPCMD copy command on command line LBRA GETC wait for another keyboard input * * Printable char, add to or insert in command line * NOCTRL CMPA #$20 Printable char ? LBMI GETC Other ctrl character ignored LDB BUFLEN CMPB #127 Line too long ? LBEQ GETC Do nothing... LDX #LINBUF end of line ? ABX INC BUFLEN update buffer length CMPX LINPTR BNE INSRT if not end of line ... JSR PUTCHR Add char to buffer and print it STA ,X+ STX LINPTR CLR ,X keep end of string... LBRA GETC * Char entered must be inserted in command line INSRT STA SCRTC3 Save char entered LDA ,X CPNXT STA 1,X move string right of cursor LDA ,-X CMPX LINPTR BNE CPNXT STA 1,X LDA SCRTC3 char entered STA ,X+ put char entered at cursor pos. STX LINPTR and move cursor right CLRB WRCH JSR PUTCHR print char entered INCB and move to end of line LDA ,X+ BNE WRCH LDA #BS move cursor to its previous pos. CPBS DECB LBEQ GETC JSR PUTCHR move cursor back until BRA CPBS cursor previous position * * CR - Final step : run command * LAUNCH LDB BUFLEN LBEQ RDLINE Empty command, go to prompt LDX #LINBUF ABX STX LINPTR STA ,X LDA LINBUF CMPB #1 BNE RECALL ANDA #$5F CMPA #'H' h or H - Print history BEQ PRHIST CMPA #'Q' q or Q - quit interpreter BNE RECALL LDX ,U restore MEMEND STX MEMEND JMP WARMS Go to Flex warm start RECALL CMPA #'!' ! recall a command BNE FLXCMD LBSR BANG LBCS RDLINE No command found... LDA #CR STA [LINPTR] FLXCMD BSR ADDCMD Add command to history list LDX #LINBUF STX LINPTR Run command JSR DOCMND LBRA RDLINE * * Command 'H' - Print command history * PRHIST LDX 2,U LDD -2,U Initialise command number STD SCRTC3 LDB ,X+ BSR TSTWRP NXTCMD LDB ,X+ BSR TSTWRP TSTB LBEQ RDLINE last command ? return to prompt JSR PCRLF BSR PRCMD Print command BRA NXTCMD * * Print one command by line * PRCMD PSHS B,X Save current length and position LDX #SCRTC3 print command number JSR OUTDEC LDX SCRTC3 increment command number LEAX 1,X STX SCRTC3 NONUM LDA #$20 space JSR PUTCHR PULS B,X PRC1 LDA ,X+ print command BSR TSTWRP PRC2 JSR PUTCHR DECB BNE PRC1 LDB ,X+ BSR TSTWRP wap around history buffer PRCE RTS * * Wrap in history buffer ? * TSTWRP CMPX ,U at MEMEND ? BLE WRPOK LEAX 8,U yes, go to HIST first byte WRPOK RTS * * Add command in history * ADDCMD LDX 4,U last command place ADDC0 LEAX 1,X Get next byte BSR TSTWRP hit MEMEND ? LDB BUFLEN STB ,X+ store command length (without CR) BSR TSTWRP hit MEMEND ? LDY #LINBUF Command to add ADDC1 BSR TSTHIT Hit the beginning of list ? LDA ,Y+ STA ,X+ BSR TSTWRP DECB BNE ADDC1 BSR TSTHIT LDB BUFLEN ADDB #2 length of command + 2 (header) STX 4,U set pointers for LAST and CURRENT STX 6,U STB ,X+ header of last (future entry) BSR TSTWRP BSR TSTHIT CLR ,X mark end of new entry RTS * * Move FIRST pointer to next entry * * * Start of history list reached when adding a command * in history ? If yes, move first ptr to next entry * TSTHIT PSHS A,B,X CMPX 2,U hit first command in history ? BNE NOHIT no, return LDA ,X+ BSR TSTWRP MVH2 LDB ,X+ ABX CMPX ,U past the end of HIST buffer ? BLE MVOK no, OK, go with it TFR X,D compute offset from HIST SUBD ,U SUBD #1 LEAX 8,U LEAX D,X MVOK STX 2,U New value to FIRST CLR ,X LDD -2,U to keep the number for commands ADDD #1 STD -2,U NOHIT PULS A,B,X,PC * * Copy command to line buffer, print it for edit * X contains the current command address in memory * REPCMD LDA #CR rewrite prompt at start of line JSR PUTCHR LDA #'$' JSR PUTCHR LDA #$20 JSR PUTCHR LDY #LINBUF LDA ,X+ skip link to previous BSR TSTWRP end of hist buffer reached ? LDB ,X+ STB BUFLEN save length of command BNE NXTCC TFR Y,X BRA REPC1 NXTCC LBSR TSTWRP copy to line buffer LDA ,X+ STA ,Y+ DECB BNE NXTCC LDX #LINBUF LDB BUFLEN NXPR LDA ,X+ print command JSR PUTCHR DECB BNE NXPR REPC1 STX LINPTR update buffer pointer LDA ,X BEQ PREND former cmd shorter than actual ? PRSP INCB CLRA STA ,X+ terminate the command line LDA #$20 clear end of line on screen JSR PUTCHR LDA ,X BNE PRSP LDA #BS and move cursor to end of cmd PRBS JSR PUTCHR DECB BNE PRBS PREND RTS (test => carry always clear) * * Command !N - run the Nth command * BANG LDX #LINBUF+1 STX LINPTR get number JSR INDEC BCS ERRBG not a decimal number TSTB BEQ ERRBG CMPX -2,U compare to first command number BLO ERRBG lost in wrap around STX SCRTC3 LDY -2,U Y containe current command number LDX 2,U Oldest command COMPAR CMPY SCRTC3 BEQ RUNIT command found in history LDA ,X+ no, go to next command LBSR TSTWRP LDB ,X+ BEQ ERRBG LBSR TSTWRP LEAY 1,Y increment command number ABX CMPX ,U BLE COMPAR end of history ? TFR X,D SUBD ,U LEAX 8,U LEAX D,X BRA COMPAR no, go to next command RUNIT LEAY 1,X Last command is an empty slot CMPY ,U (length = 0) and not in history BLE RUN2 LEAY 8,U RUN2 LDA ,Y BEQ ERRBG hence go to error message LDA #LF command ok JSR PUTCHR skip line LDB ,X and print command LBRA REPCMD carry is clear on return... * Command not found in history ERRBG LEAX ERRMSG,PCR JSR PSTRNG ORCC #1 set carry if error RTS ERRMSG FCC "Bad command number" FCB 4 * * Data for history. Must be accessed position independant * CMDNUM FDB 1 First command number HEND FDB 0 MEMEND old val. = HIST buffer end FIRST FDB 0 First (oldest) command in history LAST FDB 0 Last command in history CURRNT FDB 0 Current command in history HIST FDB 0 History list (up to MEMEND)