; HISTORY.ASM
; (c) 1989, 1990 Ashok P. Nadkarni
;
; This module implements the history feature of the cmdedit program.
; DFA stopped lines of length less than min_length being stored on stack
; (December 1990).
; WD made history stack cyclic and allowed display of current history.
; jmh added application buffer to hist_type (March, 1997).
; Removed hist_fwd and hist_back - now inherent in edit.asm (jmh 010406).
; Renamed hist_type to set_type and moved to cmdedit.asm (jmh 011221).


	INCLUDE	common.inc
	INCLUDE	buffers.inc

	PUBLIC	hist_top
	;PUBLIC	hist_fwd
	;PUBLIC	hist_back
	PUBLIC	hist_fwd_match
	PUBLIC	hist_bck_match
	PUBLIC	remember
	PUBLIC	execute_auto_recall
	PUBLIC	execute_rsthist
	PUBLIC	history
	PUBLIC	hist_ptr

	PUBLIC	History_instance_offset 	;Added by jmh
	PUBLIC	History_instance_size

CSEG	SEGMENT	BYTE PUBLIC 'CODE'


	EXTRN	linebuf:BYTE		;line buffer
	EXTRN	lastchar:WORD
	EXTRN	dot:WORD		;current position in line buffer
	EXTRN	min_length:WORD 	;added by dfa


