;
; A RAM-resident (TSR) DOS Screen Capture utility
;
	.186
	.model	tiny
	.code

stklen	equ	512
	org	100h
start:	jmp	around

;
; Signature is 4 byte, hotkey included
; - to Screen Capture DOSBMP in action
;
tsr_signature	db 'DM'
tsr_keyscan	db 2Ah
tsr_keyshift	db 01h

USE_TSR 	equ	1

BIOS		equ	0400h
shiftkeys	equ	0017h
shiftstate	equ	0018h
videomode 	equ	0049h
psp_memseg	equ	0002h
psp_environ	equ	002Ch

CONTEXT		STRUC
seg_psp	    	dw ?
seg_stack	dw ?
off_stack	dw ?
seg_dta	    	dw ?
off_dta	    	dw ?
seg_VECTOR_1B	dw ?
off_VECTOR_1B	dw ?
seg_VECTOR_23	dw ?
off_VECTOR_23	dw ?
seg_VECTOR_24	dw ?
off_VECTOR_24	dw ?
cursor_size	dw ?
cursor_loc	dw ?
video_page	db ?
cont_break_flag	db ?
CONTEXT		ENDS

S_MCB		STRUC
mcb_flag	db ?
mcb_owner	dw ?
mcb_size	dw ?
mcb_unused	db 3 dup(?)
mcb_name	db 8 dup(?)
S_MCB		ENDS

tsr_keyfound	db	0
tsr_running	dw	0
tsr_unloading	dw 	0
tsr_psp		dw	0
tsr_mcbseg	dw	0
tsr_diskflag	dw	0
tsr_dosbusy	dd	0
tsr_doslist	dd	0
cur_keyscan	db	?
cur_keyshift	db	?
OLDVECTOR_13	dd	0
OLDVECTOR_28	dd	0
OLDVECTOR_09	dd	0
OLDVECTOR_08	dd	0
int_context	CONTEXT	<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>
tsr_context	CONTEXT <0,0,0,0,0,0,0,0,0,0,0,0B0Ch,0,0,0>

tsr_isready PROC
	xor	ax,ax
	cmp     ax,cs:[tsr_running]
	jne 	ready_00
	cmp     ax,cs:[tsr_diskflag]
	jne 	ready_00
	cmp     al,cs:[tsr_keyfound]
	je 	ready_00
	les	bx,cs:[tsr_dosbusy]
	cmp	al,es:[bx]
	jne 	ready_00
	inc	ax
    ready_00:
	or	ax,ax
	ret
tsr_isready ENDP

tsr_setcontext PROC
	mov	ax,cs	; DI = &tsr_context or &int_context
	mov	es,ax
	mov	ds,es:[di.CONTEXT.seg_VECTOR_24]
	mov	dx,es:[di.CONTEXT.off_VECTOR_24]
	mov	ax,2524h
	int	21h
	mov	ds,es:[di.CONTEXT.seg_VECTOR_23]
	mov	dx,es:[di.CONTEXT.off_VECTOR_23]
	mov	ax,2523h
	int	21h
	mov	ds,es:[di.CONTEXT.seg_VECTOR_1B]
	mov	dx,es:[di.CONTEXT.off_VECTOR_1B]
	mov	ax,251Bh
	int	21h
	mov	ah,1Ah
	mov	ds,es:[di.CONTEXT.seg_dta]
	mov	dx,es:[di.CONTEXT.off_dta]
	int	21h
	mov	ax,es
	mov	ds,ax
	mov	ah,50h
	mov     bx,[di.CONTEXT.seg_psp]
	int	21h
	mov	ax,3301h
	mov	dl,[di.CONTEXT.cont_break_flag]
	int	21h
	mov	ah,1
	mov	bh,[di.CONTEXT.video_page]
	mov	cx,[di.CONTEXT.cursor_size]
	int     10h
	mov	ah,2
	mov	dx,[di.CONTEXT.cursor_loc]
	mov	bh,[di.CONTEXT.video_page]
	int	10h
	ret
tsr_setcontext ENDP

tsr_unload PROC
	xor	ax,ax
	mov	es,ax
	mov	ax,ds
	cmp	ax,es:[13h*4+2]
	jne	tsr_unload_04
	cmp	ax,es:[28h*4+2]
	jne	tsr_unload_04
	cmp	ax,es:[09h*4+2]
	jne	tsr_unload_04
	cmp	ax,es:[08h*4+2]
	jne	tsr_unload_04
	push	si
	mov	si,ds
	lds	dx,OLDVECTOR_13
	mov	ax,2513h
	int	21h
	mov	ds,si
	lds	dx,OLDVECTOR_28
	mov	ax,2528h
	int	21h
	mov	ds,si
	lds	dx,OLDVECTOR_09
	mov	ax,2509h
	int	21h
	mov	ds,si
	lds	dx,OLDVECTOR_08
	mov	ax,2508h
	int	21h
	mov	ds,si
	pop	si
	mov	dx,ds
	xor	bx,bx
	mov	ds,tsr_mcbseg
    tsr_unload_00:
	cmp	[bx.S_MCB.mcb_flag],'M'
	jne	tsr_unload_02
	cmp	[bx.S_MCB.mcb_owner],dx
	jne	tsr_unload_01
	mov	ax,ds
	inc	ax
	mov	es,ax
	mov	ah,49h
	int	21h
	jc	tsr_unload_03
    tsr_unload_01:
	mov	ax,ds
	add	ax,[bx.S_MCB.mcb_size]
	inc	ax
	mov	ds,ax
	jmp	tsr_unload_00
    tsr_unload_02:
	mov	ax,1
	jmp	tsr_unload_05
    tsr_unload_03:
	mov	ax,-1		; error FREE MEMORY
	jmp	tsr_unload_05
    tsr_unload_04:
	xor	ax,ax   	; not loaded
    tsr_unload_05:
	mov	ds,dx
	mov	word ptr tsr_signature,0
	mov	word ptr tsr_signature+2,0
	ret
tsr_unload ENDP

; TSR Popup -- save context and execute the TSR program
;
tsr_popup PROC
	mov	ax,cs
	mov	ds,ax
	mov	ax,1
	mov     tsr_running,ax	; set TSR running metaphore
	mov     tsr_keyfound,ah
	mov	di,offset int_context
	mov	si,offset tsr_context
	mov     [di.CONTEXT.seg_stack],ss	; interrupted stack
	mov     [di.CONTEXT.off_stack],sp
	mov	ss,[si.CONTEXT.seg_stack]	; TSR stack
	mov	sp,[si.CONTEXT.off_stack]
	mov	ax,3524h
	int	21h
	mov	[di.CONTEXT.off_VECTOR_24],bx
	mov	[di.CONTEXT.seg_VECTOR_24],es
	mov	ax,351Bh
	int	21h
	mov	[di.CONTEXT.off_VECTOR_1B],bx
	mov	[di.CONTEXT.seg_VECTOR_1B],es
	mov	ax,3523h
	int	21h
	mov	[di.CONTEXT.off_VECTOR_23],bx
	mov	[di.CONTEXT.seg_VECTOR_23],es
	mov	ax,3300h
	int	21h
	mov	[di.CONTEXT.cont_break_flag],dl
	mov	ah,2Fh
	int	21h
	mov	[di.CONTEXT.off_dta],bx
	mov	[di.CONTEXT.seg_dta],es
	mov	ah,51h
	int	21h
	mov     [di.CONTEXT.seg_psp],bx
	mov	bh,0
	mov	ah,0Fh
	int	10h
	mov	[di.CONTEXT.video_page],bh
	mov	[si.CONTEXT.video_page],bh
	mov	ah,3
	int	10h
	mov	[di.CONTEXT.cursor_size],cx
	mov	[di.CONTEXT.cursor_loc],dx
	mov	di,si
	call	tsr_setcontext
	xor	ax,ax		; Only popup in text modes..
	mov	es,ax
	mov	al,es:[BIOS+videomode]
	cmp	al,7
	je	tsr_popup_00
	cmp	al,0
	jl	tsr_popup_01
	cmp	al,4
	jae	tsr_popup_01
    tsr_popup_00:
	call	tsrmain
    tsr_popup_01:
	xor	ax,ax
	mov     cs:tsr_running,ax
	mov     ax,cs:tsr_unloading
	or	ax,ax
	jz	tsr_popup_02
	call	tsr_unload
    tsr_popup_02:
	mov	di,offset int_context
	call	tsr_setcontext
	mov     ss,int_context.seg_stack
	mov     sp,int_context.off_stack
	ret
tsr_popup ENDP

NEWVECTOR_24 PROC
	mov	ax,3
NEWVECTOR_24 ENDP

NEWVECTOR_1B PROC
	iret
NEWVECTOR_1B ENDP

NEWVECTOR_08 PROC
	push	ax
	push	bx
	push	cx
	push	dx
	push	es
	push	ds
	push	si
	push	di
	push	bp
	pushf
	call	cs:OLDVECTOR_08
	call	tsr_isready
	jz	NEWVECTOR_08_00
	mov	al,20h
	out	20h,al
	xor	ax,ax
	mov	cs:[tsr_keyfound],al
	call	tsr_popup
    NEWVECTOR_08_00:
	pop	bp
	pop	di
	pop	si
	pop	ds
	pop	es
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	iret
NEWVECTOR_08 ENDP

NEWVECTOR_09 PROC
	pushf
	push	ax
	push	es
	xor	ax,ax
	mov	es,ax
	mov	al,es:[BIOS+shiftkeys]
	pop	es
	and	al,0Fh
	mov	ah,al
	mov	cs:[cur_keyshift],al
	in      al,60h
	mov	cs:[cur_keyscan],al
	cmp     cs:[tsr_running],0
	jne 	NEWVECTOR_09_00
	cmp	al,cs:[tsr_keyscan]
	jne	NEWVECTOR_09_00
	cmp	ah,cs:[tsr_keyshift]
	jne	NEWVECTOR_09_00
	in	al,61h		; reset the keyboard
	mov	ah,al
	or	al,80h
	out	61h,al
	mov	al,ah
	out	61h,al
	cli
	mov	al,20h
	out	20h,al
	sti
	mov	al,1
	mov	cs:[tsr_keyfound],al
	pop	ax
	popf
	iret
    NEWVECTOR_09_00:
	pop	ax
	call	cs:[OLDVECTOR_09]
	iret
NEWVECTOR_09 ENDP

NEWVECTOR_28 PROC
	push	ax
	push	bx
	push	cx
	push	dx
	push	es
	push	ds
	push	si
	push	di
	push	bp
	pushf
	call	cs:OLDVECTOR_28
	call	tsr_isready
	jz	NEWVECTOR_28_00
	xor	ax,ax
	mov	cs:tsr_keyfound,al
	call	tsr_popup
    NEWVECTOR_28_00:
	pop	bp
	pop	di
	pop	si
	pop	ds
	pop	es
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	iret
NEWVECTOR_28 ENDP

NEWVECTOR_13 PROC
	inc	cs:tsr_diskflag
	pushf
	call	cs:OLDVECTOR_13
	dec	cs:tsr_diskflag
	iret
NEWVECTOR_13 ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

tsrmain_start label byte

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

USE_MOUSE	= 0
USE_CLIPBOARD	= 1
USE_TSRKEYBOARD	= 1
TSR_KEY		= 9900h

memzero	PROC
	push	ds
	pop	es
	push	di
	mov	di,ax
	cld
	xor	ax,ax
	rep	stosb
	pop	di
	ret
