Category : Display Utilities
Archive   : ANSI.ZIP
Filename : ANSI.ASM

 
Output of file : ANSI.ASM contained in archive : ANSI.ZIP
;------------------------------------------------------------------------;
; ANSI.COM - Replacement for the ANSI.SYS console device driver. ;
; Unlike ANSI.SYS which must be installed at boot time, ANSI.COM ;
; can be installed and uninstalled at anytime. Enhancements include ;
; a fast screen write and variable sized keyboard reassignment buffer. ;
;------------------------------------------------------------------------;
_TEXT SEGMENT PUBLIC 'CODE'
ASSUME CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
ORG 100H
START: JMP INITIALIZE

SIGNATURE DB "ANSI 1.0 (C) 1989 Ziff Communications Co.",CR,LF
PROGRAMMER DB "PC Magazine ",254," Michael J. Mefford",CR,LF,LF,"$",26

CR EQU 13
LF EQU 10
SPACE EQU 32
ESC_CHAR EQU 27
SINGLE_QUOTE EQU 39
DOUBLE_QUOTE EQU 34
BELL EQU 7
BS EQU 8

OFF EQU 1
ON EQU 2
SLOW EQU 4
FAST EQU 8
STATUS_MASK EQU 11111100B

ANSI_STATE DW ESC_STATE
STATUS DB ON OR FAST
PARAMETERS DB "OFF ON SLOWFAST"
LAST_PARAMETER EQU $ - PARAMETERS

OLD_INT_29 DW ?,?
OLD_INT_16 DW ?,?
OLD_INT_21 DW ?,?

ATTRIBUTE DB 7
SAVE_POSITION DW 0
LINE_WRAP DB ON
QUOTE_TYPE DB ?
ESC_COUNT DW 0
NUMBER_COUNT DW 0

FORMAT_CHARS DB CR,LF,BS,BELL
FORMAT_LENGTH EQU $ - FORMAT_CHARS

COMMAND_TABLE LABEL BYTE
DB "H", "A", "B", "C", "D", "f", "n", "s", "u", "K", "m", "h", "l", "p", "J"
COMMAND_LENGTH EQU $ - COMMAND_TABLE

DW CURS_POSITION, CURSOR_UP, CURSOR_DOWN, CURS_FORWARD, CURS_BACKWARD
DW HORZ_VERT_POS, DEVICE_STATUS, SAVE_CURSOR, RESTORE_CURS, ERASE_IN_LINE
DW SGR, SET_MODE, RESET_MODE, REASSIGNMENT, CLS
COMMAND_END EQU $ - 2

ATTRIBUTE_TABLE LABEL BYTE
DB 00,01,04,05,07,08,30,31,32,33,34,35,36,37,40,41,42,43,44,45,46,47
ATTRIBUTE_LENGTH EQU $ - ATTRIBUTE_TABLE

;Format: AND mask,OR mask
DB 000H,07H, 0FFH,08H, 0F8H,01H, 0FFH,80H, 0F8H,70H, 088H,00H
DB 0F8H,00H, 0F8H,04H, 0F8H,02H, 0F8H,06H, 0F8H,01H, 0F8H,05H
DB 0F8H,03H, 0F8H,07H, 08FH,00H, 08FH,40H, 08FH,20H, 08FH,60H
DB 08FH,10H, 08FH,50H, 08FH,30H, 08FH,70H
ATTRIBUTE_END EQU $ - 2

BIOS_ACTIVE_PAGE EQU 62H
ACTIVE_PAGE DB ?
ADDR_6845 DW ?
BIOS_CRT_MODE EQU 49H
CRT_MODE DB ?
CRT_COLS DW ?
CRT_LEN DW ?
CRT_START DW ?
CRT_DATA_LENGTH EQU $ - CRT_MODE
CURSOR_POSN LABEL WORD
CURSOR_COL DB ?
CURSOR_ROW DB ?
CRT_ROWS DB ?

DOS_INPUT DB OFF
BUSY_FLAG DB OFF
REASSIGN_FLAG DB OFF
REMOVE_FLAG DB ON
REASSIGN_COUNT DW 0
REASSIGN_POS DW ?
FUNCTION_16 DB ?
ZR EQU 1000000B

ESC_BUFFER_SIZE EQU 126
REASSIGNMENT_DEFAULT EQU 200
REASSIGNMENT_SIZE DW REASSIGNMENT_DEFAULT
REASSIGNMENT_MAX EQU 60 * 1024
REASSIGN_END DW REASSIGNMENT_BUFFER
BUFFER_END DW REASSIGNMENT_BUFFER + REASSIGNMENT_DEFAULT

;------------------------------------------------------------------------------;
; INT 29 is an undocumented interrupt called by DOS for output to the console. ;
;------------------------------------------------------------------------------;
ANSI_INT_29 PROC FAR

PUSH AX ;Save all registers.
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
PUSH BP

CLD ;All string operations forward.
MOV BX,CS ;Point to our data segment.
MOV DS,BX
MOV ES,BX
CALL ANSI_STATE ;Call the current state of
; the ANSI Esc sequence.
POP BP
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX ;Restore all registers and
IRET ; return.
ANSI_INT_29 ENDP

;------------------------------------------------;
ANSI_INT_21 PROC FAR
PUSHF
CMP AH,0AH ;If DOS Int 21 functions Ah,
JZ INPUT ; 7h, 1h or console input (6h)
CMP AH,7 ; then tell INT 16, DOS input
JZ INPUT ; is active.
CMP AH,1
JZ INPUT
CMP AH,6
JNZ QUICK21_EXIT
CMP DL,0FFH
JZ INPUT
QUICK21_EXIT: POPF ;If not, let the original
JMP DWORD PTR CS:OLD_INT_21 ; interrupt process the call.

INPUT: POPF
MOV CS:DOS_INPUT,ON ;INT 16 handler flag.
PUSHF
CALL DWORD PTR CS:OLD_INT_21 ;Emulate an interrupt.
MOV CS:DOS_INPUT,OFF ;Turn flag back off.
RET 2 ;Return with current flags.
ANSI_INT_21 ENDP

;-----------------------------------------------------------------;
; If we get here via a DOS console input call, any awaiting key ;
; in keyboard buffer is checked to see if it is to be reassigned. :
;-----------------------------------------------------------------;
ANSI_INT_16 PROC FAR
STI ;Interrupts back on.
PUSHF ;Preserve flags on stack.
PUSH BP
PUSH DS
PUSH AX
PUSH CS ;Point to our data.
POP DS

