Source file: /~heha/hs/dos/mrec_src.zip/MREC.ASM

;Makrorecorder für Tastatureingaben
;Tastaturmakro-Datei mit Klartext, mit beliebigem Whitespace und speziellem
;Operator für ClearBuf-Umschiffung

;Bei definiertem Symbol NERV (Shareware-Nervrequester) erfolgt zu Beginn
;und beim Ende der Lernphase ein Nervrequest (Vorbild AMISETUP).

MaxKeys		equ	1000		;Nur ≤ 32767 zulässig!!
MaxWait		equ	100h		;Vorgabe
scrkw		equ	372ch		;Scramble-Kennung
;switches-Bitbelegung
;0	Record /r
;1
;2
;3
;4
;5	Show mit Hex
;6	Show-Bit /s
;7

;8	Makrodateiname abgeparst
;9	Direkte Programmausführung /x
;10	Programmdateiname abgeparst (?)
;11	Video-Check /v
;12	Tastatur-Unterbrechung AUS /t
;13	Übersetzungs-Modus /t
;14	Binär-Modus /b
;15	Gescrambled /bx
DKEY macro str,hi,lo	;Definiere Tastencode, 3 Parameter
	ifb <lo>		;Wenn kein "LO" definiert...
	 db	'&str'
	else
	 db	lo
	endif
	db	hi,'&str',0
	endm

	include	prolog.asm
	include	"strings.asm"
	call	trans
	call	setvecs
	mov	sp,100h
	ResizeM
		mov	bx,ofs PBlock
		DOS	4b00h
		xchg	bx,ax
		mov	cx,cs
		mov	ss,cx
		mov	sp,100h
		pushf
		lds	dx,[cs:OldInt16]
		DOS	2516h
		mov	ds,cx
		popf
		jnc	noerr
		mov	dx,ofs errmsg
wrerr:		push	dx
		PRINT	err$
		mov	al,bl
		call	ahex
		pop	dx
		DOS	9
		jr	wrdone

noerr:		test	[switches],1
		jz	wrdone
		call	runovl
		mov	dx,ofs ovlmsg
		mov	bl,al
		jc	wrerr
wrdone:
		xchg	al,bl
		DOS	4ch		;Das Ende vom Lied der Echse

err$:
 db 'MREC: Fehler $'
errmsg:
 db ' beim Ausführen des Hauptprogramms!',nl,'$'
ovlmsg:
 db ' beim Laden des Dekodier-Overlays (MREC NIEMALS lighten)!',nl,'$'

readwo:	;read a word!, CY=1: Puffer abgerasselt! (leer)
	;PE: Bit 0(ah)=1: nur Tastaturstatus
	;PA: AX: Tastencode
	;    CY=1: Puffer leer
	;VR: AX,F
		push	si
		mov	si,[cs:BufPtr]
		cmp	si,[cs:BufFst]	;SI noch kleiner als Füllstand?
		cmc
		jc	rw1		;nein: Puffer ausgekuddelt
		test	ah,1
		segcs	lodsw
		jnz	rw1
		mov	[cs:BufPtr],si
rw1:		pop	si
		ret

writewo:;write a word! (CY=1: Puffer voll)
		push	si
		mov	si,[cs:BufPtr]
		cmp	si,[cs:BufFst]	;hier: Pufferende
		cmc
		jc	ww1
		mov	[cs:si],ax
		add	[cs:BufPtr],2	;erhöhen
ww1:		pop	si
		ret

NewInt16:
		pushf
		 mov	[cs:axstore],ax
		 test	[cs:switches],1	;Play?
		 jnz	NoEmulP
		 cmp	ah,10h
		 jz	rwo
		 or	ah,ah
		 jz	rwo
		 cmp	ah,11h
		 jz	stat
		 cmp	ah,1
		 jnz	NoEmulP
stat:
		 call	readwo
		 jc	NoEmulP		;Puffer leer, Umschalten normal KBD
		 push	ax
		  mov	ax,[cs:kpCount]
		  inc	ax
		  cmp	[cs:kpCmax],ax	;Wenn kpCmax=65535 dann IMMER
				;readkey=false!!! (Verklemmung möglich)
		  jnc	stat1
		  mov	ax,0		;Rücksetzen
stat1:		  mov	[cs:kpCount],ax
		 pop	ax
		 jc	em2		;Größer? -> Code emulieren
		 test	[cs:switches],800h
		 jz	em21		;abwechselnd Code und kein Code!
		 push	ax
		  call	VChk
		  xchg	[cs:vchks],ax
		  cmp	[cs:vchks],ax
		 pop	ax
		 jz	em21
		 mov	[cs:kpCount],0	;Von vorn warten!
		 jr	em21
rwo:
		 call	readwo
		 jc	NoEmulP
		 mov	[cs:kpCount],0
		 jr	em3		;raus mit Emulation
NoEmulP:
		popf
		mov	ax,[cs:axstore]
		pushf
		CALLF
OldInt16	dd	?		;Original-ISR
		pushf
		 test	[cs:switches],1	;Record?
		 jz	NoRec
		 cmp	[by cs:axstore+1],0
		 jz	recit
		 cmp	[by cs:axstore+1],10h
		 jnz	norec
recit:		 call	WriteWo		;Abspeichern
NoRec:		popf
		sti
		retf	2

em21:	;wenn keypressed false liefern soll
	;Ausbruchmöglichkeit via Tasten-Hit
		test	[cs:switches],1000h
		jnz	em22		;nie abbrechen!
		push	ax		;der Code aus dem Puffer
		call	kread
		pop	ax
		jnz	em2		;Tastencode durchlassen
em22:		xor	ax,ax
em2:		;Flag entsprechend AX pfuschen
		and	ax,ax		;Null?
		jnz	em4
		mov	ax,[cs:axstore]	;restaurieren!
em4:
		call	dummy
		sti
		retf	2

em3:		popf
		iret

dummy:		ret	2
		_AXHX			;AX Hexausgabe!
kread:
		mov	ah,1
		pushf
		call	[cs:OldInt16]
		jz	kr1
		mov	ah,0
		pushf
		call	[cs:OldInt16]
		or	ax,ax		;Z=0!
kr1:		ret			;Z=1: keine Taste gedrückt