memzero	ENDP

memcpy	PROC
	push	si
	push	di
	mov	di,ax
	mov	si,dx
	push	ds
	pop	es
	cld
	rep	movsb
	pop	di
	pop	si
	ret
memcpy	ENDP

memmove	PROC
	push	si
	push	di
	push	ds
	pop	es
	mov	di,ax
	mov	si,dx
	cmp	ax,si
	ja	memmove_01
	cld
    memmove_00:
	rep	movsb
	pop	di
	pop	si
	ret
    memmove_01:
	std
	dec	cx
	add	si,cx
	add	di,cx
	inc	cx
	jmp	memmove_00
memmove	ENDP

strlen	PROC
	push	di
	push	cx
	push	ds
	pop	es
	mov	di,ax
	or	ax,ax
	jz	strlen_00
	xor	ax,ax
	cld
	mov	cx,-1
	repnz	scasb
	mov	ax,cx
	not	ax
	dec	ax
    strlen_00:
	pop	cx
	pop	di
	ret
strlen	ENDP

strcpy	PROC
	push	si
	push	di
	push	ds
	pop	es
	mov	di,ax
	mov	si,dx
	mov	dx,ax
	cld
    strcpy_00:
	lodsb
	stosb
	or	al,al
	jnz	strcpy_00
	mov	ax,dx
	pop	di
	pop	si
	ret
strcpy	ENDP

strchr	PROC
	push	bx
	mov	bx,ax
	xor	ax,ax
	push	ds
	pop	es
    strchr_00:
	mov	al,[bx]
	or	al,al
	jz	strchr_02
	cmp	al,dl
	je	strchr_01
	inc	bx
	jmp	strchr_00
    strchr_01:
	mov	ax,bx
    strchr_02:
	or	ax,ax
	pop	bx
	ret
strchr	ENDP

WMAXPATH  = 260
WMAXDRIVE = 3
WMAXDIR   = 256
WMAXFILE  = 256
WMAXEXT   = 256
MAXPATH	  = 80
MAXDRIVE  = 3
MAXDIR    = 66
MAXFILE   = 9
MAXEXT    = 5
SIZEWFBLK = 318

USE_DOS40EXOPEN = 1

SEEK_CUR = 1
SEEK_END = 2
SEEK_SET = 0

_A_NORMAL EQU	00h
_A_RDONLY EQU	01h
_A_HIDDEN EQU	02h
_A_SYSTEM EQU	04h
_A_VOLID  EQU	08h
_A_SUBDIR EQU	10h
_A_ARCH	  EQU	20h

_ifsmgr		dw 0
_osversion	dw ?
_maxfile	dw 66
_maxpath	dw 80

dosinit	PROC
	push	di
	sub	sp,32
	mov	di,sp
	mov	ah,30h
	int	21h
	mov	_osversion,ax
	mov	bx,argv
	mov	ax,[bx]
	cmp	ah,':'
	jne	dosinit_00
	sub	al,'A'
	jmp	dosinit_01
    dosinit_00:
	mov	ah,19h
	int	21h
    dosinit_01:
	push	ds
	pop	es
	mov	dx,di
	add     al,'A'
	mov	ah,':'
	mov	[di],ax
	mov	ax,'\'
	mov	[di+2],ax
	mov	cx,32
	mov	ax,71A0h
	stc
	int	21h
	jc	dosinit_end
	mov	_maxfile,cx
	mov	_maxpath,dx
	xor	ax,ax
	and	bh,40h
	jz	dosinit_end
	inc	ax
	mov	_ifsmgr,ax
    dosinit_end:
	add	sp,32
	pop	di
	ret
dosinit	ENDP

osopen	PROC
	push	si
	push	di
	mov	si,ax
	mov	ax,_ifsmgr
	or	ax,ax
	mov	ax,716Ch
	jnz	ospen_21h
	mov	ax,6C00h	; DOS 4.0+ - EXTENDED OPEN/CREATE
    ospen_21h:
	stc
	int	21h
	pop	di
	pop	si
	ret
osopen ENDP

OSIZE		EQU	1024
ISIZE		EQU	1024
IO_ERROR	EQU	8000h	; Write fault

A_OPEN	 	EQU	0001h
A_TRUNC	 	EQU	0002h
A_CREATE	EQU	0010h

M_RDONLY	EQU	0000h
M_WRONLY	EQU	0001h
M_RDWR		EQU	0002h

S_IOST		STRUC
ios_bp		DW ?
ios_i		DW ?
ios_c		DW ?
ios_size	DW ?
ios_flag	DW ?
ios_file	DW ?
ios_total_ax	DW ?
ios_total_dx	DW ?
S_IOST		ENDS

_ibuf	db ISIZE dup(?)
_obuf	db OSIZE dup(?)

STDI S_IOST <offset _ibuf,0,0,ISIZE,0,0,0,0>
STDO S_IOST <offset _obuf,0,0,OSIZE,0,1,0,0>

ofread	PROC
	push	si
	push	di
	mov	di,STDI.ios_c
	sub	di,STDI.ios_i
	jnz	ofread_copy
    ofread_read:
	xor	ax,ax
	mov	STDI.ios_i,ax
	mov	STDI.ios_c,di
	mov	cx,STDI.ios_size
	sub	cx,di
	mov	bx,STDI.ios_file
	mov	dx,STDI.ios_bp
	add	dx,di
	mov	ax,3F00h
	int	21h
	jc	ofread_error
	add	STDI.ios_c,ax
	add	ax,di
    ofread_end:
	or	ax,ax
	pop	di
	pop	si
	ret
    ofread_copy:
	cmp	di,STDI.ios_c
	je	ofread_eof
	mov	ax,STDI.ios_bp
	mov	dx,ax
	add	dx,STDI.ios_i
	mov	cx,di
	call	memcpy
	jmp	ofread_read
    ofread_error:
	or	STDI.ios_flag,IO_ERROR
    ofread_eof:
	xor	ax,ax
	jmp	ofread_end
ofread	ENDP

oopen	PROC
  ifdef USE_DOS40EXOPEN
	mov	cx,_A_NORMAL
	mov	dx,A_CREATE or A_TRUNC
	mov	bx,M_WRONLY
	call	osopen
  else
	mov	dx,ax
	mov	ah,3Ch
	xor	cx,cx
	int	21h
  endif
	mov	STDO.ios_file,ax
	jc	oopen_error
    oopen_ok:
	xor	ax,ax
	mov	STDO.ios_c,ax
	mov	STDO.ios_i,ax
	inc	ax
	ret
    oopen_error:
	xor	ax,ax
	ret
oopen	ENDP

oclose	PROC
	mov	bx,STDO.ios_file
	mov	ah,3Eh
	int	21h
	xor	ax,ax
	ret
oclose	ENDP

oputc	PROC
	push	bx
	mov	bx,STDO.ios_i
	cmp	bx,STDO.ios_size
	je	oputc_flush
    oputc_ok:
	mov	bx,STDO.ios_bp
	add	bx,STDO.ios_i
	inc	STDO.ios_i
	mov	[bx],al
	mov	ax,1
    oputc_eof:
	pop	bx
	ret
    oputc_flush:
	push	cx
	push	dx
	push	ax
	;push	es
	call	oflush
	;pop	es
	pop	ax
	pop	dx
	pop	cx
	jnz	oputc_ok
	xor	ax,ax
	jmp	oputc_eof
oputc	ENDP

owrite  PROC
	push	si
	push	di
	push	cx
	cld
	mov	si,ax
	mov	di,STDO.ios_i
	mov	ax,STDO.ios_size
	sub	ax,di
	cmp	ax,cx
	jb	owrite_slow
	push	es
	push	ds
	pop	es
	mov	ax,cx
	add     STDO.ios_i,ax
	add	di,STDO.ios_bp
	rep	movsb
	pop	es
    owrite_end:
	pop	cx
	pop	di
	pop	si
	ret
    owrite_slow:
	xor	di,di
    owrite_loop:
	lodsb
	call	oputc
	jz	owrite_end
	inc	di
	dec	cx
	jnz	owrite_loop
	mov	ax,di
	or	ax,ax
	jmp	owrite_end
owrite	ENDP

oswrite PROC
	mov	dx,STDO.ios_bp
	mov	bx,STDO.ios_file
	mov	cx,STDO.ios_i
	mov	ax,4000h
	int	21h
	jc	oswrite_error
	cmp	ax,cx
	jne	oswrite_error
	or	dx,dx
    oswrite_end:
	ret
    oswrite_error:
	xor     ax,ax
	ret
oswrite	ENDP

oflush	PROC
	mov	ax,STDO.ios_i
	or	ax,ax
	jz	oflush_ok
    oflush_write:
	call	oswrite
	jz	oflush_error
	xor	ax,ax
	mov	STDO.ios_c,ax
	mov	STDO.ios_i,ax
    oflush_ok:
	inc	ax
	ret
    oflush_error:
	or	STDO.ios_flag,IO_ERROR
	xor	ax,ax
	ret
oflush	ENDP

scrrow label byte
_scrrow	dw 25
scrcol label byte
_scrcol	dw 80
_scrseg	dw 0B800h

initscrseg PROC
	mov	ax,0040h
	mov	es,ax
	mov	bx,0063h
	mov	ax,es:[bx]
	and	ax,0FF0h
	cmp	ax,03B0h
	mov	ax,0B800h
	jne	initscrseg_B800
	mov	ax,0B000h
    initscrseg_B800:
	mov	_scrseg,ax
	mov	bx,004Ah	; screen columns [0040:004A]
	mov	al,es:[bx]
	mov	scrcol,al
	mov	ah,al		; = ah
	mov	bl,84h		; screen rows minus one [0040:0084]
	mov	al,es:[bx]
	mov	scrrow,al	; = al
	ret
initscrseg ENDP

rcsprc	PROC
	mov	al,scrcol
	mul	bh
	add	ax,ax
	xor	dx,dx
	mov	dl,bl
	add	ax,dx
	add	ax,dx
	mov	dx,_scrseg
	ret
rcsprc	ENDP

getxyp	PROC
	push	ax
	push	dx
  if USE_MOUSE
	call	mousehide
  endif
	call	rcsprc
	mov	es,dx
	mov	bx,ax
	pop	dx
	pop	ax
	ret
getxyp	ENDP

getxya	PROC
	call	getxyp
	mov	ah,0
	mov	al,es:[bx+1]
  if USE_MOUSE
	call	mouseshow
  endif
	ret
getxya	ENDP

wcputc	PROC
	mov	ah,0
wcputc	ENDP

wcputw	PROC
	push	cx
	push	di
	cld
	mov	di,bx
	or	ah,ah
	jz	wcputw_loop
	rep	stosw
	jmp     wcputw_end
    wcputw_loop:
	stosb
	inc	di
	dec	cx
	jnz	wcputw_loop
    wcputw_end:
	pop	di
	pop	cx
	ret
wcputw	ENDP

scputc	PROC
	mov	ah,0	; BL,BH,CX,AL
scputc	ENDP

scputw	PROC
	push	es	; BL,BH,CX,AX
	push	bx
	call	getxyp
	call	wcputw
  if USE_MOUSE
	call	mouseshow
  endif
	pop	bx
	pop	es
	ret
scputw	ENDP

