;
; GRDP
;
; Copyright(c) LADsoft
;
; David Lindauer, camille@bluegrass.net
;
;
; HISTORY.ASM
;
; Function: Handle command line history
;
	;MASM MODE
	.MODEL SMALL
	.386
HISTSIZE EQU 1024	; MUST be longer than longest command line!!!!
			; but shorter than 32K

include	eprints.inc 
include	einput.inc 
include	emtrap.inc 
include	ebreaks.inc 
include	eloader.inc
include	edos.inc
include	eoptions.inc
include	eexec.inc
include	ememory.inc
include	elogging.inc

	PUBLIC CheckHistory, EnterHistory, LoadHistory, histoff,histon
	.data
oldhistory	db	0	;to keep track of when history opt changes
		db	0	; safety net for pushing value
histlen		dw	0	;length of history segment
histseg 	dw	0	;history segment itself
histpos 	dw	0	;position in history segment
nonext		db	0	; flag to not do first find next after new
				; command entered
	.code
histonm		db	13,10,"History enabled",0
histoffm		db	13,10,"History disabled",0
histerrm		db	13,10,"No mem for history",0
histmsg 	db	" (History access)",0
;
; turn history off temporarily
;
histoff proc
	mov	ax,word ptr [oldhistory]
	xchg	ax,[esp]
	mov	[oldhistory],0
	jmp	ax
histoff endp
;
; turn history back on
;
histon	proc
	pop	ax
	pop	word ptr [oldhistory]
	jmp	ax
histon	endp
	
; log that we are doing a history access
;
CommandToLog PROC
	push	di			; save hist buffer index
	sub	si,offset inputbuffer	; get length of input
	mov	cx,si 			; this many backspaces
	jcxz	nobkspc
clrlp:
	mov	ah,2			; we are bypassing the logger
					; for this, in a moment we will
					; log a message saying we did this
	mov 	dl,8
	int	21h			;
	mov 	dl,' '
	int	21h			;
	mov 	dl,8
	int	21h			;
	loop	clrlp			;
nobkspc:
	mov	bx,offset histmsg	; now log a message saying we
cllp:					; did this
	mov	al,cs:[bx]
	or	al,al
	jz	clnd
	inc	bx
	call	LogToFile
	jmp	cllp
clnd:
	pop	si			; retreive hist buffer index
	push	si
cllp2:
	lods	byte ptr es:[si]	; play out the new string
	or	al,al
	jz	clnd2
	mov	dl,al
	call	PutChar
	jmp	cllp2
clnd2:
	pop	di
	ret
CommandToLog ENDP
;
; go back one history line
;
findprev proc
	mov	di,[histpos]	; start here
	or	di,di		; check if here is beginning
	jnz	prevnowrap
	add	di,[histlen]	; yes,start at end

prevnowrap:
	dec	di		; point back one char
	or	di,di
	jle	zerprev		; get out if past zero
	test	byte ptr es:[di-1],0ffh	; check for null terminator
	jnz	prevnowrap	; loop if not
	mov	[histpos],di	; else exit with pointer
	ret

zerprev:
	sub	di,di		; zero pointer
	mov	[histpos],di
	ret
findprev endp
;
; go forward one history line
;
findnext proc
	mov	di,[histpos]	; start here
	test	[nonext],1
	jnz	nofindnext
fnlp:
	inc	di		; inc di
	cmp	di,[histlen]	; see if past end
	jae	zernext		; yes, zero
	test	byte ptr es:[di-1],0ffh	; no, test for null term
	jnz	fnlp        	; loop until found
	mov	[histpos],di	; exit with pointer
	ret
zernext:
	sub	di,di       	;
	mov	[histpos],di
	ret
nofindnext:
	mov	[nonext],0
	ret
findnext endp
;
; compare two strings
;
compare1 proc
	jcxz	matches
	push	cx
	push	si
	push	di
	repe	cmpsb
	pop	di
	pop	si
	pop	cx
	ret
matches:
	sub	ax,ax
	ret
compare1 endp
;
; search to see if in history list
;
search1	proc
	push	es
	mov	es,[histseg]
	sub	di,di
	mov	[histpos],di
lp:
	call	stringsize
	mov	cx,ax
	dec	cx
	push	si
	call	compare1
	pop	si
	jz	founds
	call	findnext
	or	di,di
	jnz	lp
	pop	es
	stc
	ret
founds:
	pop	es
	clc
	ret
search1	endp
;
; find the size of a string, including null terminator
;
stringsize proc
	push	di
	push	cx
	mov	cx,-1
	sub	al,al
	repne	scasb
	not	cx
	mov	ax,cx
	pop	cx
	pop	di
	ret