runovl:	;Overlay laden und starten
		push	ds es bx
		 push	cs
		 pop	es
		ResizeM	MemEnd		;etwas Speicher *mehr* bitte!
					;für ein paar Dollar mehr
		jc	roexi01
		mov	ds,ax
		mov	es,[2ch]	;Entwirronment
		xor	ax,ax
		xor	di,di
		cld
envs1:		scasb
		jnz	envs1
		scasb
		jnz	envs1
		inc	ax
		scasw			;die "1" lesen
		stc
		jnz	roExi		;Fehler bei keiner Eins!
		push	ds
		 push	es
		 pop	ds
		xchg	dx,di
		DOS	3d00h		;OpenRead
		pop	ds
roexi01:	jc	roexi
		mov	bx,ax		;Handle
		xor	cx,cx
		mov	dx,ResEnd-COMentry
		DOS	4200h		;MoveFP
		jc	roexi
		mov	dx,ofs ResEnd
		mov	cx,PgmEnd-ResEnd
		DOS	3fh		;Reading
		jc	roexi
		cmp	ax,cx		;Sind alle Bytes da?
		mov	al,10h		;Fehler-Code
		stc
		jne	roexi
		DOS	3eh		;close
		call	decodex
	ifdef NERV
xnerv	equ	(' ' XOR '─')		;das Xorbyte zum Verscramblen
		VID	0fh
		cmp	al,7		;Monochrom?
		jz	ne1
		mov	al,3
ne1:		VID	0		;Löschen und Textmodus
		mov	si,ofs Nerv$
		cld
ne2:		lodsb
		xor	al,xnerv
		jz	ne3
		cmp	al,9		;TAB?
		jnz	ne4
		xor	bh,bh		;Seite Null
		VID	3		;GetCurs
		add	dl,8
		and	dl,not 7
		VID	2		;Extrawurst fürs TAB braten
		jr	ne2
ne4:		VID	0eh		;simple Ausgabe
		jr	ne2
ne3:		DOS	0ch,7		;ClrKeybrdBuf und Tastaturabfrage
	endif
		clc			;Kein Fehler melden!
roexi:		pop	bx es ds
		ret

VChk:	;Video-Checksum (Textmode) bilden
	;PE: -
	;PA: AX: Checksumme
	;VR: AX,F
		push	bx cx si ds
		mov	ah,0fh
		int	10h		;GetVideoMode
		mov	bx,40h
		mov	ds,bx
		mov	bx,0b000h	;Segment Hercules
		cmp	al,7
		mov	al,25		;Zeilenzahl Hercules
		jz	vc1
		mov	al,[84h]	;Zeilenzahl EGA/VGA
		inc	al
		mov	bx,0b800h	;Segment EGA/VGA

vc1:		mov	si,[4eh]	;Startoffset
		mul	ah		;ax:=ah*al
		mov	cx,ax
		mov	ds,bx
		xor	ax,ax
		jcxz	vc3
vc2:		add	ax,[si]
		add	si,2
		loop	vc2
vc3:		pop	ds si cx bx
		ret

axstore		dw	?
switches	dw	?
handle		dw	1		;Standardausgabe

vchks		dw	0		;Video-Checksumme zum Zählerhochsetzen
kpcmax		dw	MaxWait		;Keypressed-Zähler-Maximum
kpcount		dw	0		;KeyPressed-Zähler
PBlock		dw	0
ParOfs		dw	?
ParSeg		dw	?
BufPtr		dw	ofs KBDBuf	;default: Pufferanfang (lesebereit)
BufFst		dw	ofs ResEnd	;default: Pufferende
comc$:		db	'X:\command.com',0
KBDBuf:
hlp$:
    db 'Tastatur-Makrorecorder',nl
    db 'MREC {/? /r /x /v /l /nn /t /s /bx} <tastaturmakrodatei> <hauptprogramm>',nl
    db '/?	Diese Hilfeseite',nl
    db '/r	Aufnahme erzwingen',nl							;force Recording
    db '/x	<hauptprogramm> wird ohne Kommandointerpreter gestartet',nl		;eXecute directly
    db '/v	Veränderungen auf Bildschirm erfassen zum Zählerrücksetzen',nl		;check Video changes
    db '/l	Tastatur gänzlich sperren; sonst hilft Tastendruck bei Verklemmung',nl	;Lock keyboard
    db '/nn	(nn=Zahl von 0 bis 65535): Festlegung der keypressed-Wiederholrate',nl
    db '/t	nur <tastaturmakrodatei> übersetzen, nichts ausführen',nl
    db '/b	Ausgabeformat binär, /bx: binär gescrambled',nl
    db '/s	Anzeige aller möglichen Tastenkürzel, /sx mit Hex-Code',nl
    db 'Ist die <tastaturmakrodatei> nicht vorhanden, wird Aufnahme gestartet,',nl
    db 'sonst Wiedergabe ("Geisterfahrt")',nl,0
		org	KBDBuf+2*MaxKeys