putstr	PROC
	push	si
	push	di
	cld
	or	cl,cl
	jnz	putstr_lod
	dec	cl
	jmp	putstr_lod
    putstr_TAB:
	add	di,16
	and	di,0FFF0h
	jmp	putstr_lod
    putstr_0D:
	lodsb
	cmp	al,0Ah
	je	putstr_0A
	dec	si
    putstr_0A:
	pop	di
	add	di,dx
	push	di
    putstr_lod:
	lodsb
	or	al,al
	jz	putstr_end
	cmp	al,0Dh
	je	putstr_0D
	cmp	al,0Ah
	je	putstr_0A
	cmp	al,9
	je	putstr_TAB
	or	ah,ah
	jz	putstr_ch
	stosw
	jmp	putstr_next
    putstr_ch:
	stosb
	inc	di
    putstr_next:
	dec	cl
	jnz	putstr_lod
    putstr_end:
	mov	ax,si
	pop	di
	pop	si
	sub	ax,si
	ret
putstr	ENDP

scputds	PROC
	mov	dx,ds
scputds	ENDP

scputs	PROC ; (BL, BH, CH, CL, [DX:]AX);
	push	dx
	push	cx
	push	bx
	push	ds
	push	si
	push	di
	mov	si,ax
	push	dx
	call	getxyp
	mov	dh,0
	mov	dl,scrcol
	add	dx,dx
	pop	ds
	mov	di,bx
	mov	ah,ch
	mov	ch,0
	call	putstr
  if USE_MOUSE
	call	mouseshow
  endif
	pop	di
	pop	si
	pop	ds
	pop	bx
	pop	cx
	pop	dx
	ret
scputs	ENDP

rcxchg PROC
	push	si
	push	di
	mov	si,ax
	xor	cx,cx
	push	_scrseg
	pop	es
	cld
    rcxchg_loopl:
	mov	di,dx
	add	dx,160
	mov	cl,bl
    rcxchg_loopc:
	mov	ax,es:[di]
	xchg	ax,[si]
	mov	es:[di],ax
	add	di,2
	add	si,2
	dec	cx
	jnz	rcxchg_loopc
	dec	bh
	jnz	rcxchg_loopl
	pop	di
	pop	si
	ret
rcxchg ENDP

CURSOR_NORMAL	equ	0607h
CURSOR_HIDDEN	equ	0F00h

cursoron PROC
	mov	cx,CURSOR_NORMAL
	mov	ah,1
	int	10h
	ret
cursoron ENDP

cursoroff PROC
	mov	cx,CURSOR_HIDDEN
	mov	ax,0103h
	int	10h
	ret
cursoroff ENDP

__mouse	db 0	; Installed
__mbool	db 0	; Visible

mouseon	PROC
	mov	ax,1
	cmp	al,__mbool
	je	mouseon_00
	cmp	ah,__mouse
	je	mouseon_00
	mov	__mbool,al
	int	33h
    mouseon_00:
	ret
mouseon	ENDP

mouseoff PROC
	xor	ax,ax
	cmp	al,__mbool
	jz	mouseoff_00
	mov	__mbool,al
	mov	ax,2
	int	33h
    mouseoff_00:
	ret
mouseoff ENDP

KEY_ESC		= 011Bh
KEY_BKSP    	= 0E08h
KEY_TAB        	= 0F09h
KEY_ENTER      	= 1C0Dh
KEY_KPENTER	= 0E00Dh
KEY_SPACE      	= 3920h
KEY_HOME       	= 4700h
KEY_UP         	= 4800h
KEY_PGUP       	= 4900h
KEY_LEFT       	= 4B00h
KEY_RIGHT      	= 4D00h
KEY_END        	= 4F00h
KEY_DOWN       	= 5000h
KEY_PGDN       	= 5100h
KEY_INS        	= 5200h
KEY_DEL        	= 5300h

KEY_F1         	= 3B00h
KEY_F2         	= 3C00h
KEY_F3         	= 3D00h
KEY_F4         	= 3E00h
KEY_F5         	= 3F00h
KEY_F6		= 4000h
KEY_F7		= 4100h
KEY_F8		= 4200h
KEY_F9		= 4300h
KEY_F10		= 4400h
KEY_F11		= 8500h
KEY_F12		= 8600h

KEY_ALTUP	= 9800h
KEY_ALTDN	= 0A000h
KEY_ALTLEFT	= 9B00h
KEY_ALTRIGHT	= 9D00h
KEY_ALTX	= 2D00h

KEY_CTRLUP	= 8D00h
KEY_CTRLDN	= 9100h
KEY_CTRLLEFT	= 7300h
KEY_CTRLRIGHT	= 7400h
KEY_CTRLB	= 3002h

getkey	PROC
	mov	ah,11h
	int	16h
	jz	getkey_nul
	mov	ah,10h
	int	16h
	cmp	al,0E0h
	jne	getkey_end
	and	ax,0FF00h
	jnz	getkey_end
    getkey_nul:
  ifdef USE_TSRKEYBOARD
	mov	ax,word ptr cur_keyscan
	cmp	ax,word ptr tsr_keyscan
	jne	getkey_set
	mov	ax,TSR_KEY
	jmp	getkey_end
    getkey_set:
  endif
	xor	ax,ax
    getkey_end:
	or	ax,ax
	ret
getkey	ENDP

tmaxascii 	db 250
tminascii 	db ' '
tclrascii 	db 250

CONTINUE 	equ	0	; continue edit
RETEVENT 	equ	1	; return current event (keystroke)
CMFAILED 	equ	2	; operation fail (end of line/buffer)
MAXCLIPSIZE 	equ	128

S_TINFO		STRUC
ti_base		dw ?	; base pointer
ti_xpos		dw ?	; text window x,y
ti_ypos		dw ?
ti_cols		dw ?	; size of screen-line
ti_bcol		dw ?	; size of buffer-line
ti_xoff		dw ?	; offset on screen
ti_boff		dw ?	; offset in buffer (start of screen-line)
ti_bcnt		dw ?	; byte count in line
if USE_CLIPBOARD
ti_clst		dw ?	; Clipboard start
ti_clen		dw ?	; Clipboard end
endif
ti_clat		dw ?	; Normal string attrib
S_TINFO		ENDS

tedit		S_TINFO <?>

ti_proctab label word
	dw	ticontinue
	dw      tinextword
	dw      tiprevword
	dw      tidelete
	dw      tiesc
	dw      timouse
	dw      tileft
	dw      tiright
	dw      tihome
	dw      titoend
	dw      tibacksp
	dw      tiesc
	dw      tiesc
	dw      tiesc

ti_keytable label word
	dw	CONTINUE
	dw      KEY_CTRLRIGHT
	dw      KEY_CTRLLEFT
	dw      KEY_DEL

MOUSECMD	= -2

ti_skipkeys label word
	dw      KEY_ESC		; 011B
	dw      MOUSECMD	; FFFE
	dw      KEY_LEFT	; 4B00
	dw      KEY_RIGHT	; 4D00
	dw      KEY_HOME	; 4700
	dw      KEY_END 	; 4F00
	dw      KEY_BKSP	; 0E08
	dw      KEY_TAB		; 0F09
	dw      KEY_ENTER	; 1C0D
	dw      KEY_KPENTER	; E00D
	dw	KEY_UP		; 4800
	dw	KEY_DOWN	; 5000

ti_key_count =	14

ticurlp	PROC
	mov	bx,tedit.ti_base; current line offset (in buffer)
	mov	ax,bx		; return AX and BX
	ret
ticurlp	ENDP

ticursp	PROC
	call	ticurlp		; current line offset (on screen)
	add	ax,tedit.ti_boff
	mov	bx,ax
	ret
ticursp	ENDP

ticurp	PROC
	call	ticurlp		; current char offset (on screen)
	add	ax,tedit.ti_boff
	add	ax,tedit.ti_xoff
	mov	bx,ax
	ret
ticurp	ENDP

nocando	PROC
;	push	9
;	push	1
;	call	beep	; end of line/buffer
	mov	ax,CMFAILED
	ret
nocando	ENDP

tihome	PROC
	xor	ax,ax
	mov	tedit.ti_xoff,ax
	mov	tedit.ti_boff,ax
	ret
tihome	ENDP

titoend	PROC
	mov	dx,tedit.ti_cols
	dec	dx
	mov	ax,tedit.ti_bcnt
	cmp	ax,dx
	jle	titoend_00
	mov	ax,dx
    titoend_00:
	mov	tedit.ti_xoff,ax
	mov	dx,tedit.ti_bcnt
	sub	dx,tedit.ti_cols
	inc	dx
	xor	ax,ax
	cmp	ax,dx
	jg	titoend_01
	mov	ax,dx
    titoend_01:
	mov	tedit.ti_boff,ax
	mov	ax,tedit.ti_boff
	dec	ax
	cmp	ax,tedit.ti_bcnt
	jne	titoend_02
	dec	tedit.ti_boff
    titoend_02:
	mov	ax,CONTINUE
	ret
titoend	ENDP

tiseto	PROC
	call	ticurlp
	add	bx,tedit.ti_bcol
	dec	bx
	mov	byte ptr [bx],0
	call	strlen
	mov	tedit.ti_bcnt,ax
	mov	dx,tedit.ti_boff
	add	dx,tedit.ti_xoff
	cmp	dx,ax
	jb	tiseto_00
	call	titoend
	mov	ax,1
	ret
    tiseto_00:
	xor	ax,ax
	ret
tiseto	ENDP

tiputl	PROC
	push	ds
	push	si
  if USE_CLIPBOARD
	push	di
	mov	di,bx
  endif
	push	es
	push	bx
	mov	bh,byte ptr tedit.ti_ypos
	mov	bl,byte ptr tedit.ti_xpos
	call	getxyp
  if USE_CLIPBOARD
	push	bx
	inc	bx
	mov	ah,70h	; at_background[B_DarkGray]
	mov	cx,tedit.ti_cols
    tiputl_00:
	cmp	di,tedit.ti_clen
	jge	tiputl_02
	cmp	di,tedit.ti_clst
	jl	tiputl_01
	mov	es:[bx],ah
    tiputl_01:
	inc	di
	add	bx,2
	dec	cx
	jnz	tiputl_00
    tiputl_02:
	pop	bx
  endif
	mov	cx,tedit.ti_cols
	pop	si
	pop	ds
    tiputl_03:
	mov	al,[si]
	inc	si
	or	al,al
	jz	tiputl_04
	mov	es:[bx],al
	add	bx,2
	dec	cx
	jnz	tiputl_03
    tiputl_04:
  if USE_MOUSE
	call	mouseshow
  endif
  if USE_CLIPBOARD
	pop	di
  endif
	pop	si
	pop	ds
	ret
tiputl	ENDP

tiputs	PROC
	mov	bh,byte ptr tedit.ti_ypos
	mov	bl,byte ptr tedit.ti_xpos
	mov	cx,tedit.ti_cols
	mov	al,tclrascii
  if USE_CLIPBOARD
	mov	ah,byte ptr tedit.ti_clat
	call	scputw
  else
	call	scputc
  endif
	mov	ax,tedit.ti_base
	call	strlen
	cmp	ax,tedit.ti_boff
	jbe	tiputs_00
	mov	bx,tedit.ti_base
	add	bx,tedit.ti_boff
	call	tiputl
    tiputs_00:
	mov	ax,tedit.ti_xpos
	add	ax,tedit.ti_xoff
	mov	dx,tedit.ti_ypos
	call	gotoxy
	xor	ax,ax
	ret
tiputs	ENDP

