Metropoli BBS
VIEWER: e32.asm MODE: TEXT (ASCII)
; E32.ASM - Copyright (C) 1993, 1994 Douglas Herr
;  all rights reserved

;
; This is the main E32 source file
;

include	model.inc

public	main32

extrn	getcmd:near, mload:near, keyifwaiting:near
extrn	strchr:near, cursoron:near, qfname:near
extrn	insert:near
extrn	tprintce:near
extrn	ucursoron:near
extrn	htext:near

extrn	showfkey:near
extrn	display_screen:near
extrn	topline:near, showpos:near
extrn	get_screen_data:near
extrn	insert_key:near
extrn	readfile:near

extrn	isalpha:near, isdigit:near

extrn	undo:near, print:near, mark:near, cut:near
extrn	paste:near, save:near, del_eol:near, del_l:near, udel_l:near
extrn	new:near, screen_rows:near, ffeed:near, copy:near, dosshell:near
extrn	upcase:near, load:near, screen_columns:near, locase:near, search:near
extrn	home:near, up:near, pgup:near, left:near, right:near
extrn	endd:near, down:near, pgdn:near, cursoron:near, del_char:near
extrn	del_eol:near, bottom:near, top:near, goto:near
extrn	window_mode:near, switch:near, swapmode:near, search_again:near
extrn	pushpos:near, poppos:near, replace:near, merge:near, setup:near

extrn	yesno_message:near
extrn	working:near
extrn	swap_files:near

;extrn	breakrelease:near
public	x0

includelib	..\asm32cw.lib

include	dataseg.inc

breakflag	db 0
public	breakflag

public	cursor, top_of_screen, filesel, filesiz, buffersiz
public	cur_posn, file_row, filename, first_row, mouse_on
public	normal, inverse, warning, key_status, insert_mode
public	columns, rows, dirty_bits, left_margin
public	screen_addr, screen_data_size, screen2_data
public	save_column, count_bytes, count_start, save_row
public	undo_buffer, undo_length
public	push_mode, push_offset
public	int24h_msg, verify_msg, extended_key, no_file_name

public	mark_mode, mark_start, mark_end, mark_home, nul
public	file_data_ptr, file_data_len, number_of_files
public	display_mode

extrn	window_row:byte
extrn	swapmode_prompt:byte

programmer	db 0Dh,0Ah,0Dh,0Ah,' E32.EXE version 1.32',0Dh,0Ah
		db ' Copyright (C) 1995 Douglas Herr',0Dh,0Ah,'$'
exit_mess	db ' Quit E32 (Y/N)?',0
verify_mess	db ' Lose changes (Y/N)?',0
no_file_name	db '<no file name>',0

; default colors used by GET_SCREEN_DATA
public	default_normal
default_normal	db 17h
default_inverse	db 70h
default_warning	db 0Ch

columns		dw 0
rows		dw 0
screen_addr	dd ?
normal		db 23
inverse		db 70h
warning		db 0Ch
screen_data_size	equ	$-columns

mouse_on	db 0
key_status	db 0FFh
insert_mode	db ?

undo_buffer	dd ?
undo_length	dd 0
paste_buffer	dd 0		; near pointer to paste buffer
valid_keys	db 59,60,61,62,63
		db 64,65,66,67,68

		db 104,105,106,107,108
		db 109,110,111,112,113

		db 71,72,73,75,77
		db 79,80,81,82,83

		db 115,116,117,118,132
		db 99,100,101,102,103

		db 84,97,98,93,90
nul		dw 0,0

dispatch_table  dd quit, offset undo, offset print, offset mark
		dd offset cut, offset paste, offset save
		dd offset del_eol, offset del_l, offset udel_l

		dd new, screen_rows, ffeed, copy, dosshell
		dd upcase, load, screen_columns, locase, search
		dd home, up, pgup, left, right
		dd endd, down, pgdn, cursoron, del_char

		dd word_left, word_right, del_eol, bottom, top
		dd window_mode,switch, swapmode, goto, search_again

		dd setup, pushpos, poppos, replace, merge