stringsize endp
;
; string copy back to main buffer
;
copystring proc
	lodsb
	or	al,al
	jz	csend
	stosb
	jmp	copystring
csend:
	ret
copystring endp


CheckHistory PROC
	push	di
	push	si
	push	es
	test	[oldhistory],1	;history on?
	jz	okcheck
	test	[histlen],-1	; anything in history buf?
	jz	okcheck
	mov	cx,si		; calculate length of input
	sub	cx,di
	mov	si,di
	cmp	ax,3d00h	; F3 key
	jz	dof3
	cmp	ax,5000h	; down arrow
	jz	up
	cmp	ax,4800h	; up arrow
	clc
	jnz	okcheck
down:
	mov	es,[histseg]	; down arr, load stuf
	mov	di,[histpos]
	call	findprev	; back one
	jmp	found
dof3:
	mov	es,[histseg]
	sub	di,di   	; F3, just go to last item
	mov	[histpos],di
	call	findprev
	jmp	found
up:
	mov	es,[histseg]	; up arr, load stuff
	mov	di,[histpos]
	call	findnext	; forward one
	jmp	found
found:
	call	CommandToLog	; output the command
	pop	es		; found, swap seg regs
	push	es
	push	ds
	mov	ds,[histseg]
	mov	si,di           	; put string in input buffer
	mov	di,offset inputbuffer
	call	copystring
	pop	ds
	pop	es
	pop	si
	add	sp,2
	stc
	ret
nokcheck:
	stc
okcheck:
	pop	es
	pop	si
	pop	di
	ret

CheckHistory ENDP

;
; add a new line to the history segment
;
EnterHistory PROC
	test	[oldhistory],1		; history on ?
	jz	noenter
	mov	cx,di			; yes, any chars besides CR?
	sub	cx,si
	cmp	cx,1
	jbe	noenter			; no, get out
	push	di     			; is in hist list?
	push	cx
	push	[histpos]
	call	search1
	pop	[histpos]
	pop	cx
	pop	di
	jnc	noenter			; yes, don't put again
	push	es
	push	si
	mov	es,[histseg]		; ES = hist segment
ehsl:
	sub	di,di			; di = pointer to first string
	mov	ax,HISTSIZE		; See if enough room for new string
	sub	ax,[histlen]
	sub	ax,cx
	jnc	enoughroom		; yes, go insert new string
	push	cx			; no, get size of first string
	call	stringsize
	mov	cx,HISTSIZE		; count to move = seg size - string size
	sub	cx,ax
	mov	si,di
	add	si,ax			; SI = second string
	push	ds
	mov	ds,[histseg]
	rep	movsb			; cancel out first string
	pop	ds
	sub	[histlen],ax
	pop	cx
	jmp	ehsl			; loop
enoughroom:
	mov	di,[histlen]		; add new length to hist seg
	pop	si
	push	si
	push	di
	add	[histlen],cx
	rep	movsb       		; concat new string
	mov	byte ptr es:[di-1],0	; null terminator
	pop	di
	pop	si
	pop	es
	mov	[histpos],0		; pos = 0...
noenter:
	ret
EnterHistory ENDP
;
; turn history on or off
;
LoadHistory PROC
	sub	ah,ah
	mov	al,[opthist]  		; see if history flag changed
	cmp	al,[oldhistory]
	jz	nochange		; get out if not
	call	KillFiles		; else clear mem state to allow
	call	ReleaseMemory		; the change
	test	[opthist],0ffh		; turning on?
	jnz	doload			; yes, turn on
	push	es
	mov	es,[histseg]		; else unload history seg
	mov	ah,49h
	int	21h
	mov	[oldhistory],0		; flag off
	pop	es
	mov	bx,offset histoffm	; history off message
	jmp	reload
doload:
	mov	bx,HISTSIZE SHR 4	; load history seg
	mov	ax,4800h
	int	21h
	mov	bx, offset histerrm
	mov	[opthist],0		; assume it didn't succeed
	jc	reload
	mov	[oldhistory],1		; turn on history
	mov	[opthist],1
	mov	[histseg],ax		; init the vars
	mov	[histlen],0
	mov	[histpos],0
	mov	[nonext],1
	mov	bx, offset histonm	; history on message
reload:
	call	olMessage
	mov	si,offset grdbname	; reload empty program
	call	MakeEmptyProg
	sub	ax,ax
	test	[loadfile],0ffh
	jz	nochange
	call	LoadProgram		; reload user program
	lahf
nochange:
	ret
LoadHistory ENDP

end