; DOS-EDIT.ASM -- Resident DOS Command Line Editor ; ================================================ CSEG Segment Assume CS:CSEG Org 0080h KeyboardBuffer Label Byte Org 0100h Entry: Jmp Initialize ; All Data ; -------- db "(C) Copyright 1985 Ziff-Davis Publishing Co." OldInterrupt21 dd ? ; Original Interrupt 21 vector OldInterrupt16 dd ? ; Original Interrupt 16 vector DoingBuffKey db 0 ; Flag for doing Function Call 0Ah BufferPointer dw KeyboardBuffer ; Pointer to Keyboard Buffer BufferCounter db 0 ; Number of characters in buffer MaxCharCol db ? ; Maximum Character Column on screen OriginalCursor dw ? ; Place to save cursor on full-screen InsertOn db 0 ; Insert mode flag KeyRoutine dw Home,Up,PgUp,Dummy,Left,Dummy,Right dw Dummy,End,Down,PgDn,Insert,Delete ; New Interrupt 21 (DOS Function Calls) ; ------------------------------------- NewInterrupt21 Proc Far Mov CS:[DoingBuffKey],0 ; Turn flag off initially Cmp AH,0Ah ; Check if doing buffered input Jz BufferedInput Jmp CS:[OldInterrupt21] ; If not, do regular interrupt BufferedInput: Mov CS:[DoingBuffKey],-1 ; If so, turn on flag PushF ; Simulate regular interrupt Call CS:[OldInterrupt21] Mov CS:[DoingBuffKey],0 ; Turn off flag Mov CS:[BufferCounter],0 ; Re-set character counter IRet ; Return to user program NewInterrupt21 EndP ; New Interrupt 16 (BIOS Keyboard Routine) ; ---------------------------------------- NewInterrupt16 Proc Far Sti ; Re-enable interrupts Cmp CS:[DoingBuffKey],0 ; Check if doing call 0Ah Jz DoNotIntercept ; If not, do old interrupt Cmp CS:[BufferCounter],0 ; Check if chars in buffer Jnz Substitute ; If so, get them out Cmp AH,0 ; See if doing a get key Jz CheckTheKey ; If so, get the key DoNotIntercept: Jmp CS:[OldInterrupt16] ; Otherwise, do old interrupt CheckTheKey: PushF ; Save flags Call CS:[OldInterrupt16] ; Do regular interrupt Cmp AX,4800h ; Check if up cursor Jnz NotTriggerKey ; If not, don't bother Call FullScreen ; Move around the screen Cmp CS:[BufferCounter],0 ; Any chars to deliver? Jz CheckTheKey ; If not, get another key ReturnBuffer: Call GetBufferChar ; Otherwise, pull one out Inc CS:[BufferPointer] ; Kick up the pointer Dec CS:[BufferCounter] ; And knock down the counter NotTriggerKey: IRet ; And go back to calling prog ; Substitute Key from Buffer ; -------------------------- Substitute: Cmp AH,2 ; See if shift status check Jae DoNotIntercept ; If so, can't be bothered Cmp AH,0 ; See if get a key Jz ReturnBuffer ; If so, get the key above Call GetBufferChar ; Otherwise get a key Cmp CS:[BufferCounter],0 ; And clear zero flag Ret 2 ; Return with existing flags NewInterrupt16 EndP ; Get Buffer Character ; -------------------- GetBufferChar: Push BX Mov BX,CS:[BufferPointer] ; Get pointer to key buffer Mov AL,CS:[BX] ; Get the key Sub AH,AH ; Blank out scan code Pop BX Ret ; Full Screen Routine ; ------------------- FullScreen: Push AX ; Save all these registers Push BX Push CX Push DX Push DI Push DS Push ES Mov AX,CS ; Set AX to this segment Mov DS,AX ; Do DS is this segment Mov ES,AX ; And ES is also Assume DS:CSEG, ES:CSEG ; Tell the assembler Mov AH,0Fh ; Get Video State Int 10h ; through BIOS Dec AH ; Number of columns on screen Mov [MaxCharCol],AH ; Save maximum column ; BH = Page Number throughout Mov AH,03h ; Get cursor in DX Int 10h ; through BIOS Mov [OriginalCursor],DX ; And save the cursor position Call Up ; Move cursor up MainLoop: Cmp DH,Byte Ptr [OriginalCursor + 1] ; If at line Jz TermFullScreen ; stated from, terminate Mov AH,02h ; Set cursor from DX Int 10h ; through BIOS GetKeyboard: Mov AH,0 ; Get the next key PushF ; By simulating Interrupt 16h Call CS:[OldInterrupt16] ; which goes to BIOS Cmp AL,1Bh ; See if Escape key Jz TermFullScreen ; If so, terminate full screen ; Back Space ; ---------- Cmp AL,08h ; See if back space Jnz NotBackSpace ; If not, continue test Or DL,DL ; Check if cursor at left Jz MainLoop ; If so, do nothing Dec DL ; Otherwise, move cursor back Call ShiftLeft ; And shift line to the left Jmp MainLoop ; And continue for next key ; Carriage Return ; --------------- NotBackSpace: Cmp AL,0Dh ; See if Carriage Return Jnz NotCarrRet ; If not, continue test Call End ; Move line into buffer Mov AL,0Dh ; Tack on a Carriage Return Stosb ; By writing to buffer Inc [BufferCounter] ; One more character in buffer Jmp MainLoop ; And continue ; Normal Character ; ---------------- NotCarrRet: Cmp AL,' ' ; See if normal character Jb NotNormalChar ; If not, continue test Cmp [InsertOn],0 ; Check for Insert mode Jz OverWrite ; If not, overwrite Call ShiftRight ; Shift line right for insert Jmp Short NormalCharEnd ; And get ready to print OverWrite: Mov CX,1 ; Write one character Mov AH,0Ah ; By calling BIOS Int 10h NormalCharEnd: Call Right ; Cursor to right and print Jmp MainLoop ; Back for another key ; Cursor Key, Insert, or Delete Subroutine ; ---------------------------------------- NotNormalChar: Xchg AL,AH ; Put extended code in AL Sub AX,71 ; See if it's a cursor key Jc GetKeyboard ; If not, no good Cmp AX,12 ; Another check for cursor Ja GetKeyboard ; If not, skip it Add AX,AX ; Double for index Mov DI,AX ; into vector table Call [KeyRoutine + DI] ; Do the routine Jmp MainLoop ; Back for another key ; Terminate Full Screen Movement ; ------------------------------ TermFullScreen: Mov DX,[OriginalCursor] ; Set cursor to original Mov AH,2 ; And set it Int 10h ; through BIOS Pop ES ; Restore all registers Pop DS Pop DI Pop DX Pop CX Pop BX Pop AX Ret ; And return to New Int. 16h ; Cursor Movement ; --------------- Home: Mov DL,Byte Ptr [OriginalCursor] ; Move cursor to Ret ; to original column Up: Or DH,DH ; Check if at top row Jz UpEnd ; If so, do nothing Dec DH ; If not, decrement row UpEnd: Ret PgUp: Sub DL,DL ; Move cursor to far left Ret Left: Or DL,DL ; Check if cursor at far left Jnz GoWest ; If not, move it left Mov DL,[MaxCharCol] ; Move cursor to right Jmp Up ; And go up one line GoWest: Dec DL ; Otherwise, decrement column Ret Right: Cmp DL,[MaxCharCol] ; Check if cursor at far right Jb GoEast ; If not, move it right Sub DL,DL ; Set cursor to left of screen Jmp Down ; And go down one line GoEast: Inc DL ; Otherwise, increment column Ret End: Call TransferLine ; Move line to buffer Mov DX,[OriginalCursor] ; Set cursor to original Ret Down: Inc DH ; Move cursor down one row Ret PgDn: Mov CL,[MaxCharCol] ; Get last column on screen Inc CL ; Kick it up by one Sub CL,DL ; Subtract current column Sub CH,CH ; Set top byte to zero Mov AL,' ' ; Character to write Mov AH,0Ah ; Write blanks to screen Int 10h ; through BIOS Dummy: Ret ; Insert and Delete ; ----------------- Insert: Xor [InsertOn],-1 ; Toggle the InsertOn flag Ret ; and return Delete: Call ShiftLeft ; Shift cursor line left Ret ; and return ; Transfer Line on Screen to Keyboard Buffer ; ------------------------------------------ TransferLine: Sub CX,CX ; Count characters in line Mov DI,Offset KeyboardBuffer ; Place to store 'em Mov [BufferPointer],DI ; Save that address Cld ; String direction forward GetCharLoop: Mov AH,02h ; Set Cursor at DX Int 10h ; through BIOS Mov AH,08h ; Read Character & Attribute Int 10h ; through BIOS Stosb ; Save the character Inc CX ; Increment the counter Inc DL ; Increment the cursor column Cmp DL,[MaxCharCol] ; See if at end of line yet Jbe GetCharLoop ; If not, continue Dec DI ; Points to end of string Mov AL,' ' ; Character to search through Std ; Searching backwards Repz Scasb ; Search for first non-blank Cld ; Forward direction again Jz SetBufferCount ; If all blanks, skip down Inc CL ; Number of non-blanks Inc DI ; At last character SetBufferCount: Inc DI ; After last character Mov [BufferCounter],CL ; Save the character count Ret ; Return from routine ; Shift Line One Space Right (For Insert) ; --------------------------------------- ShiftRight: Push DX ; Save original cursor Mov DI,AX ; Character to insert ShiftRightLoop: Call ReadAndWrite ; Read character and write Inc DL ; Kick up cursor column Cmp DL,[MaxCharCol] ; Check if it's rightmost Jbe ShiftRightLoop ; If not, keep going Pop DX ; Get back original cursor Ret ; And return from routine ; Shift Line One Space Left (For Delete) ; -------------------------------------- ShiftLeft: Mov DI,0020h ; Blank at end Mov BL,DL ; Save cursor column Mov DL,[MaxCharCol] ; Set cursor to end of line ShiftLeftLoop: Call ReadAndWrite ; Read character and write Dec DL ; Kick down cursor column Cmp DL,BL ; See if at original yet Jge ShiftLeftLoop ; If still higher, keep going Inc DL ; Put cursor back to original Ret ; And return from routine ; Read and Write Character for Line Shifts ; ---------------------------------------- ReadAndWrite: Mov AH,2 ; Set Cursor from DX Int 10h ; through BIOS Mov AH,08h ; Read Character and Attribute Int 10h ; through BIOS Xchg AX,DI ; Switch with previous char Mov CX,1 ; One character to write Mov AH,0Ah ; Write character only Int 10h ; through BIOS Ret ; Return from Routine ; Initialization on Entry ; ----------------------- Initialize: Sub AX,AX ; Make AX equal zero Mov DS,AX ; To point to vector segment Les BX,dword ptr DS:[21h * 4]; Get and save Int. 21h Mov Word Ptr CS:[OldInterrupt21],BX Mov Word Ptr CS:[OldInterrupt21 + 2],ES Les BX,dword ptr DS:[16h * 4]; Get and save Int. 16h Mov Word Ptr CS:[OldInterrupt16],BX Mov Word Ptr CS:[OldInterrupt16 + 2],ES Push CS ; Restore DS register Pop DS ; by setting to CS Mov DX,Offset NewInterrupt21 Mov AX,2521h ; Set new Interrupt 21h Int 21h ; through DOS Mov DX,Offset NewInterrupt16 Mov AX,2516h ; Set new Interrupt 16h Int 21h ; through DOS Mov DX,Offset Initialize ; Number of bytes to stay Int 27h ; Terminate & remain resident CSEG EndS End Entry