drive_error	db 'Drive not ready:  retry? (Y/N)',0
verify_msg	db 'Lose changes?',0
int24h_msg	dd offset @curseg:drive_error
		dd critical_exit
sptr		dd 0		; storage for stack ptr at read_next_key
sseg		dw 0

file_data_ptr	dd filename
filename	dd 0FFFFFFFFh	; pointer to current filename
filesel		dw 0FFFFh	; selector of file buffer
filesiz		dd 0		; size of file
buffersiz	dd 0		; size of file buffer
cursor		dd 0
top_of_screen	dd 0
left_margin	dw 0
file_row	dd 1
push_offset	dd 0
push_mode	db 0		; push status

save_column	db 0
save_row	db 0
dirty_bits	db 0
cur_posn	dw 0100h
mark_mode	db 0
mark_start	dd 0
mark_end	dd 0
mark_home	dd 0

count_rows	db 0
count_start	dd 0
count_bytes	dd 0
first_row	db 1		; leave space at top for filename, etc
display_mode	db 0		; assumes ASCII file
file_data_len	equ	$-filename
number_of_files	equ	4

file2data	label	byte
	dd 0FFFFFFFFh	; pointer to current filename
	dw 0FFFFh	; selector of file buffer
	dd 0		; size of file
	dd ?		; size of file buffer
	dd ?
	dd ?
	dw 0
	dd 1		; file_row
	dd 0
	db 0		; push status

	db ?
	db 0
	db ?
	dw 0100h
	db 0
	dd 0
	dd 0
	dd 0

	db 0
	dd 0
	dd 0
	db 1		; leave space at top for filename, etc
	db 0

file3data	label	byte
	dd 0FFFFFFFFh	; pointer to current filename
	dw 0FFFFh	; selector of file buffer
	dd 0		; size of file
	dd ?		; size of file buffer
	dd ?
	dd ?
	dw 0
	dd 1		; file_row
	dd 0
	db 0		; push status

	db ?
	db 0
	db ?
	dw 0100h
	db 0
	dd 0
	dd 0
	dd 0

	db 0
	dd 0
	dd 0
	db 1		; leave space at top for filename, etc
	db 0

file4data	label	byte
	dd 0FFFFFFFFh	; pointer to current filename
	dw 0FFFFh	; selector of file buffer
	dd 0		; size of file
	dd ?		; size of file buffer
	dd ?
	dd ?
	dw 0
	dd 1		; file_row
	dd 0
	db 0		; push status

	db ?
	db 0
	db ?
	dw 0100h
	db 0
	dd 0
	dd 0
	dd 0

	db 0
	dd 0
	dd 0
	db 1		; leave space at top for filename, etc
	db 0


screen2_data	label	dword
@curseg	ends

include	codeseg.inc
get_cmd_line:
	push	ebp
	xor	ebp,ebp

; initialize first file buffer
	xor	ebx,ebx
	call	swap_files

; get files on command line, last first
	mov	ecx,number_of_files
get0:	push	ecx
	mov	ebx,ecx
	dec	ebx		; offset format
	push	ebx		; save parameter number
	mov	eax,ebx		; copy to EAX for GETCMD
	call	getcmd
	jecxz	short get1	; skip if no parameter
	call	qfname
	mov	edi,filename
	push	ds
	pop	es
	cld
	rep	movsb
	mov	al,cl
	stosb

 	mov	edx,filename
	call	readfile
	inc	ebp
	jnc	short get1
	dec	ebp
	mov	edx,filename
	mov	byte ptr [edx],0
get1:
	pop	ebx
	call	swap_files
	pop	ecx
	loop	get0

	cmp	bp,2
	jbe	get2
	mov	byte ptr swapmode_prompt,'4'
get2:
	pop	ebp
	ret