CMP DOS_INPUT,OFF ;If not called via a DOS
JZ QUICK16_EXIT ; console input call, exit.
CMP BUSY_FLAG,ON ;If already processing a call,
JZ QUICK16_EXIT ; exit.
CLD ;All string operations forward.
MOV BP,SP ;Base reference to flags on stack
MOV FUNCTION_16,AH ;Save function request.
AND AH,NOT 10H ;Strip possible extended request.
JZ GET_KEY ;If zero, it's wait for a key.
DEC AH ;Else, decrement. If zero it's
JZ KEY_STATUS ; key status, else exit.

QUICK16_EXIT: POP AX ;Restore registers and let
POP DS ; original interrupt handler
POP BP ; process the call.
POPF
JMP DWORD PTR CS:OLD_INT_16

KEY_STATUS: OR BYTE PTR [BP+6],ZR ;Assume none ready; ZR = 1.
GET_KEY: MOV BUSY_FLAG,ON ;Non-reentrant; flag busy.
POP AX
PUSH BX ;Save some more registers.
PUSH CX
PUSH DX
PUSH SI
PUSH DI
CMP REASSIGN_FLAG,ON ;Already in process of reassign?
JZ CK_BUFFER ;If yes, check kbd buffer.

PUSHF ;Else, emulate an interrupt.
CALL DWORD PTR OLD_INT_16
PUSHF ;Status call results in flags.
TEST FUNCTION_16,1 ;Was it a status call?
JZ CK_DUP ;If no, check key returned.
POPF ;Else, retrieve status results.
JZ INT16_EXIT ;If zero, no key waiting.
AND BYTE PTR [BP+6],NOT ZR ;Else, ZR = 0.
PUSHF ;PUSHF just to keep stack right.

CK_DUP: POPF ;Fix stack.
MOV BX,AX ;Match procedure wants key in BX.
CALL CK_MATCH ;Check reassignment buffer.
JC INT16_EXIT ;If no match, exit.
MOV AX,[DI] ;Else, retrieve string length.
SUB AX,3 ;Adjust for length word and match
ADD DI,3 ; byte; same for string pointer.
OR BL,BL ;Extended key? ie. key = 0.
JNZ STORE_COUNT ;If no, save length and pointer.
DEC AX ;Else, adjust for extended code.
INC DI
STORE_COUNT: MOV REASSIGN_COUNT,AX ;Save string length.
MOV REASSIGN_POS,DI ;Save pointer to string.
MOV REASSIGN_FLAG,ON ;Flag that replacement in effect.
CK_BUFFER: TEST FUNCTION_16,1 ;Was it a key wait function call?
JNZ RETRIEVE ;If no, key status; get it.
CMP REMOVE_FLAG,OFF ;Removed it from kbd buffer?
JZ RETRIEVE ;If yes, get reassignment.
MOV AH,FUNCTION_16 ;Else, eat the replaced character
INT 16H ; via INT 16.
MOV REMOVE_FLAG,OFF ;Flag character eaten.

RETRIEVE: MOV DI,REASSIGN_POS ;Retrieve pointer to string.
MOV AX,[DI] ;Retrieve replacement character.
TEST FUNCTION_16,1 ;Is it a key wait function call?
JZ REMOVE ;If yes, bump pointer up one.
AND BYTE PTR [BP+6],NOT ZR ;If no, status call; ZR = 0
JMP SHORT INT16_EXIT ;All done.

REMOVE: INC REASSIGN_POS ;Move pointer to next character.
DEC REASSIGN_COUNT ;One less character to replace.
JZ REASSIGN_DONE ;If end of string, reset flags.
OR AL,AL ;Else, extended replacement?
JNZ INT16_EXIT ;If no, done here.
INC REASSIGN_POS ;Else adjust pointers.
DEC REASSIGN_COUNT
JNZ INT16_EXIT ;End of string?
REASSIGN_DONE: MOV REASSIGN_FLAG,OFF ;If yes, reset flags.
MOV REMOVE_FLAG,ON

INT16_EXIT: MOV BUSY_FLAG,OFF ;Reset the busy flag.
POP DI ;Restore registers.
POP SI
POP DX
POP CX
POP BX
POP DS
POP BP
POPF ;Flags on stack have status
RET 2 ; results; kill old flags.
ANSI_INT_16 ENDP

;************* ANSI ESCAPE STATE ROUTINES ************* ;

ESC_STATE: MOV BX,OFFSET BRACKET_STATE ;Assume Esc character.
CMP AL,ESC_CHAR ;Is it Esc? If yes, store
JZ SHORT_JUMP ; char. and next state.
JMP WRITE_CHAR ;Else, normal char; write it.

;------------------------------------------------;
BRACKET_STATE: MOV BX,OFFSET SPECIAL_STATE ;Assume left bracket.
CMP AL,"[" ;Is it left bracket? If yes,
SHORT_JUMP: JZ STORE_STATE ;store char. and next state.
JMP FLUSH_BUFFER ;Else, flush Esc out of buffer.