tiputc	PROC
	cmp	al,tminascii
	jb	tiputc_ret
	cmp	al,tmaxascii
	ja	tiputc_ret
	inc	tedit.ti_bcnt
	mov	bx,tedit.ti_bcnt
	mov	dx,tedit.ti_bcol
	cmp	dx,bx
	jbe	tiputc_eof
	push	ax
	call	ticurp
	mov	dx,ax
	inc	ax
	mov	cx,tedit.ti_bcol
	sub	cx,tedit.ti_xoff
	sub	cx,tedit.ti_boff
	dec	cx
	call	memmove
	dec	ax
	mov	bx,ax
	pop	ax
	mov	[bx],al
	inc	tedit.ti_xoff
	mov	ax,tedit.ti_cols
	cmp	tedit.ti_xoff,ax
	jl	tiputc_end
	dec	ax
	mov	tedit.ti_xoff,ax
	add	ax,tedit.ti_boff
	cmp	tedit.ti_bcnt,ax
	jbe	tiputc_end
	inc	tedit.ti_boff
	jmp	tiputc_end
    tiputc_ret:
	mov	ax,RETEVENT
	ret
    tiputc_end:
	mov	ax,CONTINUE
	ret
    tiputc_eof:
	dec	dx
	mov	tedit.ti_bcnt,dx
	call	nocando
	ret
tiputc	ENDP

tinextword PROC
	call	ticurp
	xor	ax,ax
	cmp	al,[bx]
	jz	tinextword_06
	mov	ax,tedit.ti_boff
	add	ax,tedit.ti_xoff
	cmp	ax,tedit.ti_bcnt
	mov	ax,' '
	jnb	tinextword_06
	cmp	[bx+1],ah
	jz	tinextword_06
	mov	dl,al
	mov	ax,bx
	inc	ax
	call	strchr
	jz	tinextword_05
	xchg	ax,bx
    tinextword_00:
	cmp	byte ptr [bx],' '
	jne	tinextword_01
	inc	bx
	jmp	tinextword_00
    tinextword_01:
	sub	bx,ax
	jmp	tinextword_04
    tinextword_02:
	dec	bx
	mov	ax,tedit.ti_cols
	dec	ax
	cmp	ax,tedit.ti_xoff
	jbe	tinextword_03
	inc	tedit.ti_xoff
	jmp	tinextword_04
    tinextword_03:
	inc	tedit.ti_boff
    tinextword_04:
	or	bx,bx
	jnz	tinextword_02
	jmp	tinextword_06
    tinextword_05:
	call	titoend
	ret
    tinextword_06:
	mov	ax,CONTINUE
	ret
tinextword ENDP

tiback	PROC
	mov	ax,CMFAILED
	cmp	cx,tedit.ti_xoff
	je	tiback_00
	dec	tedit.ti_xoff
	xor	ax,ax
	ret
    tiback_00:
	cmp	cx,tedit.ti_boff
	je	tiback_end
	dec	tedit.ti_boff
	xor	ax,ax
    tiback_end:
	ret
tiback	ENDP

tiprevword PROC
	mov	ax,tedit.ti_boff
	add	ax,tedit.ti_xoff
	or	ax,ax
	jz	tiprevword_03
	call	ticurp
	dec	bx
	mov	dl,' '
	xor	cx,cx
    tiprevword_00:
	cmp	[bx],dl
	ja	tiprevword_01
	call	tiback
	dec	bx
	jmp	tiprevword_00
    tiprevword_01:
	cmp	bx,ax
	jbe	tiprevword_02
	call	tiback
	dec	bx
	cmp	[bx],dl
	ja	tiprevword_01
    tiprevword_02:
	cmp	ax,bx
	jnz	tiprevword_03
	xor	ax,ax
	mov	tedit.ti_boff,ax
	mov	tedit.ti_xoff,ax
    tiprevword_03:
	mov	ax,CONTINUE
	ret
tiprevword ENDP

tidelete PROC
	call	ticurp
	cmp	byte ptr [bx],0
	je	tidelete_end
	dec	tedit.ti_bcnt
	mov	dx,ax
	inc	dx
	call	strcpy
    tidelete_end:
	mov	ax,CONTINUE
	ret
tidelete ENDP

tibacksp PROC
	xor	cx,cx
	mov	ax,tedit.ti_boff
	add	ax,tedit.ti_xoff
	or	ax,ax
	jz	tibacksp_end
	call	tiback
	dec	tedit.ti_bcnt
	call	ticurp
	mov	dx,ax
	inc	dx
	call	strcpy
	mov	ax,CONTINUE
	ret
    tibacksp_end:
	call	nocando
	ret
tibacksp ENDP

timouse	PROC
  if USE_MOUSE
	call	mousey
	cmp	ax,tedit.ti_ypos
	jne	timouse_end
	call	mousex
	mov	dx,tedit.ti_xpos
	cmp	al,dl
	jb	timouse_end
	add	dx,tedit.ti_cols
	cmp	ax,dx
	jnb	timouse_end
	sub	ax,xpos
	mov	xoff,ax
	mov	ax,tedit.ti_base
	add	ax,tedit.ti_boff
	call	strlen
	cmp	ax,tedit.ti_xoff
	jnb	timouse_00
	mov	tedit.ti_xoff,ax
    timouse_00:
	mov	ax,tedit.ti_xpos
	add	ax,tedit.ti_xoff
	mov	dx,tedit.ti_ypos
	call	gotoxy
	call	msloop
	jmp	ticontinue
    timouse_end:
	mov	ax,RETEVENT
	ret
  else
	mov	ax,CONTINUE
	ret
  endif
timouse	ENDP

tiesc	PROC
	mov	ax,RETEVENT
	ret
tiesc	ENDP

tileft	PROC
	xor	cx,cx
	call	tiback
	ret
tileft	ENDP

ticontinue PROC
	xor	ax,ax
	ret
ticontinue ENDP

tiright	PROC
	call	ticurp
	mov	al,[bx]
	sub	bx,tedit.ti_xoff
	or	al,al
	jz	tiright_00
	mov	ax,tedit.ti_cols
	dec	ax
	cmp	ax,tedit.ti_xoff
	jbe	tiright_00
	inc	tedit.ti_xoff
	jmp	ticontinue
    tiright_00:
	mov	ax,bx
	call	strlen
	cmp	ax,tedit.ti_cols
	jb	tiright_eof
	inc	tedit.ti_boff
	jmp	ticontinue
    tiright_eof:
	call	nocando
	ret
tiright	ENDP

if USE_CLIPBOARD

WINOLDAP  	dw 0
clipbsize 	dw 0
clipboard 	dw 0
clipbuf		db MAXCLIPSIZE dup(?)

clipboard_init PROC
	xor	ax,ax
	mov	WINOLDAP,ax
	mov	ax,1700h
	int	2Fh
	mov	dx,ax
	xor	ax,ax			; AX <> 1700h
	cmp	dx,1700h		; - AL = WINOLDAP major version
	jz	clipboard_init_00	; - AH = WINOLDAP minor version
	mov	WINOLDAP,dx
    clipboard_init_00:
	mov	clipboard,offset clipbuf
	inc	ax
	ret
clipboard_init ENDP

clipboard_clear PROC
	xor	ax,ax
	mov	clipbsize,ax
	ret
clipboard_clear ENDP

clipboard_close PROC
	mov	dx,1708h
clipboard_close ENDP

clipboard_2F PROC
	xor	ax,ax
	cmp	WINOLDAP,ax
	je	clipboard_2F_end
	mov	ax,dx
	int	2Fh
    clipboard_2F_end:
	ret
clipboard_2F ENDP

clipboard_open PROC
	mov	dx,1701h
	call	clipboard_2F
	xor	ax,ax
	inc	ax
	ret
clipboard_open ENDP

clipboard_empty PROC
	mov	dx,1702h
	call	clipboard_2F
	call	clipboard_clear
	ret
clipboard_empty ENDP

clipboard_copy PROC PASCAL, string:word, len:word
	call	clipboard_clear
	cmp	WINOLDAP,ax
	je	clipboard_copy_00
	mov	dx,1		; set type to text
	mov	cx,len		; SI:CX = size of data
	push	si
	mov	si,ax		; HSIZE = 0
	push	ds
	pop	es
	mov	bx,string	; ES:BX = data
	mov	ax,1703h
	int	2Fh
	pop	si
	or	ax,ax
	jnz	clipboard_copy_01
    clipboard_copy_00:
	mov	cx,len
	mov	ax,clipboard
	mov	dx,string
	call	memcpy
	mov	cx,len
	mov	bx,ax
	add	bx,cx
	mov	byte ptr [bx],0
    clipboard_copy_01:
	ret
clipboard_copy ENDP

clipboard_size PROC
	xor	dx,dx
	cmp	WINOLDAP,dx
	je	clipboard_size_00
	inc	dx
	mov	ax,1704h
	int	2Fh
	or	dx,dx
	jz	clipboard_size_01
    clipboard_size_00:
	mov	ax,clipbsize
    clipboard_size_01:
	xor	dx,dx
	ret
clipboard_size ENDP

	;;;;;;;;;;;;;;;;;;;;;;;;;;;

set_clipboard PROC
	call	ticurp	; set clipboard to current position
	mov	tedit.ti_clst,ax
	mov	tedit.ti_clen,ax
	ret
set_clipboard ENDP

clipboard_delete PROC
	mov	ax,tedit.ti_clen
	sub	ax,tedit.ti_clst
	jz	clipboard_delete_end
	mov	ax,tedit.ti_clst
	mov	dx,tedit.ti_clen
	call	strcpy
	mov	dx,tedit.ti_clen
	sub	dx,ax
	mov	bx,tedit.ti_base
	add	bx,tedit.ti_boff
	add	bx,tedit.ti_xoff
	cmp	ax,bx
	je	clipboard_delete_set
	sub	tedit.ti_xoff,dx
    clipboard_delete_set:
	call	tiseto
	call	set_clipboard
	xor	ax,ax
	inc	ax
    clipboard_delete_end:
	ret
clipboard_delete ENDP

clipboard_cut PROC
	mov	dx,ax
	mov	ax,tedit.ti_clen
	sub	ax,tedit.ti_clst
	jle	clipboard_cut_end
	push	dx
	push	tedit.ti_clst
	push	ax
	call	clipboard_open
	call	clipboard_empty
	call	clipboard_copy
	call	clipboard_close
	pop	ax
	or	ax,ax
	jz	clipboard_cut_end
	call	clipboard_delete
    clipboard_cut_end:
	call	set_clipboard
	xor	ax,ax
	ret
clipboard_cut ENDP

clipboard_paste PROC
	xor	dx,dx
	cmp	WINOLDAP,dx
	je	clipboard_paste_NOAP
	inc	dx		; clipboard format supported by WinOldAp
	mov	ax,1704h
	int	2Fh
	or	dx,dx
	jnz	clipboard_paste_NOAP
	or	ax,ax
	jz	clipboard_paste_NOAP
	cmp	ax,MAXCLIPSIZE
	jae	clipboard_paste_NOAP
	mov	clipbsize,ax
	mov	ax,clipboard
	mov	cx,MAXCLIPSIZE
	call	memzero
	mov	dx,1
	push	ds
	pop	es
	mov	bx,clipboard	; ES:BX = buffer
	mov	ax,1705h	; GET CLIPBOARD DATA
	int	2Fh		; AX = status - nonzero success
    clipboard_paste_NOAP:
	mov	ax,clipbsize
	or	ax,ax
	ret
clipboard_paste ENDP