ResEnd:
;===========================================================================
null$	db	0
keylist:	;gültig für DEUTSCHE Tastatur unter KEYB.COM
		;(wieder eine andere gilt unter KEYBSCR.COM)
	dkey	esc,1,1Bh
	dkey	1,2
	dkey	2,3
	dkey	3,4
	dkey	4,5
	dkey	5,6
	dkey	6,7
	dkey	7,8
	dkey	8,9
	dkey	9,0Ah
	dkey	0,0Bh
	dkey	!ß,0Ch
	dkey	<''>,0Dh
	dkey	bksp,0Eh,8
	dkey	tab,0Fh,9
	dkey	q,10h
	dkey	w,11h
	dkey	e,12h
	dkey	r,13h
	dkey	t,14h
	dkey	z,15h
	dkey	u,16h
	dkey	i,17h
	dkey	o,18h
	dkey	p,19h
	dkey	!ü,1Ah
	dkey	!+,1Bh
	dkey	enter,1ch,0dh
	dkey	et,1Ch,0Dh
	dkey	a,1Eh
	dkey	s,1Fh
	dkey	d,20h
	dkey	f,21h
	dkey	g,22h
	dkey	h,23h
	dkey	j,24h
	dkey	k,25h
	dkey	l,26h
	dkey	!ö,27h
	dkey	!ä,28h
	dkey	#,29h
	dkey	!<,2Bh
	dkey	y,2Ch
	dkey	x,2Dh
	dkey	c,2Eh
	dkey	v,2Fh
	dkey	b,30h
	dkey	n,31h
	dkey	m,32h
	dkey	!,,33h		;Literales Komma!
	dkey	.,34h
	dkey	-,35h
	dkey	spc,39h,' '
	dkey	f1,3Bh,0
	dkey	f2,3Ch,0
	dkey	f3,3Dh,0
	dkey	f4,3Eh,0
	dkey	f5,3Fh,0
	dkey	f6,40h,0
	dkey	f7,41h,0
	dkey	f8,42h,0
	dkey	f9,43h,0
	dkey	f10,44h,0
	dkey	f11,85h,0
	dkey	f12,86h,0
	dkey	num*,37h,'*'
	dkey	num-,4Ah,'-'
	dkey	num+,4Eh,'+'
	dkey	numet,0E0h,0Dh
	dkey	num/,0E0h,'/'
	dkey	home,47h,0
	dkey	cuu,48h,0
	dkey	pgup,49h,0
	dkey	cul,4Bh,0
	dkey	cur,4Dh,0
	dkey	end,4Fh,0
	dkey	cud,50h,0
	dkey	pgdn,51h,0
	dkey	ins,52h,0
	dkey	del,53h,0
	dkey	{,7Eh
	dkey	[,7Fh
	dkey	],80h
	dkey	},81h
	dkey	\,82h
	dkey	@,10h
	dkey	~,1Bh
	dkey	|,2Bh
	dkey	!µ,32h
;ab hier mit SHIFT
	dkey	ESC,1,1Bh
	dkey	!!,2
	dkey	!",3
	dkey	!,4
	dkey	!$,5
	dkey	!%,6
	dkey	!&,7
	dkey	!/,8
	dkey	(,9
	dkey	),0Ah
	dkey	=,0Bh
	dkey	?,0Ch
	dkey	BKSP,0Eh,8
	dkey	TAB,0Fh,0
	dkey	Q,10h
	dkey	W,11h
	dkey	E,12h
	dkey	R,13h
	dkey	T,14h
	dkey	Z,15h
	dkey	U,16h
	dkey	I,17h
	dkey	O,18h
	dkey	P,19h
	dkey	!Ü,1Ah
	dkey	*,1Bh
	dkey	ENTER,1ch,0dh
	dkey	ET,1Ch,0Dh
	dkey	A,1Eh
	dkey	S,1Fh
	dkey	D,20h
	dkey	F,21h
	dkey	G,22h
	dkey	H,23h
	dkey	J,24h
	dkey	K,25h
	dkey	L,26h
	dkey	!Ö,27h
	dkey	!Ä,28h
	dkey	<''>,29h
	dkey	!>,2Bh
	dkey	Y,2Ch
	dkey	X,2Dh
	dkey	C,2Eh
	dkey	V,2Fh
	dkey	B,30h
	dkey	N,31h
	dkey	M,32h
	dkey	!;,33h
	dkey	!:,34h
	dkey	_,35h

	dkey	SPC,39,' '
	dkey	F1,54h,0
	dkey	F2,55h,0
	dkey	F3,56h,0
	dkey	F4,57h,0
	dkey	F5,58h,0
	dkey	F6,59h,0
	dkey	F7,5Ah,0
	dkey	F8,5Bh,0
	dkey	F9,5Ch,0
	dkey	F10,5Dh,0
	dkey	F11,87h,0
	dkey	F12,88h,0
	dkey	NUM7,47h,37h
	dkey	NUM8,48h,38h
	dkey	NUM9,49h,39h
	dkey	NUM-,4Ah,2Dh
	dkey	NUM4,4Bh,34h
	dkey	NUM5,4Ch,35h
	dkey	NUM6,4Dh,36h
	dkey	NUM+,4Eh,2Bh
	dkey	NUM1,4Fh,31h
	dkey	NUM2,50h,32h
	dkey	NUM3,51h,33h
	dkey	NUM0,52h,30h
	dkey	NUM.,53h,2Eh
	dkey	NUMET,1Ch,0Dh
	dkey	HOME,47h,0
	dkey	CUU,48h,0
	dkey	PGUP,49h,0
	dkey	PGDN,4Bh,0
	dkey	CUR,4Dh,0
	dkey	END,4Fh,0
	dkey	CUD,50h,0
	dkey	PGDN,51h,0
	dkey	INS,52h,0
	dkey	DEL,53h,0
	dw	0
;Alles ab hier mit Control:
ctrl$	db	'ctrl+',0
keylistc:
	dkey	bksp,0Eh,7Fh
	dkey	tab,94h,0
	dkey	q,10h,11h
	dkey	w,11h,17h
	dkey	e,12h,5
	dkey	r,13h,12h
	dkey	t,14h,14h
	dkey	z,15h,1ah
	dkey	u,16h,15h
	dkey	i,17h,9
	dkey	o,18h,0Fh
	dkey	p,19h,10h
	dkey	!ü,1Ah,1Bh
	dkey	+,1Bh,1Dh
	dkey	et,1Ch,0Ah
	dkey	enter,1ch,0ah
	dkey	a,1Eh,1
	dkey	s,1Fh,13h
	dkey	d,20h,4
	dkey	f,21h,6
	dkey	g,22h,7
	dkey	h,23h,8
	dkey	j,24h,0Ah
	dkey	k,25h,0Bh
	dkey	l,26h,0Ch
	dkey	!<,2Bh,1Ch	;???
	dkey	y,2Ch,19h
	dkey	x,2Dh,18h
	dkey	c,2Eh,3h
	dkey	v,2Fh,16h
	dkey	b,30h,2h
	dkey	n,31h,0Eh
	dkey	m,32h,0Dh
	dkey	num*,96h,0
	dkey	spc,39,' '
	dkey	f1,5Eh,0
	dkey	f2,5Fh,0
	dkey	f3,60h,0
	dkey	f4,61h,0
	dkey	f5,62h,0
	dkey	f6,63h,0
	dkey	f7,64h,0
	dkey	f8,65h,0
	dkey	f9,66h,0
	dkey	f10,67h,0
	dkey	f11,89h,0
	dkey	f12,8Ah,0
	dkey	numhome,77h,0
	dkey	numcuu,8Dh,0
	dkey	numpgup,84h,0
	dkey	num-,8Eh,0
	dkey	numcul,73h,0
	dkey	num5,8Fh,0
	dkey	numcur,74h,0
	dkey	num+,90h,0
	dkey	numend,75h,0
	dkey	numcud,91h,0
	dkey	numpgdn,76h,0
	dkey	numins,92h,0
	dkey	numdel,93h,0
	dkey	numet,0E0h,0Ah
	dkey	num.,95h,0
	dkey	home,77h,0E0h
	dkey	cuu,8Dh,0E0h
	dkey	pgup,84h,0E0h
	dkey	cul,73h,0E0h
	dkey	cur,74h,0E0h
	dkey	end,75h,0E0h
	dkey	cud,91h,0E0h
	dkey	pgdn,76h,0E0h
	dkey	ins,92h,0E0h
	dkey	del,93h,0E0h
	dw	0
