Source file: /~heha/hs/dos/ansi.zip/ANSI.ASM

;Mein kleiner ANSI-Treiber
;Unterstützt auch LESS-Sequenzen (NROFF)
;Zapft nur den Int29 (Console Output) an, nicht aber Int2F, um die
;Deinstallation zu erleichtern -
;leider gibt es so keine standardmäßige Erkennungsroutine.

;Für Selbst-Assemblierer: die PROLOG.ASM befindet sich unter
;"http://www.tu-chemnitz.de/~heha/hs_freeware/asmutil.zip"

	include	prolog.asm

	org	0c0h
OldInt29 dd	?
last	dw	?		;Die letzten beiden Buchstaben
argn	db	?		;Anzahl der Argumente
argv	db	5 dup (?)	;Argumentwerte
curv	dw	?		;Cursor-Merker

	org	100h
	jmp	start1

ctrl0	db	0c0h		;Allgemeine Zelle
;Bit7: ANSI-Treiber EIN
;Bit6: LESS-Treiber EIN
;Bit5: Letztes Zeichen war Ziffer
;Bit4: war mal Invers
;Bit3: war mal Hidden
;Bit2-0: alte VFarbe, falls Hidden
attrib	db	7		;Zeichenfarbe

NewInt29:
	sti
	push	ax bx cx dx ds es
	 LD	ds,cs
	 mov	dx,40h
	 mov	es,dx		;ins BIOS
	 mov	dx,[last]
	 mov	bl,7		;Standardvorgabe
	 test	[ctrl0],80h	;ANSI aktiv?
	 jz	NoAnsi
;+++ ANSI-Behandlung +++
	 mov	bl,[attrib]
	 cmp	dx,27*256+'['
	 jnz	NoAnsiSeq
	 call	AnsiSeq
	 jr	Exi
NoAnsiSeq:
	 cmp	al,27		;Escape?
	 jz	FiltOut
	 cmp	dl,27		;Escape als vorangegangenes Zeichen?
	 jnz	AnsiChr
	 cmp	al,'['
	 jz	FiltOut
	 push	ax
	  mov	al,dl
	  call	PutColor
	  VID	0eh
	 pop	ax

AnsiChr: test	[ctrl0],40h	;DAZU noch LESS?
	 jz	nigr		;nein, farbig ausgeben

NoAnsi:	 test	[ctrl0],40h	;LESS aktiv?
	 jz	PutOut
;+++ LESS-Behandlung +++
both:	cmp	dx,'_'*256+8	;Underscore und Backstep?
	jz	nige		;zum Gelbling!
	cmp	dl,8
	jnz	nigr
	cmp	dh,al		;Gleicher Buchstabe?
	jnz	nigr		;grau oder ANSI-farben
	;GRÜN
	and	bl,not 0fh
	or	bl,2		;Grün-Override
	jr	nigr
nige:	;GELB
	and	bl,not 0fh
	or	bl,0eh		;Gelb-Override
nigr:	;GRAU
	call	PutColor
	cmp	al,0ah		;Cursor Down?
	jnz	PutOut
	push	dx
	 call	GetCursor	;PA: DX
	 cmp	dh,[es:84h]	;Letzte Zeile?
	 jnz	PutO1		;nein, normal weiter
	  xor	cx,cx
	  mov	dl,[es:4ah]	;Rechte Spalte
	  dec	dl
	  mov	bh,[attrib]
	  VID	6,1		;1 Zeile rollen
	pop	dx
	mov	al,0ah
	jr	FiltOut

PutO1:	pop	dx
	;ohne alles ganz einfach
PutOut:	 VID	0eh
FiltOut: ;Gar nichts ausgeben, nur zurückhalten
	 xchg	dh,dl
	 mov	dl,al
	 mov	[last],dx
Exi:	pop	es ds dx cx bx ax
	iret

