; GrepMem v1.0 : hunts through memory for (exact) string matches
; by Kyzer/CSG

	include	include:lvo.i

; I use a local stackframe with the link command - this is how I access it.
stackframe=-30
hitcnt=-30
dosbase=-28
address=-24
rdargs=-20

; note that these 3 parts of the stack will be filled with the ReadArgs call
string=-16
begmem=-12
endmem=-8
padzero=-4

calldos	MACRO
	move.l	dosbase(a5),a6
	jsr	_LVO\1(a6)
	ENDM
print	MACRO
	movem.l	a4/a6,-(sp)
	lea	\1,a4
	move.l	a4,d1
	IFC	'\2',''
	moveq	#0,d2
	ELSEIF
	lea	\2,a4
	move.l	a4,d2
	ENDC
	calldos	VPrintf
	movem.l	(sp)+,a4/a6
	ENDM


; BEGIN
	link	a5,#stackframe
	move.w	#2,hitcnt(a5)	; start at column 2 on 1st line
	lea	dosname(pc),a1
	moveq	#36,d0
	move.l	4.w,a6
	jsr	_LVOOpenLibrary(a6)
	tst.l	d0
	bne.s	dos_ok
	moveq.l	#10,d0
	unlk	a5
	rts
dos_ok	move.l	d0,dosbase(a5)


; READ ARGUMENTS
	lea	template(pc),a0
	move.l	a0,d1
	lea	string(a5),a0	; to fill string, begmem, endmem and padzero
	move.l	a0,d2
	clr.l	(a0)+
	clr.l	(a0)+
	clr.l	(a0)+
	clr.l	(a0)+
	moveq	#0,d3
	calldos	ReadArgs
	move.l	d0,rdargs(a5)
	beq	badargs

	lea	padpos(pc),a0
	move.b	#"-",(a0)
	tst.l	padzero(a5)
	beq.s	.nopad
	move.b	#"0",(a0)	
.nopad
; set start/end address
	lea	begmem(a5),a0
	lea	endmem(a5),a1
	tst.l	(a0)
	beq.s	defvals
	tst.l	(a1)
	bne.s	.cont
	print	noend(pc)
	bra.s	defvals
.cont	move.l	(a0),a4
	bsr	hex2num
	move.l	d0,(a0)
	move.l	(a1),a4
	bsr	hex2num
	move.l	d0,(a1)
	bra.s	go

defvals	move.l	#0,begmem(a5)
	move.l	4.w,a6
	move.l	62(a6),endmem(a5)

; ACTUAL SEARCH ROUTINE
; this is the FASTEST byte-by-byte search algorithim in EXISTANCE!
; (IMHO :-) totally coded by me, it hunts down copies of a null
; terminated string
;
; Be aware that getting & printing the string with DOS will make about
; 5-20 extra copies of the string, and these may also be reported, but
; only if they are not surrouded by quotes. So typing
;    GrepMem "hello"
; will find all real occurances of hello (and 1 fake one) and
;    GrepMem hello
; will find about 20 fake ones as well. SO USE QUOTES!
; Also, the actual string supplied to it (in a4) won't be listed.

go	print	grepping(pc),string(a5)
	lea	address(a5),a0
	move.l	begmem(a5),a2
	move.l	endmem(a5),a1
	move.l	string(a5),a4
			; a4=string to search for
			; a1=end address
			; a2=address to start search from
	moveq	#0,d7
nextbyte	move.l	a4,a3	
	cmp.b	(a2)+,(a3)+
	bne.s	notsame

		move.l	a2,(a0) ; save possible match address
		movem.l	a0-a4,-(sp)
nextlet		cmp.b	#0,(a3)	; end of string?
		bne.s	notend
		subq.l	#1,a2
		cmp.l	a2,a4	; don't report your own copy
		beq.s	notmatch

			subq.l	#1,(a0)
			movem.l	d0-d3/a0-a6,-(sp)
			move.l	(a0),a0
			cmp.b	#'"',-1(a0)	; quotes?
			beq.s	fakecopy
			print	foundat(pc),address(a5)
			add.w	#1,hitcnt(a5)
			cmp.w	#7,hitcnt(a5)
			blt.s	.nohit
			print	newline(pc)
			move.w	#1,hitcnt(a5)