;Ab hier alles mit ALT
alt$	db	'alt+',0
keylista:
	dkey	esc,1,0
	dkey	1,78h,0
	dkey	2,79h,0
	dkey	3,7Ah,0
	dkey	4,7Bh,0
	dkey	5,7Ch,0
	dkey	6,7Dh,0
	dkey	7,7Eh,0
	dkey	8,7Fh,0
	dkey	9,80h,0
	dkey	0,81h,0
	dkey	!ß,82h,0
	dkey	=,83h,0
	dkey	bksp,0Eh,0
	dkey	tab,0A5h,0
	dkey	q,10h,0
	dkey	w,11h,0
	dkey	e,12h,0
	dkey	r,13h,0
	dkey	t,14h,0
	dkey	z,15h,0
	dkey	u,16h,0
	dkey	i,17h,0
	dkey	o,18h,0
	dkey	p,19h,0
	dkey	!ü,1Ah,0
	dkey	+,1Bh,0
	dkey	et,1Ch,0
	dkey	enter,1ch,0
	dkey	a,1Eh,0
	dkey	s,1Fh,0
	dkey	d,20h,0
	dkey	f,21h,0
	dkey	g,22h,0
	dkey	h,23h,0
	dkey	j,24h,0
	dkey	k,25h,0
	dkey	l,26h,0
	dkey	!ö,27h,0
	dkey	!ä,28h,0
	dkey	#,29h,0
	dkey	!<,2Bh,0
	dkey	y,2Ch,0
	dkey	x,2Dh,0
	dkey	c,2Eh,0
	dkey	v,2Fh,0
	dkey	b,30h,0
	dkey	n,31h,0
	dkey	m,32h,0
	dkey	!,,33h,0
	dkey	.,34h,0
	dkey	-,35h,0
	dkey	num*,37h,0
	dkey	spc,39h,' '
	dkey	f1,68h,0
	dkey	f2,69h,0
	dkey	f3,6Ah,0
	dkey	f4,6Bh,0
	dkey	f5,6Ch,0
	dkey	f6,6Dh,0
	dkey	f7,6Eh,0
	dkey	f8,6Fh,0
	dkey	f9,70h,0
	dkey	f10,71h,0
	dkey	f11,8Bh,0
	dkey	f12,8Ch,0
	dkey	num-,4Ah,0
	dkey	num+,4Eh,0
	dkey	numet,0A6h,0
	dkey	num.,0A4h,0
	dkey	home,97h,0
	dkey	cuu,98h,0
	dkey	pgup,99h,0
	dkey	cul,9Bh,0
	dkey	cur,9Dh,0
	dkey	end,9Fh,0
	dkey	cud,0A0h,0
	dkey	pgdn,0A1h,0
	dkey	ins,0A2h,0
	dkey	del,0A3h,0
	dw	0

proc Open	;AX: Fehlercode!
	mov	ax,3d00h
	test	bp,2000h	;/t?
	jz	@@2
	mov	al,2		;R/W bei Translation!
@@2:	DOS			;Open Read
	jc	@@1
	mov	bx,ax
	mov	[handle],bx
	mov	di,ofs ptr1
	mov	ax,ofs buf
	cld
	stosw			;Ptr1
	stosw			;Ptr2
	mov	ax,1
	stosw			;Zeilennummer
	dec	ax
	stosw			;Fehler
@@1:	ret
	endp

proc Create
	xor	cx,cx		;Keine Attribute
	or	bp,1	;Record Modus!
	DOS	3ch		;Create
	jc	@@1
	mov	bx,ax
	mov	[handle],bx
@@1:	ret
	endp

proc rb		;Blocklesen
	push	cx dx ax
	mov	dx,si
	mov	cx,length buf	;=sizeof(buf)
	mov	bx,[handle]
	DOS	3fh
	xchg	bx,ax
	pop	ax dx cx
	ret
	endp

proc Write	;Schreibt den durch DI adressierten ASCIIZ in die
		;Datei und hängt 1 Leerzeichen (bei Länge≤1)
		;oder 1 CRLF (Länge >1) an
	push	dx bx
	mov	dx,di
	mov	bx,[handle]
	call	ZKOUTH		;ASCIIZ ausgeben in einem Ruck
	mov	dx,ofs @@3		;Space
	mov	ax,[di]
	or	al,al		;Länge Null
	jz	@@1
	or	ah,ah		;oder Eins
	jz	@@1
	mov	dx,ofs nl$	;Newline
@@1:	call	ZKOUTH
	pop	bx dx
	ret
nl$:	db	nl,0
@@3:	db	' ',0
	endp

proc Read	;liest bis zum nächsten Whitespace (Nul, Tab, Spc, EOF, EOL)
		;PE: ES:DI: (leerer) Puffer
		;    CX: Puffer-Größe (max. Zeichenzahl-1)
		;PA: Mit einem ASCIIZ gefüllter Puffer garantiert ohne
		;    Whitespace
		;    Cy=1: Fehler, BX=Fehlercode
		;    Nul am Anfang: Dateiende
		;VR: ax bx
	push	si di cx
	and	ah,not 3	;Null: Startphase, KEINE Zwischenphase
@@3:	dec	cx
@@1:	mov	si,[ptr1]
	cmp	[ptr2],si	;Füllstand erreicht?
	jnz	@@2
	mov	si,ofs buf
	mov	[ptr1],si
	call	rb		;Blocklesen ab ds:si
	jc	@@exi
	add	bx,si
	mov	[ptr2],bx
	sub	bx,si		;Null, Dateiende?
	jz	@@eos