proc PutColor			;' ' mit Farbe BL ausgeben
	cmp	al,7
	jz	@@e
	cmp	al,8
	jz	@@e
	cmp	al,10
	jz	@@e
	cmp	al,13
	jz	@@e
	push	cx ax
	 mov	bh,[es:62h]
	 mov	cx,1
	 VID	9,' '
	pop	ax cx
@@e:	ret
	endp

proc AnsiSeq
	push	si
	 mov	bl,[argn]	;Erst mal BX hinstellen
	 xor	bh,bh
	 add	bx,ofs argv-1
	 sub	al,'0'
	 jc	@@1
	 cmp	al,10		;Ziffer?
	 jnc	@@1		;nein
	 test	[ctrl0],20h	;War eine Ziffer vorneweg?
	 jnz	@@2		;ja - nur Zahl bilden
	 inc	[argn]		;nein - Neues Argument
	 inc	bx
	 jr	@@3		;1. Ziffer eintragen

@@2:	 mov	ah,[bx]		;Alte Ziffer verzehnfachen
	 add	ah,ah
	 add	ah,ah
	 add	ah,[bx]
	 add	ah,ah
	 add	al,ah
@@3:	 mov	[bx],al
	 or	[ctrl0],20h
	 jr	@@e
@@1:
	 add	al,'0'
	 call	subfunc
@@e:	pop	si
	ret
	endp

proc GetCursor
	push	bx
	 mov	bl,[es:62h]
	 xor	bh,bh
	 add	bl,bl
	 mov	dx,[es:50h+bx]	;GetCursor ohne BIOS-Ruf
	pop	bx
	ret
	endp

proc subfunc
	mov	si,ofs UPT
	call	upv
	jc	endansi		;Funktion nicht unterstützt
	call	GetCursor
	cmp	[argn],1	;CY=1 wenn ARGN=0
	call	[wo si]
endansi:xor	ax,ax
	mov	[last],ax	;Löschen der ANSI-Vergangenheit
	mov	[wo argn],ax	;Keine Argumente mehr
	mov	[wo argv+1],ax	;Argumente sicherheitshalber nullsetzen
	and	[ctrl0],not 20h	;Ende einer Ziffernfolge
	ret
	endp

upt:	dvt	';',afsemi		;ANSI-Funktion für Semikolon
	dvt	'H',afh
	dvt	'f',afh
	dvt	'A',afa
	dvt	'B',afb
	dvt	'C',afc
	dvt	'D',afd
	dvt	's',afs
	dvt	'u',afu
	dvt	'J',afj
	dvt	'K',afk
	dvt	'm',afm
	dvt	'=',afgleich
	dvt	'h',afx
	dvt	'l',afx
	db	-1

;=== Hilfsfunktionen mit Stackkorrektur ===
afsemi:	and	[ctrl0],not 20h	;Ende einer Ziffernfolge
afgleich:
	pop	si		;Stack abräumen
	ret			;1 Ebene drüber

;=== Cursorfunktionen ===
afa:	sbb	dh,[argv]
	jnc	setcur
	xor	dh,dh
	jr	setcur

afb:	adc	dh,[argv]
	jc	afb1
	cmp	dh,[es:84h]	;Letzte Zeile
	jc	setcur
afb1:	mov	dh,[es:84h]
	jr	setcur

afc:	adc	dl,[argv]
	jc	afc1
	cmp	dl,[es:4ah]
	jc	setcur
afc1:	mov	dl,[es:4ah]
	dec	dl
	jr	setcur

afd:	sbb	dl,[argv]
	jnc	setcur
	xor	dl,dl
	jr	setcur

afh:	mov	dx,[wo argv]
	xchg	dh,dl		;Vertauschen erforderlich
	cmp	dh,[es:84h]
	ja	retu
	cmp	dl,[es:4ah]
	jc	setcur		;zum Cursorpositionieren!
	ret

