Category : Display Utilities
Archive   : ANSI_ETC.ZIP
Filename : ANSI.DEF

 
Output of file : ANSI.DEF contained in archive : ANSI_ETC.ZIP
PAGE , 132
.LFCOND

FALSE EQU 0
TRUE EQU NOT FALSE

REV EQU 0; revision number for compatibility

TEST EQU FALSE; ansi test program
PASS EQU FALSE; implement password
MINE EQU FALSE; insert my default substitutions
EGA EQU TRUE; implement column checks

BTIMER EQU 5D3H; beep counter value

MOVINT MACRO NUM, ALT
MOV AX, (INTVEC + 4 * 0&NUM&H).LW
MOV VEC&NUM.LW, AX
IFNB
MOV VEC&NUM&ALT.LW, AX
ENDIF
MOV AX, (INTVEC + 4 * 0&NUM&H).HW
MOV VEC&NUM.HW, AX
IFNB
MOV VEC&NUM&ALT.HW, AX
ENDIF
NEWINT NUM
ENDM

NEWINT MACRO NUM
MOV (INTVEC + 4 * 0&NUM&H).LW, OFFSET INT&NUM
MOV (INTVEC + 4 * 0&NUM&H).HW, CS
ENDM

STR1 STRUC; conversion to byte
LB DB ?
HB DB ?
STR1 ENDS
B EQU LB

STR2 STRUC; conversion to word
LW DW ?
HW DW ?
STR2 ENDS
W EQU LW

STR3 STRUC; conversion to dword
D DD ?
STR3 ENDS

BEL EQU 7; beep
BS EQU 8; backspace
HT EQU 9; horizontal tab
LF EQU 10; line feed
FF EQU 12; form feed
CR EQU 13; carriage return
ESC EQU 27; escape: ctrl-[
AESC EQU 29; alternate escape: ctrl-]

ROWS EQU 25; number of lines on screen if not EGA

HEADER STRUC; device header
NXTOFS DW -1; offset of next device header or -1
NXTSEG DW -1
ATTR DW ?; device attributes
STRAT DW ?; offset of strategy procedure
INTRP DW ?; offset of interrupt procedure
NAME DB ' '; device name
HEADER ENDS

REQ STRUC; request header
LEN DB ?; length of header
DB ?
COMMAND DB ?; device command
STATUS DW ?; device status
REQ ENDS

INIREQ STRUC; init request header
DB 14 DUP(?); REQ struc & other stuff
TOP DD ?; return end of resident part of driver
CONFIG DD ?; ^ char after '=' on config.sys line
INIREQ ENDS

RWREQ STRUC; read or write request header
DB 14 DUP(?)
TRANSF DD ?; source/destination address
COUNT DW ?; byte count
RWREQ ENDS

NDRREQ STRUC; non-destructive read request header
DB 13 DUP(?)
LOOK DB ?; return next char
NDRREQ ENDS

INTSEG SEGMENT AT 0
INTVEC DD 100H DUP(?); interrupt vectors
INTSEG ENDS

BIOS SEGMENT AT 40H
ORG 1AH
REAR DW ?; near pointers to queue
FRONT DW ?
KBUF DW 16 DUP(?); keyboard input queue
BIOS ENDS

DUMMYS SEGMENT AT 2000H; Actually nowhere
DUMMYB LABEL BYTE; Used to stick ES: & B or W on LODS
DUMMYW LABEL WORD
DUMMYF LABEL FAR; used for dummy far call & jump
DUMMYS ENDS


IF TEST; generate ANSI.EXE for DEBUG
; using impacted EXE file
T SEGMENT
ASSUME CS: T

CHKBYTE DB 0
BADTEST DB 'execution attempted from unimpacted .EXE file$'
TSTABO: MOV AX, CS
MOV DS, AX; write message & quit
ASSUME DS: T
MOV AH, 9
MOV DX, OFFSET BADTEST
INT 21H
MOV AX, 4CFFH
INT 21H

ORG 100H
INITH DB CFGLIN - INITH, ?, 0
DW 5 DUP (?)
DB ?
DD ?
DD CFGLIN
DB ?
CFGLIN DB 'ansi.sys 16384 256 512', 13

ASSUME DS: NOTHING

START: CMP CHKBYTE, 0
JNZ START0
JMP TSTABO
ASSUME DS: T, SS: T, ES: T
START0: MOV BX, OFFSET INITH
CALL FAR PTR STRATEGY
CALL FAR PTR CONENT
INT 20H
T ENDS

ENDIF; TEST


IFDEF ANSISYS
ANSI SEGMENT
ELSE
ANSI SEGMENT AT 0C000H; anywhere
ENDIF
ASSUME CS: ANSI, ES: DUMMYS, DS: NOTHING, SS: NOTHING

ZERO:

CONHDR HEADER <,,8013H,STRATEGY,CONENT,'CON '>