;
; program starts here
;
main32:

; lock program code and data

	mov	bx,cs
	sys	GetSelDet32
	mov	esi,edx
	mov	ebx,ecx
	sys	LockMem32

	xor	eax,eax
	mov	cursor,eax
	mov	top_of_screen,eax
	or	dirty_bits,00100000b

	call	get_screen_data
	cli
	mov	sseg,ss
	mov	sptr,esp
	sti

; set INT 24h address
	mov	cx,cs
	lea	edx,int24h
	mov	bl,24h
	sys	SetVect

; turn insert key toggle on
	mov	ax,1
	call	insert

; get command line input
	call	get_cmd_line

; create undo buffer
	mov	ebx,128
	sys	GetMemNear
	mov	undo_buffer,esi
	jmp	short read_next_key

critical_exit:
	cli
	mov	ss,sseg
	mov	esp,sptr
	sti

read_next_key:
	call	showpos
	mov	fs,filesel
	cmp	mark_mode,0	; is the mark state on?
	je	short mark_off	; if not, skip this
	or	dirty_bits,4	; refresh the current row
	mov	dx,cur_posn
	cmp	save_row,dh	; are we on the same row?
	je	short same_row	; yup, redo the row only
	or	dirty_bits,1	; refresh the whole screen
	and	dirty_bits,(NOT 4)	; cancel refresh row request
same_row:
	mov	eax,cursor	; get cursor position
	mov	ebx,mark_home	; get the anchor mark position
	cmp	eax,ebx		; moving backward in file?
	ja	short s1	;  no: update mark_end & mark_start
	xchg	eax,ebx		; switch start and end position
s1:	mov	mark_end,eax	; store start and end marks
	mov	mark_start,ebx
mark_off:
	mov	dx,cur_posn
	mov	save_row,dh
	call	cursoron
	test	dirty_bits,4 or 1	; need screen update?
	jz	short check_shift_keys
	call	display_screen

check_shift_keys:
	call	capslock
	shr	mouse_on+1,1
	jnc	short s2
	jmp	read_next_key
s2:	call	keyifwaiting
	jnc	short process_key
	call	topline
	jmp	check_shift_keys

process_key:
; turn mouse cursor off if it is on
	shr	mouse_on,1
	jnc	short key0
	push	eax
	mov	ax,2
	int	33h
	pop	eax
key0:
	shr	ah,1
	jnc	short normal_key
	call	extended_key
	jc	short exit
	jmp	read_next_key

normal_key:
	cmp	al,08h			; backspace?
	jne	short normal1
	cmp	cursor,0		; start of file?
	je	read_next_key		;  yup, no backspace
	call	left
	call	del_char
	jmp	read_next_key
normal1:
	call	insert_key
	jmp	read_next_key
x0:
exit:
	lea	edx,programmer
	mov	ah,9
	int	21h
	mov	ax,4C00h
	int	21h

subroutines	proc	near

;
; process extended key code
;
extended_key:
	lea	ebx,valid_keys
	call	strchr
	jc	short bad_key
	push	ds
	pop	es
	shl	ax,2		; make the code an offset
	movzx	ebx,ax		; put offset in EBX
	jmp	dispatch_table[ebx]

bad_key:
	clc
	ret

;
; check status of CAPSLOCK, SHIFT, CTRL, ALT keys
;
capslock:
	mov	ax,0200h
	int	16h		; get key toggle status byte
	mov	ah,al
	and	ah,80h		; isolate INSERT status
	mov	insert_mode,ah

	cmp	key_status,al	; compare with previous and update
	mov	key_status,al	; ZF = 1 if no changes
	jnz	showfkey	; update prompt line if changed
	ret


;
; move cursor one word right
;
word_right:
;
; move to end of current word
; exit when non-AlphaNum character found
;
word_end_right:
	push	fs
	pop	es
	mov	esi,cursor
	cmp	esi,filesiz
	jae	short wer9
	movzx	ax,byte ptr es:[esi]
	call	isalphanumber
	jc	short wer9
	call	right
	jmp	word_end_right