;=== Zeilen- und Bildschirmlöschen ===
afj:	cmp	[argv],2	;mind. 1 Parameter, der "2" ist?
	jnz	retu		;nein, dann KEIN CLS
	xor	cx,cx
	mov	dl,[es:4ah]	;Spaltenzahl
	dec	dl
	mov	dh,[es:84h]
	mov	bh,[attrib]
	VID	0600h		;Bildschirm löschen
	xor	dx,dx
setcur:	mov	bh,[es:62h]
	VID	02h		;Cursor zu 0/0
retu:	ret

afk:	mov	cx,dx
	mov	dl,[es:4ah]	;Spaltenzahl
	dec	dl
	mov	bh,[attrib]
	VID	0600h		;Zeilenrest löschen
	ret

;=== Cursor retten und wiederherstellen ===
afs:	mov	[curv],dx	;Cursorpos speichern
	ret

afu:	mov	dx,[curv]
	jr	SetCur

;=== Farben und Attribute wählen ===
afm:	mov	bx,ofs argv	;zunächst auf "argv"
	mov	cl,[argn]
	xor	ch,ch
	jcxz	retu
afml:
	 mov	al,[bx]
	 cmp	al,30
	 jc	novf
	 cmp	al,38
	 jnc	novf
	 sub	al,30
	 push	bx
	  mov	bx,ofs BRevTab
	  xlat
	 pop	bx
	 mov	ah,not 7
	 jr	afm1		;Neue Vordergrundfarbe
novf:
	 cmp	al,40
	 jc	nohf
	 cmp	al,48
	 jnc	nohf
	 sub	al,40
	 push	bx
	  mov	bx,ofs BRevTab
	  xlat
	 pop	bx
	 push	cx
	  mov	cl,4
	  rol	al,cl		;High- und Low-Nibble vertauschen
	 pop	cx
	 mov	ah,not 70h
afm1:	 call	atMani
	 jr	afme
nohf:
	 mov	si,ofs atUvt
	 call	upv
	 jc	afme
	 call	[wo si]
afme:
	inc	bx		;nächstes Argument
	loop	afml
	ret

BRevTab: ;Bitreversionstabelle für korrekte Farben
	db	0,4,2,6,1,5,3,7

;+++ dazu Unterfunktionen +++
atReset:
	mov	[attrib],7	;Blinken und Intensiv AUS, Standardfarbe
	ret

atIntens:
	or	[attrib],8
	ret

atUnderl:
	mov	ax,0f801h	;Vordergrund BLAU ergibt Underline
	jr	atMani		;Attribut manipulieren

atFlash:
	or	[attrib],80h
	ret

atInvert:
	mov	ax,8870h
atMani:
	and	ah,[attrib]	;Alte HFarbe ausmaskieren
	or	al,ah
	mov	[attrib],al	;Neue Hintergrundfarbe (bzw. VFarbe)
atRetu:	ret

atHide:
	mov	ax,8800h
	jr	atMani		;VFarbe:=HFarbe

atUvt:	dvt	0,atReset
	dvt	1,atIntens
	dvt	4,atUnderl
	dvt	5,atFlash
	dvt	7,atInvert
	dvt	8,atHide
	db	-1

;=== Videomodus wählen ===
afx:	jc	afxe		;wenn argn=0
	mov	al,[argv]
	VID	0
afxe:	ret

uv2:	add	si,3
proc upv	;Unterprogrammverteiler
	cld
	cmp	[si],al
	jz	@@1
	cmp	[by si],-1	;Abschlußbyte?
	cmc
	jnc	uv2
	;CY=1 - Fehler: Funktion nicht unterstützt (Tabelle zu Ende)
@@1:	inc	si
	ret
	endp

ResEnd:
;===== Transientes Programmteil =====

SetLess:
	mov	ah,40h
	jr	SetBit
SetAnsi:
	mov	ah,80h