EVEN
ANSIREV DW REV; compatibility checkword
ISEG DW INTSEG; segment at 0
BSEG DW BIOS; segment at 40h
STACK DW LAST + 100H; stack at init time - changed by init
OLDSTK DD ?; save old SS:SP
PTRSAV DD ?; strategy puts req header address here
VEC05 DD ?; print screen vector goes here
VEC08 DD ?; clock interrupt vector goes here
VEC09 DD ?; keyboard interrupt vector goes here
LASTK DW ?; check against front of key queue for click
STATE DW SCAN; current scanner/parser address
CRNTCHR DW P999; where parser is working
CHRPTR DW ?; pointer to next char of function

CMDTBL DW INIT; initialize driver
DW DONE; no-op: media check
DW DONE; no-op: build BPB
DW DONE; no-op: ioctl input
DW INPUT; read
DW NDINP; non-destructive input: no wait
DW DONE; no-op: input status
DW FLUSH; input flush
DW OUTPUT; write
DW OUTPUT; write with verify
DW DONE; no-op: output status
DW DONE; no-op: output flush
DW DONE; no-op: ioctl output
ENCTBL:

SAVEDC DW ?; saved cursor position
CURSOR LABEL WORD; cursor location
COLUMN DB ?; cursor column
ROW DB ?; cursor line
PGAT LABEL WORD; video page & attributes
ATTRIB DB 6; attributes
VPAGE DB ?; page
CROW LABEL WORD; columns & rows - 1 for scroll
COLUMNS DB ?
EROWS DB ROWS - 1; default if not EGA
WRAP DB TRUE; wrap at end of line
NAT DB ?; blanking attribute
STANDARD DB ?; standard or nonstandard functions
QUOTE DB ?; type of quote used: " or '

PRSC DB FALSE; print screen enable
CHRCNT DB ?; count for function string
TIC DB 1; key click flag
TCOUNT DB ?; used for click
TEN DB 10
BEEPCNT DB 0; counter for bel
SCRTEST DB 1; flag to check screen parameters
SFFF DB 1; special form feed enable flag
TEXT DB -1; used to determine if NAT = ATTRIB

REPSTR DB ESC, '['; string for cursor position report
RSR DW ?
DB ';'
IF EGA
RSCU DB ?; 3 digits for column for EGA
ENDIF; EGA
RSC DW ?
DB 'R', CR
REPCNT EQU $ - REPSTR

STDTBL LABEL BYTE; standard ansi function table: "["
DB 'A'
DW CSRUP
DB 'B'
DW CSRDN
DB 'C'
DW CSRFW
DB 'D'
DW CSRBK
DB 'H'
DW CSRPOS
DB 'J'
DW CLRSCR
DB 'K'
DW TELA
DB 'L'
DW INSL
DB 'M'
DW DELL
DB 'R'
DW SKIP
DB 'f'
DW CSRPOS
DB 'h'
DW MODEHL
DB 'l'
DW MODEHL
DB 'm'
DW MODES
DB 'n'
DW REPORT
DB 'p'
DW MAPKEY
DB 's'
DW SAVCSR
DB 'u'
DW RSTCSR
DB 0

; Non-standard function table - "]" - allows upgrading standard
NSTDTBL LABEL BYTE; functions without retrofitting
DB 'A'; programs that use ANSI
DW CHATTR
DB 'C'
DW FCC
DB 'I'
DW MISC
DB 'K'
DW CTYPE
DB 'P'
DW PUTSCR
DB 0

; Miscellaneous non-standard functions address table
MLIST DW SHOLD, FTS, FBL, TEL
DW TES, SWTIC, SWPRSC, SWFF
MSIZE EQU $ - MLIST

STRATEGY:
STRG PROC FAR; save request header address
MOV PTRSAV.LW, BX
MOV PTRSAV.HW, ES
RET
STRG ENDP

CONENT:
ENTRY PROC FAR
CLI; disable interrupts
PUSH ES; & save registers
PUSH DS; on old stack
PUSH DI
PUSH SI
PUSH BP
PUSH DX
PUSH CX
PUSH BX
PUSH AX
MOV OLDSTK.LW, SP; save old SS:SP
MOV OLDSTK.HW, SS
MOV AX, CS
MOV DS, AX; move CS to DS & SS
MOV SS, AX
ASSUME DS: ANSI, SS: ANSI
MOV SP, STACK; set local stack
STI; enable interrupts

LES DI, PTRSAV; get request header address
MOV BL, ES: [DI].COMMAND; get command
CMP BL, (ENCTBL - CMDTBL) / 2; valid?
JAE CMDERR; not valid: unknown
SHL BL, 1; valid: use for index into CMDTBL
XOR BH, BH
CALL CMDTBL [BX]; execute command procedure

EXIT: LES DI, PTRSAV; get request header address
MOV ES: [DI].STATUS, AX; return status
CLI; disable interrupts
MOV SS, OLDSTK.HW; get old SS:SP
MOV SP, OLDSTK.LW
POP AX; restore registers
POP BX
POP CX
POP DX
POP BP
POP SI
POP DI
POP DS
POP ES
STI; enable interrupts
RET
ENTRY ENDP

CMDERR: MOV AX, 8103H; unknown command error status
JMP EXIT


; Trapped interrupt procedures
ASSUME DS: NOTHING, SS: NOTHING