@@2:
	lodsb
	mov	[ptr1],si
	call	chkws
	jz	@@4
	or	ah,1		;Startphase Ende!
	jcxz	@@1
	stosb
	jr	@@3
@@4:
	cmp	al,0ah		;LF?
	jnz	@@41
	inc	[linenr]
@@41:	test	ah,1		;Startphase?
	jz	@@1
@@eos:
	xor	al,al		;CY=0
	stosb
@@exi:
	pop	cx di si
	ret
	endp

	;Externe "Module" aus PROLOG.ASM
	_CHKWS
	_ZKONL
	_INW2
	_STRCOMP
	_STRCPY
	_AXDEZ
	_UPCASE
	_INLIN
	_UPV
	_CASE

proc StrCmp	;vergleicht ASCIIZ [DS:SI] mit Anfang von [ES:DI]
		;Z=1: Übereinstimmung; dann: DI zeigt auf 1. Zeichen
		;danach; sonst: VR: si
	push	di si
	cld
@@2:	cmp	[by si],0
	jz	@@1
	cmpsb
	jz	@@2
	pop	si di
	ret
@@1:	pop	si si
	ret
	endp

proc WriteASCII	;Keyboardpuffer als ASCII-Datei ausgeben
		;- Datei muß zum Schreiben geöffnet sein
	mov	[BufPtr],ofs KBDbuf
	mov	di,ofs mrec$
	call	Write
	jc	@@e
	cld
@@1:	call	ReadWo
	jc	@@e0		;Ende ist kein böser Fehler...
	mov	di,ofs obuf	;Ziel der Operation
	mov	si,ofs keylist
	mov	dx,ofs null$
	call	@@s
	jnc	@@f
	mov	si,ofs keylistc
	mov	dx,ofs ctrl$
	call	@@s
	jnc	@@f
	mov	si,ofs keylista
	mov	dx,ofs alt$
	call	@@s
	jnc	@@f
	;Was bleibt ist schnöde Hexausgabe
	push	di
	 mov	[by di],'$'
	 inc	di
	 call	Hex2Mem		;AX: Hexzahl nach DI
	 xor	al,al
	 stosb			;Ende-Null
	pop	di
@@f:	call	Write
	jnc	@@1
@@e:	ret			;Fehler-Ausstieg

@@s:	;Such mal AX im Heuhaufen!
	cmp	[wo si],1
	jc	@@se
	cmp	[si],ax
	jz	@@sf
	inc	si
	inc	si
	call	ScaEnd		;ohne AX einzusauen!
	jr	@@s		;Nächster Vergleich
@@sf:	inc	si
	inc	si
	;es folgt ein StrCat, auch "Geigenkatze" genannt
	push	di
	 push	si
	  mov	si,dx
	  call	strcpy
	 pop	si
	 dec	di		;Zeiger ans Ende zurück
	 call	strcpy
	pop	di
@@e0:	clc
@@se:	ret
	endp

proc Hex2Mem	;Hexzahl AX nach ES:DI schreiben, VR: DI!
	xchg	al,ah
	call	@@1
	xchg	al,ah
@@1:	push	ax cx		;Werte erhalten
	  mov	cl,4		;oberes Nibble auf Bit 3...0
	  shr	al,cl		; schieben
	 pop	cx
	 call	@@2
	pop	ax
@@2:	and	al,0fh
	add	al,90h		;Hex -> ASCII
	daa
	adc	al,40h
	daa
	stosb			;universell wär's mit JMP [SI]
	ret
	endp

proc AllList	;Alle 3 Tablisten ausgeben nach [handle]
		;- Ggf. muß Datei zum Schreiben geöffnet sein
		;(ansonsten geht Ausgabe auf Bildschirm)
	mov	si,ofs keylist
	mov	dx,ofs null$
	call	tablist
	mov	si,ofs keylistc
	mov	dx,ofs ctrl$
	call	tablist
	mov	si,ofs keylista
	mov	dx,ofs alt$
	endp			;läuft in TabList ein!

proc Tablist	;Tabelle SI zu Kontrollzwecken ausgeben, DX zeigt auf Prolog
	cld
@@2:
	mov	bx,[handle]
	lodsw
	or	ax,ax
	jz	@@e
	test	bp,20h
	jz	@@2a
	mov	di,ofs obuf
	call	Hex2Mem
	mov	ax,' '
	stosw			;1 Trenn-Space
	push	dx
	 mov	dx,ofs obuf
	 call	ZkoutH
	pop	dx
@@2a:	call	ZkoutH		;String DX
	test	bp,20h
	jz	@@2b
	push	dx
	 mov	dx,si
	 call	ZkoutH
	 mov	dx,ofs nl$	;Newline immer!
	 call	ZKOUTH
	pop	dx
	jr	@@3

@@2b:	mov	di,si
	call	Write		;String SI
@@3:	call	ScaEnd
	jr	@@2
@@e:
	ret
	endp

proc ScaEnd	;rückt SI=PChar hinters Stringende
	push	ax
	 SKEND
	pop	ax
	ret
	endp

proc ReadASCII	;ASCII-Text einlesen und konvertieren
		;- Datei [handle] muß zum Lesen geöffnet sein
		;- Das Sclüsselwort (Header) muß bereits ausgelesen sein
		;Programm kann Fehlermeldungen ausgeben!
@@2:	mov	di,ofs obuf
	mov	cx,length obuf
	call	Read		;1 Wort lesen
	jnc	@@ne
	ret			;Lesefehler!
@@ne:	mov	dx,di
	cmp	[by di],0
	jz	@@1		;Ende mit Allende, kein Fehler
	mov	si,ofs ctrl$
	call	StrCmp
	mov	dx,ofs Keylistc
	jz	@@4
	mov	si,ofs alt$
	call	StrCmp
	mov	dx,ofs Keylista
	jz	@@4
	mov	dx,ofs Keylist
@@4:	cld
	mov	si,dx		;DI enthält Restzeichenkettenanfang
@@5:	lodsw			;AX=Scancode
	or	ax,ax
	jz	@@6		;Nichts gefunden: Syntaxfehler!
	call	StrComp
	jz	@@51
	call	ScaEnd		;String übergehen
	jr	@@5
