		OPT	!
		MACHINE	68020

		XDEF	_GetSize
		XDEF	_HashLines
		XDEF	_CheckLine
		XDEF	_AllocVecPooled
		XDEF	_FreeVecPooled

		XREF	_LVOAllocPooled
		XREF	_LVOFreePooled

		SECTION	code,code

temp_store:	; Temporary store line (speed is not essential here)
		; INPUT	A0.L: memory pool
		;	A1.L: line
		;	A2.L: possible previous temp node
		;	D0.L: line size
		; OUPUT	D0.L: temp node (0 for error)
		cmp.l	#0,a2
		bne	.prevnode
		movem.l	d1/a1/a2,-(sp)
		move.l	d0,d1
		add.l	#4,d0
		jsr	_AllocVecPooled
		tst.l	d0
		beq	.no_mem
		move.l	d0,a2
		move.l	d1,(a2)+
.loop1:		move.b	(a1)+,(a2)+
		subq.l	#1,d1
		bne	.loop1
.no_mem:	movem.l	(sp)+,d1/a1/a2
		rts
.prevnode:	movem.l	d1-d3/a1-a3,-(sp)
		move.l	d0,d1
		move.l	a2,d2
		add.l	(a2),d0
		add.l	#4,d0
		jsr	_AllocVecPooled
		tst.l	d0
		beq	.no_mem2
		move.l	d0,a3
		move.l	d0,d3
		move.l	d1,(a3)
		move.l	(a2)+,d3
		add.l	d3,(a3)+
.loop2:		move.b	(a2)+,(a3)+
		sub.l	#1,d3
		bne	.loop2
.loop3:		move.b	(a1)+,(a3)+
		sub.l	#1,d1
		bne	.loop3
		move.l	d2,a1
		jsr	_FreeVecPooled
.no_mem2:	movem.l	(sp)+,d1-d3/a1-a3
		rts

; hash index -> hash store
;		0000 next store
;		0004 data line (without hash!)

_HashLines:	; Hash lines (little bit too large routine but makes C part more
		;             readable:-)
		; INPUT	A3.L: lines
		;	A5.L: hash index
		;	A2.L: ptr to line count to update (ulong *)
		;	A0.L: memory pool
		;	D1.L: line buffer size
		;	D2.L: mode
		;	D3.L: previous return (pass 0 in initial)
		; OUPUT	D0.L: incomplete line adr (-1 = error)
		movem.l	a2-a6/d2-d7,-(sp)

		moveq	#' ',d4		; end of cmpline mark (space or dot)
		btst	#2,d2
		beq	.no_strip
		moveq	#'.',d4
.no_strip:	and.l	#%11,d2
		move.l	conv(pc,d2.w*4),a4
		moveq	#000,d2
		moveq	#$0a,d5
		moveq	#000,d6
		cmp.l	#1,d3		; eol search?
		bne	.no_eol
		moveq	#0,d3
		bra	.search_eol
.no_eol:	move.l	a3,a6
		tst.l	d3		; incomplete line in buffer?
		bne	.search_end

.search_start:	move.b	(a3)+,d0
		cmp.b	d5,d0
		beq	.cont
		cmp.b	#' ',d0
		bne	.found_start
		sub.l	#1,d1
		bne	.search_start
		bra	.clean_exit
.cont:		move.l	#-1,(a5)	; mark empty line
		add.l	#1,(a2)		; add line count
		sub.l	#1,d1
		bne	.search_start
		bra	.clean_exit
.found_start:	lea	-1(a3),a6
		sub.l	#1,d1
		beq	.dirty_exit

.search_end:	move.b	(a3)+,d0
		cmp.b	d4,d0
		beq	.found_end
		cmp.b	d5,d0
		beq	.found_end
		cmp.b	#' ',d0
		beq	.found_end
		sub.l	#1,d1
		bne	.search_end
		bra	.dirty_exit
.found_end:	sub.l	#1,a3		; causes one cmp more in eol, but makes
		tst.l	d3		; everything simpler
		beq	.simple

		move.l	a3,d0		; speed of this don't mean much
		sub.l	a6,d0		; unless buffer is very small
		move.l	d0,d5
		move.l	(d3.l),d7
		add.l	d7,d0
		sub.l	#2,d0
		bpl	.do_string2
		move.b	4(d3.l),d2	; no node needed for line size 1
		lsl.w	#8,d2		; hash key
		move.l	#-1,a6
		move.l	d3,a1
		jsr	_FreeVecPooled
		moveq	#0,d3
		bra	.only_hash