clipboard_get PROC
	push	si
	push	di
	push	tedit.ti_xoff
	push	tedit.ti_boff
	call	clipboard_delete
	call	clipboard_open
	call	clipboard_paste
	mov	si,ax
	call	clipboard_close
	or	si,si
	jz	clipboard_get_01
	mov	di,clipboard
    clipboard_get_00:
	mov	al,[di]
	or	al,al
	jz	clipboard_get_01
	inc	di
	call	tiputc
	or	ax,ax
	jnz	clipboard_get_01
	dec	si
	jnz	clipboard_get_00
    clipboard_get_01:
	pop	dx
	pop	ax
	mov	tedit.ti_xoff,ax
	mov	tedit.ti_boff,dx
	xor	ax,ax
	pop	di
	pop	si
	ret
clipboard_get ENDP

KEY_CTRLINS	= 9200h
KEY_CTRLDEL	= 9300h

clipboard_event PROC
	push	si
	mov	si,ax
	mov	ax,tedit.ti_clst
	cmp	ax,tedit.ti_clen
	jne	clipboard_event_00
	call	set_clipboard
    clipboard_event_00:
	cmp	si,KEY_CTRLINS
	je	clipboard_event_05
	cmp	si,KEY_CTRLDEL
	je	clipboard_event_06
	mov	ax,0040h
	mov	bx,0017h
	mov	es,ax
	mov	al,es:[bx]
	and	al,3
	jnz	clipboard_event_01
	cmp	si,KEY_DEL
	jne	clipboard_event_12
	call	clipboard_delete
	jz	clipboard_event_set
	xor	ax,ax
	jmp	clipboard_event_end
    clipboard_event_01:
	cmp	si,KEY_INS
	je	clipboard_event_get
	cmp	si,KEY_DEL
	je	clipboard_event_06
	cmp	si,KEY_HOME
	je	clipboard_event_08
	cmp	si,KEY_LEFT
	je	clipboard_event_08
	cmp	si,KEY_RIGHT
	je	clipboard_event_08
	cmp	si,KEY_END
	je	clipboard_event_08
    clipboard_event_12:
	cmp	si,KEY_ESC
	je	clipboard_event_set
  if USE_MOUSE
	cmp	si,MOUSECMD
	je	clipboard_event_set
  endif
	cmp	si,KEY_BKSP
	je	clipboard_event_set
	cmp	si,KEY_TAB
	je	clipboard_event_set
	cmp	si,KEY_ENTER
	je	clipboard_event_set
	cmp	si,KEY_KPENTER
	je	clipboard_event_set
	mov	ax,si
	or	al,al
	jz	clipboard_event_set
	call	clipboard_delete
    clipboard_event_set:
	call	set_clipboard
	mov	ax,si
    clipboard_event_end:
	pop	si
	ret
    clipboard_event_get:
	call	clipboard_get
	jmp	clipboard_event_end
    clipboard_event_05:
	xor	ax,ax
	jmp	clipboard_event_cut
    clipboard_event_06:
	mov	ax,1
    clipboard_event_cut:
	call	clipboard_cut
	jmp	clipboard_event_end
    clipboard_event_08:
	mov	ax,si
	call	tievent
	or	ax,ax
	jnz	clipboard_event_nul
	call	ticurp
	cmp	ax,tedit.ti_clst
	jb	clipboard_event_10
	cmp	si,KEY_RIGHT
	jne	clipboard_event_09
	mov	dx,ax
	dec	dx
	cmp	dx,tedit.ti_clst
	jne	clipboard_event_09
	cmp	dx,tedit.ti_clen
	jnz	clipboard_event_10
    clipboard_event_09:
	mov	tedit.ti_clen,ax
	jmp	clipboard_event_nul
    clipboard_event_10:
	mov	tedit.ti_clst,ax
    clipboard_event_nul:
	xor	ax,ax
	jmp	clipboard_event_end
clipboard_event ENDP

endif	; Clipboard

tievent	PROC
	mov	cx,ti_key_count
	xor	bx,bx
    tievent_cmp:
	cmp	ax,[bx+ti_keytable]
	je	tievent_found
	add	bx,2
	dec	cx
	jnz	tievent_cmp
	call	tiputc
	ret
    tievent_found:
	jmp	[bx+ti_proctab]
tievent	ENDP

timodal	PROC
	push	si
	push	di
	mov	si,CONTINUE
    timodal_idle:
	call	tiseto
	call	tiputs
	cmp	si,RETEVENT
	je	timodal_break
	call	tgetevent
  if USE_CLIPBOARD
	call	clipboard_event
  endif
	mov	di,ax
	call	tievent
	mov	si,ax
	jmp	timodal_idle
    timodal_break:
	call	ticurlp
	call	strlen
	mov	tedit.ti_bcnt,ax
	mov	ax,di
	pop	di
	pop	si
	ret
timodal	ENDP

if USE_CLIPBOARD
 init_clipboard PROC
	mov	ax,tedit.ti_base
	mov	tedit.ti_clst,ax; start = end = base
	mov	tedit.ti_clen,ax
	call	clipboard_init	; init WINOLDAP functions
	ret
 init_clipboard ENDP
endif

tdedit	PROC
  if USE_CLIPBOARD
	push	si
	mov	si,cx
	and	cx,not 8000h
  endif
	mov	tedit.ti_base,ax
	mov	tedit.ti_bcol,cx
	xor	ax,ax
	mov	al,bl
	mov	tedit.ti_xpos,ax
	mov	al,bh
	mov	tedit.ti_ypos,ax
	mov	al,dl
	mov	tedit.ti_cols,ax
	call	tihome
	mov	tedit.ti_xoff,ax
	mov	al,byte ptr tedit.ti_xpos
	mov	dx,ax
	mov	ax,tedit.ti_xpos
	call	gotoxy
	mov	bl,byte ptr tedit.ti_xpos ; get attrib of text to select
	mov	bh,byte ptr tedit.ti_ypos
	call	getxya
	mov	tedit.ti_clat,ax	 ; save text color
  if USE_CLIPBOARD
	call	init_clipboard
	and	si,8000h
	pop	si
	jz	tdedit_00
	call	tiseto
	call	titoend
	call	ticurp
	mov	tedit.ti_clen,ax
    tdedit_00:
  endif
	call	tiseto
	call	timodal
	push	ax
	call	tiputs
	pop	ax
	ret
tdedit	ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RC_X = 15
RC_Y = 5
RC_C = 50
RC_R = 4

;******** Resource begin DM *
DLG_DM LABEL WORD
	DW	0035h
	DB	0,0,15,5,50,4
OBJ_DM LABEL WORD
;	8 byte
WIN_DM LABEL WORD
	DW	007DAh,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h
	DW	007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,00720h,00744h
	DW	0074Fh,00753h,00742h,0074Dh,00750h,00720h,00756h,00765h
	DW	00772h,00773h,00769h,0076Fh,0076Eh,00720h,00732h,0072Eh
	DW	00730h,00734h,00720h,007C4h,007C4h,007C4h,007C4h,007C4h
	DW	007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h
	DW	007C4h,007BFh,007B3h,00720h,00742h,0074Dh,00750h,0073Ah
	DW	00720h,00720h,00720h,00720h,00720h,00720h,00720h,00720h
	DW	00720h,00720h,00720h,00720h,00720h,00720h,00720h,00720h
	DW	00720h,00720h,00720h,00720h,00720h,00720h,00720h,00720h
	DW	00720h,00720h,00720h,00720h,00720h,00720h,00720h,00720h
	DW	00720h,00720h,00720h,00720h,00720h,00720h,00720h,00720h
	DW	00720h,00720h,00720h,007B3h,007B3h,00720h,00749h,00744h
	DW	00744h,0073Ah,00720h,00720h,00720h,00720h,00720h,00720h
	DW	00720h,00720h,00720h,00720h,00720h,00720h,00720h,00720h
	DW	00720h,00720h,00720h,00720h,00720h,00720h,00720h,00720h
	DW	00720h,00720h,00720h,00720h,00720h,00720h,00720h,00720h
	DW	00720h,00720h,00720h,00720h,00720h,00720h,00720h,00720h
	DW	00720h,00720h,00720h,00720h,00720h,007B3h,007C0h,007C4h
	DW	007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h
	DW	007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h
	DW	007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h
	DW	007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h
	DW	007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h
	DW	007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007C4h,007D9h
;	400 byte
;******** Resource end   DM *

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RC_MAXY = 25 - RC_R
RC_MAXX = 80 - RC_C

ciscr_w	label word
ciscr_x	db RC_X
ciscr_y	db RC_Y

bmpfile db WMAXPATH dup(0)
iddfile db WMAXPATH dup(0)
LSIZE	EQU 128
linebuf	db LSIZE dup(?)

circxchg PROC
	mov	bx,ciscr_w
	call	rcsprc
	mov	dx,ax
	mov	ax,offset WIN_DM
	mov	bl,RC_C
	mov	bh,RC_R
	call	rcxchg
	ret
circxchg ENDP

gotoxy	PROC
	mov     dh,dl
	mov     dl,al
  if USE_TSR
	mov     bh,tsr_context.video_page
  else
	mov     bh,0
  endif
	mov     ah,02h
	int     10h
	ret
gotoxy	ENDP

ciclrsection PROC
	mov	cx,RC_C-10
	mov	bx,ciscr_w
	add	bx,0107h
	mov	al,' '
	call	scputc
	inc	bh
	call	scputc
	ret
ciclrsection ENDP

ciputsection PROC
	call	ciclrsection
	dec	bh
	mov	ax,offset bmpfile
	call	scputds
	inc	bh
	mov	ax,offset iddfile
	call	scputds
	ret
ciputsection ENDP

tgetevent PROC
	call	getkey
	jz	tgetevent
	ret
tgetevent ENDP

cp_help	db 'Hit Enter to Save, Alt-X or Esc to Quit',10
	db 'Ctrl-B to Hide - Alt-[Left|Up|Dn|Right]',0

cihelp	PROC
	call	cursoroff
	call	ciclrsection
	dec	bh
	xor	cx,cx
	mov	ax,offset cp_help
	call	scputds
	call	tgetevent
	call	ciputsection
	call	cursoron
	ret
cihelp	ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

message	db	'File created',10
	db	'Hit any key to continue..',0

exitmsg	PROC
	call	cursoroff
	call	ciclrsection
	dec	bh
	mov	cx,RC_C-10
	mov	ax,offset message
	call	scputds
	call	tgetevent
	call	ciputsection
	call	cursoron
	ret
exitmsg ENDP

_eropen	db	'Error open file:',0

eropen	PROC
	push	ax
	call	cursoroff
	call	ciclrsection
	pop	ax
	mov	cx,RC_C-10
	call	scputds
	dec	bh
	mov	ax,offset _eropen
	call	scputds
	call	tgetevent
	call	ciputsection
	call	cursoron
	ret
eropen	ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

S_RGB	STRUC
	rgb_R		db ?
	rgb_G		db ?
	rgb_B		db ?
	rgb_Q		db ?
S_RGB	ENDS

S_BMP	STRUC
	bmp_type	dw ?
	bmp_filesize	dd ?
	bmp_res1	dd ?
	bmp_offset_bit	dd ?
	bmp_res2	dd ?
	bmp_width	dd ?
	bmp_height	dd ?
	bmp_planes	dw ?
	bmp_bitcount	dw ?
	bmp_compression	dd ?
	bmp_sizeimage	dd ?
	bmp_xpelsperm	dd ?
	bmp_ypelsperm	dd ?
	bmp_colorused	dd ?
	bmp_climportant dd ?
	bmp_palett	db 64 dup(?)