@@51:
	call	WriteWo
	jnc	@@2
	mov	al,82h		;PF$
	jr	@@e		;Puffer voll
@@6:
	cmp	dx,ofs keylist	;Prologe vorhanden?
	jnz	m61
	mov	si,di		;Zur Quelle machen
	mov	bl,10		;Default Dezimal
	call	inw2		;Zahl einlesen
	jc	m61
	push	ax
	mov	al,[si]
	call	chkws
	pop	ax
	jz	@@51		;Es folgt Whitespace: ok!

m61:	cmp	[errors],0	;Erster Fehler?
	jnz	m62
	call	crlf
m62:	WrStr	obuf
	WrStr	sf$
	mov	ax,[linenr]
	call	axdez
	call	crlf
	inc	[errors]
	jmp	@@2
@@1:
	cmp	[errors],1	;CY oder nicht CY!
	cmc
	mov	al,81h		;Fehlerart SFT!
@@e:	ret
	endp

;*********************************************
tr31:	mov	al,[si]
	mov	di,ofs upv0
	call	case		;Ist Folgezeichen ' ','/','-' oder #13 ?
	jnc	tr2
	jmp	errmf		;sonst Kommandozeilenfehler
trl:	;Weißraum übergehen...
		add	sp,4		;Korrektur
		jr	tr2
trans:	;Transientes Unterprogramm
		ResizeM	MemEnd		;etwas Speicher *mehr* bitte!
					;für ein paar Dollar mehr
		jc	errm00
		xor	bp,bp		;BP sind meine neuen SWITCHES
		WrStr	intro$
		mov	[ParSeg],ds
		mov	si,81h

tr2:		mov	di,ofs upv0
		push	si
		call	upv		;1. Ebene
		pop	di
		jnc	tr31		;Nächste Option muß auf Weißraum folgen
		cmp	si,di		;Steckengeblieben?
		jz	filin
		jmp	errmf		;FEHLER! ...sonst andere Zeichen

noopt:		add	sp,6		;Stackkorrektur
filin:		test	bp,100h
		jnz	progname
		or	bp,100h
		call	term0		;dx=si, Terminiere, si auf die Null
		test	bp,1		;Record zwingend vorgegeben?
		jnz	oprec
		call	Open		;Bei Fehler Code in AX!
					;Öffnet R/W bei gesetztem Trans-Bit!
		jnc	opsucc2
		cmp	al,2
		jnz	errm00
opRec:		test	bp,2000h	;Translate?
		jnz	errm00
		call	Create		;Datei zum Schreiben öffnen, setzt Bit0(BP)
tr21:		jnc	tr2
errm00:		jmp	errm

opsucc2:	test	bp,40h		;Show?
		mov	al,80h
		jnz	errm00		;Already exist!
		call	encode
		jr	tr21		;evtl. Fehler beim Einlesen

progname:	test	bp,2040h
		JN	nz,errmf	;Fehler in Kommandozeile (/t oder /s)!
		mov	dx,ofs rec$
		test	bp,1
		jnz	pro1
		mov	dx,ofs Play$
pro1:		call	zkout2
		call	crlf
		test	bp,200h		;/x aufgetaucht?
		mov	[switches],bp
		jnz	exeimm
		sub	si,4
		mov	[wo si+1],'C/'
		mov	[by si+3],' '
		call	calctail
		call	GetComspec
		EX	es,ds		;command.com!
		xchg	dx,di
		ret			;zu 103h!

exeimm:		call	term0
		call	calctail
		ret			;zu 103h!

Opt:	test	bp,100h
	jnz	errmf		;Keine Option HINTER Makrodatei!!
	mov	di,ofs upv1
	call	UPV		;Unterprogrammverteiler
	jnc	opexi
	mov	bl,10
	call	InW2		;Dezimalzahl einlesen
	jc	opexi
	mov	[kpCmax],ax
opexi:	ret

fault:	;Unerwartetes Kommandozeilenende
	add	sp,4		;Stackkorrektur: Kein CALL!
	test	bp,40h		;Show?
	jz	nalli
	WrStrLn	out$
	call	AllList		;Dann ist's ja okay!
	jc	errm
	DOS	4c00h

nalli:	test	bp,2000h	;Translate?
	jz	errmf
	test	bp,100h		;War Dateiname schon dran?
	jz	errmf
	WrStrLn	trans$
	call	tran		;Das ist auch okay
	jc	errm
	DOS	4ch
errmf:	mov	al,1		;Mein Fehlercode

errm:	mov	di,ofs errlist
	push	ax		;die komprimierte CASE-Anweisung!
	call	case
	pushf
	 WrStrLn fehl$
	popf
	pop	ax		;für Hexausgabe
	mov	dx,[di]
	jnc	TXTO1
	call	AHEX		;noch vorher Fehlernummer ausgeben
	jr	txto

txto1:	cmp	al,81h
	jnz	txto
	mov	ax,[errors]
	call	AXDEZ		;Anzahl der Fehler ausgeben
	jr	txto

help:	mov	dx,ofs hlp$
TXTO:	push	ax
	 call	ZKOUT2
	 call	crlf
	pop	ax		;Errorlevel rückmelden
	DOS	4ch

setBin:	mov	al,[si]		;Folgezeichen
	call	UpCase
	cmp	al,'X'
	jnz	tr011
	inc	si		;X übergehen
	or	bp,8000h
tr011:	or	bp,4000h
	ret


ResFP:	xor	cx,cx
	mov	dx,cx
	mov	bx,[handle]
	DOS	4200h
	ret

encode:	;Tastaturdatei einlesen
	;jetzt auch mit ASCII-Datei
	;PE: [handle]: offene Datei
	;    CS=DS
	;PA: CY: Fehler aufgetreten!
	push	si dx
	mov	di,ofs obuf
	mov	cx,length obuf
	call	Read		;1 Wort lesen
	mov	si,ofs mrec$
	call	StrComp
	jnz	ecBin
	call	ReadASCII	;ASCII's einlesen, schiebt BufPtr hinter!
	mov	bx,ofs KBDbuf
	xchg	[BufPtr],bx
	mov	[BufFst],bx
	jc	deClos		;bei Fehler 81 in Errors die Anzahl!
	jr	okClos		;mit oder ohne Carry?