; The history stack is maintained as a string stack using the functions in
; the string stack library. The top and bottom of the stack are always
; zero length strings (the bottom is always a zero length sentinel
; implemented by the string stack package but the top is explicitly 
; maintained by the history code.
History_instance_offset = $
history	$string_stack 2 DUP (<>)	;Buffer descriptors
hist_ptr	DW	?		;Ptr to current buffer descriptor
History_instance_size = $ - offset History_instance_offset

DGROUP	GROUP	CSEG

	EXTRN	set_type:PROC
	EXTRN	bell:PROC
	EXTRN	set_disp_marks:PROC
	EXTRN	erase_to_dot:PROC

	ASSUME	CS:DGROUP,DS:DGROUP,ES:DGROUP,SS:DGROUP


;+
; FUNCTION : execute_rsthist
execute_rsthist proc	near
	mov	bx,hist_ptr		;added this, removed above by jmh
	call	near ptr strstk_reset	;Initialize buffer and descriptor
	xor	al,al			;Push a zero length string onto stack
	jmp	near ptr strstk_push	;Assumes no errors
;	ret				;commented jmh 990517
execute_rsthist	endp



;+
; FUNCTION : hist_top
;
;	Resets the history pointer to the null string at top of history stack.
;	The line buffer itself is NOT changed.
; Parameters:
;	None.
;
; Returns:
;	Nothing.
; Registers destroyed:  BX
;-
hist_top proc near
	mov	bx,hist_ptr		;Point to current descriptor
	jmp	near ptr strstk_settop	;Set to top of history stack.
;	ret				;commented jmh 990517
hist_top endp



;+
; FUNCTION : hist_back
;
;	Gets the previous history line (if there is one) and stores it
;	in the line buffer. Also makes it the current line.
;
; Parameters:
;	None.
;
; Returns:
;	Nothing.
; Registers destroyed: AX,BX,CX
;-
;hist_back proc near
;	mov	dot,offset DGROUP:linebuf
;	jmp	short hist_bck_match	;Will return to caller
;hist_back endp



;+
; FUNCTION : hist_fwd
;
;	Gets the next history line (if there is one) and stores it
;	in the line buffer. Also makes it the current line.
;
; Parameters:
;	None.
;
; Returns:
;	Nothing.
; Registers destroyed :
;-
;hist_fwd proc near
;	mov	dot,offset DGROUP:linebuf
;fall through to hist_fwd_match (jmh 980511)
;hist_fwd endp



;+
; 
; FUNCTION : hist_fwd_match, hist_bck_match
;
;	Looks fwd/back thru the history buffer starting from the current
;	history location looking for a line whose first n chracters match
;	the n characters before the current position in the line buffer.
;
; Parameters:
;	None.
;
; Returns:
;	CF	= 0 if match found
;		  1 if no match
;
; Registers destroyed:
;-
hist_match proc near
hist_fwd_match LABEL near
	mov	dx,offset DGROUP:strstk_fwd_match

; wd added following 10 lines
	mov	bx,hist_ptr
	mov	ax,[bx].cur
	cmp	ax,[bx].top	;If the history pointer is at the end,
	jne	@hist_match_10
	mov	ax,[bx].low_end	;reset it to the start before going forward
	inc	ax
	mov	[bx].cur,ax	;Set current pointer
;	push	dx		;These three lines removed by jmh
;	call	near ptr bell
;	pop	dx

	jmp	short @hist_match_10
hist_bck_match label near
	mov	dx,offset DGROUP:strstk_bck_match
@hist_match_10:  ; (wd reorganized this section)
	mov	bx,hist_ptr	;Descriptor address
	mov	ax,offset DGROUP:linebuf ;start of pattern
	mov	cx,dot		;Current position in linebuffer
	sub	cx,ax		;Number of chars to match
	push	cx		;Save
	call	dx		;Will set CF if no match, else sets
				; 'current' to matched string & AX to len
	pop	cx		;Restore count
	jc	@hist_match_20	;No match

	cmp	ax,cx   	;Line must be longer than the search string
	je	@hist_match_10	;...otherwise, try again (wd)
	call	near ptr hist_copy ;Copy and display the history line
	clc			;Indicate we matched
;	jmp	short @hist_match_99 ; exit (removed by jmh)
	ret

@hist_match_20:
	mov	ax,lastchar	;AX->end-of-line
	call	erase_to_dot	;Else delete remaining chars in the
;				 line (chars between AX and dot)
	stc			;Indicate no match
@hist_match_99:
	ret
hist_match endp



;+
; 
; FUNCTION : hist_copy
;
;	Copies the current history line into the line buffer. The dot
;	is set to the beginning of the line.
;
; Parameters:
;	None.          (fixed these comments -- wd)
;
; Returns:
;	Nothing.
;	Sets lastchar to end of new history line.
;
; Registers destroyed: AX,BX,CX,DX
;-
hist_copy proc near
	mov	bx,hist_ptr	;Current descriptor
	mov	ax,offset DGROUP:linebuf ;the history line storage
	push	ax		;Remember
;	mov	dot,ax	;Cursor will be at the beginning of line (removed--wd)
	xchg	dx,ax		;DX->first char in line (parameter)
	mov	ax,lastchar	;AX->upper limit (parameter)
	call	near ptr set_disp_marks ;Indicate changed range
				;No registers destroyed
	xchg	ax,dx		;Restore beginning of line
	mov	cx,LINEBUF_SIZE ;CX<-max length of line (fixed this -- wd)
	call	near ptr strstk_copy ;Copy history line into linebuf
				;AX == length of history string
	jnc	@hist_copy_90	;Jump if no error from strstk_copy
	call	near ptr bell	;History line too long for buffer
	mov	ax,LINEBUF_SIZE ;Number of bytes = max length of line
@hist_copy_90:
	pop	dx		;DX->beginning of line
	add	ax,dx		;AX->end
	mov	lastchar,ax	;Update end of line
	jmp	near ptr set_disp_marks ;Indicate changed range
;	ret				;commented jmh 990517
hist_copy endp



;+
; 
; FUNCTION : remember
;
;	Saves the line buffer in the history area. If the line already
;	exists, it is moved to the top of the stack.
;   Added by dfa:  lines less than min_length are ignored.
;
; Parameters:
;	None.
;
; Returns:
;	Nothing.
;
; Registers destroyed:
;	AX,BX,CX,DX
;-
remember proc near
	mov	bx,hist_ptr		;Descriptor
	call	near ptr strstk_settop	;Reset stack pointer
	mov	ax,offset DGROUP:linebuf ;AX->line to be stored
	mov	cx,lastchar
	sub	cx,ax			;CX<-length of line
	cmp	cx,min_length		;these two lines added by dfa
	jb	@remember_20 		;ignore request if line too short
	call	near ptr strstk_bck_find ;Look for it in history
;					  buffer. Note that if it is a
;					  null string, the sentinel at
;					  top of the stack is not found
;					  which is at it should be.
	jc	@remember_10		;Not in stack
	call	near ptr strstk_kill	;If found delete it from stack
@remember_10:
	call	near ptr strstk_settop	;Point to sentinel at top of stack
	call	near ptr strstk_kill	;Delete it
	mov	dx,offset DGROUP:linebuf ;String to be remembered
	mov	ax,lastchar		;Length of string
	sub	ax,dx			;AX(AL)<-length of string
	call	near ptr strstk_force_push  ;ignore success/fail status
	xor	ax,ax			    ;Zero length sentinel
	call	near ptr strstk_force_push  ;Push it
@remember_20:				; label added by dfa
	ret
remember endp



;+
; FUNCTION : execute_auto_recall
;
;	This function looks backward through the history buffer for a
;	line with a prefix that matches the characters to the left of
;	the dot. The search begins with the CURRENT history line. ie.
;	if the current history line has a matching prefix, the current
;	pointer is not changed. If no match is found, the history stack
;	is reset.
;
; Parameters:
;	None.
;
; Returns:
;	CF	= 0 if match found
;		  1 if no match
; Register(s) destroyed:
;	AX,BX,CX,DX
;-
execute_auto_recall proc near
	mov	bx,hist_ptr		;BX->current history stack descriptor
	mov	ax,offset DGROUP:linebuf ;AX->pattern
	mov	cx,dot
	sub	cx,ax			;CX<-length of pattern
	call	near ptr strstk_prefix	;Current history line matches?
	jne	@execute_auto_recall_50	;No
	clc				;Yes, current line matches
;	jmp	short @execute_auto_recall_99 ;removed by jmh
	ret

@execute_auto_recall_50:
	call	near ptr hist_bck_match	;Search backward
	jnc	@execute_auto_recall_99	;Found a match
;	No match, reset history stack pointer
	mov	bx,hist_ptr		;BX->current history stack descriptor
	call	near ptr hist_top	;Reset history stack
	stc				;Indicate no match
@execute_auto_recall_99:
	ret
execute_auto_recall endp


CSEG	ENDS

	END