wer9:


;
; skip spaces if starting from a space character
;
strip_space_right:
	push	fs
	pop	es
	mov	esi,cursor
	cmp	esi,filesiz
	jae	short ssr9
	movzx	ax,byte ptr es:[esi]
	call	isalphanumber
	jnc	short ssr9		; exit if Digit
	call	right			; go to previous character
	jmp	strip_space_right
ssr9:
	clc
	ret


;
; move cursor one word left
;
word_left:
;
; skip spaces if starting from a space character
;
strip_space_left:
	push	fs
	pop	es
	mov	esi,cursor
	test	esi,esi
	jz	short ssl9		; done if at start of file

	movzx	ax,byte ptr es:[esi-1]
	call	isalphanumber
	jnc	short ssl9		; exit if Digit
	call	left			; go to previous character
	jmp	strip_space_left
ssl9:

;
; go to start of current word
; scan off alpha and digit characters
; moving left
;
word_start_left:
	push	fs
	pop	es
	mov	esi,cursor
	test	esi,esi
	jz	short wsl9		; done if at start of file

	movzx	ax,byte ptr es:[esi-1]
	call	isalphanumber
	jc	short wsl9		; continue if digit
	call	left
	jmp	word_start_left
wsl9:
	clc
	ret

isalphanumber:
	call	isalpha
	jc	isdigit
	ret


;
; INT 24h management
;
int24h:
	sti				; Enable interrupts
	pushf				; Push flags
	pushad
	push	ds
	push	es
	mov	ax,_NEAR
	mov	ds,ax
	mov	es,ax
	mov	esi,int24h_msg
	mov	ah,warning
	call	yesno_message
	cmp	al,'Y'
	je	short int24exit
	jmp	int24h_msg+4

int24exit:
	call	working
	pop	es
	pop	ds
	popad
	popf				; Pop flags
	mov	al,1
	iretd				; Interrupt return

;
; exit E32, checking for unsaved changes
;
quit:
	push	dword ptr window_row
	mov	window_row,1
	mov	key_status,0FFh		; force redo of F-key prompts

; check hidden file data areas for unsaved files
q0:	mov	ecx,number_of_files
q1:	push	ecx

	mov	ebx,ecx
	dec	ebx
	jnz	short q1a		; skip if not last file
	mov	ebx,number_of_files	; else retrieve initial file
	dec	ebx
q1a:
	call	swap_files		; get file data
	test	dirty_bits,10000000b	; continue if not changed
	jz	short q2
	call	display_screen
	mov	ah,warning
	mov	esi,offset verify_mess
	call	yesno_message
	cmp	al,'Y'			; is the answer YES?
	je	short q2		; yup, check next file
	pop	ecx
	jmp	short dont_exit

q2:	pop	ecx
	loop	q1

	lea	esi,exit_mess		; prompt for 'EXIT'
	mov	ah,inverse
	call	yesno_message
	cmp	al,'Y'			; is the answer YES?
	jne	short dont_exit

	cmp	columns,90	; in RamFont mode?
	jne	short exit100
	call	htext
exit100:
	pop	dword ptr window_row

; clear last row
	mov	dh,byte ptr rows
	xor	dl,dl
	call	ucursoron
	inc	dh
	lea	esi,nul
	mov	ah,normal
	call	tprintce
	stc				; exit flag
	ret

dont_exit:
	pop	dword ptr window_row
	clc				; no exit flag
	ret

;
; PRINT_MSG
; print message at [ESI] on last row of screen
;

public	print_msg

print_msg:
	mov	ah,inverse
	mov	dh,byte ptr rows
	inc	dh
	xor	dl,dl
	call	tprintce
	ret

subroutines	endp

@curseg	ends
	end
[ RETURN TO DIRECTORY ]