ecBin:	call	ResFP
	mov	dx,ofs kword
	mov	cx,4		;1 Schlüssel- und 1 Code-Wort
	mov	bx,[handle]
	DOS	3fh
	jc	deClos
	mov	ax,[kword]
	cmp	ax,'RM'		;MREC-Header
	jz	ecBinN		;Normal-binär
	cmp	ax,scrkw
	jnz	ecBinC
	jr	ecBinX
ecBinN:	cmp	[cword],'CE'
ecBinC:	mov	ax,11h		;Ungültige Datei
	stc
	jnz	deClos
	mov	cl,-1		;No crypted!
	jr	ecNoPwd
ecBinX:	mov	cl,0		;Crypted!
	test	bp,2000h	;Translate?
	jz	ecNoPwd
	WrStrLn	lock$
	call	InSecP		;Paßworteingabe ohne Echo!
	cmp	ax,[cword]
	mov	ax,12h		;Falsches Paßwort
	stc
	jnz	deClos
	mov	cl,0
ecNoPwd:push	cx
	 mov	dx,ofs KBDBuf
	 mov	cx,MaxKeys*2
	 mov	bx,[handle]
	 DOS	3fh		;lesen
	pop	cx
	jc	deClos
	add	ax,dx		;Endadresse berechnen, CY bleibt 0
	mov	[BufFst],ax	;Füllstand eintragen, BufPtr bleibt am Anfang
	sub	ax,dx
	or	cl,cl
	jnz	okClos
	mov	cx,ax
	mov	si,dx		;KBDBuf
	mov	ax,[cword]
	call	decrypt
okClos:	test	bp,2000h	;Translate
	jnz	deExi		;Nicht schließen!
deClos:	pushf
	 push	ax
	  mov	bx,[handle]
	  DOS	3eh		;zumachen
	 pop	ax
	popf
deExi:	pop	dx si
	ret

decrypt:jcxz	decre		;Nichts zu descrambeln
decr1:	add	[si],cx
	xor	[si],ax
	inc	si
	inc	si
	loop	decr1
decre:	ret

InSecP:	;Eingabe Paßwort und 'Berechnung' eines 2-Byte-Wortes
	WrStr	passwd$
	mov	di,ofs obuf
	mov	cx,length obuf
	call	InSec		;Eingabe
	push	di bx
	mov	bx,scrkw	;zufällig derselbe Startwert, warum nicht?
insecl:	mov	al,[es:di]
	or	al,al
	jz	insece
	cbw
	inc	di
	shl	bx,1
	add	bx,ax
	shl	bx,1
	xor	bx,ax		;das dürfte zur Verwirrung genügen
	jr	insecl
insece:	xchg	ax,bx		;Ergebnis in AX
	pop	bx di
	ret

BufCrypt: ;Puffer scrambeln
	mov	si,ofs KBDBuf
	mov	cx,[BufFst]
	sub	cx,si
	jcxz	bufcre		;Nichts zu scrambeln
encrypt:xor	[si],ax
	sub	[si],cx
	inc	si
	inc	si
	loop	encrypt
bufcre:	ret

decodex:mov	ax,cs
	mov	ds,ax
	mov	es,ax
	mov	bp,[switches]
	mov	ax,ofs KBDbuf
	xchg	[BufPtr],ax
	mov	[BufFst],ax	;Pointer an Füllstand für korrekte Arbeit!
	jr	decode

tran:	call	ResFP		;Zeiger rücksetzen zum Schreiben!
	mov	ax,[BufFst]
	mov	[BufPtr],ax	;Pointer an Füllstand für korrekte Arbeit!
decode:	;Tastaturdatei schreiben
	;jetzt auch als ASCII
	;PE: [handle]: Na was wohl???
	;CS=DS
	;Beachte: Das Handle wird VOR DEM CHILDSTART erstellt!
	push	si dx
	test	bp,4000h	;Binär?
	jz	deASC
	test	bp,8000h
	jz	deBin
	mov	[kword],scrkw
	WrStrLn	neu$
	call	InSecP
	mov	bx,ax
	WrStrLn	sicher$
	call	InSecP
	cmp	bx,ax
	jnz	deBin0
	mov	[cword],ax	;das Paßwort
	call	BufCrypt	;mit AX als Paßwort
	WrStrLn	match$
	jr	deWri

deBin0:	WrStrLn	nomatch$
	and	bp,not 8000h	;Nicht scrambeln
deBin:	mov	[kword],'RM'
	mov	[cword],'CE'
deWri:	mov	bx,[handle]
	mov	dx,ofs kword
	mov	cx,4
	DOS	40h
	jc	deClos00
	mov	dx,ofs KBDBuf
	mov	cx,[BufFst]
	sub	cx,dx		;Nur Länge!
	DOS	40h		;schreiben
	jc	deClos00
	cmp	ax,cx
	mov	ax,9		;"Out Of Disk Space"
	stc
	jnz	deClos00
	clc
	jr	deClos00
deASC:	call	WriteASCII
deClos00:
	xor	cx,cx
	mov	bx,[handle]
	DOS	40h		;Truncate!
	jmp	deClos

coms$:	db	'COMSPEC='

upv1:
	dvt	'?',Help
	dvt	'H',Help
	dvt	'X',setx
	dvt	'R',setr
	dvt	'V',setv
	dvt	'L',setlock
	dvt	'T',setT
	dvt	'B',setBin
	dvt	'S',Show
	dvt	'-',noopt
	db	0			;Abschluß
upv0:
	dvt	'/',Opt
	dvt	'-',Opt
	dvt	' ',trl
	dvt	13,fault
	db	0

Show:	mov	al,[si]		;Folgezeichen
	call	UpCase
	cmp	al,'X'
	jnz	sh011
	inc	si		;X übergehen
	or	bp,20h
sh011:	or	bp,40h		;Show-Flag: Keinen EXEC-Dateinamen erwarten!
	ret

setT:	or	bp,2000h	;Nur übersetzen!
	ret
setv:	or	bp,800h		;Video-Check-Flag setzen
	ret
setx:	or	bp,200h		;Direkt-Execute ohne command.com
	ret
setr:	or	bp,1		;Record zwingen VOR Dateiöffnung!
	ret
setlock:or	bp,1000h	;Tastatur-Sperr-Flag setzen
	ret