INT05: CMP PRSC, 0; new interrupt 5 procedure
JNZ DOPRT; if switch not zero then execute
IRET; else return
DOPRT: JMP VEC05

INT08: CMP BEEPCNT, 0; system clock controls beep time
JZ I08B; instead of a wait loop
PUSH AX; if BEEPCNT != 0
IN AL, 61H
AND AL, 0FCH
DEC BEEPCNT; decrement
JZ I08A; if != 0 then enable beep else disable
OR AL, 3
I08A: OUT 61H, AL
POP AX
I08B: JMP VEC08; execute clock interrupt

INT09: PUSHF; execute keyboard interrupt
CALL VEC09; upon return, interrupts remain disabled
CMP TIC, 0
JZ I09E
PUSH DS; if click enabled
PUSH CX
MOV DS, BSEG
ASSUME DS: BIOS
MOV CX, FRONT; if front pointer has changed
CMP CX, LASTK; since last interrupt
JE I09D
MOV LASTK, CX; save new front pointer
PUSH AX
IN AL, 61H; send some pulses to speaker
AND AL, 0FCH
MOV TCOUNT, 2; number of pulse sets
I09A: MOV AH, 2; number of transitions per set
I09B: MOV CX, 30H; delay between transitions
XOR AL, 2
OUT 61H, AL
LOOP $
DEC AH
JNZ I09B
DEC TCOUNT
JZ I09C
MOV CX, 70H; delay between sets
LOOP $
JMP I09A
I09C: POP AX
I09D: POP CX
POP DS
ASSUME DS: NOTHING
I09E: IRET

INT10: MOV SCRTEST, 1; when someone executes interrupt 10H
I10A: JMP DUMMYF; set flag to check screen parameters
VEC10 EQU DWORD PTR I10A + 1; then execute interrupt

; Additional interrupt procedures
INT1B: MOV BYTE PTR CS:NXTCHR, 3; Ctrl-Break interrupt
IRET

EVEN
; variables accessible by offsets from int 29h vector
NXTCHR DB ?; for 2 character keycodes
ACTCNT DB 0; count for active string
ACTSTR DW ?; active string pointer
FSTPARM DW PARMS; where parms begin
NXTPARM DW P999; where next parm begins & map parms end
ENDMAP DW P999 + 256; where keyboard mapping parms must end
ENDPARM LABEL WORD; where all parms must end (same as STBLO)
STBLO DW P999 + 288; buffer stack low address
STBPT DW P999 + 416; buffer stack pointer
STBHI DW P999 + 416; buffer stack high address
DB 10, 'w'; buffer stack id

INT29: PUSH ES; fast console output device
PUSH DS; interrupt
PUSH DI
PUSH SI
PUSH DX
PUSH CX
PUSH BX
PUSH AX
PUSH CS
POP DS
CALL STATE
POP AX
POP BX
POP CX
POP DX
POP SI
POP DI
POP DS
POP ES
IRET


; Int 10h simulator call
ASSUME DS: ANSI

CALL10: PUSHF
C10A: CALL DUMMYF
RET
VEC10A EQU DWORD PTR C10A + 1


; Ansi requests
ASSUME SS: ANSI

INPUT: MOV CX, ES: [DI].COUNT; get count & destination address
LES DI, ES: [DI].TRANSF
CLD
IP0: PUSH CX
CALL POPCH; get input
POP CX
STOSB
LOOP IP0
JMP SHORT DONE

OUTPUT: MOV CX, ES: [DI].COUNT; get byte count & address
LES SI, ES: [DI].TRANSF
CLD
OP0: LODS DUMMYB; assume initial count ^= 0
PUSH CX; save count
CALL STATE; output or parse bytes
POP CX; restore count
LOOP OP0; until CX = 0
DONE: MOV AX, 100H; status = done; no-ops call here
RET

NDINP: MOV AL, NXTCHR; check next character

AND AL, AL; if != 0 then send it
JZ NDI1
NDI0: MOV ES: [DI].LOOK, AL
JMP DONE
NDI1: MOV SI, STBPT; else check buffer stack
CMP SI, STBHI
JZ NDI2
LODSB
JMP NDI0
NDI2: CMP AL, ACTCNT; else check for active string (AL = 0)
JZ NDI3
MOV SI, ACTSTR; if found then get char & send it
MOV AL, [SI]
JMP NDI0
NDI3: MOV AH, 1; else check keyboard input
INT 16H
JNZ NDI4
MOV AX, 300H; if not found then busy
RET
NDI4: AND AX, AX; else if Ctrl-Break then
JNZ NDI5; eat it & retry
INT 16H
JMP NDINP
NDI5: CALL KSRCH; else check string list
JZ NDI0; if no match then send char
XOR AH, AH
INT 16H; else read character
CALL RK0; get active string character
DEC ACTSTR; back up pointer & count
INC ACTCNT
JMP NDI0; send character

FLUSH: MOV NXTCHR, 0; clear next character
MOV SI, STBHI; pop buffer stack
MOV STBPT, SI
MOV ACTCNT, 0; clear active string
FL0: MOV ES, BSEG
ASSUME ES: BIOS
MOV AX, FRONT; clear keyboard buffer
MOV REAR, AX
JMP DONE