.do_string2:	add.l	#5,d0
		jsr	_AllocVecPooled
		tst.l	d0
		beq	.panic
		move.l	d0,a1
		add.l	#4,a1
		move.l	a2,-(sp)
		move.l	d3,a2
		add.l	#4,a2
		move.b	(a2)+,d6
		move.b	(a4,d6.w),d2
		lsl.w	#8,d2
		sub.l	#1,d7
		bne	.decok
		move.b	(a6)+,d6
		move.b	(a4,d6.w),d2
		sub.l	#1,d5
		bra	.no_first
.decok:		move.b	(a2)+,d6
		move.b	(a4,d6.w),d2
		sub.l	#1,d7
		beq	.no_first
.loop1:		move.b	(a2)+,d6
		move.b	(a4,d6.w),(a1)+
		sub.l	#1,d7
		bne	.loop1
.no_first:	tst.l	d5
		beq	.skip
.loop2:		move.b	(a6)+,d6
		move.b	(a4,d6.w),(a1)+
		sub.l	#1,d5
		bne	.loop2
.skip:		clr.b	(a1)+
		move.l	d3,a1
		jsr	_FreeVecPooled
		move.l	(sp)+,a2
		moveq	#000,d3
		moveq	#$0a,d5
		bra	.line_done

.simple:	move.l	a3,d0		; speed of this has some meaning :)
		sub.l	a6,d0
		sub.l	#2,d0
		bpl	.do_string
		move.b	(a6),d2		; no node needed for line size 1
		lsl.w	#8,d2		; hash key
		move.l	#-1,a6
		bra	.only_hash
.do_string:	move.l	d0,d7
		add.l	#5,d0
		jsr	_AllocVecPooled
		tst.l	d0
		beq	.panic
		move.l	d0,a1
		add.l	#4,a1
		move.b	(a6)+,d6	; hash key
		move.b	(a4,d6.w),d2
		lsl.w	#8,d2
		move.b	(a6)+,d6
		move.b	(a4,d6.w),d2
		tst.l	d7
		beq	.no_string
.loop3:		move.b	(a6)+,d6
		move.b	(a4,d6.w),(a1)+
		sub.l	#1,d7
		bne	.loop3
.no_string:	clr.b	(a1)+

.line_done:	move.l	d0,a6		; make hash entry
		move.l	(a5,d2.l*4),(a6)
.only_hash:	move.l	a6,(a5,d2.l*4)
		add.l	#1,(a2)		; add line count
.search_eol:	cmp.b	(a3)+,d5
		beq	.hit_eol
		sub.l	#1,d1
		bne	.search_eol
		moveq	#1,d3
		bra	.clean_exit
.hit_eol:	sub.l	#1,d1
		bne	.search_start
		bra	.clean_exit

.dirty_exit:	move.l	a6,a1
		move.l	d3,a2
		move.l	a3,d0
		sub.l	a6,d0
		bsr	temp_store
		move.l	d0,d3
		beq	.panic
.clean_exit:	move.l	d3,d0
		movem.l	(sp)+,a2-a6/d2-d7
		rts
.panic:		move.l	#-1,d0
		movem.l	(sp)+,a2-a6/d2-d7
		rts

_GetSize:	; Get line size from buffer
		; INPUT	A0.L: buffer
		;	D0.L: buffer size
		; OUPUT	D0.L: line size or 0 for buffer end
		move.l	a0,a1
		moveq	#$0a,d1
.loop:		cmp.b	(a0)+,d1
		beq	.hit_eol
		sub.l	#1,d0
		bne	.loop
		move.l	#0,d0
		rts
.hit_eol:	sub.l	a1,a0
		move.l	a0,d0
		rts

_CheckLine:	; Check line against hash
		; INPUT	A0.L: line
		;	A1.L: hash
		;	D0.L: mode
		; OUPUT	D0.L: TRUE/FALSE
		movem.l	d2-d4/a2-a4,-(sp)

		moveq	#' ',d3
		btst	#2,d0
		beq	.no_strip
		moveq	#'.',d3
.no_strip:	and.l	#%11,d0
		move.l	conv(pc,d0.w*4),a4
		moveq	#000,d0
		moveq	#000,d1
		moveq	#$0a,d2
		moveq	#' ',d4

.search_start	move.b	(a0)+,d0
		cmp.b	d2,d0
		beq	.short
		cmp.b	d4,d0
		beq	.search_start
		move.b	(a4,d0.w),d0
		lsl.w	#8,d0
		move.b	(a0)+,d1
		cmp.b	d3,d1
		beq	.short
		cmp.b	d4,d1
		beq	.short
		cmp.b	d2,d1
		beq	.short
		move.b	(a4,d1.w),d0
		bra	.not_short