setvecs:	;Vektorenverbiege-UP
		push	ds dx es
		 push	cs
		 pop	ds
		DOS	3516h
		SES	<OldInt16>,bx
		mov	dx,ofs NewInt16
		DOS	2516h
		pop	es dx ds
		ret

CalcTail:	;Länge der Parameterzeile berechnen, SI zeigt drauf
		mov	cx,si
		sub	cl,80h
		sub	cl,[80h]
		neg	cl
		jns	ct1
		mov	cx,13*256	;Endezeichen in High-Teil
		mov	[si],cx
ct1:		mov	[si],cl
		mov	[ParOfs],si	;eintragen
		ret

GetComspec:	;DS=PSP
	;PA: ES:DI: Location des Kdo-Interpreters
	mov	es,[2ch]
	xor	di,di
	xor	ax,ax
	cld
lp3:	mov	cx,8		;Länge von COMSPEC=
	mov	si,offset coms$
	repe	cmpsb		;Vergleichen
	je	lp2		;gleich
	dec	di
lp1:	scasb
	jnz	lp1
	scasb
	dec	di
	jnz	lp3

	;nicht gefunden
	push	ds
	pop	es
	mov	di,ofs comc$
	DOS	3305h
	add	dl,40h
	mov	[di],dl		;Bootlaufwerk wird wohl kaum X sein!
lp2:	ret

term0:	;Hilfsprogrämmchen, SI hinter die Null!
	mov	dx,si
	cld
te1:	lodsb
	cmp	al,0dh		;Zeilenende?
	jz	teEOL
	cmp	al,21h
	jnc	te1
	mov	[by si-1],0
	ret
teEOL:	mov	[wo si-1],13*256
	ret

errlist:
	dvt	1,flt$
	dvt	2,NoFile$
	dvt	3,NoPath$
	dvt	4,NoHndl$
	dvt	5,AccDen$
	dvt	8,NoMem$
	dvt	9,DiskFl$
	dvt	11h,fhead$
	dvt	12h,falsch$
	dvt	13h,dwp$
	dvt	80h,exist$
	dvt	81h,sft$
	dvt	82h,pf$
	dvt	0,sonst$

;Hier sind die Texte (außer Hilfetext, der ist im residenten Bereich)
fehl$	db 'FEHLER:',0
flt$	db 'Falscher oder fehlender Parameter in der Kommandozeile! (Hilfe mit /?)',0
NoFile$	db 'Datei nicht gefunden!',0
NoPath$	db 'Pfad nicht gefunden!',0
NoHndl$	db 'Keine Handles mehr!',0
AccDen$	db 'Zugriff verweigert!',0
NoMem$	db 'Zu wenig Speicher!',0
DiskFl$ db 'Diskette voll!',0
dwp$	db 'Diskette / Verzeichnis schreibgeschützt',0
exist$	db 'Datei existiert bereits!',0
rec$	db 'Aufnahme beginnt!',0
play$	db 'Wiedergabe beginnt!',0
trans$	db 'Übersetzung läuft...',0
out$	db 'Ausgabe aller Kürzel',0
intro$:
	ifdef NERV
	db 'MREC Tastaturmakrorekorder - UNREGISTRIERTE SHAREWARE-VERSION ZUM 30-TAGE-TEST!',nl
	dz '(Copyright 1994 Berauer Computer): '
	else
	dz 'MREC (Copyr. 1994 Berauer Computer): '
	endif
mrec$	db 'MREC#ASCII',0
sicher$	db 'Zur Sicherheit noch einmal..',0
neu$	db 'NEUES PASSWORT eingeben..',0
passwd$	db 'Paßwort: ',0
falsch$ db 'Falsches Paßwort! - Kein Zugriff!',0
nomatch$ db 'Die beiden Paßwörter stimmen nicht überein! Speichere als normale Binärdatei.',0
match$	db 'Paßwort in Datei gespeichert.',0
lock$	db '(Eingabedatei ist paßwortgeschützt)',0
fhead$	db 'Die angegebene Datei ist keine gültige Tastaturmakrodatei!',0
sonst$	db '.. Unerwarteter interner oder sonstiger Fehler!',0
sf$	db ' ... Syntaxfehler in Zeile ',0
sft$	db ' Fehler in der Makrodatei, Programm abgebrochen!',0
pf$	db 'Interner Pufferüberlauf, maximal sind '
	dcd	MaxKeys
	db ' Tastenanschläge zulässig!',0

	ifdef NERV
xnl	equ	(xnerv xor 13),(xnerv xor 10)
Nerv$:
	db	xnl
	dxs	xnerv,<	┌────────── Unterstützen Sie Shareware ──────────┐>
	db	xnl
	dxs	xnerv,<	│						 │>
	db	xnl
	dxs	xnerv,<	│	Shareware ist keine Gratis-Software.	 │>
	db	xnl
	dxs	xnerv,<	│						 │>
	db	xnl
	dxs	xnerv,<	│ Sie dürfen dieses Programm 30 Tage lang testen.│>
	db	xnl
	dxs	xnerv,<	│						 │>
	db	xnl
	dxs	xnerv,<	│ Danach müssen Sie eine geringe Registrierungs- │>
	db	xnl
	dxs	xnerv,<	│ gebühr entrichten.				 │>
	db	xnl
	dxs	xnerv,<	│						 │>
	db	xnl
	dxs	xnerv,<	│ Für den geringen Registrierungsbetrag lohnt	 │>
	db	xnl
	dxs	xnerv,<	│ sich eine Raubkopie wirklich nicht!!		 │>
	db	xnl
	dxs	xnerv,<	│						 │>
	db	xnl
	dxs	xnerv,<	└───────────────────────────── Taste drücken... ─┘>
	db	xnl
	db	xnerv		;Abschlußzeichen
	endif
;und hier die transienten Arbeitszellen
PGMEnd:				;Ende initialisierte Variablen
ptr1	dw	?
ptr2	dw	?
linenr	dw	?
errors	dw	?
kword	dw	?		;Kennwort
cword	dw	?		;Codewort
buf	db	80h dup (?)	;1 CP/M-Sektor Lesepuffer
obuf	db	16 dup (?)
MemEnd:
	ENDC
Detected encoding: OEM (CP437)1
Wrong umlauts? - Assume file is ANSI (CP1252) encoded