; Input procedures
POPCH: MOV SI, STBPT; check for pushed string chars
CMP SI, STBHI
JZ CHKNXT
CLD
LODSB
MOV STBPT, SI
RET

CHKNXT: XOR AX, AX
XCHG AL, NXTCHR; exchange 0 with NXTCHR
AND AL, AL; if not 0 then use it
JNZ CKR
CMP ACTCNT, AH; (AH = 0) else check count for
JZ RDKEY; active string
MOV SI, ACTSTR; if not 0 then get character
CLD; from active string
LODSB
MOV ACTSTR, SI
DEC ACTCNT
CKR: RET

RDKEY: INT 16H; no chars - read from keyboard
AND AX, AX; check for break
JZ CHKNXT; if break then try again
CALL KSRCH; check for mapped key
JZ RK2
RK0: AND AL, AL; if found then if low byte == 0
JNZ RK1
INC SI; then skip extra character
DEC CX
RK1: INC SI; skip char count & match char
INC SI
SUB CL, 3; dec for count, match & input char
MOV ACTCNT, CL
LODSB; get character
MOV ACTSTR, SI
RET
RK2: AND AL, AL; no match - check for 2 char keystroke
JNZ RKR
MOV NXTCHR, AH
RKR: RET

KSRCH: MOV SI, OFFSET PARMS; search string list for key match
XOR CH, CH
KS0: CMP SI, NXTPARM; check for end of list
JAE KS3; jump if end
MOV CL, [SI]
AND AL, AL
JZ KS1
CMP AL, 1 [SI]; AL != 0: match AL
JMP SHORT KS2
KS1: CMP AX, 1 [SI]; AL == 0: match AX
KS2: JE KS4
ADD SI, CX; no match: add string length to address
JMP KS0; repeat
KS3: XOR SI, SI; end of list: return 0 & 0 flag set
RET
KS4: AND SI, SI; found match: return address
RET; & zero flag clear


; Output procedures
ASSUME SS: NOTHING; might come from int 29h

BEEP: MOV AL, 0B6H; set beep timer
OUT 43H, AL
MOV AL, LOW BTIMER
OUT 42H, AL
MOV AL, HIGH BTIMER
OUT 42H, AL
MOV BEEPCNT, 6; set beep duration
BR: RET

COLM0: MOV DL, 0; carriage return: go to column 0
COLMX: MOV DH, ROW; go to column x, same line
COLROW: CMP DX, CURSOR; go to column x, row y
JE BR
MOVCSR: MOV CURSOR, DX; if not already there then move
MOV BH, VPAGE
MOV AH, 2
JMP CALL10

NL: MOV DX, CURSOR; new line
IF EGA
CMP DH, EROWS
ELSE
CMP DH, ROWS - 1
ENDIF; EGA
JB NL0
JMP SCRUP1; if last line then scroll up
NL0: INC DH
JMP MOVCSR; else move down

BAKS: MOV DL, COLUMN
AND DL, DL
JZ BR
DEC DL; if not column 0 then backspace
JMP COLMX

OUTSCR: CMP AL, CR; if CR then go to column 0
JE COLM0; output procedure
CMP AL, BEL
JE BEEP; if Ctrl-G then beep
CMP AL, LF
JE NL; if LF then new line
CMP AL, BS
JE BAKS; if BS then backspace
CMP AL, FF
JNE OS1
CMP SFFF, 0; if FF then check special form-feed flag
JZ OS1; if zero then use regular output
XOR CH, CH
MOV CL, COLUMNS; else output a double bar from current
SUB CL, COLUMN; position to the end of screen
MOV BX, PGAT
MOV AX, 9CDH
CALL CALL10
JMP NL; then go to new line
OS1: MOV CX, 1
MOV BX, PGAT
MOV AH, 9
CALL CALL10; write character to screen
MOV DX, CURSOR
INC DX
CMP DL, COLUMNS; try to move cursor right
JB MOVCSR
CMP WRAP, 0; if at right of screen then check WRAP
JZ OSR
MOV DL, 0; if not 0 then go to column 0
CALL MOVCSR
JMP NL; & go to new line
OSR: RET


; Output function trapping

SCAN: CMP SCRTEST, 0
JZ SC0; see if video status needs checking
PUSH AX
CALL SCRCHK
POP AX
SC0: CMP AL, AESC
JA OS1; catch most characters here
JE ST0
CMP AL, ESC; if not escape or alternate escape
JNE OUTSCR; then go to output procedure
ST0: MOV STATE, OFFSET ST1; else change state for next char
RET

ST1: XOR DL, DL
CMP AL, ']'; if non-standard sequence then DL = 0
JE ST100
CMP AL, '['; else if not standard sequence then
JNE RSCAN; return to scanner (error)
INC DX; else DL = 1
ST100: MOV STANDARD, DL; save standard flag
MOV BX, NXTPARM
MOV [BX].W, 2; initialize parameter string
INC BX
MOV CRNTCHR, BX
ST301: MOV STATE, OFFSET ST2; change state for next character
RET