SetBit:	lodsb
	cmp	al,'+'
	jnz	sa1
	or	[es:ctrl0],ah
	jr	scancl
sa1:	cmp	al,'-'
	jnz	scancl
	not	ah
	and	[es:ctrl0],ah
	jr	scancl

start1:	;Hier gehts richtig los!
	Print	Text0		;Erst mal 'ne Message
	mov	cl,-1		;Alle Bits setzen
	DOS	3529h		;Alter Int29
	SES	<OldInt29>,bx
	cmp	bx,offset NewInt29
	jne	NotInst
	mov	si,110h
	mov	di,si
	mov	cx,40h		;128 Bytes der Speicherkopien vergleichen
	cld
	repe	cmpsw		;Wenn okay dann CL=0!
	jr	IsInst
NotInst:
	LD	es,cs		;fein rückstellen!
IsInst:	mov	si,81h
	cld
scancl:	lodsb
	cmp	al,'-'
	jz	scancl
	cmp	al,'?'
	je	help
	and	al,not 20h
	cmp	al,'U'
	je	UnInst
	cmp	al,'H'
	je	help
	cmp	al,'A'
	je	SetAnsi
	cmp	al,'L'
	je	SetLess
	cmp	al,0dh
	jne	scancl
	or	cl,cl
	jnz	newinst
	call	OutInfo
	jr	LFOut

UnInst:	mov	dx,ofs Text2
	or	cl,cl
	jnz	TXTOut

	lds	dx,[es:OldInt29]
	DOS	2529h		;den Interrupt zurückstellen
	DOS	49h		;den Speicher ab es freigeben
	LD	ds,cs		;verpfuschtes Segment zurückholen
	mov	dx,ofs Text3
	jr	TXTOut

help:	mov	dx,ofs TextH
TXTOut:	DOS	9
LFOut:	PRINT	nl$
	DOS	4c00h

newinst:
	call	endansi		;ANSI AUS
	mov	dx,ofs NewInt29
	DOS	2529h		;SetInt29

	mov	es,[2ch]	;Segment Environment
	DOS	49h		;ENV-Speicher ab es freigeben
	mov	dx,ofs Text1	;"geladen"
	mov	ax,cs
	cmp	ax,0a000h
	jc	newlow
	mov	dx,ofs Text1a	;"hochgeladen"
newlow:	DOS	9
	mov	dx,ParaRes
	DOS	3100h		;TSR

OutInfo:	;Statusanzeige
	PRINT	Text4
	test	[es:ctrl0],80h
	call	OnOff			;je nach Z-Flag
	PRINT	Text5
	test	[es:ctrl0],40h
	call	OnOff
	ret

OnOff:	mov	dx,ofs off$
	jz	pOff
	mov	dx,ofs on$
pOff:	DOS	9
	ret

Text0	db	'ANSI 1.02 (haftmann#software): $'
Text1a	db	'hoch'
Text1	db	'geladen, Speicherbedarf '
	dcd	%((ParaRes)*16+16)
	db	' Bytes.',nl,'$'
Text2	db	'TSR nicht installiert oder verdeckt!$'
Text3	db	'vom Speicher entfernt.$'
Text4	db	'Status ANSI $'
Text5	db	', LESS $'
on$	db	'EIN (+)$'
off$	db	'AUS (-)$'
TextH	db	'Kombinierter ANSI- und LESS-Treiber,   FREEWARE',nl
	db	'Parameter:   (keiner)	ANSI.COM laden oder Status anzeigen',nl
	db	'	/a{+|-}		ANSI-Treiber ein/aus, Standard EIN',nl
	db	'	/l{+|-}		LESS-Treiber ein/aus, Standard EIN',nl
	db	'	/h oder /?	Diese Hilfe',nl
	db	'	/u		TSR entfernen$'
nl$	db	nl,'$'
	ENDC
Detected encoding: OEM (CP437)1
Wrong umlauts? - Assume file is ANSI (CP1252) encoded