S_BMP	ENDS

Bitmap label byte
	db	'BM'
bfz_ax	dw	0F400h + size S_BMP	; file size
bfz_dx	dw	00001h
	dd	0			;
	dd	size S_BMP		; offset bit
	dd	40			;
bcol_ax	dw	80*8
bcol_dx	dw	0
brow_ax	dw	25*16
brow_dx	dw	0
	dw	1			; planes
	dw	4			; bit count
	dd	0			; compression
bmz_ax	dw	0F400h			; size image
bmz_dx	dw	00001h
	dd	2835			; x pels per meter
	dd	2835			; y pels per meter
	dd	16			; color used
	dd	0			; color important
  ifdef _RCEDIT_
	db	  0,  0,  0,0	; Black
	db	102,  0,  0,0	; Desktop
	db	175,175,175,0	; Dialog
	db	174,174,174,0	; Menus
	db	  0,  0,153,0	; Error Dialog
	db	255,255,255,0	; Title-Line
	db	128,128,  0,0	; Selected file
	db	174,174,174,0	; Gray
	db	 80, 80, 80,0	; Reverse
	db	255,255,  0,0	; Desktop
	db	  0,  0,  0,0	; Dialog
	db	  0,  0,  0,0	; Menus
	db	  0,  0,155,0	; PushButton
	db	128,128,  0,0	; Desktop
	db	255,255,255,0	; Dialog
	db	255,255,255,0	; Menus
  else	;		[B] [G] [R]
	db	  0,  0,  0,0	; Black
	db	128,  0,  0,0	; Blue
	db	  0,128,  0,0	; Green
	db	128,128,  0,0	;
	db	  0,  0,128,0	; Red
	db	128,  0,128,0	;
	db	  0,128,128,0	;
	db	192,192,192,0	; Gray
	db	128,128,128,0	; Dark Gray
	db	255,  0,  0,0	; Blue
	db	  0,255,  0,0	; Green
	db	255,255,  0,0	;
	db	  0,  0,255,0	; Red
	db	255,  0,255,0	; Pink
	db	  0,255,255,0	; Yellow
	db	255,255,255,0	; White
  endif

font	dd	0

initfont PROC
	push	bp
	mov 	bx,0600h	; ROM 8x16 font
	mov 	ax,1130h	; GET FONT INFORMATION
	int 	10h
	mov	dx,es
	mov	ax,bp
	pop	bp
	mov	word ptr font,ax
	mov	word ptr font+2,dx
	ret
initfont ENDP

fontputc PROC
	push	si	; AX = Screen word
	push	di	; SI = Font line [15..0]
	push	es
	push	cx
	mov	bh,0
	mov	bl,al	; mask = *(font + (AL * 16) + SI);
	shl	bx,4
	add	bx,si
	les     si,font
	add	bx,si
	mov	si,es:[bx]
	mov	di,4	; output 4 byte
	mov	al,ah
	mov	ah,0
    fontputc_00:
	mov	cx,ax
	test	si,128
	jnz	fontputc_01
	shr	cl,4
	jmp	fontputc_02
    fontputc_01:
	and	cl,15
    fontputc_02:
	shl	cx,4
	shl	si,1
	push	ax
	test	si,128
	jnz	fontputc_03
	shr	al,4
	jmp	fontputc_04
    fontputc_03:
	and	al,15
    fontputc_04:
	or	al,cl
	shl	si,1
	call	oputc
	pop	ax
	jz	fontputc_05
	dec	di
	jnz	fontputc_00
	xor	ax,ax
	inc	ax
	jmp	fontputc_06
    fontputc_05:
	xor	ax,ax
    fontputc_06:
	pop	cx
	pop	es
	pop	di
	pop	si
	ret
fontputc ENDP

fontputl PROC
	push	si	; AX = line [24..0]
	push	di

	xor	bx,bx
	mov	bh,al
	call	rcsprc

;	mov	bx,_scrcol
;	add	bx,bx
;	mul	bx
	mov	di,ax
	mov	si,15
    fontputl_00:
	mov	ax,_scrseg
	mov	es,ax
	mov	cx,_scrcol
	push	di
    fontputl_01:
	mov	ax,es:[di]
	add	di,2
	call	fontputc
	jz	fontputl_05
	dec	cx
	jnz	fontputl_01
	pop	di
	dec	si
	cmp	si,-1
	jne	fontputl_00
    fontputl_04:
	xor	ax,ax
	pop	di
	pop	si
	ret
    fontputl_05:
	pop	di
	jmp	fontputl_04
fontputl ENDP

cmsavebmp PROC
	push	si
	push	di
	mov	ax,_scrrow
	inc	ax
	shl	ax,4
	mov	brow_ax,ax
	mov	bx,ax
	mov	ax,_scrcol
	shl	ax,3
	mov	bcol_ax,ax
	shr	bx,1
	mul	bx
	mov	bmz_ax,ax
	mov	bmz_dx,dx
	add	ax,size S_BMP
	adc	dx,0
	mov	bfz_ax,ax
	mov	bfz_dx,dx
	mov	ax,offset bmpfile
	call    oopen
	jz	cmsavebmp_eropen
	mov	cx,size S_BMP
	mov	ax,offset Bitmap
	call	owrite
	jz	cmsavebmp_erwrite
	call	circxchg
	call	initfont
	mov	si,_scrrow	; line [24..0]
    cmsavebmp_00:
	mov	ax,si
	call	fontputl
	dec	si
	cmp	si,-1
	jne	cmsavebmp_00
    cmsavebmp_flush:
	call	oflush		; flush STDO
	call	oclose
	call	circxchg
	call	exitmsg		; print exit status
    cmsavebmp_end:
	pop	di
	pop	si
	ret
    cmsavebmp_erwrite:
	call	oclose
	mov	ax,offset bmpfile
	call	remove
    cmsavebmp_eropen:
	call	eropen
	jmp	cmsavebmp_end
cmsavebmp ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

remove	PROC
	mov	dx,ax
	mov	ah,41h
	int	21h
	mov	ax,0
	jc	remove_err
    remove_end:
	or	ax,ax
	ret
    remove_err:
	dec	ax
	jmp	remove_end
remove	ENDP


Resource 	dw	4000+16	; alloc size
		dw	0010h	; flag
		dw	0000h	; index, count
Resource_X 	db	0	; RECT
Resource_Y 	db	0	;
Resource_C 	db	80	;
Resource_R 	db	25	;

compressidd PROC
	mov	al,es:[di]
	add	di,2
	mov	dl,al
	mov	dh,al
	and	dh,0F0h
	cmp	al,es:[di]
	jne	compressidd_01
	mov	bx,0F001h
	jmp	compressidd_04
    compressidd_01:
	cmp	dh,0F0h
	jne	compressidd_08
	mov	ax,01F0h
	jmp	compressidd_07
    compressidd_03:
	inc	bx
	mov	al,es:[di]
	add	di,2
	cmp	al,es:[di]
	jne	compressidd_05
    compressidd_04:
	dec	cx
	jnz	compressidd_03
    compressidd_05:
	mov	ax,bx
	cmp	bx,0F002h
	jne	compressidd_06
	cmp	dh,0F0h
	je	compressidd_06
	mov	al,dl
	call	oputc
	mov	al,dl
	jmp	compressidd_08
    compressidd_06:
	xchg	ah,al
    compressidd_07:
	push	ax
	call	oputc
	pop	ax
	mov	al,ah
	call	oputc
	mov	al,dl
    compressidd_08:
	call	oputc
	or	cx,cx
	jz	compressidd_09
	dec	cx
	jnz	compressidd
    compressidd_09:
	ret
compressidd ENDP

cmsaveidd PROC
	mov	ax,offset iddfile
	call    oopen
	jz	cmsaveidd_eropen
	mov	cx,10
	mov	ax,offset Resource
	call	owrite
	jz	cmsaveidd_erwrite
	call	circxchg
	push	di

	xor	bx,bx
	call	rcsprc
	mov	cx,80*25
	;mov	ax,_scrseg
	;mov	es,ax
	mov	es,dx
	mov	di,ax
	inc	di
	push	di
	;mov	di,1
	call	compressidd
	;xor	di,di
	pop	di
	dec	di
	mov	cx,80*25
	call	compressidd
	pop	di
	call	oflush		; flush STDO
	call	oclose
	call	circxchg
	call	exitmsg		; print exit status
	ret
    cmsaveidd_erwrite:
	call	oclose
	mov	ax,offset iddfile
	call	remove
    cmsaveidd_eropen:
	mov	ax,offset iddfile
	call	eropen
	ret
cmsaveidd ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ID_COUNT 	= 2
KEY_ALTF5	= 6C00h

modal	PROC
	push	si
	push	di
	xor	si,si
    modal_event:
	call	ciputsection
	cmp	si,ID_COUNT
	jb	modal_xy
	mov	si,ID_COUNT-1
    modal_xy:
	mov	ax,offset bmpfile
	mov	cx,WMAXPATH
	mov	bx,ciscr_w
	add	bx,0107h
	or	si,si
	jz	modal_edit
	inc	bh
	mov	ax,offset iddfile
    modal_edit:
  if USE_CLIPBOARD
	or	cx,8000h
  endif
	mov	dl,40
	call	tdedit
	mov	di,ax
  if USE_TSRKEYBOARD
	cmp	ax,TSR_KEY
	jne	modal_key
    modal_05:
	mov	ax,word ptr cur_keyscan
	cmp	ax,word ptr tsr_keyscan
	je	modal_05
	mov	ax,TSR_KEY
  endif
    modal_key:
	xor	bx,bx
	mov	cx,numlabels
    modal_nextkey:
	cmp	ax,cishkeys[bx]
	je	modal_found
	add	bx,2
	dec	cx
	jnz	modal_nextkey
	jmp	modal_event
    modal_found:
	jmp	cilabels[bx]
    modal_end:
	pop	di
	pop	si
	ret
    case_help:
	call	cihelp
	jmp	modal_event
    case_dn:
	inc	si
	cmp	si,ID_COUNT
	jnb	case_home
	jmp	modal_event
    case_home:
	xor	si,si
	jmp	modal_event
    case_end:
	mov	si,ID_COUNT-1
	jmp	modal_event
    case_up:
	or	si,si
	jz	case_end
	dec	si
	jmp	modal_event
    case_enter:
	or	si,si
	jz	case_bmp
	call	cmsaveidd
	jmp	modal_event
    case_bmp:
	call	cmsavebmp
	jmp	modal_event
    case_userscreen:
	call	circxchg
	call	tgetevent
	call	circxchg
	jmp	modal_event
    case_dlgright:
	cmp	ciscr_x,RC_MAXX
	je	case_dlg_end
	call	circxchg
	inc	ciscr_x
	call	circxchg
	jmp	modal_event
    case_dlgup:
	cmp	ciscr_y,0
	je	case_dlg_end
	call	circxchg
	dec     ciscr_y
	call	circxchg
    case_dlg_end:
	jmp	modal_event
    case_dlgdn:
	cmp	ciscr_y,RC_MAXY
	je	case_dlg_end
	call	circxchg
	inc	ciscr_y
	call	circxchg
	jmp	modal_event
    case_dlgleft:
	cmp	ciscr_x,0
	je	case_dlg_end
	call	circxchg
	dec     ciscr_x
	call	circxchg
	jmp	modal_event