ST2: MOV BX, CRNTCHR; get current char (of string) address
CMP AL, ';'
JNE ST200
ST302: INC BX; if parameter separator then next char
CMP BX, ENDPARM; if buffer overflow then quit
JAE RSCAN
MOV [BX].B, 0; else initialize character to 0
MOV CRNTCHR, BX; save new address
MOV BX, NXTPARM; get string character count address
INC [BX].B; increment count
JZ RSCAN; if back to 0 (overflow) then quit
RET

ST200: CMP AL, '0'; not separator: check if '0' .. '9'
JB ST201; below
CMP AL, '9'
JA ST204; above
SUB AL, '0'; get digit value
XCHG AL, [BX]
MOV AH, 10; multiply current character by 10
MUL AH; & add digit value
ADD [BX], AL
RET

RSCAN: MOV STATE, OFFSET SCAN; abort current state
OUTOFF: JMP OUTSCR; output offending character

ST201: CMP AL, '"'; character below '0'; check if quote
JE ST202
CMP AL, "'"
JNE ST205
ST202: MOV QUOTE, AL; save type of quote & change state
MOV STATE, OFFSET ST3
ST203: RET

ST204: CMP AL, '?'; character above '9'
JE ST203; ignore if '?' or '='
CMP AL, '='
JE ST203
ST205: MOV STATE, OFFSET SCAN; else restore scanner
MOV BX, NXTPARM
MOV CL, [BX]; string complete: get count
INC BX; & address of first character
DEC CX
MOV CHRPTR, BX; save them
MOV CHRCNT, CL
CMP STANDARD, 0; check for standard or non-standard
JNZ ST206; jump table
MOV BX, OFFSET NSTDTBL
JMP SHORT ST207
ST206: MOV BX, OFFSET STDTBL
ST207: CMP [BX].B, 0; if end of table with no match
JZ OUTOFF; then output offending character
CMP AL, [BX]; else check for match with
JE ST208; last character
ADD BX, 3; if no match then advance pointer
JMP ST207; & loop
ST208: PUSH ES
PUSH SI; match: call procedure at
CALL 1 [BX]; address in table
POP SI
POP ES
RET

ST3: CMP AL, QUOTE; if same quote
JNE ST300
DEC CRNTCHR; then end of quoted string
MOV BX, NXTPARM; decrement pointer & count
DEC [BX].B
JMP ST301; go to change state

ST300: MOV BX, CRNTCHR; else save character
MOV [BX], AL
JMP ST302; go to increment pointer & count


; Output functions

CSRUP: CALL GET1; cursor up: get count > 0
MOV DX, CURSOR
SUB DH, AL; new row
JNC CU0
XOR DH, DH; if past top row then top row
CU0: JMP COLROW; move cursor

CSRDN: CALL GET1; cursor down: get count > 0
MOV DX, CURSOR
ADD DH, AL
JC CD0; if past last row then last row
IF EGA
CMP DH, EROWS
JBE CU0
CD0: MOV DH, EROWS
ELSE
CMP DH, ROWS - 1
JBE CU0
CD0: MOV DH, ROWS - 1
ENDIF; EGA
JMP CU0

CSRFW: CALL GET1; cursor forward
MOV DX, CURSOR
ADD DL, AL
JC CF0
CMP DL, COLUMNS
JB CU0
CF0: MOV DL, COLUMNS; if past last column then last column
DEC DX
JMP CU0

CSRBK: CALL GET1; cursor back
MOV DX, CURSOR
SUB DL, AL
JNC CU0
XOR DL, DL; if past first column then first column
JMP CU0

CSRPOS: CALL GET1; cursor position
DEC AX
MOV DH, AL; allow row past end of screen
CALL GET1
CMP AL, COLUMNS; but check column
JBE CP0
MOV AL, COLUMNS
CP0: DEC AX
MOV DL, AL
JMP CU0

CLRSCR: XOR AL, AL; clear screen
CALL SCRUP; send AL = 0 to this procedure
XOR DX, DX
JMP CU0; home cursor

RSTCSR: MOV DX, SAVEDC; restore cursor to saved position
JMP CU0

SAVCSR: MOV DX, CURSOR; save cursor position
MOV SAVEDC, DX
RET

MODEHL: MOV DL, AL; set screen mode or wrap
CALL GETC
CMP AL, 7; if 7 then set wrap
JE MO1
IF EGA
CMP AL, 255; else if 255 then mode 7
JNE MO0
MOV AL, 7
ENDIF; EGA
MO0: XOR AH, AH; set mode through interrupt
INT 10H; sets screen test flag
RET
MO1: SUB DL, 'l'; if 'l' then 0; if 'h' then not 0
MOV WRAP, DL
RET

MODES: CALL GETC; set screen attributes; get at least
M0: CALL M1; 1 parameter even if none exist
CALL GETC
JNC M0
MOV AL, ATTRIB
AND AL, TEXT
MOV NAT, AL; if text then NAT = ATTRIB else 0
RET