.nohit			addq.l	#1,d7
fakecopy			movem.l	(sp)+,d0-d3/a0-a6
			bra.s	notmatch

notend		cmp.b	(a2)+,(a3)+
		beq.s	nextlet
notmatch		movem.l	(sp)+,a0-a4

notsame	cmp.l	a2,a1
	bne.s	nextbyte


; CLEAN UP
cleanup	move.l	d7,address(a5)
	beq.s	none
	print	finished(pc),address(a5)
	bra.s	freeargs
none	print	nonefnd(pc)

freeargs	move.l	rdargs(a5),d1
	calldos	FreeArgs
	moveq.l	#0,d7	; return OK
	bra.s	closedos

badargs	print	info(pc)
	moveq.l	#10,d7
closedos	move.l	dosbase(a5),a1
	movea.l	4.w,a6
	jsr	_LVOCloseLibrary(a6)
	unlk	a5
	move.l	d7,d0
	rts

hex2num	movem.l	d1-d2/a0/a1/a4,-(sp)
	cmp.b	#'$',(a0)
	bne.s	.noadd
	addq.l	#1,a0
.noadd	moveq	#0,d0
	move.l	d0,d1
	move.l	d0,d2
	move.l	a4,a0
.nxtlet	lea	hextable(pc),a1
.nxtcmp	move.b	(a1),d0	
	beq.s	.nothex
	addq.l	#2,a1
	cmp.b	(a0),d0
	bne.s	.nxtcmp
	move.b	-1(a1),d1
	asl.l	#4,d2
	add.l	d1,d2
	addq.l	#1,a0
	tst.b	(a0)
	bne.s	.nxtlet
	move.l	d2,d0
	movem.l	(sp)+,d1-d2/a0/a1/a4
	rts

.nothex	movem.l	(sp)+,d1-d2/a0/a1/a4
	addq.l	#4,sp
	print	nhexmsg(pc)
	bra	defvals
	rts

hextable
	dc.b	'0',0
	dc.b	'$',0
	dc.b	'x',0
	dc.b	'1',1
	dc.b	'2',2
	dc.b	'3',3
	dc.b	'4',4
	dc.b	'5',5
	dc.b	'6',6
	dc.b	'7',7
	dc.b	'8',8
	dc.b	'9',9
	dc.b	'a',10
	dc.b	'b',11
	dc.b	'c',12
	dc.b	'd',13
	dc.b	'e',14
	dc.b	'f',15
	dc.b	'A',10
	dc.b	'B',11
	dc.b	'C',12
	dc.b	'D',13
	dc.b	'E',14
	dc.b	'F',15
	dc.b	0,0

dosname	dc.b	'dos.library',0
	dc.b	'$VER: '
info	dc.b	'GrepMem v1.1 by Kyzer/CSG (20.2.95)',10,10
	dc.b	'STRING/A      - The string to Grep (search) for in memory. USE QUOTES!',10
	dc.b	'STARTADDRESS  - The starting address in hex. If not specified, the Grep will',10
	dc.b	'                take place from $0 to the end of your Chip RAM memory.',10
	dc.b	'ENDADDRESS    - The ending address. Must be specified if STARTADDRESS is.',10,10
	dc.b	'PADZERO/S     - Pad results with zeros, or spaces (default)',10,10
	dc.b	'GrepMem is FreeWare, and may be used by anyone who wants it!',10,0
grepping	dc.b	'Grepping memory for "%ls" from $%lx to $%lx, please wait.'
	dc.b	10,'Hits:       ',0
finished	dc.b	10,'Grep finished, %ld occurences.',10,0
nonefnd	dc.b	9,'None',10,'Grep finished.',10,0
nhexmsg	dc.b	'Address supplied is not hexadecimal, using defaults...',10,0
noend	dc.b	'No end address specified, using defaults...',10,0
newline=*-2
foundat	dc.b	'$%-8lx   ',0
padpos=foundat+2
template	dc.b	'STRING/A,STARTADDRESS,ENDADDRESS,PADZERO/S',0