.short:		clr.b	d0		; fast check for 0/1 byte lines
		tst.l	(a1,d0.l*4)
		beq	.nomatch
		bra	.match

.not_short:	move.l	(a1,d0.l*4),d1	; get with hash key
		beq	.nomatch
		move.l	d1,a1
		not.l	d1
		beq	.nomatch
		moveq	#0,d0
.next_node:	moveq	#0,d1
		lea	4(a1),a2	; string
		move.l	a0,a3
.more:		move.b	(a2)+,d0
		bne	.cmp_target
		move.b	(a3)+,d1	; check if target end matchs...
		cmp.b	d3,d1
		beq	.match
		cmp.b	d4,d1
		beq	.match
		cmp.b	d2,d1
		beq	.match
		bra	.next
.cmp_target:	move.b	(a3)+,d1
		cmp.b	d3,d1
		beq	.next
		cmp.b	d4,d1
		beq	.next
		cmp.b	d2,d1
		beq	.next
		move.b	(a4,d1.w),d1
		cmp.b	d0,d1
		beq	.more
.next:		move.l	(a1)+,d1
		beq	.nomatch
		move.l	d1,a1
		not.l	d1		; no crash if comparing binary...
		beq	.nomatch
		bra	.next_node

.match:		moveq	#1,d0
		movem.l	(sp)+,d2-d4/a2-a4
		rts
.nomatch:	moveq	#0,d0
		movem.l	(sp)+,d2-d4/a2-a4
		rts

_AllocVecPooled:
		movem.l	d1/a0-a1/a6,-(sp)
		addq.l	#4,d0
		move.l	d0,-(sp)
		move.l	$4.w,a6
		jsr	_LVOAllocPooled(a6)
		move.l	(sp)+,d1
		tst.l	d0
		beq	.nomem
		move.l	d0,a0
		move.l	d1,(a0)+
		move.l	a0,d0
.nomem:		movem.l	(sp)+,d1/a0-a1/a6,-(sp)
		rts

_FreeVecPooled:
		movem.l	d0/d1/a0-a1/a6,-(sp)
		move.l	-(a1),d0
		move.l	$4.w,a6
		jsr	_LVOFreePooled(a6)
		movem.l	(sp)+,d0/d1/a0-a1/a6,-(sp)
		rts

; These tables make routines much simpler...
conv:		dc.l	nocase_noequ	; %00
		dc.l	case_noequ	; %01
		dc.l	nocase_equ	; %10
		dc.l	case_equ	; %11
case_equ:	; *
		dc.b	000,001,002,003,004,005,006,007,008,009
		dc.b	010,011,012,013,014,015,016,017,018,019
		dc.b	020,021,022,023,024,025,026,027,028,029
		dc.b	030,031,032,033,034,035,036,037,038,039
		dc.b	040,041,042,043,044,045,046,047,048,049
		dc.b	050,051,052,053,054,055,056,057,058,059
		dc.b	060,061,062,063,064,065,066,067,068,069
		dc.b	070,071,072,073,074,075,076,077,078,079
		dc.b	080,081,082,083,084,085,086,087,088,089
		dc.b	090,091,092,093,094,045,096,097,098,099
		dc.b	100,101,102,103,104,105,106,107,108,109
		dc.b	110,111,112,113,114,115,116,117,118,119
		dc.b	120,121,122,123,124,125,126,127,128,129
		dc.b	130,131,132,133,134,135,136,137,138,139
		dc.b	140,141,142,143,144,145,146,147,148,149
		dc.b	150,151,152,153,154,155,156,157,158,159
		dc.b	160,161,162,163,164,165,166,167,168,169
		dc.b	170,171,172,173,174,175,176,177,178,179
		dc.b	180,181,182,183,184,185,186,187,188,189
		dc.b	190,191,192,193,194,195,196,197,198,199
		dc.b	200,201,202,203,204,205,206,207,208,209
		dc.b	210,211,212,213,214,215,216,217,218,219
		dc.b	220,221,222,223,224,225,226,227,228,229
		dc.b	230,231,232,233,234,235,236,237,238,239
		dc.b	240,241,242,243,244,245,246,247,248,249
		dc.b	250,251,252,253,254,255