M1: CMP AL, 30
JAE M9
CMP AL, 1
JA M3
JE M2
MOV ATTRIB, 7; 0 - fg white low intensity: bg black
RET
M2: OR ATTRIB, 8; 1 - set high intensity
RET
M3: CMP AL, 3
JA M5
JE M4
AND ATTRIB, 0F7H; 2 - clear high intensity
RET
M4: XOR ATTRIB, 77H; 3 - toggle current video
RET
M5: CMP AL, 5
JA M7
JE M6
MOV AX, 1F8H; 4 - underscore on
JMP SHORT M11
M6: OR ATTRIB, 80H; 5 or 6 - blink on
RET
M7: CMP AL, 7
JB M6
JA M8
MOV ATTRIB, 70H; 7 - reverse video
RET
M8: CMP AL, 8
JNE M12
MOV AX, 88H; 8 - invisible
JMP SHORT M11
M9: CMP AL, 37
JA M13
SUB AL, 30 - 0C0H; 30..37 - set foreground
MOV AH, 0E0H
CALL M14
M11: AND ATTRIB, AL
OR ATTRIB, AH
M12: RET
M13: CMP AL, 40
JB M12
CMP AL, 47
JA M12
SUB AL, 40; 40..47 - set background
MOV AH, 0FEH
CALL M14
MOV AL, 8FH
JMP M11

M14: RCR AL, 1; trick
RCL AH, 1
JNO M14
RET

CHATTR: CALL GETC; change attributes
MOV ATTRIB, AL; new attributes = parameter
AND AL, TEXT
MOV NAT, AL; if text then NAT = ATTRIB else 0
RET

FCC: MOV NXTCHR, 3; Ctrl-C on next read
FCR: RET

PUTSCR: CALL GETC; write any character to screen
JC FCR
CALL OS1
JMP PUTSCR

MISC: MOV DX, CURSOR; miscellaneous screen functions
MI0: CALL GETC
JC SHOL1; while another character in string
MOV BX, 0FEH; it is index into address list
AND BL, AL; bit 0 masked out & used in function
CMP BL, MSIZE
JAE MI0; if too large then continue
CALL MLIST [BX]; call function
JMP MI0; continue

SHOLD: AND AL, 1; 0, 1 - wait for keystroke
JNZ SHOL0
CALL FL0; if 0 then flush key buffer
SHOL0: XOR AH, AH
INT 16H; get key
CMP AL, 3
JNE SHOL1
MOV NXTCHR, AL; if Ctrl-C then put in NXTCHR
SHOL1: RET; else discard

FTS: PUSH DX; 2, 3 - erase from top of screen
PUSH AX; to position ahead of cursor
PUSH DX; save cursor twice & function #
XOR DX, DX
CALL COLROW; go to top of screen
POP DX
MOV AL, DH; figure out how many characters to erase
MUL COLUMNS
XOR DH, DH
ADD AX, DX
MOV CX, AX
JMP SHORT FBL0

FBL: PUSH DX; 4, 5 - erase from beginning of line
PUSH AX; to position ahead of cursor
PUSH DX
XOR DL, DL
CALL COLROW; go to column 0 same row
POP CX; get number of characters to erase
XOR CH, CH
FBL0: POP AX; get function number
CALL TES2; erase
POP DX; restore cursor position
JMP COLROW

TELA: MOV DX, CURSOR; standard function 'K'
XOR AX, AX; dummy function number

TEL: PUSH AX; 6, 7 - erase from cursor to end of line
MOV AL, COLUMNS
SUB AL, DL; get number of characters to erase
XOR AH, AH
JMP SHORT TES1

TES: PUSH AX; 8, 9 - erase from cursor to end of screen
IF EGA
MOV AL, EROWS
INC AX
ELSE
MOV AL, ROWS
ENDIF; EGA
SUB AL, DH
MUL COLUMNS; figure out how many characters to erase
XOR DH, DH
SUB AX, DX
TES1: MOV CX, AX; put number of characters in CX
POP AX
TES2: JCXZ SWT0; miscellaneous erase functions
MOV BX, PGAT; all come here
AND AX, 1; if odd function # then leave existing
ADD AL, 9; attributes else use current attribute
XCHG AH, AL
JMP CALL10; execute screen function 9 or 10

SWTIC: AND AL, 1; 10, 11 - enable key click if odd
MOV TIC, AL; else disable
SWT0: RET

SWPRSC: AND AL, 1; 12, 13 - enable print screen if odd
MOV PRSC, AL
RET

SWFF: AND AL, 1; 14, 15 - enable special form-feed if odd
MOV SFFF, AL
RET

INSL: CALL IDL; insert line: get scrolling parameters
MOV AH, 7
INSL0: JMP CALL10; scroll down

DELL: CALL IDL; delete line: get scrolling parameters
MOV AH, 6
JMP INSL0; scroll up

IDL: MOV DX, CURSOR; prepare to scroll
IF EGA
CMP DH, EROWS
ELSE
CMP DH, ROWS - 1
ENDIF; EGA
JE IDL0; if last line then just clear line
CALL GET1
XOR CL, CL
MOV CH, DH
MOV DX, CROW; load registers & return
DEC DX
MOV BH, NAT
RET
IDL0: POP AX; eat return address
PUSH DX
MOV AH, 2
XOR DL, DL
CALL CALL10; go to beginning of line
MOV AX, 0A00H
MOV CL, COLUMNS
XOR CH, CH
CALL CALL10; erase line
POP DX
JMP MOVCSR; restore cursor position