cishkeys label word
	dw	KEY_ESC
	dw	KEY_DOWN
	dw	KEY_UP
	dw	KEY_ENTER
	dw	KEY_KPENTER
	dw	KEY_F1
	dw	KEY_ALTX
	dw	KEY_ALTF5
	dw	KEY_CTRLB
	dw	KEY_ALTUP
	dw	KEY_ALTDN
	dw	KEY_ALTLEFT
	dw	KEY_ALTRIGHT
cilabels label word
	dw	modal_end
	dw	case_dn
	dw	case_up
	dw	case_enter
	dw	case_enter
	dw	case_help
	dw	modal_end
	dw	case_userscreen
	dw	case_userscreen
	dw	case_dlgup
	dw	case_dlgdn
	dw	case_dlgleft
	dw	case_dlgright
numlabels = ((offset cilabels - offset cishkeys) / 2)
modal	ENDP

tsrmain PROC
	pusha
	call	mouseoff
	call	initscrseg
	call	circxchg
	call	cursoron
	call	modal
	call	circxchg
	call	mouseon
	popa
	ret
tsrmain ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

tsr_endcode label byte

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Note: these functions is not loaded into memory..
;
oputs	PROC
	push	si
	mov	si,ax
    oputs_put:
	mov	al,[si]
	or	al,al
	jz	oputs_end
	call	oputc
	jz	oputs_eof
	inc	si
	jmp	oputs_put
    oputs_end:
	inc	ax
    oputs_eof:
	pop	si
	ret
oputs	ENDP

ogetc	PROC
	mov	ax,STDI.ios_i
	cmp	ax,STDI.ios_c
	je	ogetc_read
    ogetc_do:
	inc	STDI.ios_i
	mov	bx,STDI.ios_bp
	add	bx,ax
	inc	ax
	mov	ah,0
	mov	al,[bx]
	ret
    ogetc_read:
	push	cx
	push	dx
	call	ofread
	pop	dx
	pop	cx
	mov	ax,STDI.ios_i
	jnz	ogetc_do
	mov	ax,-1
	ret
ogetc	ENDP

ogetl	PROC
	call	ogetc
	jz	ogetl_eof
	cmp	al,0Ah
	jne	ogetl
	inc	ax
    ogetl_eof:
	ret
ogetl ENDP

iopen	PROC
	mov	cx,_A_NORMAL
  ifdef USE_DOS40EXOPEN
	mov	dx,A_OPEN
	mov	bx,M_RDONLY
	call	osopen
  else
	mov	dx,ax
	mov	ax,3D00h	; DOS 2+ - OPEN EXISTING FILE
	int	21h
  endif
	mov	STDI.ios_file,ax
	jc	iopen_error
	xor	ax,ax
	mov	STDI.ios_c,ax
	mov	STDI.ios_i,ax
	inc	ax
	ret
    iopen_error:
	xor	ax,ax
	ret
iopen	ENDP

iclose	PROC
	mov	bx,STDI.ios_file
	mov	ah,3Eh
	int	21h
	xor	ax,ax
	ret
iclose	ENDP

strtrim	PROC
	push	di
	mov	di,ax
	call	strlen
	mov	dx,ax
	or	ax,ax
	jz	strtrim_02
	mov	cx,di
	add	di,ax
	dec	di
	mov	ax,' '
    strtrim_00:
	cmp	[di],al
	ja	strtrim_01
	mov	[di],ah
	dec	di
	cmp	di,cx
	jnb	strtrim_00
    strtrim_01:
	mov	ax,di
	sub	ax,cx
	inc	ax
    strtrim_02:
	pop	di
	ret
strtrim	ENDP

inientry PROC
	push	si
	push	di
	push	bp
	mov	si,ax
	mov	bp,dx
    inientry_do:
	call	ogetc
	jz	inientry_eof
	cmp	al,'['
	jne	inientry_line
	mov	di,si
	jmp	inientry_cmpc
    inientry_line:
	call	ogetl
	jz	inientry_eof
	jmp	inientry_do
    inientry_cmpc:
	call	ogetc
	jz	inientry_eof
	mov	ah,[di]
	inc	di
	or	ax,2020h
	cmp	ah,al
	je	inientry_cmpc
	cmp	ax,207Dh
	jne	inientry_line
    inientry_nextline:
	call	ogetl
	jz	inientry_eof
    inientry_entry:
	call	ogetc
	jz	inientry_eof
	cmp	al,' '
	je	inientry_entry
	cmp	al,9
	je	inientry_entry
	cmp	al,'['
	je	inientry_eof
	mov	di,bp
	jmp	inientry_testentry
    inientry_eof:
	call	iclose
	jmp	inientry_fail
    inientry_loop:
	call	ogetc
	jz	inientry_eof
    inientry_testentry:
	mov	ah,[di]
	inc	di
	or	ah,ah   	; match if entry name is zero
	jz	inientry_found
	or	ax,2020h
	cmp	ah,al
	je	inientry_loop
	jmp	inientry_nextline
    inientry_found:
	cmp	al,'='
	je	inientry_equal
    inientry_sign:
	call	ogetc
	jz	inientry_eof
	jmp	inientry_found
    inientry_equal:
	call	ofread
	jz	inientry_eof
	call	iclose
	mov	si,STDI.ios_bp
	mov	di,si
	cld
    inientry_start:
	lodsb
	inc	di
	cmp	al,' '
	je	inientry_start
	cmp	al,9
	je	inientry_start
	dec	si
	dec	di
	mov	cx,STDI.ios_c
	inc	cx
	cmp	cx,LSIZE
	jb	inientry_parse
	mov	cx,LSIZE
    inientry_parse:
	lodsb
	cmp	al,';'
	je	inientry_done
	cmp	al,0Dh
	je	inientry_done
	dec	cx
	jnz	inientry_parse
    inientry_done:
	xor	ax,ax
	mov	[si-1],al
	cmp	al,[di]
	je	inientry_fail
	mov	ax,di
	call	strtrim
	or	ax,ax
	jz	inientry_fail
	mov	ax,di
	jmp	inientry_ret
    inientry_fail:
	xor	ax,ax
    inientry_ret:
	pop	bp
	pop	di
	pop	si
	ret
inientry ENDP

getdrv	PROC
	mov	ah,19h
	int	21h
	mov	ah,0
	ret
getdrv	ENDP

getcwdd	PROC
	push	si
	mov	si,ax
	mov	ah,47h
	int	21h
	mov	ax,0
	jc	getcwdd_end
	mov	ax,si
    getcwdd_end:
	or	ax,ax
	pop	si
	ret
getcwdd	ENDP

fullpath PROC
	push	si
	push	di
	mov	si,ax
	mov	di,dx
	add	ax,3
	call	getcwdd
	or	ax,ax
	jz	fullpath_end
	mov	ax,di
	or	ax,ax
	jz	fullpath_get
	add	al,'@'
	jmp	fullpath_drv
    fullpath_get:
	call	getdrv
	add	al,'A'
    fullpath_drv:
	mov	ah,':'
	mov	[si],ax
	mov	al,'\'
	mov	[si+2],al
	mov	ax,si
    fullpath_end:
	pop	di
	pop	si
	ret
fullpath ENDP

getfattr PROC
	mov	dx,ax
	mov	ax,_ifsmgr
	or	ax,ax
	mov	ax,4300h
	jz	getfattr_21h
	stc
	mov	ax,7143h
	mov	bl,0
    getfattr_21h:
	int	21h
	jc	getfattr_err
	mov	ax,cx
    getfattr_end:
	ret
    getfattr_err:
	mov	ax,-1
	jmp	getfattr_end
getfattr ENDP

strcat	PROC
	push	si
	push	di
	push	ds
	pop	es
	cld
	mov	di,ax
	mov	si,dx
	mov	dx,ax
	xor	al,al
	mov	cx,-1
	repne	scasb
	dec	di
    cpy_loop:
	lodsb
	stosb
	or	al,al
	jnz	cpy_loop
	mov	ax,dx
	pop	di
	pop	si
	ret
strcat	ENDP

strfcat	PROC
	push	si
	push	di
	mov	di,ax
	mov	si,cx
	or	dx,dx
	jz	strfcat_00
	call	strcpy
    strfcat_00:
	call	strlen
	or	ax,ax
	mov	dx,di
	jz	strfcat_01
	dec	ax
	add	di,ax
	mov	ax,'\'
	cmp	al,[di]
	je	strfcat_01
	inc	di
	mov	[di],ax
    strfcat_01:
	mov	ax,dx
	mov	dx,si
	call	strcat
	pop	di
	pop	si
	ret
strfcat	ENDP

setext	PROC
	push	si
	push	di
	mov	di,dx	; DX: offset ext
	mov	si,ax   ; AX: offset file name
	call	strfn
	mov	dl,'.'
	call	strrchr
	jz	setext_cat
	xchg	ax,di
	mov	BYTE PTR [di],0
	mov	di,ax
    setext_cat:
	mov	ax,si
	mov	dx,di
	call	strcat
	pop	di
	pop	si
	ret
setext	ENDP

strfn	PROC
	push	ax
	mov	dx,'/\'
	call	strrcxr
	pop	dx
	jz	strfn_01
	inc	ax
    strfn_00:
	ret
    strfn_01:
	mov	ax,dx
	jmp	strfn_00
strfn	ENDP

strrchr	PROC
	xor	dh,0
strrchr	ENDP

strrcxr PROC
	push	si
	push	di
	mov	si,ax
	xor	di,di
	cld
    strrchr_lod:
	lodsb
	or	al,al
	jz	strrchr_end
	cmp	al,dh
	je	strrchr_set
	cmp	al,dl
	jne	strrchr_lod
    strrchr_set:
	mov	di,si
	dec	di
	jmp	strrchr_lod
    strrchr_end:
	mov	ax,di
	or	ax,ax
	pop	di
	pop	si
	ret
strrcxr ENDP

envlen	dw	0
argv0	dd	0
argc	dw	0
argv	dw	0
	db	13,10

around	PROC
	call	startup
	db	'DOSBMP Version 2.04 Copyright (c) 1997-2010 Hjort Nidudsson'
	db	13,10
	db	13,10,'$'
around	ENDP

startup	PROC
	pop	dx
	mov	ah,9
	int	21h
	push	offset _abort
	xor	si,si
	mov	dx,ds
	mov  	[si+tsr_psp],dx
	mov  	bp,[si+psp_memseg]
	sub	bp,dx
	mov	es,[si+psp_environ]
	xor	ax,ax
	mov	argc,ax
	mov	bx,ax
	mov	di,ax
	mov	cx,7FFFh
	cld
    startup_envloop:
	repne	scasb
	inc	bx
	cmp	es:[di],al
	je	startup_envlend
	or	cx,cx
	jnz	startup_envloop
    startup_fail:
	ret
    startup_envlend:
	or	ch,80h
	neg     cx
	mov   	envlen,cx
	mov	di,stklen
	add	di,offset tsr_endcode
	jb	startup_fail
	shr	di,4
	inc	di
	cmp	bp,di
	jb	startup_fail
	mov	ah,34h
	int	21h
	mov	word ptr tsr_dosbusy,bx
	mov	word ptr tsr_dosbusy+2,es
	mov	ah,52h
	int	21h
	mov	word ptr tsr_doslist+2,es
	mov	word ptr tsr_doslist,bx
	sub	bx,2
	mov	ax,es:[bx]
	mov	tsr_mcbseg,ax
	mov	ah,2Fh
	int	21h
	mov	tsr_context.off_dta,bx
	mov	tsr_context.seg_dta,es
	mov     tsr_context.off_stack,di
	mov	ax,ds
	mov	es,ax
	mov     tsr_context.seg_stack,ax
	mov     tsr_context.seg_psp,ax
	mov	tsr_context.seg_VECTOR_1B,ax
	mov	tsr_context.seg_VECTOR_23,ax
	mov	tsr_context.seg_VECTOR_24,ax
	mov	tsr_context.off_VECTOR_1B,offset NEWVECTOR_1B
	mov	tsr_context.off_VECTOR_23,offset NEWVECTOR_1B
	mov	tsr_context.off_VECTOR_24,offset NEWVECTOR_24
	mov	ax,[si+psp_environ]
	mov	word ptr argv0+2,ax
	mov	ax,envlen
	inc	ax
	inc	ax
	mov	word ptr argv0,ax
	push	offset terminate
	jmp	main