;---------------------------------------------------------------;
; Must process [2J (CLS) regardless if ANSI.COM ON or OFF. ;
;---------------------------------------------------------------;
SPECIAL_STATE: MOV BX,OFFSET CLS_STATE ;Assume Erase in Display code.
CMP AL,"2" ;Is it the "2" ?
JZ STORE_STATE ;If yes, progress to next state.
TEST STATUS,OFF ;Else, is ANSI OFF ?
JNZ FLUSH_BUFFER ;If yes, flush Esc, bracket.
MOV BX,OFFSET PARAM_STATE ;Else, check for first Set,
CMP AL,"=" ; Reset Mode characters of
JZ STORE_STATE ; "=" and "?".
CMP AL,"?"
JZ STORE_STATE ;If found, store.
JMP SHORT DO_PARAMETER ;Else, check other codes.

;------------------------------------------------;
CLS_STATE: CMP AL,"J" ;Is it second character of CLS?
MOV DI,OFFSET COMMAND_END ;If yes, execute
JZ EXECUTE ; Erase in Display procedure.
TEST STATUS,OFF ;ANSI OFF? If yes, flush buffer.
JNZ FLUSH_BUFFER ; If not fall through to process.
MOV BYTE PTR NUMBER_BUFFER,2 ;Store the previous 2.
DO_PARAMETER: MOV ANSI_STATE,OFFSET PARAM_STATE ;Parameter state.

;------------------------------------------------;
PARAM_STATE: CALL CK_QUOTE ;Is it single or double quotes?
JZ STORE_STATE ;If yes, store string state.
CMP AL,";" ;Is it semi-colon delimiter?
JNZ CK_NUMBER ;If no, check if number.
INC NUMBER_COUNT ;Else, increment number count.
JMP SHORT BUFFER_CHAR ;Buffer the semi-colon.

CK_NUMBER: CMP AL,"0" ;Is it below 0 ?
JB FLUSH_BUFFER ;If yes, illegal; flush buffer.
CMP AL,"9" ;Else, is it above 9 ?
JA DO_COMMAND ;If yes, check for command char.
CALL ACCUMULATE ;Else it's a number; accumulate.
JMP SHORT BUFFER_CHAR ;Buffer the character.

DO_COMMAND: MOV DI,OFFSET COMMAND_TABLE ;Point to legal ANSI commands.
MOV CX,COMMAND_LENGTH ;Number of commands.
REPNZ SCASB ;Check for a match.
JNZ FLUSH_BUFFER ;If no match, flush sequence.
INC NUMBER_COUNT ;Else, increment for last number.
MOV DI,OFFSET COMMAND_END ;Point to appropriate command
SHL CX,1 ; processing procedure.
SUB DI,CX
EXECUTE: CALL GET_BIOS_DATA ;Get cursor position data.
CALL DS:[DI] ;Do command subroutine.
JMP SHORT FLUSH_END ;Clear buffer.

;------------------------------------------------;
QUOTE_STATE: CMP AL,QUOTE_TYPE ;Is it an ending string quote?
JNZ BUFFER_CHAR ;If no, buffer literal.
MOV BX,OFFSET PARAM_STATE ;Else, back to parameter parsing.

;------------------------------------------------;
STORE_STATE: MOV ANSI_STATE,BX ;Store the ANSI state.

;------------------------------------------------;
BUFFER_CHAR: MOV DI,ESC_COUNT ;Buffer the character in case
CMP DI,ESC_BUFFER_SIZE ; ending ANSI command is illegal.
JZ FLUSH_BUFFER ;If buffer full, flush.
ADD DI,OFFSET ESC_BUFFER ;Point to next buffer position.
STOSB ;Store the character.
INC ESC_COUNT ;Increment the sequence count.
RET

;------------------------------------------------;
FLUSH_BUFFER: PUSH AX ;Save the current character.
MOV SI,OFFSET ESC_BUFFER ;Point to the sequence buffer.
MOV CX,ESC_COUNT ;Count of buffered characters.
NEXT_FLUSH: LODSB ;Retrieve one.
PUSH CX ;Save counter and pointer.
PUSH SI
CALL WRITE_CHAR ;Write character to screen.
POP SI ;Restore counter and pointer.
POP CX
LOOP NEXT_FLUSH ;Flush entire buffer.
POP AX ;Retrieve last character.
CALL WRITE_CHAR ;Write it also.
FLUSH_END: MOV ESC_COUNT,0 ;Reset counter.
MOV ANSI_STATE,OFFSET ESC_STATE ;Back to Esc state.
MOV NUMBER_COUNT,0 ;Reset parameter counter.
PUSH CS ;Point to our data.
POP ES
MOV DI,OFFSET NUMBER_BUFFER ;Clear number buffer
MOV CX,ESC_BUFFER_SIZE / 2 ; to zeros.
XOR AX,AX
REP STOSW
RET

;------------------------------------------------;
; Slow video writes are via BIOS Write TTY. ;
;------------------------------------------------;
WRITE_CHAR: MOV DI,OFFSET FORMAT_CHARS ;Let BIOS process carriage
MOV CX,FORMAT_LENGTH ; return, linefeed, backspace
REPNZ SCASB ; and bell via
JZ WRITE_TTY ; TTY.

CALL GET_BIOS_DATA ;Get BIOS video data.
CMP AL,9 ;Is character a TAB?
JNZ CK_ACTIVE ;If no, process normally.
MOV CX,CURSOR_POSN ;Else, expand TAB to
AND CX,7 ; appropriate space characters.
NEG CX
ADD CX,8
NEXT_TAB: PUSH CX
MOV AL,SPACE
CALL CK_ACTIVE
POP CX
LOOP NEXT_TAB
RET

CK_ACTIVE: TEST STATUS,OFF ;Is ANSI OFF?
JNZ WRITE_TTY ;If yes, write via BIOS TTY.
CK_FAST: CALL CK_SLOW_TEXT ;Is ANSI SLOW or in graphics
JNC WRITE_FAST ; mode? If no, write fast.

WRITE_SLOW: PUSH AX ;Else, write character/attribute
MOV CX,1 ; at current cursor position
MOV BH,ACTIVE_PAGE ; via BIOS.
MOV BL,ATTRIBUTE
MOV AH,9
INT 10H
POP AX

CMP LINE_WRAP,ON ;Is line wrap on?
JZ TTY ;If yes, continue.
MOV CX,CRT_COLS ;Else, cursor at rightmost
DEC CL ; column?
CMP CL,CURSOR_COL ;If yes, continue, else
JNZ TTY ; return without writing.
RET

;------------------------------------------------;
WRITE_TTY: MOV BL,7 ;Attribute in graphics mode.
TTY: MOV AH,0EH
INT 10H
RET

;----------------------------------------------------------------------------;
; Fast screen writes are directly to the video buffer without retrace check. ;
;----------------------------------------------------------------------------;
WRITE_FAST: PUSH ES ;Preserve extra segment.
MOV DX,CURSOR_POSN ;Retrieve cursor position.
CALL VIDEO_SETUP ;Calculate video address.
MOV AH,ATTRIBUTE ;Retrieve attribute.
STOSW ;Put char/attrib in video buffer.
INC DL ;Increment cursor column.
CMP DL,BYTE PTR CRT_COLS ;End of row?
JB UPDATE_CURSOR ;If no, update cursor.

CMP LINE_WRAP,OFF ;Else, line wrap off?
JZ FAST_END ;If yes, don't move cursor.
XOR DL,DL ;Else, column zero.
INC DH ;Next row.
CALL INFORMATION ;Get displayable row info.
CMP DH,AL ;Beyond the bottom of screen?
JBE UPDATE_CURSOR ;If no, update cursor.

DEC DH ;Else, cursor to original row.
MOV DI,CRT_START ;Point destination to top.
MOV SI,DI ;Point source to second row
MOV AX,CRT_COLS ; by adding width in columns
PUSH AX ; twice for char/attribute.
ADD SI,AX
ADD SI,AX
MUL DH ;Times displayable rows - 1.
MOV CX,AX ; equals char/attrib to scroll.
PUSH DS ;Save data segment and
PUSH ES ; point to video segment.
POP DS
REP MOVSW ;Scroll the screen.
POP DS ;Restore data segment.
POP CX ;Retrieve CRT columns.
MOV AL,SPACE ;Write space/attrib to
MOV AH,ATTRIBUTE ; bottom row.
REP STOSW

UPDATE_CURSOR: CALL SET_CURSOR ;Update the cursor position.
FAST_END: POP ES ;Restore extra segment.
RET

;************* SUPPORT ROUTINES *************;

CK_QUOTE: MOV BX,OFFSET QUOTE_STATE ;Assume quote state.
MOV AH,DOUBLE_QUOTE
CMP AL,AH ;Is it double quote?
JZ GOT_QUOTE ;If yes, string delimiter.
MOV AH,SINGLE_QUOTE ;Is it single quote?
CMP AL,AH ;Is yes, string delimiter.
JNZ QUOTE_END ;Else, return ZR = 0.
GOT_QUOTE: MOV QUOTE_TYPE,AH ;Store as matching string end.
QUOTE_END: RET

;------------------------------------------------;
ACCUMULATE: PUSH AX ;Preserve number character.
SUB AL,"0" ;Convert ASCII to binary.
MOV CL,AL ;Save the number.
MOV AX,10 ;Multiply previous count by 10.
MOV BX,NUMBER_COUNT
MUL BYTE PTR NUMBER_BUFFER[BX]
ADD AL,CL ;Add in new number
MOV BYTE PTR NUMBER_BUFFER[BX],AL ; and store.
POP AX
RET

;---------------------------------------------------------------------------;
; OUTPUT: CY = 1 if write SLOW mode or in graphics mode; CY = 0 otherwise. ;
;---------------------------------------------------------------------------;
CK_SLOW_TEXT: TEST STATUS,SLOW
JNZ SLOW_MODE
CMP CRT_MODE,7
JZ TEXT_MODE
CMP CRT_MODE,3
JA SLOW_MODE
TEXT_MODE: CLC
RET

SLOW_MODE: STC
RET

;-------------------------------------;
; OUTPUT: AL = Screen rows minus one ;
;-------------------------------------;
INFORMATION: PUSH DS ;Save data segment.
MOV AX,40 ;Point to BIOS data.
MOV DS,AX
MOV AL,DS:[84H] ;Retrieve rows - 1.
OR AL,AL ;BIOS supported?
JNZ INFO_END ;If yes, done here.
MOV AL,24 ;Else, assume 25 lines.
INFO_END: POP DS
RET

;------------------------------------------------------------------------------;
; INPUT: DX = Cursor position. ;
; OUTPUT: ES = Video buffer segment; DI = Video buffer offset; AX,DX preserved ;
;------------------------------------------------------------------------------;
VIDEO_SETUP: PUSH AX
MOV AX,CRT_COLS ;Retrieve CRT columns.
MUL DH ;Times cursor row.
MOV BL,DL
XOR BH,BH
ADD AX,BX ;Plus cursor column.
SHL AX,1 ;Times two for attribute.
MOV DI,CRT_START ;Plus starting video offset.
ADD DI,AX ;Equals destination.

MOV BX,0B000H ;Assume mono card.
CMP ADDR_6845,3B4H ;Is it mono port?
JZ VIDEO_SEGMENT ;If yes, guessed right.
ADD BX,800H ;Else, point to color segment.
VIDEO_SEGMENT: MOV ES,BX
POP AX
RET

;------------------------------------------------;
; Move BIOS video data into our data segment. ;
;------------------------------------------------;
GET_BIOS_DATA: PUSH DS
PUSH DI ;Point to BIOS data segment.
MOV BX,40H
MOV DS,BX
MOV SI,BIOS_ACTIVE_PAGE ;Start with active page.
MOV DI,OFFSET ACTIVE_PAGE
MOVSB ;Retrieve active page
MOVSW ; and address of 6845 port.
MOV SI,BIOS_CRT_MODE ;Retrieve CRT mode, CRT columns,
MOV CX,CRT_DATA_LENGTH ; CRT length, CRT start.
REP MOVSB
MOV BL,ES:ACTIVE_PAGE ;Use active page as index
XOR BH,BH ; of active cursor position.
SHL BX,1
ADD SI,BX
MOVSW
POP DI
POP DS
RET

;----------------------------------------------------------------------------;
; OUTPUT: BL = First parameter; BH = Second parameter; DX = cursor position. ;
;----------------------------------------------------------------------------;
ADJUST_NUMBER: MOV BX,WORD PTR NUMBER_BUFFER
OR BH,BH
JNZ ADJUST_AL ;If either parameter zero,
INC BH ; increment to convert
ADJUST_AL: OR BL,BL ; to base one.
JNZ ADJUST_END
INC BL
ADJUST_END: MOV DX,CURSOR_POSN ;Return cursor position.
RET

;--------------------------------------------------------------------------;
; INPUT: AX = number; BP = 0 if console output; BP = 1 if storage output. ;
;--------------------------------------------------------------------------;
DECIMAL_OUT: MOV BX,10 ;Divisor of ten.
XOR CX,CX ;Zero in counter.
NEXT_COUNT: XOR DX,DX ;Zero in high half.
DIV BX ;Divide by ten.
ADD DL,"0" ;Convert to ASCII.
PUSH DX ;Save results.
INC CX ;Also increment count.
CMP AX,0 ;Are we done?
JNZ NEXT_COUNT ;Continue until zero.
OR BP,BP ;If BP zero, output to screen.
JNZ DEVICE_OUTPUT ;Else, store in buffer.

REPORT_OUTPUT: POP AX ;Retrieve number.
CALL PRINT_CHAR ;Display it.
LOOP REPORT_OUTPUT
RET

DEVICE_OUTPUT: POP AX ;Retrieve number.
STOSB ;Store it
LOOP DEVICE_OUTPUT
RET

;************* ANSI COMMAND SUBSET *************;

CLS: CALL INFORMATION ;Get displayable rows.
MOV DH,AL ;Store in DH.
MOV BH,7 ;Assume normal attribute.
TEST STATUS,OFF ;Is ANSI OFF?
JNZ CLS_SLOW ;If yes, CLS via BIOS.
MOV BH,ATTRIBUTE ;Else, requested attribute.
CALL CK_SLOW_TEXT
JC CLS_SLOW ;If ANSI SLOW, via BIOS.

CLS_FAST: MOV AH,BH ;Else, attribute in high half.
MOV AL,SPACE ;Space character in low half.
XOR DX,DX ;Cursor position home.
CALL VIDEO_SETUP ;Calculate video address.
MOV CX,CRT_LEN ;Retrieve CRT length.
SHR CX,1 ;Times two for attribute.
REP STOSW ;Write directly to video buffer.
JMP SHORT SET_CURSOR ;Set the cursor top left corner.

CLS_SLOW: MOV DL,BYTE PTR CRT_COLS ;Retrieve CRT columns.
DEC DL ;Adjust to zero base.
XOR CX,CX ;Scroll active page.
MOV AX,600H
INT 10H
XOR DX,DX ;Home the cursor.
JMP SHORT SET_CURSOR

;------------------------------------------------;
CURS_POSITION: ;These two commands are the same.
HORZ_VERT_POS: CALL INFORMATION ;Returns AL = screen rows.
CALL ADJUST_NUMBER ;Returns BL,BH = parameters.
SUB BX,101H ;Zero based.
CMP BL,AL ;If cursor request within
JA CURSOR_END ; boundaries of screen, set it.
CMP BH,BYTE PTR CRT_COLS
JAE CURSOR_END
XCHG BH,BL
MOV DX,BX

SET_CURSOR: MOV BH,ACTIVE_PAGE ;Set cursor via BIOS.
MOV AH,2
INT 10H
CURSOR_END: RET

;------------------------------------------------;
CURSOR_UP: CALL ADJUST_NUMBER ;Move cursor up one or more rows
OR DH,DH ; without changing column.
JZ CURSOR_END ;If already at top, ignore.
SUB DH,BL
JNC SET_CURSOR ;Stay in bounds.
XOR DH,DH
JMP SHORT SET_CURSOR

;------------------------------------------------;
CURSOR_DOWN: CALL INFORMATION ;Returns AL = screen rows.
CALL ADJUST_NUMBER ;Returns BL,BH =nos.; DX = cursor
CMP DH,AL ;Move cursor down requested
JZ CURSOR_END ; rows without changing column.
ADD DH,BL
CMP DH,AL
JNA SET_CURSOR
MOV DH,AL ;Stay in bounds.
JMP SHORT SET_CURSOR

;------------------------------------------------;
CURS_FORWARD: CALL ADJUST_NUMBER ;Returns BL,BH =nos.; DX = cursor
MOV BH,BYTE PTR CRT_COLS ;Retrieve displayable columns.
DEC BH ;Adjust to zero base.
CMP DL,BH ;Move cursor forward one or more
JZ CURSOR_END ; columns without changing row.
ADD DL,BL
CMP DL,BH
JNA SET_CURSOR
MOV DL,BH ;Stay in bounds.
JMP SHORT SET_CURSOR

;------------------------------------------------;
CURS_BACKWARD: CALL ADJUST_NUMBER ;Returns BL,BH =nos.; DX = cursor
OR DL,DL ;Move cursor backward one or
JZ CURSOR_END ; more columns without changing
SUB DL,BL ; row. Ignore if already left.
JNC SET_CURSOR
XOR DL,DL ;Stay in bounds.
JMP SHORT SET_CURSOR

;--------------------------------------------------------;
; Report cursor position via console; Format: ESC[#;#R ;
;--------------------------------------------------------;
DEVICE_STATUS: MOV DI,OFFSET DEVICE_STATUS_BUFFER
MOV AL,ESC_CHAR
STOSB ;Store leading Esc, bracket
MOV AL,"[" ;in special Device Status Buffer.
STOSB

MOV AL,CURSOR_ROW ;Retrieve cursor row.
XOR AH,AH ;Zero in high half.
INC AX ;Convert to base one.
MOV BP,1 ;Flag as storage.
CALL DECIMAL_OUT ;Convert to ASCII.
MOV AL,";" ;Store delimiting semi-colon.
STOSB
MOV AL,CURSOR_COL ;Do same with cursor column.
XOR AH,AH
INC AX
CALL DECIMAL_OUT
MOV AL,"R" ;Add command character
STOSB
MOV AL,CR ; and carriage return.
STOSB
SUB DI,OFFSET DEVICE_STATUS_BUFFER ;Setup for console out.
MOV REASSIGN_COUNT,DI
MOV REASSIGN_POS,OFFSET DEVICE_STATUS_BUFFER
MOV REASSIGN_FLAG,ON
MOV REMOVE_FLAG,OFF
RET

;------------------------------------------------;
SAVE_CURSOR: MOV DX,CURSOR_POSN
MOV SAVE_POSITION,DX
RET

;------------------------------------------------;
RESTORE_CURS: MOV DX,SAVE_POSITION
JMP SET_CURSOR

;------------------------------------------------;
ERASE_IN_LINE: MOV DX,CURSOR_POSN ;Erase from the cursor to
MOV CX,CRT_COLS ; the end of the line, including
SUB CL,DL ; the current cursor position.
CALL CK_SLOW_TEXT
JC ERASE_SLOW ;If ANSI ON and not graphics,
CALL VIDEO_SETUP ; write directly to video buffer
MOV AL,SPACE ; with space/attribute.
MOV AH,ATTRIBUTE
REP STOSW
RET

ERASE_SLOW: MOV CX,DX ;Else, erase SLOW via
MOV DL,BYTE PTR CRT_COLS ; BIOS scroll active page.
DEC DL
MOV BH,ATTRIBUTE
MOV AX,601H
INT 10H
RET

;------------------------------------------------;
; Set Graphics Rendition ;
;------------------------------------------------;
SGR: MOV SI,OFFSET NUMBER_BUFFER ;Point to number parameters.
NEXT_SGR: LODSB ;Retrieve parameter.
MOV DI,OFFSET ATTRIBUTE_TABLE ;Look up attribute in
MOV CX,ATTRIBUTE_LENGTH ; translation table.
REPNZ SCASB
JNZ SGR_LOOP

MOV DI,OFFSET ATTRIBUTE_END
SHL CX,1
SUB DI,CX
MOV AX,[DI]
AND ATTRIBUTE,AL ;If match, AND with strip mask.
OR ATTRIBUTE,AH ;OR with add mask.
SGR_LOOP: DEC NUMBER_COUNT ;Do all parameters.
JNZ NEXT_SGR
RET

;------------------------------------------------;
SET_MODE: MOV AH,ON ;Assume command 7,
JMP SHORT CK_WRAP ; turn line wrap on.

;------------------------------------------------;
RESET_MODE: MOV AH,OFF ;Assume turn line wrap off.
CK_WRAP: MOV AL,BYTE PTR NUMBER_BUFFER ;Retrieve number parameter.
CMP AL,7 ;Is it 7?
JZ SET_WRAP ;If yes, set wrap mode.
JB DO_MODE ;1 - 6 valid modes.
CMP AL,14 ;14 - 16 valid modes.
JB MODE_END
CMP AL,19
JA MODE_END ;If above 16, illegal.
DO_MODE: XOR AH,AH ;Else, set video mode
INT 10H ; to parameter.
RET

SET_WRAP: MOV LINE_WRAP,AH
MODE_END: RET

;--------------------------------------------------------------------;
; Keyboard Key Reassignment: First convert ASCII numbers to binary, ;
; parse out delimiting semi-colons, and quote string delimiters. ;
;--------------------------------------------------------------------;
REASSIGNMENT: MOV CX,ESC_COUNT ;Retrieve length of Esc sequence.
DEC CX ;Adjust.
MOV SI,OFFSET ESC_BUFFER + 2 ;Point past Esc, bracket.
MOV DI,OFFSET PARSE_BUFFER ;Point to parse storage.
NEXT_STRING: MOV QUOTE_TYPE,0 ;Reset quote type.
NEXT_NUM: XOR DL,DL ;Use DL to carry number; init = 0
XOR BP,BP ;Use BP as number flag.
NEXT_PARAM: LODSB ;Retrieve a byte.
DEC CX ;Decrement string length counter.
JZ PARSE_END ;If zero, done.
MOV AH,QUOTE_TYPE ;Else, retrieve quote type.
OR AH,AH ;If zero, not in string.
JNZ QUOTE_MODE ;Else, go to string mode.
CALL CK_QUOTE ;Is character a quote?
JZ NEXT_PARAM ;If yes, ignore.
CMP AL,";" ;Else, is it semi-colon?
JZ STORE_NUMBER ;If yes, number delimiter.

SUB AL,"0" ;Else, must be number; convert
MOV DH,AL ; to binary; save in DH.
MOV AX,10 ;Multiply current total by ten.
MUL DL
ADD AL,DH ;Add new number.
MOV DL,AL ;Save in DL.
MOV BP,1 ;Flag that number mode active.
JMP SHORT NEXT_PARAM ;Next parameter.

STORE_NUMBER: OR BP,BP ;If number mode flag not set then
JZ NEXT_PARAM ;semi-colon not prefaced with no.
MOV AL,DL ;Else, store number.
STOSB
JMP SHORT NEXT_NUM ;Reset number carrying registers.

QUOTE_MODE: CMP AL,AH ;Is current char a string ending
JZ NEXT_STRING ; quote? If yes, exit quote mode
STOSB ;Else, store char as literal.
JMP SHORT NEXT_PARAM

;----------------------------------------------------------------------------;
; Remove duplicate assignments if removal leaves room for new assignment. ;
; If no duplicate and room, add new assignment, else flush buffer to screen. ;
;----------------------------------------------------------------------------;
PARSE_END: OR BP,BP ;Was last parameter a number?
JZ CK_LENGTH ;If no, skip.
MOV AL,DL ;Else, store the last number.
STOSB
CK_LENGTH: SUB DI,OFFSET PARSE_BUFFER - 2 ;Calculate string length
MOV AX,DI ; including word for length.
MOV BX,WORD PTR PARSE_BUFFER ;BL=new first ASCII; BH=2nd.
MOV CX,5 ;String length has to be at
OR BL,BL ;least word + 2 for old + new = 5
JZ CK_LEGAL ; for extended key reassignment.
DEC CX ;And word + 1 for old + new = 4
CK_LEGAL: CMP AX,CX ; for regular ASCII reassignment.
JB ASSIGN_FLUSH ;If not, illegal; flush buffer.
MOV BP,BUFFER_END ;BP to carry buffer end pointer.
CALL CK_MATCH ;Is char already reassigned?
JC CK_ROOM ;If no, check room for new.

CK_REMOVE: MOV CX,DX ;REASSIGN_END - string end
SUB CX,SI ; = bytes to move.
JZ CK_ROOM ;If zero, last string.
SUB DX,[DI] ;Is REASSIGN_END - old string
ADD DX,AX ; + new string >
CMP DX,BP ; BUFFER_END?
JA ASSIGN_FLUSH ;If yes, flush buffer to screen.
REP MOVSB ;Else, move them down in buffer.
JMP SHORT STORE_NEW

CK_ROOM: ADD DX,AX ;New string + current strings.
CMP DX,BP ;Greater than buffer size?
JA ASSIGN_FLUSH ;If yes, flush new string.
STORE_NEW: MOV SI,OFFSET PARSE_BUFFER ;Else, room for new string.
STOSW ;Store string length first.
MOV CX,AX ;Adjust counter.
DEC CX
DEC CX
REP MOVSB ;Store the actual string.
MOV REASSIGN_END,DI ;Store new string end.
RET

ASSIGN_FLUSH: MOV AL,"p" ;If buffer full, flush string
JMP FLUSH_BUFFER ; including ending "p" command.

;------------------------------------------------------------------------------;
; INPUT: BL = first ASCII code to match; BH = extended if BL = 0 ;
; OUTPUT: CY = 1 if no match found; CY = 0 if match found. ;
; DI points to string length of match; DI+2 points to start of string. ;
; SI = end of string; DX = REASSIGN_END; BP = BUFFER_END ;
;------------------------------------------------------------------------------;
CK_MATCH: MOV DX,REASSIGN_END ;Current strings end.
MOV SI,OFFSET REASSIGNMENT_BUFFER ;Point to buffer.
NEXT_MATCH: MOV DI,SI ;Current record.
CMP DI,DX ;End of strings?
JAE NO_MATCH ;If yes, no match.
MOV CX,[DI+2] ;CL=current first ASCII; CH=2nd
ADD SI,[DI] ;Point to next record.
CMP BL,CL ;First characters match?
JNZ NEXT_MATCH ;If no, check next record.
OR BL,BL ;Extended code? ie zero.
JNZ MATCH ;If no, then match.
CMP BH,CH ;Else, check second code.
JNZ NEXT_MATCH ;If not same, no match.
MATCH: CLC ;Else return with CY = 0
RET

NO_MATCH: STC ;No match; CY = 1.
RET

;----------------------------------------------------------------------;
; Buffer area will write over disposable data and initialization code. ;
;----------------------------------------------------------------------;
ESC_BUFFER = $
NUMBER_BUFFER = ESC_BUFFER + ESC_BUFFER_SIZE
PARSE_BUFFER = NUMBER_BUFFER
DEVICE_STATUS_BUFFER = PARSE_BUFFER + ESC_BUFFER_SIZE
DEVICE_STATUS_SIZE = 11
REASSIGNMENT_BUFFER = DEVICE_STATUS_BUFFER + DEVICE_STATUS_SIZE

; DISPOSABLE DATA
; ---------------

SYNTAX LABEL BYTE
DB "Usage: ANSI [FAST | SLOW][ON | OFF][/B nnn][/C][/U]",CR,LF
DB "FAST = direct screen writes; default",CR,LF
DB "SLOW = screen writes via BIOS",CR,LF
DB "ON/OFF = active/inactive; default is ON",CR,LF
DB "nnn = buffer size in bytes (0-60K) reserved for key reassignment; "
DB "default 200",CR,LF
DB "/U = Uninstall"
CR_LF DB CR,LF,LF,"$"

STATUS_MSG DB "Status: $"
BUFFER_MSG DB CR,LF,"Buffer size: $"
BYTES_FREE DB CR,LF,"Bytes free: $"
ANSI_SYS_MSG DB "ANSI.SYS is installed so "
NOT_INSTALLED DB "ANSI.COM not installed",CR,LF,"$"
CON DB "CON"
CON_OFFSET EQU 10

SIZE_MSG DB "Uninstall to change buffer size",CR,LF,LF,"$"
UNLOAD_MSG DB "ANSI can't be uninstalled",CR,LF
DB "Uninstall resident programs in reverse order",CR,LF,"$"
NOT_ENOUGH DB "Not enough memory",CR,LF,"$"
ALLOCATE_MSG DB "Memory allocation error",CR,LF,BELL,"$"
INSTALL_MSG DB "Installed",CR,LF,"$"
UNINSTALL_MSG DB "Uninstalled",CR,LF,"$"

;--------------------------------------------------------------------;
; Search memory for a copy of our code, to see if already installed. ;
;--------------------------------------------------------------------;
INITIALIZE PROC NEAR
CLD ;All string operations forward.
MOV BX,OFFSET START ;Point to start of code.
NOT BYTE PTR [BX] ;Change a byte so no false match.
XOR DX,DX ;Start at segment zero.
MOV AX,CS ;Store our segment in AX.
NEXT_PARAG: INC DX ;Next paragraph.
MOV ES,DX
CMP DX,AX ;Is it our segment?
JZ ANNOUNCE ;If yes, search is done.
MOV SI,BX ;Else, point to our signature.
MOV DI,BX ; and offset of possible match.
MOV CX,16 ;Check 16 bytes for match.
REP CMPSB
JNZ NEXT_PARAG ;If no match, keep looking.

;------------------------------------------------;
ANNOUNCE: MOV DX,OFFSET SIGNATURE ;Display our signature.
CALL PRINT_STRING
MOV DX,OFFSET SYNTAX ;And syntax.
CALL PRINT_STRING
MOV SI,81H ;Point to command line.
NEXT_CAP: LODSB ;Capitalize parameters.
CMP AL,CR
JZ PARSE
CMP AL,"a"
JB NEXT_CAP
CMP AL,"z"
JA NEXT_CAP
AND BYTE PTR [SI - 1],5FH
JMP SHORT NEXT_CAP

;------------------------------------------------;
PARSE: MOV SI,81H ;Point to command line again.
NEXT_PARA: XOR AX,AX ;Position in status parameters.
MOV BX,4 ;Status parameters each 4 bytes.
NEXT_STATUS: MOV DI,OFFSET PARAMETERS ;Point to "OFF ON SLOWFAST"
ADD DI,AX ;Point to next parameter.
ADD AX,BX
CMP AX,LAST_PARAMETER ;Check all four possible statuses
JA CK_SWITCHES
PUSH SI ;Save command line pointer.
MOV CX,2 ;Check first two bytes for match.
REP CMPSB
POP SI ;Recover command line pointer.
JNZ NEXT_STATUS

DIV BL ;If match, divide offset by four.
MOV CL,1 ;Set a bit to match offset.
NEXT_SHIFT: SHL CL,1
DEC AL
JNZ NEXT_SHIFT
SHR CL,1 ;Adjust.
MOV AH,STATUS_MASK ;Retrieve appropriate ON/OFF
CMP CL,ON ; or FAST/SLOW mask.
JBE ADD_STATUS
ROL AH,1
ROL AH,1

ADD_STATUS: AND ES:STATUS,AH ;Mask off old status.
OR ES:STATUS,CL ;Add new status.
INC SI ;Bump command line pointer.
INC SI

CK_SWITCHES: LODSB ;Get a byte.
CMP AL,CR ;Is it carriage return?
JZ INSTALL ;If yes, done here.
CMP AL,"/" ;Is there a switch character?
JNZ NEXT_PARA ;If no, keep looking.
LODSB ;Else, get the switch character.
CMP AL,"B" ;Is it "B" ?
JNZ CK_C ;If no, check "C".
CALL CK_INSTALLED ;Else, see if already installed.
JZ GET_SIZE ;If no, get buffer request size.
MOV DX,OFFSET SIZE_MSG ;Else, display error message.
CALL PRINT_STRING
JMP SHORT NEXT_PARA
GET_SIZE: CALL DECIMAL_INPUT ;Get number parameter.
CMP BX,REASSIGNMENT_MAX ;If greater than maximum, use
JBE STORE_BUFFER ; maximum, else use requested
MOV BX,REASSIGNMENT_MAX ; size.
STORE_BUFFER: MOV REASSIGNMENT_SIZE,BX
ADD BX,OFFSET REASSIGNMENT_BUFFER ;Calculate end of buffer.
MOV BUFFER_END,BX
JMP SHORT NEXT_PARA

CK_C: CMP AL,"C" ;Is it "C" ?
JNZ CK_U ;If not, check "U".
MOV ES:REASSIGN_END,OFFSET REASSIGNMENT_BUFFER ;Clear buffer
CK_U: CMP AL,"U" ;Is it "U" ?
JZ DO_U ;If yes, try to uninstall.
JMP NEXT_PARA ;Else, next parmater.
DO_U: CALL CK_INSTALLED ;Else, see if installed.
MOV DX,OFFSET NOT_INSTALLED ;If no, exit with error message.
JZ LILLY_PAD ;Too far for short jump.
JMP UNINSTALL ;Else, uninstall.

;------------------------------------------------;
INSTALL: CALL STATUS_REPORT ;Display status.
CALL CK_INSTALLED ;Check if already installed.
JZ CK_AVAILABLE ;If no, see if enough memory.
OR AL,AL ;Else, done.
JMP EXIT ;Exit with ERRORLEVEL = 0.

;--------------------------------;
; This is the install procedure. ;
;--------------------------------;
CK_AVAILABLE: MOV BP,OFFSET REASSIGNMENT_BUFFER ;TSR ends at end
ADD BP,REASSIGNMENT_SIZE ; of reassignment buffer.
ADD BP,15 ;Round up.
CMP BP,DS:[6] ;Buffer > PSP bytes in segment?
MOV DX,OFFSET NOT_ENOUGH ;If yes, exit without installing
JA MSG_EXIT ; with message.

MOV AX,3529H ;Get undocumented INT 29 vector.
INT 21H
MOV SI,OFFSET CON ;Does it point to ANSI.SYS?
MOV DI,CON_OFFSET ;Check by looking for "CON"
MOV CX,3 ; as device name.
REP CMPSB
MOV DX,OFFSET ANSI_SYS_MSG ;Exit with error message if
LILLY_PAD: JZ MSG_EXIT ;ANSI.SYS loaded.

MOV OLD_INT_29[0],BX ;Else save old interrupt.
MOV OLD_INT_29[2],ES
MOV DX,OFFSET ANSI_INT_29 ;Install new interrupt.
MOV AX,2529H
INT 21H
MOV AX,3516H ;Get INT 16 vector.
INT 21H
MOV OLD_INT_16[0],BX ;Save old interrupt.
MOV OLD_INT_16[2],ES
MOV DX,OFFSET ANSI_INT_16 ;Install new interrupt.
MOV AX,2516H
INT 21H
MOV AX,3521H ;Get DOS 21h interrupt.
INT 21H
MOV OLD_INT_21[0],BX ;Save old interrupt.
MOV OLD_INT_21[2],ES
MOV DX,OFFSET ANSI_INT_21 ;Install new interrupt.
MOV AX,2521H
INT 21H

MOV AX,DS:[2CH] ;Get environment segment.
MOV ES,AX
MOV AH,49H ;Free up environment.
INT 21H

MOV DX,OFFSET INSTALL_MSG ;Display install message.
CALL PRINT_STRING
CALL FLUSH_END ;Setup the number buffer.
MOV DX,BP ;Retrieve resident byte request.
MOV CL,4
SHR DX,CL ;Convert to paragraphs.
MOV AX,3100H ;Return error code of zero.
INT 21H ;Terminate but stay resident.

;-------------------------------------------------------------------;
; Exit. Return ERRORLEVEL code 0 if successful, 1 if unsuccessful. ;
;-------------------------------------------------------------------;
MSG_EXIT: CALL PRINT_STRING
ERROR_EXIT: MOV AL,1 ;ERRORLEVEL = 1.
EXIT: MOV AH,4CH ;Terminate.
INT 21H

;---------------------------------------------------;
; This subroutine uninstalls the resident ANSI.COM. ;
;---------------------------------------------------;
UNINSTALL: AND ES:STATUS,NOT ON ;Turn OFF ANSI, just in case
OR ES:STATUS,OFF ; can't uninstall.
MOV CX,ES ;Save segment in CX.
MOV AX,3529H ;Get interrupt 29h.
INT 21H
CMP BX,OFFSET ANSI_INT_29 ;Has it been hooked by another?
JNZ UNINSTALL_ERR ;If yes, exit with error message.
MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JNZ UNINSTALL_ERR ;If no, exit with error message.

MOV AX,3516H ;Get interrupt 16h.
INT 21H
CMP BX,OFFSET ANSI_INT_16 ;Has it been hooked by another?
JNZ UNINSTALL_ERR ;If yes, exit with error message.

MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JNZ UNINSTALL_ERR ;If no, exit with error message.

MOV AX,3521H ;Get interrupt 21h.
INT 21H
CMP BX,OFFSET ANSI_INT_21 ;Has it been hooked by another?
JNZ UNINSTALL_ERR ;If yes, exit with error message.
MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JNZ UNINSTALL_ERR ;If no, exit with error message.

MOV AH,49H ;Return memory to system pool.
INT 21H
MOV DX,OFFSET ALLOCATE_MSG
JC MSG_EXIT ;Display message if problem.

MOV DX,ES:OLD_INT_29[0] ;Restore old INT 29.
MOV DS,ES:OLD_INT_29[2]
MOV AX,2529H
INT 21H
MOV DX,ES:OLD_INT_16[0] ;Restore old INT 16.
MOV DS,ES:OLD_INT_16[2]
MOV AX,2516H
INT 21H
MOV DX,ES:OLD_INT_21[0] ;Restore old INT 21.
MOV DS,ES:OLD_INT_21[2]
MOV AX,2521H
INT 21H

PUSH CS
POP DS ;Point to our data.
MOV DX,OFFSET UNINSTALL_MSG ;Display uninstall message.
CALL PRINT_STRING
OR AL,AL ;Exit with ERRORLEVEL = 0.
JMP EXIT

UNINSTALL_ERR: MOV ES,CX ;If error, display OFF status.
CALL STATUS_REPORT
MOV DX,OFFSET UNLOAD_MSG ;And exit with error message.
JMP MSG_EXIT
INITIALIZE ENDP

;--------------------------------------------------;
; INPUT: SI points to parameter start. ;
; OUTPUT: SI points to parameter end; BX = number. ;
;--------------------------------------------------;
DECIMAL_INPUT PROC NEAR
XOR BX,BX ;Start with zero as number.
NEXT_DECIMAL: LODSB ;Get a character.
CMP AL,CR ;Carriage return?
JZ ADJUST_DEC ;If yes, done here.
CMP AL,"/" ;Forward slash?
JZ ADJUST_DEC ;If yes, done here.
SUB AL,"0" ;ASCII to binary.
JC NEXT_DECIMAL ;If not between 0 and 9, skip.
CMP AL,9
JA NEXT_DECIMAL
CBW ;Convert byte to word.
XCHG AX,BX ;Swap old and new number.
MOV CX,10 ;Shift to left by multiplying
MUL CX ; last entry by ten.
JC DECIMAL_ERROR ;If carry, too big.
ADD BX,AX ;Add new number and store in BX.
JNC NEXT_DECIMAL ;If not carry, next number.
DECIMAL_ERROR: MOV BX,-1 ;Else, too big; return -1.

ADJUST_DEC: DEC SI ;Adjust pointer.
RET
DECIMAL_INPUT ENDP

;-------------------------------------------------------;
; OUTPUT: ZR = 1 if not installed; ZR = 0 if installed. ;
;-------------------------------------------------------;
CK_INSTALLED: MOV AX,ES
MOV BX,CS
CMP AX,BX ;Compare segments.
RET

;------------------------------------------------;
STATUS_REPORT: MOV DX,OFFSET STATUS_MSG
CALL PRINT_STRING ;Display "Status: ".
MOV BL,ES:STATUS
MOV BH,1
NEXT_REPORT: TEST BL,BH
JZ LOOP_STATUS

MOV DL,BH
MOV AX,-1
NEXT_BIT: INC AX
SHR DL,1
JNC NEXT_BIT
SHL AX,1
SHL AX,1
MOV SI,OFFSET PARAMETERS ;Display appropriate ON or OFF,
ADD SI,AX ; SLOW or FAST.
MOV CX,4
REPORT: LODSB
CALL PRINT_CHAR
LOOP REPORT

LOOP_STATUS: SHL BH,1
CMP BH,FAST
JBE NEXT_REPORT
MOV DX,OFFSET BUFFER_MSG ;Display "Buffer size: ".
CALL PRINT_STRING
MOV AX,ES:REASSIGNMENT_SIZE
PUSH AX
XOR BP,BP
CALL DECIMAL_OUT ;Display the size.
MOV DX,OFFSET BYTES_FREE ;Display "Bytes free: ".
CALL PRINT_STRING
POP AX
ADD AX,OFFSET REASSIGNMENT_BUFFER
SUB AX,ES:REASSIGN_END
CALL DECIMAL_OUT ;Display the bytes free.
MOV DX,OFFSET CR_LF
CALL PRINT_STRING
RET

;------------------------------------------------;
PRINT_CHAR: MOV DL,AL
MOV AH,2 ;Print character via DOS.
JMP SHORT DOS_INT

PRINT_STRING: MOV AH,9 ;Print string via DOS.
DOS_INT: INT 21H
RET

_TEXT ENDS
END START


  3 Responses to “Category : Display Utilities
Archive   : ANSI.ZIP
Filename : ANSI.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/