MAPKEY: MOV BX, NXTPARM; get start address of string
CMP [BX].B, 3; check length (including length descriptor)
JA MK2; > 3: ok
JE MK1; = 3: maybe
MK0: MOV AL, 'p'; no good - write 'p'
JMP OUTSCR
MK1: CMP 1 [BX].B, 0
JZ MK0; length == 3 && first char == ^@: no good
MK2: MOV AX, 1 [BX]; get first 2 characters
CALL KSRCH; execute key search
MOV CL, CH; CH == 0 after KSRCH, do not disturb flags
JZ MK3; determine if string was found
MOV CL, [SI]; if found CX = length else 0
MK3: AND AL, AL
JZ MK4; if first char == 0 then compare 2 chars
CMP AL, 2 [BX]; compare 1 character
JNE MK5; if first 2 characters equal
CMP [BX].B, 3; and only 2 characters
JE MK6; then unmap key else remap key
JMP SHORT MK5
MK4: CMP AX, 3 [BX]; compare chars 1 & 2 with 3 & 4
JNE MK5; if first pair == second pair
CMP [BX].B, 5; and only 4 characters
JE MK6; then unmap key else remap key
MK5: ADD BL, [BX]; remap - compute new end address
ADC BH, 0
MK6: SUB BX, CX; subtract size of old string if any
CMP BX, ENDMAP; check for overflow
JA MK0
MOV NXTPARM, BX; save new next-parameter address
AND SI, SI; SI = address of old string
JZ MK8; if zero then no old string - done
CALL ABACT; abort active string
MOV DI, SI; first destination is start of old string
MOV CL, [SI]
ADD SI, CX; first source is start of next string
MOV CX, BX
SUB CX, DI; size of move is next - destination
PUSH CS
POP ES; get destination segment
CLD
REP MOVSB; move strings
MK8: RET

REPORT: CALL GETC; cursor position report
CMP AL, 6
JNE RR
MOV AL, ROW
CALL DIA; convert row to 2 digit string
MOV RSR, AX; put into special output string
MOV AL, COLUMN
IF EGA; three digit columns for EGA
MOV RSCU, '0'
CMP AL, 99; (ansi column 100)
JB R0
INC RSCU; if equal or greater then first digit is 1
SUB AL, 100; subtract the hundred
ENDIF; EGA
R0: CALL DIA; get 2 digit string
MOV RSC, AX; save in output string
CALL ABACT; check for conflicting active string
MOV ACTSTR, OFFSET REPSTR; activate report string
MOV ACTCNT, REPCNT
RR: RET

DIA: INC AX; convert number into 2 digit string
CBW
DIV TEN
ADD AX, '00'
RET

SKIP: MOV STATE, OFFSET SCAN; if position report is echoed to
RET; console driver then eat it

CTYPE: CALL GETC; set cursor type
MOV CH, AL; get top & bottom line
CALL GETC
MOV CL, AL
MOV AH, 1
JMP CALL10; execute screen function


; Output function utilities

GETC: XOR AL, AL; get parameter
CMP CHRCNT, 1; if count = 0 then
JC GTC0; return with 0 in AL & carry set
DEC CHRCNT
MOV SI, CHRPTR; else get next character
CLD
LODSB
MOV CHRPTR, SI
GTC0: RET

GET1: CALL GETC; get parameter
PUSHF; save flags
AND AL, AL
JNZ G10
INC AX; if 0 then return 1
G10: POPF; restore flags
RET

SCRCHK: MOV AH, 0FH; screen check
CALL CALL10; gets video status initially,
MOV COLUMNS, AH; after standard 'h' or 'l' calls,
MOV VPAGE, BH; & after interrupt 10h has been
XOR AH, AH; executed by another program
CMP AL, 4
JB SCH0; determine if mode is text or graphics
CMP AL, 7
JE SCH0; if text then the new line & scrolling
CMP AL, 23H; attribute is set to ATTRIB else 0
JB SCH1
CMP AL, 51H
JB SCH0
CMP AL, 58H
JNE SCH1
SCH0: DEC AH
SCH1: MOV TEXT, AH; text flag = 0FFH if text else 0
AND AH, ATTRIB
MOV NAT, AH
MOV AH, 3
CALL CALL10
MOV CURSOR, DX
IF EGA
MOV AX, 1130H; if EGA then get number of rows - 1
MOV DL, 24; default number if call fails
CALL CALL10
MOV EROWS, DL
ENDIF; EGA
MOV SCRTEST, 0; clear screen test flag
SCR: RET

SCRUP1: MOV AL, 1; scroll up 1 line
SCRUP: MOV AH, 6; scroll up
SCROLL: XOR CX, CX; scroll
MOV DX, CROW
DEC DX
MOV BH, NAT
JMP CALL10

ABACT: CMP ACTCNT, 0; check for active string before
JZ SCR; string move or cursor position report
MOV ACTCNT, 0; if active then deactivate & beep
JMP BEEP