startup ENDP

cp_startup label byte
	db	'DOSBMP installed',13,10
	db	'Press <Hotkey> to activate',13,10,'$'

_exit	PROC
	pop	dx
	push	ax
	mov	ah,9
	int	21h
	pop	ax
_exit	ENDP

terminate PROC
	mov     ah,4Ch
	int     21h
terminate ENDP

_abort	PROC
	mov	al,3
	call	_exit
	db	'Abnormal program termination',13,10,'$'
_abort	ENDP

load_tsr PROC
	call	tsr_resident
	or	ax,ax
	jz	load_tsr_do
	mov	al,1
	call	_exit
	db	'DOSBMP is already installed',13,10,'$'
    load_tsr_do:
	mov	dx,offset cp_startup
	mov	ah,9
	int	21h
	mov	ax,3508h
	int	21h
	mov	WORD PTR OLDVECTOR_08,bx
	mov	WORD PTR OLDVECTOR_08+2,es
	mov	ax,3509h
	int	21h
	mov	WORD PTR OLDVECTOR_09,bx
	mov	WORD PTR OLDVECTOR_09+2,es
	mov	ax,3528h
	int	21h
	mov	WORD PTR OLDVECTOR_28,bx
	mov	WORD PTR OLDVECTOR_28+2,es
	mov	ax,3513h
	int	21h
	mov	WORD PTR OLDVECTOR_13,bx
	mov	WORD PTR OLDVECTOR_13+2,es
	mov	dx,offset NEWVECTOR_13
	mov	ax,2513h
	int	21h
	mov	dx,offset NEWVECTOR_28
	mov	ax,2528h
	int	21h
	mov	dx,offset NEWVECTOR_09
	mov	ax,2509h
	int	21h
	mov	dx,offset NEWVECTOR_08
	mov	ax,2508h
	int	21h
	mov	cx,4
	mov	ax,offset tsr_endcode
	add	ax,stklen
	shr	ax,cl
	inc	ax
	shl	ax,cl
	mov     tsr_context.off_stack,ax
	shr	ax,4
	mov	dx,ax
	mov	ax,3100h
	int	21h
load_tsr ENDP

tsr_resident PROC
	mov	ax,tsr_mcbseg
	mov	es,ax
	xor	ax,ax
	mov	bx,ax
    tsr_resident_00:
	cmp	es:[bx.S_MCB.mcb_flag],'M'
	jne	tsr_resident_02
	mov	dx,es
	mov	es,es:[bx.S_MCB.mcb_owner]
	mov	ax,es:[0]
	mov	es,dx
	cmp	ax,20CDh
	jne	tsr_resident_01
	mov	ax,es:[bx.S_MCB.mcb_owner]
	cmp	ax,ds:[tsr_psp]	; the transient copy
	je	tsr_resident_01
	mov	es,ax
	mov	si,offset tsr_signature
	mov	ax,es:[si]
	cmp	ax,ds:[si]
	jne	tsr_resident_01
	mov	ax,es:[si+2]
	cmp	ax,ds:[si+2]
	jne	tsr_resident_01
	mov	ax,1
	ret
    tsr_resident_01:
	mov	es,dx
	add	dx,es:[bx.S_MCB.mcb_size]
	inc	dx
	mov	es,dx
	jmp	tsr_resident_00
    tsr_resident_02:
	xor	ax,ax
	ret
tsr_resident ENDP

initargv PROC
	mov	cx,80
	mov	di,offset argv + 16
	mov	bx,offset argv
	mov	[bx],di
	lds	si,argv0
    initargv_file:
	lodsb
	or	al,al
	jz	initargv_file_end
	stosb
	dec	cx
	jnz	initargv_file
	dec	di
    initargv_file_end:
	mov	ax,es
	mov	ds,ax
	xor	ax,ax
	mov	dx,ax
	stosb
	mov	si,128
	lodsb
	or	al,al
	jz	initargv_end
	add	bx,2
	mov	[bx],di
	mov	cx,ax
	inc	si
    initargv_loop:
	lodsb
	or	al,al
	jz	initargv_end
	cmp	al,13
	je	initargv_end
	cmp	al,' '
	je	initargv_add
	stosb
    initargv_next:
	dec	cx
	jnz	initargv_loop
    initargv_end:
	xor	ax,ax
	stosb
	mov	ax,bx
	sub	ax,offset argv
	shr	ax,1
	mov	argc,ax
	ret
    initargv_add:
	xor	ax,ax
	stosb
	add	bx,2
	mov	[bx],di
	jmp	initargv_next
initargv ENDP

exitusage PROC
	mov	ax,1
	call	_exit
	db	'USAGE:', 9, 9, 'DOSBMP [options]',13,10
	db	13,10
	db	'/H,/?,?',9, 9,	'Display this help screen',13,10
	db	'/M', 9, 9,	'Assume mouse is on',13,10
	db	'/U', 9, 9,	'Remove DOSBMP from memory',13,10
	db	'/P<path>', 9,  'Output directory',13,10
	db	'/K<xxyy>', 9,	'Hotkey: xx=shift, yy=scan',13,10
	db	'$'
exitusage ENDP

atox	PROC
	push	si
	cld
	mov	si,ax
	lodsb
	sub	al,'0'
	cmp	al,9
	jng	atox_00
	sub	al,7
    atox_00:
	shl	al,4
	mov	ah,al
	lodsb
	sub	al,'0'
	cmp	al,9
	jng	atox_01
	sub	al,7
    atox_01:
	or	al,ah
	pop	si
	ret
atox	ENDP

initargs PROC
	mov	cx,argc
	xor	bx,bx
    initargs_loop:
	add	bx,2
	mov	si,[bx+argv]
	lodsb
	cmp	al,'?'
	je	initargs_usage
	cmp	al,'-'
	je	initargs_option
	cmp	al,'/'
	je	initargs_option
	jmp	initargs_usage
    initargs_next:
	dec	cx
	jnz	initargs_loop
    initargs_end:
	ret
    initargs_m:
	inc	__mouse
	inc	__mbool
	jmp	initargs_next
    initargs_option:
	lodsb
	or	al,20h
	cmp	al,'m'
	je	initargs_m
	cmp	al,'u'
	je	initargs_u
	cmp	al,'k'
	je	initargs_k
	cmp	al,'p'
	je	initargs_p
    initargs_usage:
	jmp	exitusage
    initargs_p:		; /P<path>	Output directory
	mov	dx,si
	mov	ax,offset iddfile
	call	strcpy
	mov	dx,ax
	mov	ax,offset bmpfile
	call	strcpy
	jmp	initargs_next
    initargs_k:		; /K<xxyy>	Hotkey: xx=shift, yy=scan
	mov	ax,si
	call	atox
	mov	tsr_keyshift,al
	mov	ax,si
	add	ax,2
	call	atox
	mov	tsr_keyscan,al
	jmp	initargs_next
    initargs_u:		; /U		Remove DOSBMP from memory
	call	tsr_resident
	or	ax,ax
	jz	initargs_notinstalled
	mov	ax,es
	mov	ds,ax
	call	tsr_unload
	mov	dx,cs
	mov	ds,dx
	or	ax,ax
	jz	initargs_notinstalled
	inc	ax
	jnz	initargs_isremoved
	jmp	_abort
    initargs_notinstalled:
	mov	al,0
	call	_exit
	db	'DOSBMP is not installed',13,10,'$'
    initargs_isremoved:
	mov	al,0
	call	_exit
	db	'DOSBMP is removed from memory',13,10,'$'
initargs ENDP

cfgfile	db	'[default]',13,10
	db	'; -xx- key shift  01h - Right Shift',13,10
	db	'; -yy- key scan   2Ah - Left Shift',13,10
	db	'xxyy=012A',13,10
	db	'mice=1',13,10
	db	'; Use current directory',13,10
	db	'iddd=; Output directory for IDD files',13,10
	db	'bmpd=; Output directory for BMP files',13,10
	db	'[',0
dosbmp	db	'dosbmp'
extini	db	'.ini',0
default	db	'default',0
ci_xxyy	db	'xxyy',0
ci_bmpd	db	'bmpd',0
ci_iddd	db	'iddd',0
ci_mice	db	'mice',0

initcfg	PROC
	mov	ax,argv
	call	strfn
	mov	dx,offset dosbmp
	call	strcpy
	mov	ax,argv
	call	getfattr
	inc	ax
	jnz	initcfg_end
	mov	ax,argv
	call	oopen
	jz	initcfg_end
	mov	ax,offset cfgfile
	call	oputs
	call	oflush
	call	oclose
    initcfg_end:
	ret
initcfg	ENDP

getdefault PROC
	mov	ax,argv
	call	iopen
	jz	getdefault_end
	mov	ax,offset default
	mov	dx,si
	call	inientry
	jz	getdefault_end
	mov	dx,ax
	mov	ax,di
	call	strcpy
    getdefault_end:
	ret
getdefault ENDP

setdefault PROC
	push	si
	push	di
	mov	si,offset ci_xxyy
	mov	di,offset linebuf
	call	getdefault
	xor	ax,ax
	cmp	[di],al
	je	setdefault_list
	mov	ax,di
	call	atox
	mov	tsr_keyshift,al
	mov	ax,di
	add	ax,2
	call	atox
	mov	tsr_keyscan,al
    setdefault_list:
	add	si,5
	mov	di,offset bmpfile
	call	getdefault
	add	si,5
	mov	di,offset iddfile
	call	getdefault
	add	si,5
	mov	di,offset linebuf
	call	getdefault
	cmp	linebuf,'1'
	jne	setdefault_end
	inc	__mouse
    setdefault_end:
	pop	di
	pop	si
	ret
setdefault ENDP

default_idd db 'default.idd',0
default_bmp db 'default.bmp',0

main	PROC
	call	initargv
	mov	si,ax
	call	dosinit
	call	initcfg
	call	setdefault
	or	si,si
	jz	main_initfile
	call	initargs
    main_initfile:
	cmp	bmpfile,0
	jne	main_iddfile
	mov	ax,offset bmpfile
	xor	dx,dx
	call	fullpath
    main_iddfile:
	cmp	iddfile,0
	jne	main_default
	mov	ax,offset iddfile
	xor	dx,dx
	call	fullpath
    main_default:
	mov	ax,offset bmpfile
	xor	dx,dx
	mov	cx,offset default_bmp
	call	strfcat
	mov	ax,offset iddfile
	xor	dx,dx
	mov	cx,offset default_idd
	call	strfcat
  ifdef DEBUG_TSRMAIN
	call	tsrmain
  else
	call	load_tsr
  endif
	ret
main	ENDP

end_dataseg label byte

	END	start