case_noequ:	; *
		dc.b	000,001,002,003,004,005,006,007,008,009
		dc.b	010,011,012,013,014,015,016,017,018,019
		dc.b	020,021,022,023,024,025,026,027,028,029
		dc.b	030,031,032,033,034,035,036,037,038,039
		dc.b	040,041,042,043,044,045,046,047,048,049
		dc.b	050,051,052,053,054,055,056,057,058,059
		dc.b	060,061,062,063,064,065,066,067,068,069
		dc.b	070,071,072,073,074,075,076,077,078,079
		dc.b	080,081,082,083,084,085,086,087,088,089
		dc.b	090,091,092,093,094,095,096,097,098,099
		dc.b	100,101,102,103,104,105,106,107,108,109
		dc.b	110,111,112,113,114,115,116,117,118,119
		dc.b	120,121,122,123,124,125,126,127,128,129
		dc.b	130,131,132,133,134,135,136,137,138,139
		dc.b	140,141,142,143,144,145,146,147,148,149
		dc.b	150,151,152,153,154,155,156,157,158,159
		dc.b	160,161,162,163,164,165,166,167,168,169
		dc.b	170,171,172,173,174,175,176,177,178,179
		dc.b	180,181,182,183,184,185,186,187,188,189
		dc.b	190,191,192,193,194,195,196,197,198,199
		dc.b	200,201,202,203,204,205,206,207,208,209
		dc.b	210,211,212,213,214,215,216,217,218,219
		dc.b	220,221,222,223,224,225,226,227,228,229
		dc.b	230,231,232,233,234,235,236,237,238,239
		dc.b	240,241,242,243,244,245,246,247,248,249
		dc.b	250,251,252,253,254,255
nocase_equ:	; *
		dc.b	000,001,002,003,004,005,006,007,008,009
		dc.b	010,011,012,013,014,015,016,017,018,019
		dc.b	020,021,022,023,024,025,026,027,028,029
		dc.b	030,031,032,033,034,035,036,037,038,039
		dc.b	040,041,042,043,044,045,046,047,048,049
		dc.b	050,051,052,053,054,055,056,057,058,059
		dc.b	060,061,062,063,064,065,066,067,068,069
		dc.b	070,071,072,073,074,075,076,077,078,079
		dc.b	080,081,082,083,084,085,086,087,088,089
		dc.b	090,091,092,093,094,045,096,065,066,067
		dc.b	068,069,070,071,072,073,074,075,076,077
		dc.b	078,079,080,081,082,083,084,085,086,087
		dc.b	088,089,090,123,124,125,126,127,128,129
		dc.b	130,131,132,133,134,135,136,137,138,139
		dc.b	140,141,142,143,144,145,146,147,148,149
		dc.b	150,151,152,153,154,155,156,157,158,159
		dc.b	160,161,162,163,164,165,166,167,168,169
		dc.b	170,171,172,173,174,175,176,177,178,179
		dc.b	180,181,182,183,184,185,186,187,188,189
		dc.b	190,191,192,193,194,195,196,197,198,199
		dc.b	200,201,202,203,204,205,206,207,208,209
		dc.b	210,211,212,213,214,215,216,217,218,219
		dc.b	220,221,222,223,224,225,226,227,228,229
		dc.b	230,231,232,233,234,235,236,237,238,239
		dc.b	240,241,242,243,244,245,246,247,248,249
		dc.b	250,251,252,253,254,255
nocase_noequ:	; *
		dc.b	000,001,002,003,004,005,006,007,008,009
		dc.b	010,011,012,013,014,015,016,017,018,019
		dc.b	020,021,022,023,024,025,026,027,028,029
		dc.b	030,031,032,033,034,035,036,037,038,039
		dc.b	040,041,042,043,044,045,046,047,048,049
		dc.b	050,051,052,053,054,055,056,057,058,059
		dc.b	060,061,062,063,064,065,066,067,068,069
		dc.b	070,071,072,073,074,075,076,077,078,079
		dc.b	080,081,082,083,084,085,086,087,088,089
		dc.b	090,091,092,093,094,045,096,065,066,067
		dc.b	068,069,070,071,072,073,074,075,076,077
		dc.b	078,079,080,081,082,083,084,085,086,087
		dc.b	088,089,090,123,124,125,126,127,128,129
		dc.b	130,131,132,133,134,135,136,137,138,139
		dc.b	140,141,142,143,144,145,146,147,148,149
		dc.b	150,151,152,153,154,155,156,157,158,159
		dc.b	160,161,162,163,164,165,166,167,168,169
		dc.b	170,171,172,173,174,175,176,177,178,179
		dc.b	180,181,182,183,184,185,186,187,188,189
		dc.b	190,191,192,193,194,195,196,197,198,199
		dc.b	200,201,202,203,204,205,206,207,208,209
		dc.b	210,211,212,213,214,215,216,217,218,219
		dc.b	220,221,222,223,224,225,226,227,228,229
		dc.b	230,231,232,233,234,235,236,237,238,239
		dc.b	240,241,242,243,244,245,246,247,248,249
		dc.b	250,251,252,253,254,255