; Initialized strings and storage area

PARMS LABEL BYTE

IF MINE
P1 DB P2 - P1, 0, 10H, ' dummy! ', 0, 3FH, 0, 3DH
DB 10 DUP (8)
P2 DB P3 - P2, 0, 30H, 'DEL *.BAK', CR
P3 LABEL BYTE
ENDIF; MINE

P999 LABEL BYTE

; Storage areas overlay initialization code

IF PASS

PUBLIC PASSLOC, PASSLEN
PASSLOC EQU PASSWORD - ZERO

PEND DB CR
PPROMPT DB LF, LF, ' ENTER SYSTEM ENABLE KEY '
PASSWORD DB '617'
ENDPW:

; First get password

INIT: CALL CLRSCR; clear screen
PUSH CS
POP ES
MOV SI, OFFSET PPROMPT; get address & length of prompt
MOV CX, OFFSET (PASSWORD - PPROMPT)
CALL OP0; output to screen
MOV DI, SI
PASSLEN EQU $ - ZERO + 1
MOV CX, ENDPW - PASSWORD
JCXZ PW5; if zero length then continue
PW1: XOR AH, AH
INT 16H; get key
SCASB; compare with password char
JE PW3
PW2: CLI; if not equal then die here
HLT
PW3: LOOP PW4
JMP SHORT PW5
PW4: AND AL, AL; check for special key
JNZ PW1
MOV AL, AH; if special then check upper byte
SCASB
JNE PW2
LOOP PW1
PW5: MOV SI, OFFSET PEND
MOV CX, 3
CALL OP0; write CR, LF, LF
ELSE
INIT:
ENDIF; PASS

LES SI, PTRSAV
LES SI, ES: [SI].CONFIG; get config.sys text after '='
ASSUME ES: DUMMYS
CLD
LODS DUMMYB
CALL SKPSPC; skip spaces if any after '='
CFG0: CMP AL, HT
JE CFG1; search for space or HT
CMP AL, ' '; (skip 'ansi.sys')
JB SETINT; if end of line or other control char
JE CFG1; then all default values are unchanged
LODS DUMMYB
JMP CFG0
CFG1: CALL SKPSPC; skip spaces after 'ansi.sys'
CALL GTINTG; look for integer: size of map buffer
JC SETINT; if not valid then keep defaults
CMP BX, 16384
JA SETINT; if too high then keep defaults
ADD BX, OFFSET P999
MOV ENDMAP, BX; set map buffer end
CALL SKPSPC; skip spaces
CALL GTINTG; look for size of reserved buffer
JC DEFMP; if not valid or too low or too high
CMP BX, 16; then adjust remaining defaults
JB DEFMP
CMP BX, 256
JA DEFMP
ADD BX, ENDMAP
MOV ENDPARM, BX; set reserved buffer end
CALL SKPSPC; skip spaces
CALL GTINTG; look for size of buffer stack
JC DEFBS; if not valid or too high then
CMP BX, 4096; use default size
JA DEFBS
ADD BX, ENDPARM
MOV STBHI, BX; set buffer stack end
MOV STBPT, BX; set buffer stack pointer
JMP SHORT SETINT

DEFMP: MOV BX, ENDMAP; adjust default reserved buffer
ADD BX, 32
MOV ENDPARM, BX
DEFBS: MOV BX, ENDPARM; adjust default buffer stack
ADD BX, 128
MOV STBHI, BX
MOV STBPT, BX

SETINT:
IF NOT TEST
CLI; disable interrupts
MOV ES, ISEG; get interrupt table segment
ASSUME ES: INTSEG

MOVINT 05; move interrupt vectors
MOVINT 08
MOVINT 09
MOVINT 10 A
NEWINT 1B; set interrupt vectors
NEWINT 29

STI; enable interrupts
ENDIF; NOT TEST

MOV AX, STBHI; set stack area for driver calls
ADD AX, 80H
MOV STACK, AX
LES DI, PTRSAV
MOV ES: [DI].TOP.LW, AX; pass size of driver to system
MOV ES: [DI].TOP.HW, CS
JMP DONE; end of initialization

ASSUME ES: DUMMYS
SKPSPC: CMP AL, ' '; while space or HT do
JE SS0; get next character
CMP AL, HT
JNE SS1
SS0: LODS DUMMYB; (ES:/LODSB)
JMP SKPSPC
SS1: RET

GTINTG: MOV CX, 3930H; get integer value
CMP AL, CL
JB GI0
CMP AL, CH
JBE GI1; if first character not digit then
STC; return error
GI0: RET
GI1: XOR BX, BX; convert string to integer
XOR AH, AH
MOV DI, 10
GI2: SUB AL, CL
XCHG AX, BX
MUL DI
JC GI0; overflow
ADD AX, BX
JC GI0; overflow
XCHG AX, BX
LODS DUMMYB
CMP AL, CH
JA GI0
CMP AL, CL
JAE GI2; continue while next char is digit
CLC
RET

LAST LABEL WORD; INIT stack = here + 100H

ANSI ENDS
ASSUME NOTHING


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

  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/