;--------------	Snoopy V1.7 - written by Gerson Kurz 

;--------------	Hey! Thanks for reading this Sourcecode. It was written using
;--------------	the BEST assembler available on the Amiga : Macro68
;--------------	and makes extensive use of Macro68 features -> screw Seka lookalikes!

		incpath	include:
		maclib	sm.mac
		macfile	macro.i
		include	snoopy.i

;--------------	this is a "magic" define which has some use although I really 
;--------------	cannot tell you what -> its probably out-of-date, but who cares
SNOOPY_CODE	equ	1

;--------------	our sexy love connection to SegTracker(tm)
		STRUCTURE SegSem,SS_SIZE
		APTR	segs_Find
		LABEL	segs_SIZEOF

;--------------	nice one, defined at the bottom of "snoopy.i"
		DETACHSTARTUPARGS <argTemplate>,<argFirst>,maincode,5000

;--------------	reset all data structures
maincode	bsr	SetupSnoopy
		tst	d0
		beq	.FAIL

;--------------	give out initial welcome to the user
		SHOWMSG	hello

;--------------	main loop ! Wait for signals to arrive, and process them 
.MainLoop	move.l	(waitsignals),d0
		CALL	Wait,<(execBase).w>
		move.l	d0,(signals)

;--------------	CTRL+C terminates the program
		BRBS	#SIGBREAKB_CTRL_C,d0,.DONE

;--------------	if we got a message, then answer it
		move.l	d0,d1
		and.l	(answersignal),d1
		tst.l	d1
		beq.b	.NoMessage
		bsr	HandleReply
		bra.b	.MainLoop
.NoMessage
;--------------	CTRL+D disables output
		BRBC.B	#SIGBREAKB_CTRL_D,d0,.DisableOutput
		tst.b	(outputactive)
		beq.b	.MainLoop
		move.b	#FALSE,(outputactive)
		SHOWMSG	disableout
		bra	.MainLoop
.DisableOutput
;--------------	CTRL+E disables output
		BRBC.B	#SIGBREAKB_CTRL_E,d0,.EnableOutput
		tst.b	(outputactive)
		bne.b	.MainLoop
		move.b	#TRUE,(outputactive)
		SHOWMSG	enableout
		bra	.MainLoop
.EnableOutput
;--------------	CTRL+F toggles the task info feature
		BRBC.B	#SIGBREAKB_CTRL_F,d0,.ToggleTI
		tst.l	(argTaskInfo)
		bne.b	.TI_Disabled
		move.l	#TRUE,(argTaskInfo)
		SHOWMSG	TIenabled
		bra	.MainLoop
.TI_Disabled	SHOWMSG	TIdisabled
		clr.l	(argTaskInfo)
.ToggleTI
		bra	.MainLoop

.CANNOTREMOVE	lea	(closesnoopy.err),a0
		bsr	ShowMessage
		move.l	(window),d1
		CALL	Flush,<(dosBase)>
		bra	.MainLoop

.DONE		bsr	RemoveFunctions	; remove all functions
		tst.w	d0
		beq.b	.CANNOTREMOVE
		bsr	CleanupSnoopy
		moveq	#RETURN_OK,d0
		rts

.FAIL		bsr	RemoveFunctions	; remove all functions (MUST succeed)
		bsr	CleanupSnoopy
		moveq	#RETURN_ERROR,d0
		rts

***********************************************************************************
;--------------	prepare Snoopy for action by opening all required resources and stuff
		ENTRY	SetupSnoopy,d1-d7/a0-a6

;--------------	setup list headers
		lea	(hides),a0
		NEWLIST	a0
		lea	(includes),a0
		NEWLIST	a0
		lea	(bases),a0
		NEWLIST	a0
		lea	(watches),a0
		NEWLIST	a0
		lea	(shows),a0
		NEWLIST	a0
		move.b	#TRUE,(outputactive)

;--------------	open intuition.library
		lea	(intName),a1
		moveq	#36,d0
		CALL	OpenLibrary,<(execBase).w>
		move.l	d0,(intBase)
		beq	.OPENDOSFAILED ; not remarkable, but working.... ;-)

;--------------	open icon.library
		lea	(iconName),a1
		moveq	#0,d0
		CALL	OpenLibrary,<(execBase).w>
		move.l	d0,(iconBase)

;--------------	NOT NEEDED ANYMORE, DETACHSTARTUPARGS TAKES CARE OF THIS
;--------------	open dos.library
;		lea	(dos.name),a1
;		moveq	#37,d0
;		CALL	OpenLibrary,<(execBase).w>
;		move.l	d0,(dosBase)
;		beq	.OPENDOSFAILED
;--------------	parse CLI arguments
;		move.l	#arg.template,d1
;		move.l	#arg.first,d2
;		moveq	#0,d3
;		CALL	ReadArgs,<(dosBase)>
;		move.l	d0,(arg.rdargs)
;		beq	.READARGSFAILED
		bsr	ReadWBArgs

;--------------	try to open script file
		move.l	(argScript),d0
		bne.b	.CallParser
		move.l	#default.script,d0
.CallParser	movea.l	d0,a0
		bsr	ParseInputFile
		tst	d0
		beq	SetupSnoopy_done

;--------------	INCLUDEs are used only during parsing
		lea	(includes),a0
		move.l	#od_SIZEOF,d0
		bsr	RemoveList

;--------------	try to find SegTracker(tm)
		lea	(SegTrackerName,pc),a1
		CALL	FindSemaphore,<(execBase).w>
		movea.l	d0,a0
		move.l	(segs_Find,a0),(SegTracker)

;--------------	create msgport
		CALL	CreateMsgPort,<(execBase).w>
		move.l	d0,(myport)
		beq	.NOMSGPORT
		move.l	(ThisTask,a6),(thistask)
		movea.l	d0,a1
		move.l	#myport.name,(LN_NAME,a1)
		moveq	#0,d0
		move.b	(MP_SIGBIT,a1),d0
		moveq	#1,d1
		lsl.l	d0,d1
		move.l	d1,(answersignal)
		or.l	#MASK_SIGNALS,d1
		move.l	d1,(waitsignals)
		CALL	AddPort

;--------------	open CON: window
		move.l	#window.name,d1
		tst.l	(argOutput)
		beq.b	.DefaultWindow
		move.l	(argOutput),d1
.DefaultWindow	move.l	#MODE_READWRITE,d2
		CALL	Open,<(dosBase)>
		move.l	d0,(window)
		beq.b	.NOWINDOW

		bsr	PatchFunctions
		tst	d0
		beq	.PATCHFAILED

;--------------	perhaps we should make some SHOWs ?
		tst.l	(argShow)
		beq.b	.NoSHOWs
		bsr	SetCmdlineSHOWs
.NoSHOWs
;--------------	set my priority (if applicable)
		move.l	(mypri),d0
		tst.l	(argPri)
		beq.b	.nopricmd
		movea.l	(argPri),a0
		move.l	(a0),d0
.nopricmd	movea.l	(execBase).w,a6
		movea.l	(ThisTask,a6),a1
		CALL	SetTaskPri

		moveq	#TRUE,d0
		bra.b	SetupSnoopy_done

.PATCHFAILED	lea	(nopatch.err),a0
		bra.b	.FAIL
.NOWINDOW	lea	(nowindow.err),a0
		bra.b	.FAIL		
.NOMSGPORT	lea	(nomsgport.err),a0
.FAIL		bsr	ShowErrorMessage
		bra.b	.OPENDOSFAILED

.READARGSFAILED	bsr	ShowDosError
.OPENDOSFAILED	moveq	#FALSE,d0
		DONE	SetupSnoopy
	
***********************************************************************************
;--------------	remove all open Snoopy resources
;--------------	ax
		ENTRY	CleanupSnoopy,d0-d7/a0-a6
		bsr	RemoveBases	; remove all library bases

;--------------	close window
		move.l	(window),d1
		beq.b	.NoWindow
		CALL	Close,<(dosBase)>
.NoWindow
;--------------	remove msgport
		move.l	(myport),d0
		beq.b	.NoMsgPort
		movea.l	d0,a1
		CALL	RemPort,<(execBase).w>
		bsr	RemoveAllMessages
		movea.l	(myport),a0
		CALL	DeleteMsgPort
.NoMsgPort
;--------------	close CLI arguments
		move.l	(arg.rdargs),d1
		beq.b	.NoRdArgs
		CALL	FreeArgs,<(dosBase)>
.NoRdArgs
;--------------	NOT NEEDED ANYMORE, DETACHSTARTUPARGS TAKES CARE OF THIS
;--------------	close dos.library properly
;		move.l	(dosBase),d0
;		beq.b	.NoDosBase
;		movea.l	d0,a1
;		CALL	CloseLibrary,<(execBase).w>
;.NoDosBase	
;--------------	close icon.library properly
		move.l	(iconBase),d0
		beq.b	.NoIconBase
		movea.l	d0,a1
		CALL	CloseLibrary,<(execBase).w>
.NoIconBase	
;--------------	close intuition.library properly
		move.l	(intBase),d0
		beq.b	.NoIntBase
		movea.l	d0,a1
		CALL	CloseLibrary,<(execBase).w>
.NoIntBase	
;--------------	remove allocated lists
		lea	(bases),a0
		move.l	#lbi_SIZEOF,d0
		bsr.b	RemoveList
		lea	(watches),a0
		move.l	#pin_SIZEOF,d0
		bsr.b	RemoveList
		lea	(hides),a0
		move.l	#task_SIZEOF,d0
		bsr.b	RemoveList
		lea	(shows),a0
		move.l	#task_SIZEOF,d0
		bsr.b	RemoveList
		DONE	CleanupSnoopy

*******************************************************************************
;--------------	clears an allocated list with all its elements
;--------------
;--------------	=> a0: struct List *
;--------------	   d0: LONG size of each element (0=don't call FreeMem() on it)
;--------------
		ENTRY	RemoveList,d0-d7/a0-a6
		movea.l	a0,a5
		move.l	d0,d7
		movea.l	(execBase).w,a6
rl.LOOP		IFEMPTY	a5,rl.DONE
		move.l	(LH_HEAD,a5),a4
		movea.l	a5,a0
		REMHEAD	
		tst.l	d7
		beq.b	rl.LOOP
		movea.l	a4,a1
		move.l	d7,d0
		CALL	FreeMem
		bra.b	rl.LOOP
rl.DONE		DONE	RemoveList

***********************************************************************************
;--------------	show a DOS errorcode

		ENTRY	ShowDosError,d0-d7/a0-a6
		CALL	IoErr,<(dosBase)>
		move.l	d0,d1			; code
		moveq	#0,d2			; header
		move.l	#errorMsgBuffer,d3	; buffer
		move.l	#256,d4			; len
		CALL	Fault
		move.l	#errorMsgBuffer,d1
		moveq	#0,d2
		bsr	ShowWarning
		DONE	ShowDosError

***********************************************************************************
;--------------	yeah, we got ourselfs a message; now show it and go home
;--------------	
		ENTRY	HandleReply,d0-d7/a0-a6

.LOOP		movea.l	(myport),a0
		CALL	GetMsg,<(execBase).w>
		move.l	d0,(message)
		beq	HandleReply_done

;--------------	now we have the message and its data, so lets go for it !
		tst.b	(outputactive)
		beq.b	.SkipOutput
		movea.l	d0,a5			; a5=message

;--------------	if the task is hidden, skip output
		bsr	IsTaskHidden
		tst	d0
		bne.b	.SkipOutput

;--------------	show extended task info if applicable
		tst.l	(argTaskInfo)
		beq.b	.NoTaskInfo
		bsr	ShowTaskInfo
		bsr.b	.NEWLINE
.NoTaskInfo
;--------------	if SEGTRACKER is there, show segment of pc
		tst.l	(SegTracker)
		beq.b	.NoSegTracker
		movea.l	(pcm_RegsBeforeCall+pcr_I7,a5),a0	; a0=address to show
		movea.l	(pcm_Info,a5),a1			; a1=PatchInfo
		move.l	(pin_Flags,a1),d0
		BRBS.B	#PINB_NOSEGTRACKER,d0,.NoSegTracker
		bsr	ShowSegTracker
		bsr.b	.NEWLINE
.NoSegTracker
;--------------	prepare output data
		move.l	(pcm_Info,a5),a4	; a4=PatchInfo
		bsr	SetupOutputData

;--------------	send message
		lea.l	(pin_Template,a4),a0
		bsr	ShowMessage
		bsr.b	.NEWLINE
.SkipOutput
;--------------	free message memory
		move.l	(message),a1
		move.l	#pcm_SIZEOF,d0
		CALL	FreeMem,<(execBase).w>

		bra	.LOOP
.NEWLINE	movea.l	(dosBase),a6
		move.l	(window),d1
		move.l	#newline.msg,d2
		moveq	#2,d3
		CALL	Write
		move.l	(window),d1
		CALL	Flush
		rts
		DONE	HandleReply

***********************************************************************************
;--------------	
;--------------	=> a0: APTR address to show
		ENTRY	ShowSegTracker,d0-d7/a0-a6
		move.l	a0,d7				; address to show

;--------------	the manual says we have to do this, so we do it 
;--------------	(although we really couldn't care less, I tell you)
		CALL	Forbid,<(execBase).w>

;--------------	call SegTracker to find Hunk & Offset
		movea.l	d7,a0
		lea	(st_SegHunk),a1
		lea	(st_SegOffset),a2
		movea.l	(SegTracker),a6
		jsr	a6
		tst.l	d0
		beq	.NOTFOUND

;--------------	name found, copy it to our internal buffer
		movea.l	d0,a0
		lea	(errorMsgBuffer),a1
		move.l	a1,(st_SegName)
		moveq	#128-1,d0
.STRCPY		move.b	(a0)+,(a1)+
		beq.b	.STRCPYEND
		dbra	d0,.STRCPY
.STRCPYEND	move.l	d7,(st_SegAddress)

;--------------	lets see if we can find the address
		movea.l	d7,a0
		lea	(st_SegList),a1
		movea.l	a1,a2
		movea.l	(SegTracker),a6
		jsr	a6

		move.l	(st_SegList),d0
		move.l	(st_SegHunk),d1
		cmp.l	d0,d1
		bne.b	.USESEGLIST
		move.l	(st_SegOffset),d1
		cmp.l	d0,d1
		bne.b	.USESEGLIST
		clr.l	(st_SegList)
.USESEGLIST
;--------------	display the message
		move.l	(window),d1
		move.l	#SegTrackerMsg,d2
		move.l	#st_SegAddress,d3
		CALL	VFPrintf,<(dosBase)>
		bra.b	.DONE

;--------------	show warning
.NOTFOUND	lea	(SegTrackerFail),a0
		bsr	ShowMessage
.DONE		CALL	Permit,<(execBase).w>
		DONE	ShowSegTracker

***********************************************************************************
;--------------	checks if the current task is hidden, returns TRUE if so
		ENTRY	IsTaskHidden,d1-d7/a0-a6

;--------------	find taskname to a4
		movea.l	(pcm_Task,a5),a0
		cmpi.b	#NT_PROCESS,(LN_TYPE,a0)
		bne.b	.DEFAULT
		tst.l	(pr_TaskNum,a0)
		beq.b	.DEFAULT
		move.l	(pr_CLI,a0),d0
		lsl.l	#2,d0
		movea.l	d0,a0
		move.l	(cli_CommandName,a0),d0
		lsl.l	#2,d0
		addq.l	#1,d0
		movea.l	d0,a4
		bra.b	.DONE
.DEFAULT	move.l	(LN_NAME,a0),a4
.DONE	

;--------------	handle SHOWs
		tst.b	(showsactive)
		beq.b	.NoSHOWs
		lea	(shows),a5
		bsr.b	CheckIfIsInList
		not.l	d0
		bra.b	IsTaskHidden_done
.NoSHOWs
;--------------	handle HIDEs
		lea	(hides),a5
		bsr.b	CheckIfIsInList
		DONE	IsTaskHidden

***********************************************************************************
;--------------	checks if an entry can be found in a list
;--------------	
;-------------- -> a5: (struct List *) HEAD
;--------------	   a4: (STRPTR) name
;--------------	<- d0: TRUE=Member of this list, FALSE otherwise
;--------------	
		ENTRY	CheckIfIsInList,d1-d7/a0-a6
		cmpa.l	#0,a4
		beq	.NotInList
		IFEMPTY	a5,.NotInList
		movea.l	(LH_HEAD,a5),a5
.LOOP		tst.l	(LN_SUCC,a5)	; a5 = current node
		beq.b	.NotInList
		movea.l	a4,a0
		lea	(task_Name,a5),a1

;--------------	NEW: exact matching enabled
		tst.l	(argMatch)
		bne.b	.STRCMP

.STRICMP	move.b	(a1)+,d0
		beq.b	.InList
		move.b	(a0)+,d1
		UCASE	d1
		cmp.b	d1,d0
		beq.b	.STRICMP
		movea.l	(LN_SUCC,a5),a5
		bra.b	.LOOP
.NotInList	moveq	#0,d0
		bra.b	CheckIfIsInList_done

;--------------	NEW: enable exact matching
.STRCMP		move.b	(a1)+,d0
		beq.b	.SEEMSTOMATCH
		move.b	(a0)+,d1
		cmp.b	d1,d0
		beq.b	.STRCMP
		movea.l	(LN_SUCC,a5),a5
		bra.b	.LOOP
.SEEMSTOMATCH	tst.b	(a0)+
		bne.b	.LOOP
.InList		moveq	#-1,d0
		DONE	CheckIfIsInList

***********************************************************************************
;--------------	show an information line about the task that called this function
;--------------	
		ENTRY	ShowTaskInfo,d1-d7/a0-a6
		lea	(taskinfo.msg),a1
		movea.l	(pcm_Task,a5),a0
		move.l	a0,(output.args)
		cmpi.b	#NT_PROCESS,(LN_TYPE,a0)
		bne.b	.DEFAULT
		tst.l	(pr_TaskNum,a0)
		beq.b	.DEFAULT
		move.l	(pr_CLI,a0),d0
		lsl.l	#2,d0
		movea.l	d0,a0
		move.l	(cli_CommandName,a0),(output.args+4)
		lea	(taskbcpl.msg),a1
		bra.b	.DONE
.DEFAULT	move.l	(LN_NAME,a0),(output.args+4)
.DONE		move.l	a1,a0
		bsr	ShowMessage
		DONE	ShowTaskInfo

***********************************************************************************
;--------------	remove all remaining messages from the port (so that we can be sure
;--------------	we have not lost any memory
;--------------	
		ENTRY	RemoveAllMessages,d0-d7/a0-a6

;--------------	free message memory
		movea.l	(execBase).w,a6
.LOOP		movea.l	(myport),a0
		CALL	GetMsg
		tst.l	d0
		beq.b	.DONE
		movea.l	d0,a1
		move.l	#pcm_SIZEOF,d0
		CALL	FreeMem
		bra.b	.LOOP
.DONE		DONE	RemoveAllMessages

***********************************************************************************
;--------------	setup output.args to contain the registers as specified by 
;--------------	the register template
;--------------	
;--------------	-> a4: Patch Info
;--------------	   a5: Register Data
		ENTRY	SetupOutputData,d0-d7/a0-a6
		lea	(output.args),a0	; a0 = current output offset
		lea.l	(pin_Arguments,a4),a1	; a1 = current position in argument template

;--------------	done ? then lets go !
.LOOP		move.w	(a1)+,d0
		cmpi.w	#ARG_DONE,d0
		beq	SetupOutputData_done

;--------------	set correct register data to a2
		lea	(pcm_RegsBeforeCall,a5),a2 ; a2 = regs before call ( default )
		BRBC.B	#ARGB_RESULT,d0,.BeforeCall
		lea	(pcm_RegsAfterCall,a5),a2 ; a2 = regs before call ( default )
		bclr	#ARGB_RESULT,d0
.BeforeCall
;--------------	set correct jump table to a3
		BRBS.B	#ARGB_BOOLEAN,d0,.UseBOOLEAN
		lea	(.JumpWORD,pc),a3
		BRBC.B	#ARGB_LONG,d0,.UseWORD
		lea	(.JumpLONG,pc),a3
		bra.b	.UseWORD
		bclr	#ARGB_LONG,d0
.UseWORD
;--------------	now get the register data and save it
.ShowOutput	andi.w	#%11111,d0
		lsl.w	#2,d0
		movea.l	(a3,d0.w),a3
		jsr	a3
		bra.b	.LOOP

;--------------	this isn't really 'clean code', but well it works
.UseBOOLEAN	lea	(.JumpWORDBOOL,pc),a3
		BRBC.B	#ARGB_LONG,d0,.UseWORDBOOL
		lea	(.JumpLONGBOOL,pc),a3
		bra.b	.UseWORDBOOL
		bclr	#ARGB_LONG,d0
.UseWORDBOOL	bclr	#ARGB_BOOLEAN,d0
		bra.b	.ShowOutput

.JumpLONG	dc.l	.SaveD0L
		dc.l	.SaveD1L
		dc.l	.SaveD2L
		dc.l	.SaveD3L
		dc.l	.SaveD4L
		dc.l	.SaveD5L
		dc.l	.SaveD6L
		dc.l	.SaveD7L
		dc.l	.SaveA0L
		dc.l	.SaveA1L
		dc.l	.SaveA2L
		dc.l	.SaveA3L
		dc.l	.SaveA4L
		dc.l	.SaveA5L
		dc.l	.SaveA5L
		dc.l	.SaveA5L
		dc.l	.SaveI0L
		dc.l	.SaveI1L
		dc.l	.SaveI2L
		dc.l	.SaveI3L
		dc.l	.SaveI4L
		dc.l	.SaveI5L
		dc.l	.SaveI6L
		dc.l	.SaveI7L

.JumpWORD	dc.l	.SaveD0W
		dc.l	.SaveD1W
		dc.l	.SaveD2W
		dc.l	.SaveD3W
		dc.l	.SaveD4W
		dc.l	.SaveD5W
		dc.l	.SaveD6W
		dc.l	.SaveD7W
		dc.l	.SaveA0W
		dc.l	.SaveA1W
		dc.l	.SaveA2W
		dc.l	.SaveA3W
		dc.l	.SaveA4W
		dc.l	.SaveA5W
		dc.l	.SaveA5W
		dc.l	.SaveA5W
		dc.l	.SaveI0W
		dc.l	.SaveI1W
		dc.l	.SaveI2W
		dc.l	.SaveI3W
		dc.l	.SaveI4W
		dc.l	.SaveI5W
		dc.l	.SaveI6W
		dc.l	.SaveI7W

.JumpLONGBOOL	dc.l	.SaveD0LB
		dc.l	.SaveD1LB
		dc.l	.SaveD2LB
		dc.l	.SaveD3LB
		dc.l	.SaveD4LB
		dc.l	.SaveD5LB
		dc.l	.SaveD6LB
		dc.l	.SaveD7LB
		dc.l	.SaveA0LB
		dc.l	.SaveA1LB
		dc.l	.SaveA2LB
		dc.l	.SaveA3LB
		dc.l	.SaveA4LB
		dc.l	.SaveA5LB
		dc.l	.SaveA5LB
		dc.l	.SaveA5LB
		dc.l	.SaveI0LB
		dc.l	.SaveI1LB
		dc.l	.SaveI2LB
		dc.l	.SaveI3LB
		dc.l	.SaveI4LB
		dc.l	.SaveI5LB
		dc.l	.SaveI6LB
		dc.l	.SaveI7LB

.JumpWORDBOOL	dc.l	.SaveD0WB
		dc.l	.SaveD1WB
		dc.l	.SaveD2WB
		dc.l	.SaveD3WB
		dc.l	.SaveD4WB
		dc.l	.SaveD5WB
		dc.l	.SaveD6WB
		dc.l	.SaveD7WB
		dc.l	.SaveA0WB
		dc.l	.SaveA1WB
		dc.l	.SaveA2WB
		dc.l	.SaveA3WB
		dc.l	.SaveA4WB
		dc.l	.SaveA5WB
		dc.l	.SaveA5WB
		dc.l	.SaveA5WB
		dc.l	.SaveI0WB
		dc.l	.SaveI1WB
		dc.l	.SaveI2WB
		dc.l	.SaveI3WB
		dc.l	.SaveI4WB
		dc.l	.SaveI5WB
		dc.l	.SaveI6WB
		dc.l	.SaveI7WB

SAVEREG		MACRO
.Save\1L	move.l	(pcr_\1,a2),(a0)+
		rts
.Save\1W	move.w	(pcr_\1,a2),(a0)+
		rts
.Save\1LB	move.l	(pcr_\1,a2),d0
		bra	.LONGBOOLEAN
.Save\1WB	move.w	(pcr_\1,a2),d0
		bra	.WORDBOOLEAN
		ENDM

.LONGBOOLEAN	move.l	#SuccessMsg,d1
		tst.l	d0
		bne.b	.LONGISTRUE
		move.l	#FailureMsg,d1
.LONGISTRUE	move.l	d1,(a0)+
		rts

.WORDBOOLEAN	move.l	#SuccessMsg,d1
		tst.w	d0
		bne.b	.WORDISTRUE
		move.l	#FailureMsg,d1
.WORDISTRUE	move.l	d1,(a0)+
		rts

		SAVEREG	A0
		SAVEREG	A1
		SAVEREG	A2
		SAVEREG	A3
		SAVEREG	A4
		SAVEREG	A5
		SAVEREG	D0
		SAVEREG	D1
		SAVEREG	D2
		SAVEREG	D3
		SAVEREG	D4
		SAVEREG	D5
		SAVEREG	D6
		SAVEREG	D7
		SAVEREG I0
		SAVEREG I1
		SAVEREG I2
		SAVEREG I3
		SAVEREG I4
		SAVEREG I5
		SAVEREG I6
		SAVEREG I7

		DONE	SetupOutputData

***********************************************************************************
;--------------	send message to window
;--------------	
;--------------	=> a0: APTR string
;--------------	 
		ENTRY	ShowMessage,d0-d7/a0-a6

;--------------	WARNING: SEGTRACKER() does its own thing
		move.l	(window),d1
		move.l	a0,d2
		move.l	#output.args,d3
		CALL	VFPrintf,<(dosBase)>
		DONE	ShowMessage

***********************************************************************************
;--------------	send error message to the default output stream
;--------------	
;--------------	=> a0: APTR string
;--------------	 
		ENTRY	ShowErrorMessage,d0-d7/a0-a6
		move.l	a0,d1
		move.l	#output.args,d2
		bsr	ShowWarning
		DONE	ShowErrorMessage

***********************************************************************************
;--------------	patch all functions in the watch list
;--------------	
		ENTRY	PatchFunctions,d1-d7/a0-a6
		lea	(watches),a5
		IFEMPTY	a5,.DONE
		movea.l	(LH_HEAD,a5),a5
		movea.l	(execBase).w,a6
.LOOP		tst.l	(LN_SUCC,a5)	; a5 = current node
		beq.b	.DONE
		movea.l	a5,a0
		bsr.b	InstallPatch
		tst	d0
		beq.b	.FAIL		
		movea.l	(LN_SUCC,a5),a5
		bra.b	.LOOP

.FAIL		moveq	#FALSE,d0
		bra.b	PatchFunctions_done

.DONE		moveq	#TRUE,d0
		DONE	PatchFunctions

***********************************************************************************
;--------------	Patch a system function
;-------------- 
;--------------	=> a0: APTR Patchinfo 
;--------------	<= d0: LONG success
;--------------	
		ENTRY	InstallPatch,d1-d7/a0-a6
		movea.l	a0,a5
		move.l	a0,(PatchInfoStruct)

;--------------	allocate patch duplicate
		move.l	#Patch_SIZEOF,d0
		move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
		CALL	AllocMem,<(execBase).w>
		tst.l	d0
		beq.b	.FAIL
		move.l	d0,a4

;--------------	setup original vector
		movea.l	(pin_LibraryBase,a5),a1
		move.w	(pin_Offset,a5),d1
		addq.w	#2,d1
		move.l	(a1,d1.w),(OriginalVector0+2)
		move.l	(a1,d1.w),(OriginalVector1+2)
		move.l	(a1,d1.w),(Patch_START+pih_OriginalFunction)

;--------------	copy patch memory
		move.l	d0,a0
		lea	(Patch_START),a1
		move.l	#Patch_SIZEOF,d0
		subq.w	#1,d0
.LOOP		move.b	(a1)+,(a0)+
		dbra	d0,.LOOP

;--------------	install new function
		move.l	(pin_LibraryBase,a5),a1
		move.w	(pin_Offset,a5),d0
		ext.l	d0
		movea.l	d0,a0
		move.l	a4,d0
		addi.l	#pih_SIZEOF,d0
		CALL	SetFunction
		
		moveq	#TRUE,d0
		bra.b	InstallPatch_done
		
.FAIL		moveq	#FALSE,d0
		DONE	InstallPatch

***********************************************************************************
;--------------	remove the patch of all functions in the watch list
;--------------	
		ENTRY	RemoveFunctions,d1-d7/a0-a6
		lea	(watches),a5
		IFEMPTY	a5,.SUCCESS
		movea.l	(LH_HEAD,a5),a5
		movea.l	(execBase).w,a6
.LOOP		tst.l	(LN_SUCC,a5)	; a5 = current node
		beq.b	.SUCCESS
		movea.l	a5,a0
		bsr.b	RemovePatch
		tst.w	d0
		beq.b	.DONE
		movea.l	(LN_SUCC,a5),a5
		bra.b	.LOOP
.SUCCESS	moveq	#TRUE,d0
.DONE		DONE	RemoveFunctions

***********************************************************************************
;--------------	Remove patch of a system function
;-------------- 
;--------------	=> a0: APTR Patchinfo 
;--------------	
		ENTRY	RemovePatch,d1-d7/a0-a3/a5/a6
		movea.l	a0,a5

;--------------	test if it is our patch
		movea.l	(pin_LibraryBase,a5),a1
		move.w	(pin_Offset,a5),d1
		addq.w	#2,d1
		move.l	(a1,d1.w),a1
		subi.l	#pih_SIZEOF,a1
		cmpi.l	#PATCH_IDSTRING,(pih_Ident,a1)
		bne.b	.REMOVEFAILED
		move.l	a1,a4			; a4 = patched memory

;--------------	restore original function
		move.l	(pin_LibraryBase,a5),a1
		move.w	(pin_Offset,a5),d0
		ext.l	d0
		movea.l	d0,a0
		move.l	(pih_OriginalFunction,a4),d0
		CALL	SetFunction,<(execBase).w>

;--------------	free patched memory
		move.l	a4,a1
		move.l	#Patch_SIZEOF,d0
		CALL	FreeMem
		moveq	#TRUE,d0
		bra.b	RemovePatch_done

;--------------	
.REMOVEFAILED	moveq	#FALSE,d0
		DONE	RemovePatch

***********************************************************************************
;--------------	this is the patch-function that replaces any original code.
;--------------	Note that we have a little recursion-protector here that will
;--------------	prevents recursions that occur inside the original vector 
;--------------	just aslong as the PatchCode() is active

Patch_START	dc.b	PATCH_IDSTRING
		dc.l	0		; original offset (to restore function)
PatchInfoStruct	dc.l	0		; pointer to patchinfo for this thing
		tas	(recursion)
		bne	OriginalVector1
		push	a6
		bsr.b	SetupReplyMsg1
		push	a6
		move.l	(4,sp),a6
OriginalVector0	jsr	$ffff0000
		pop	a6
		bsr	SendReplyMsg1
		pop	a6
		clr.w	(recursion)
		rts

***********************************************************************************
;--------------	sets up the replymsg given by the patch function
;--------------	
;--------------	=> d0-d7/a0-a5: Registers before function call
;--------------	<= a6: PatchCallMessage structure
;--------------	allocate data structure
SetupReplyMsg1	pushm	d0-d7/a0-a5
		movea.l	(execBase).w,a6
		move.l	(thistask),d0
		cmp.l	(ThisTask,a6),d0
		beq	.SKIPTHIS
		move.l	#pcm_SIZEOF,d0
		move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
		CALL	AllocMem
		move.l	d0,a6
		popm	d0-d7/a0-a5

;--------------	fail if NULL; else save all registers
		cmpa.l	#0,a6
		beq	.FAIL
		SAVEREGS pcm_RegsBeforeCall
.FAIL		rts
.SKIPTHIS	suba.l	a6,a6
		popm	d0-d7/a0-a5
		rts

***********************************************************************************
;--------------	sends the reply message back
;--------------	
;--------------	=> d0-d7/a0-a5: Registers after function call
;--------------	
;--------------	fail if NULL; else save all registers
SendReplyMsg1	cmpa.l	#0,a6
		beq	.FAIL
		SAVEREGS pcm_RegsAfterCall
		pushm	d0-d7/a0-a5

		movea.l	(execBase).w,a0
		move.l	(ThisTask,a0),(pcm_Task,a6)
		move.l	(PatchInfoStruct,pc),(pcm_Info,a6)
		movea.l	a6,a5			; a5 = Data structure
		movea.l	a0,a6

;--------------	setup other message stuff
		move.b	#NT_MESSAGE,(LN_TYPE,a5)
		move.w	#pcm_SIZEOF,(MN_LENGTH,a5)
		move.l	#0,(MN_REPLYPORT,a5)
		move.l	(myport),a0		; port
		move.l	a5,a1			; message
		CALL	PutMsg

		popm	d0-d7/a0-a5
.FAIL		rts

OriginalVector1	jsr	$ffff000
		rts

Patch_SIZEOF	equ	*-Patch_START

***********************************************************************************
;--------------	parse a Snoopy input file
;--------------	
;--------------	-> a0: APTR name
;--------------	<= d0: BOOL success
		ENTRY	ParseInputFile,d1-d7/a0-a6

;--------------	open file
		move.l	a0,d1
		move.l	d1,(output.args)
		move.l	#MODE_OLDFILE,d2
		CALL	Open,<(dosBase)>
		move.l	d0,(filehandle)
		beq.b	.NoFile

;--------------	read all lines one-by-one
.LOOP		move.l	(filehandle),d1
		move.l	#input,d2
		move.l	#256,d3
		CALL	FGets
		tst.l	d0
		beq.b	.DONE
		bsr	ProcessInput
		tst.l	d0
		beq.b	.FAIL
		bra.b	.LOOP

;--------------	FGets() returned NULL; so we have to check if it was EOF or an error
.DONE		CALL	IoErr
		move.l	d0,d1
		beq.b	.ReallyDone

;--------------	it WAS an error, so show it and exit
		bsr	ShowDosError
.FAIL		move.l	(filehandle),d1
		CALL	Close
		bra.b	.QUIT

;--------------	return to sender
.ReallyDone	move.l	(filehandle),d1
		CALL	Close
		moveq	#TRUE,d0
		bra.b	ParseInputFile_done

;--------------	some error message
.NoFile		lea	(openfile.err),a0
		bsr	ShowErrorMessage
.QUIT		moveq	#FALSE,d0
		DONE	ParseInputFile

***********************************************************************************
;--------------	NOTE: "I wouldn't normally do this kind of thing", but its just
;--------------	some error message and saves a few bytes so why not do it ....
INVALIDLINE	MACRO
.InvalidLine	bsr	INVALIDLINE_CODE
		ENDM

		ENTRY	INVALIDLINE_CODE
		lea	(invalidline.err),a0
		move.l	#input,output.args
		bsr	ShowErrorMessage
		moveq	#FALSE,d0
		DONE	INVALIDLINE_CODE

***********************************************************************************
;--------------	process current input data line (in 'input' buffer)
;--------------	
;--------------	<= d0: BOOL success
;--------------	
		ENTRY	ProcessInput,d1-d7/a0-a6

;--------------	remove comments and NEWLINE
		lea	(input),a0
		cmpi.b	#COMMENT_LINE,(a0)	; skip if its a comment line
		beq.b	.DONE
.CommentLoop	move.b	(a0)+,d0
		beq.b	.CommentDone		
		cmpi.b	#COMMENT,d0
		beq.b	.CommentFound
		cmpi.b	#"\n",d0
		bne.b	.CommentLoop	
.CommentFound	clr.b	-(a0)
.CommentDone
;--------------	skip the line if it only consists of whitespaces
		lea	(input),a0
.WhitespaceLoop	move.b	(a0)+,d0
		beq.b	.DONE
		cmpi.b	#" ",d0
		beq.b	.WhitespaceLoop
		cmpi.b	#"	",d0
		beq.b	.WhitespaceLoop
.NotWhitespaces
;--------------	see if it is one of the codewords we need 
		lea	(CodewordTable),a0
.CodewordLoop	tst.l	(a0)
		beq.b	.InvalidLine

;--------------	compare codeword and inputline
		move.l	(a0),a1
		lea	(input),a2
.STRICMP	move.b	(a1)+,d0
		beq.b	.Found
		move.b	(a2)+,d1
		UCASE	d1
		cmp.b	d1,d0
		beq.b	.STRICMP

.NotFound	addq.l	#8,a0
		bra.b	.CodewordLoop		

;--------------	codeword found -> call function !
.Found		tst.l	(4,a0)
		beq.b	.DONE
		move.l	(4,a0),a2
		jsr	a2
		bra.b	ProcessInput_done

.DONE		moveq	#TRUE,d0
		bra.b	ProcessInput_done

;--------------	invalid input line
.InvalidLine	move.l	#input,output.args
		lea	(invalidline.err),a0
		bsr	ShowErrorMessage
.QUIT		moveq	#FALSE,d0
		DONE	ProcessInput

***********************************************************************************
;--------------	setup a library base. the input line syntax is :
;--------------	
;--------------	base=<alias>,<complete name>[,<version>]
;--------------	
		ENTRY	SetBase,d1-d7/a0-a6

;--------------	find start of information
		lea	(input),a0
.FindStart	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#"=",d0
		bne.b	.FindStart

;--------------	load a new base to a5
		bsr	NewBase
		tst	d0
		beq	SetBase_done

;--------------	copy base name
		lea	(lbi_BaseName,a5),a1
		moveq	#MAX_BASENAME-2,d1
.CopyBaseName	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#",",d0
		beq.b	.BaseNameDone
		UCASE	d0
		move.b	d0,(a1)+
		dbra	d1,.CopyBaseName
.FindComma	move.b	(a0)+,d0
		beq.b	.InvalidLine
		cmpi.b	#",",d0
		bne.b	.FindComma
.BaseNameDone	clr.b	(a1)+
		move.l	a0,d7		; d7 = library name

;--------------	strip trailing whitespaces
.FindEnd	move.b	(a0)+,d0
		beq.b	.EndFound
		cmpi.b	#",",d0
		bne.b	.FindEnd
.Version	clr.b	(-1,a0)
		moveq	#STVFORMAT_DEC,d0
		bsr	StringToValue
		move.l	d0,(lbi_Version,a5)	; , library version
		bra.b	.GoOn

.EndFound	subq.l	#1,a0
.WhileIsWhite	cmpa.l	d7,a0
		beq.b	.WhiteIsDone
		move.b	-(a0),d0
		cmpi.b	#" ",d0
		beq.b	.WhileIsWhite
		cmpi.b	#"	",d0
		beq.b	.WhileIsWhite
.WhiteIsDone	clr.b	(1,a0)
.GoOn
;--------------	now try to open the library
		movea.l	d7,a1
		move.l	(lbi_Version,a5),d0
		CALL	OpenLibrary,<(execBase).w>
		move.l	d0,(lbi_Base,a5)
		beq.b	.CannotOpenLib

.DONE		moveq	#TRUE,d0
		bra.b	SetBase_done

;--------------	cannot open specified library
.CannotOpenLib	move.l	d7,output.args
		lea	(openbase.err),a0
		bra.b	.SHOWERROR

;--------------	invalid input line
.InvalidLine	move.l	#input,output.args
		lea	(invalidline.err),a0
.SHOWERROR	bsr	ShowErrorMessage
.QUIT		moveq	#FALSE,d0
		DONE	SetBase

***********************************************************************************
;--------------	load new base to a5
;--------------	
;--------------	<= a5: APTR Base
;--------------	   d0: BOOL success
		ENTRY	NewBase,d1-d7/a0-a4/a6
		move.l	#lbi_SIZEOF,d0
		move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
		CALL	AllocMem,<(execBase).w>
		tst.l	d0
		beq.b	NewBase_done
		movea.l	d0,a5
		movea.l	d0,a1
		lea	(bases),a0
		ADDHEAD
		DONE	NewBase

***********************************************************************************
;--------------	setup a watch slot. the input line syntax is :
;--------------	
;--------------	watch=<base>,<offset>,<regs>,<template>
;--------------	
		ENTRY	SetWatch,d1-d7/a0-a6

;--------------	find start of information
		lea	(input),a0
.FindStart	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#"=",d0
		bne.b	.FindStart
		move.l	a0,d7

;--------------	load a new watch to a5
		bsr	NewWatch
		tst	d0
		beq	SetWatch_done

;--------------	NEW: Setup flags
		moveq	#0,d0
		tst.b	(SegTrackerOn)
		bne.b	.SEGTRACKERON
		bset	#PINB_NOSEGTRACKER,d0
.SEGTRACKERON	move.l	d0,(pin_Flags,a5)

;--------------	try to find a base for this watch
		lea	(bases),a1
		IFEMPTY	a1,.NoBaseFound
		movea.l	(LH_HEAD,a1),a1
.FindBaseLOOP	tst.l	(LN_SUCC,a1)	; a1 = current node
		beq.b	.NoBaseFound
		lea	(lbi_BaseName,a1),a2
		movea.l	d7,a0
.STRICMP	move.b	(a0)+,d0
		UCASE	d0
		move.b	(a2)+,d1
		beq.b	.BaseFound
		cmp.b	d1,d0
		beq.b	.STRICMP
		movea.l	(LN_SUCC,a1),a1
		bra.b	.FindBaseLOOP
.BaseFound	move.l	(lbi_Base,a1),(pin_LibraryBase,a5)

;--------------	find Offset
		movea.l	d7,a0
.FindFirstComma	move.b	(a0)+,d0
		beq.b	.InvalidLine
		cmpi.b	#",",d0
		bne.b	.FindFirstComma

;--------------	NEW: if its not '-' or a digit, fail
		cmpi.b	#"-",(a0)
		beq.b	.ITSADIGIT
		bsr	FindDefine
		tst.w	d0
		beq.b	.InvalidLine
		move.w	d0,(pin_Offset,a5)
.SKIP_Comma	cmpi.b	#",",(a0)+
		bne.b	.SKIP_Comma
		bra.b	.OFFSETFOUND

.ITSADIGIT	moveq	#STVFORMAT_DEC,d0
		bsr	StringToValue
		move.w	d0,(pin_Offset,a5)
.OFFSETFOUND

;--------------	now parse the register information
		bsr	ParseRegisterInfo
		tst	d0
		beq.b	.InvalidLine

;--------------	the rest of this line is interpreted as the argument template
		lea	(pin_Template,a5),a1
		moveq	#MAX_TEMPLATE-2,d0
.CopyTemplate	move.b	(a0)+,(a1)+
		beq.b	.TemplateDone
		dbra	d0,.CopyTemplate
		clr.b	(a1)+
.TemplateDone

.DONE		moveq	#TRUE,d0
		bra.b	SetWatch_done

;--------------	cannot find base an error
.NoBaseFound	lea	(nobasefnd.err),a0
		bra.b	.SHOWERROR

;--------------	BUG!BUG!BUG! NewWatch() isn't destroyed if some error happens...
;--------------	[well, it will be destroyed anyway afterwards]

;--------------	invalid input line
.InvalidLine	lea	(invalidline.err),a0
.SHOWERROR	move.l	#input,output.args
		bsr	ShowErrorMessage
.QUIT		moveq	#FALSE,d0
		DONE	SetWatch

***********************************************************************************
;--------------	load new watch to a5
;--------------	
;--------------	<= a5: APTR Watch
;--------------	   d0: BOOL success
		ENTRY	NewWatch,d1-d7/a0-a4/a6
		move.l	#pin_SIZEOF,d0
		move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
		CALL	AllocMem,<(execBase).w>
		tst.l	d0
		beq.b	NewWatch_done
		movea.l	d0,a5
		movea.l	d0,a1
		lea	(watches),a0
		ADDHEAD
		move.l	a5,d0
		DONE	NewWatch

***********************************************************************************
;--------------	load new define to a5
;--------------	
;--------------	<= a5: APTR define
;--------------	   d0: BOOL success
		ENTRY	NewDefine,d1-d7/a0-a4/a6
		move.l	#od_SIZEOF,d0
		move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
		CALL	AllocMem,<(execBase).w>
		tst.l	d0
		beq.b	NewDefine_done
		movea.l	d0,a5
		movea.l	d0,a1
		lea	(includes),a0
		ADDHEAD
		move.l	a5,d0
		DONE	NewDefine

***********************************************************************************
;--------------	read in register information stored in a syntax of
;--------------	
;--------------	 <register 0>/<register 1>/.../<register n>
;--------------	
;--------------	where <register x> is
;--------------	
;--------------		[R](D|A)(0..7)[L]
;--------------	
;--------------	=> A0: APTR start of register information
;--------------	   A5: struct PatchInfo *pi
;--------------	

		ENTRY	ParseRegisterInfo,d1-d7/a1-a6

		lea	(pin_Arguments,a5),a4	; load register data in a4
.LOOP		moveq	#0,d0
.GetRegister	move.b	(a0)+,d1
		beq	.InvalidLine
		UCASE	d1

;--------------	a leading R signals that this register is a return value
		cmpi.b	#"R",d1
		bne.b	.NotReturn
		bset	#ARGB_RESULT,d0
		bra.b	.GetRegister
.NotReturn	
;--------------	a leading B signals that this register is a boolean value
		cmpi.b	#"B",d1
		bne.b	.NotBoolean
		bset	#ARGB_BOOLEAN,d0
		bra.b	.GetRegister
.NotBoolean
;--------------	a D is for data registers
		cmpi.b	#"D",d1
		bne.b	.NotData
		move.b	(a0)+,d1
		beq	.InvalidLine
		subi.b	#"0",d1
		andi.b	#%111,d1
		or.b	d1,d0
		bra.b	.GetRegister

;--------------	an A stands for address registers
.NotData	cmpi.b	#"A",d1
		bne.b	.NotAddr
		move.b	(a0)+,d1
		beq.b	.InvalidLine
		subi.b	#"0",d1
		andi.b	#%111,d1
		or.b	d1,d0
		ori.b	#ARG_A0,d0
		bra.b	.GetRegister

;--------------	an I stands for address registers relative
.NotAddr	cmpi.b	#"I",d1
		bne.b	.NotRelative
		move.b	(a0)+,d1
		beq.b	.InvalidLine
		subi.b	#"0",d1
		andi.b	#%111,d1
		or.b	d1,d0
		ori.b	#ARG_I0,d0
		bra.b	.GetRegister
.NotRelative
;--------------	a trailing L stands for LONG (as opposed to WORD=defaults)
		cmpi.b	#"L",d1
		bne.b	.NotLong
		bset	#ARGB_LONG,d0
		bra	.GetRegister
.NotLong
;--------------	a slash / indicates the end of one register definition, so position
;--------------	to the next register slot
		cmpi.b	#"/",d1
		bne.b	.NotSlash
		move.w	d0,(a4)+
		bra	.LOOP
.NotSlash
;--------------	a comma , indicates the end of the register list definition
		cmpi.b	#",",d1
		bne.b	.InvalidLine
		move.w	d0,(a4)+
		move.w	#ARG_DONE,(a4)
		moveq	#TRUE,d0
		bra.b	ParseRegisterInfo_done

.InvalidLine	moveq	#FALSE,d0
		DONE	ParseRegisterInfo

*******************************************************************************
;--------------	Diese Funktion konvertiert einen String in eine Zahl, wobei der
;--------------	String in Hexadezimal($),Dezimal(#),Oktal(@) oder Dual(%) vorliegen
;--------------	kann. Zusätzlich kann eine Voreinstellung angenommen werden, um
;--------------	z.B. ständige '#' bei rein Dezimalen Strings zu überbrücken.
;--------------	Irgendwann mal in absolut ferner Zukunft habe ich vor, hier noch
;--------------	einen 'Calculator' reinzuhängen: Damit wäre in jedem Programm,
;--------------	daß über StringToValue aus Strings Zahlen macht, gleich eine
;--------------	Taschenrechnerfunktion drinnen..
;--------------	=> d0: ULONG Vordefinierter Typ des Strings
;--------------	   a0: APTR Der String mit der Zahl
;--------------	<= d0: LONG Die (vorzeichenbehaftete) IntegerZahl

		ENTRY	StringToValue,d1-d2
		moveq	#10,d2
		cmp.l	#STVFORMAT_HEX,d0
		bne.b	.NotHex
		moveq	#16,d2
.NotHex		cmp.l	#STVFORMAT_BIN,d0
		bne.b	.NotBin
		moveq	#2,d2
.NotBin		cmp.l	#STVFORMAT_OCT,d0
		bne.b	.NotOct
		moveq	#8,d2
.NotOct		cmpi.b	#'-',(a0)
		bne.b	.NormalUse
		addq.l	#1,a0
		bsr.b	.Check4Sign
		bsr.b	.Get_s2v
		neg.l	d0
		bra	StringToValue_done

.NormalUse	bsr.b	.Check4Sign
		bsr.b	.Get_s2v
		bra	StringToValue_done

.Check4Sign	move.b	(a0),d0
		cmpi.b	#STVTYPE_DEC,d0
		bne.b	1$
		moveq	#10,d2
		addq.l	#1,a0
1$		cmpi.b	#STVTYPE_HEX,d0
		bne.b	2$
		moveq	#16,d2
		addq.l	#1,a0
2$		cmpi.b	#STVTYPE_OCT,d0
		bne.b	3$
		moveq	#8,d2
		addq.l	#1,a0
3$		cmpi.b	#STVTYPE_BIN,d0
		bne.b	4$
		moveq	#2,d2
		addq.l	#1,a0
4$		moveq	#0,d0
		rts

.Get_s2v	moveq	#0,d1
		move.b	(a0)+,d1
		cmpi.b	#'a',d1
		blt.b	.NoUpcaseChose
		cmpi.b	#'z',d1
		bgt.b	.NoUpcaseChose
		sub.b	#('a'-'A'),d1 
.NoUpcaseChose 	subi.b	#"0",d1
		cmpi.b	#10,d1
		bls.b	.s2v_Overdose
		cmpi.l	#16,d2
		bne.s	.s2v_Overdose
		subq.b	#'A'-('9'+1),d1
.s2v_Overdose	cmp.b	d2,d1
		bcc.b	.s2v_Done
		bsr.b	ExtendedMulu
		add	d1,d0
		bra.b	.Get_s2v
.s2v_Done	rts
		DONE	StringToValue

;--------------	Diese Funktion Multipliziert zwei Langwerte
;--------------	=> d1: LONG Wert 1 
;--------------	   d2: LONG Wert 2
;--------------	<= d0: LONG Result
		ENTRY	ExtendedMulu,d1/d2
		cmpi.l	#$7FFF,d2
		bcc.b	2$
		cmpi.l	#$7FFF,d0
		bcc.b	2$
		mulu	d2,d0
		bra.b	ExtendedMulu_done
2$		moveq	#0,d1
		subq.l	#1,d2
1$		add.l	d0,d1
		dbra	d2,1$
		move.l	d1,d0
		DONE	ExtendedMulu

***********************************************************************************
;--------------	remove all library bases opened by the Snoopy parser
		ENTRY	RemoveBases,d0-d7/a0-a6
	
;--------------	loop through all bases and close those librarys
		lea	(bases),a5
		IFEMPTY	a5,.DONE
		movea.l	(LH_HEAD,a5),a5
		movea.l	(execBase).w,a6
.LOOP		tst.l	(LN_SUCC,a5)	; a5 = current node
		beq.b	.DONE
		move.l	(lbi_Base,a5),d0
		beq.b	.NEXT
		clr.l	(lbi_Base,a5)
		movea.l	d0,a1
		CALL	CloseLibrary
.NEXT		movea.l	(LN_SUCC,a5),a5
		bra.b	.LOOP
.DONE		DONE	RemoveBases


***********************************************************************************
;--------------	hide a task from Snoopy. the syntax is
;--------------	
;--------------	hide=<taskname>
;--------------	
		ENTRY	SetHide,d1-d7/a0-a6

;--------------	find start of information
		lea	(input),a0
.FindStart	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#"=",d0
		bne.b	.FindStart
		move.l	a0,d7

;--------------	load a new watch to a5
		bsr	NewHide
		tst	d0
		beq	SetHide_done

;--------------	copy name of HIDE list
		lea	(task_Name,a5),a1
		moveq	#MAX_HIDENAME-2,d0
.COPY		move.b	(a0)+,d1
		beq.b	.DONE
		UCASE	d1
		move.b	d1,(a1)+
		dbra	d0,.COPY
.DONE		clr.b	(a1)+
		moveq	#TRUE,d0
		bra.b	SetHide_done

		INVALIDLINE
		DONE	SetHide

***********************************************************************************
;--------------	load new hide to a5
;--------------	
;--------------	<= a5: APTR hide
;--------------	   d0: BOOL success
		ENTRY	NewHide,d1-d7/a0-a4/a6
		move.l	#task_SIZEOF,d0
		move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
		CALL	AllocMem,<(execBase).w>
		tst.l	d0
		beq.b	NewHide_done
		movea.l	d0,a5
		movea.l	d0,a1
		lea	(hides),a0
		ADDHEAD
		DONE	NewHide

***********************************************************************************
;--------------	show a task from Snoopy. the syntax is
;--------------	
;--------------	show=<taskname>
;--------------	
		ENTRY	SetShow,d1-d7/a0-a6

;--------------	find start of information
		lea	(input),a0
.FindStart	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#"=",d0
		bne.b	.FindStart
		move.l	a0,d7

;--------------	load a new watch to a5
		bsr	NewShow
		tst	d0
		beq	SetShow_done

		bsr.b	CopySHOWName
		moveq	#TRUE,d0
		bra.b	SetShow_done

		INVALIDLINE
		DONE	SetShow

;--------------	copy name of SHOW list
CopySHOWName	lea	(task_Name,a5),a1
		moveq	#MAX_HIDENAME-2,d0
.COPY		move.b	(a0)+,d1
		beq.b	.DONE
		UCASE	d1
		move.b	d1,(a1)+
		dbra	d0,.COPY
.DONE		clr.b	(a1)+
		move.b	#-1,(showsactive)
		rts

***********************************************************************************
;--------------	add SHOWs from the commandline
;--------------	
		ENTRY	SetCmdlineSHOWs,d1-d7/a0-a6
		move.l	(argShow),d0
		beq.b	.DONE
		movea.l	d0,a4
.LOOP		move.l	(a4)+,d1
		beq.b	.DONE
		bsr.b	NewShow
		tst	d0
		beq.b	SetCmdlineSHOWs_done
		movea.l	d1,a0
		bsr	CopySHOWName
		bra.b	.LOOP
.DONE		moveq	#TRUE,d0
		DONE	SetCmdlineSHOWs

***********************************************************************************
;--------------	load new SHOW to a5
;--------------	
;--------------	<= a5: APTR hide
;--------------	   d0: BOOL success
		ENTRY	NewShow,d1-d7/a0-a4/a6
		move.l	#task_SIZEOF,d0
		move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
		CALL	AllocMem,<(execBase).w>
		tst.l	d0
		beq.b	NewShow_done
		movea.l	d0,a5
		movea.l	d0,a1
		lea	(shows),a0
		ADDHEAD
		DONE	NewShow

***********************************************************************************
;--------------	set snoopy task priority. The syntax is
;--------------	
;--------------	pri=<level>
;--------------	
;--------------	level should be in the range of -5 to +5 
;--------------	
		ENTRY	SetPri,d1-d7/a0-a6

;--------------	find start of information
		lea	(input),a0
.FindStart	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#"=",d0
		bne.b	.FindStart
		move.l	a0,d7

		moveq	#STVFORMAT_DEC,d0
		bsr	StringToValue
		move.l	d0,(mypri)

		moveq	#TRUE,d0
		bra.b	SetPri_done

		INVALIDLINE
		DONE	SetPri

***********************************************************************************
;--------------	define a new offset
;--------------	
		ENTRY	SetDefine,d1-d7/a0-a6

;--------------	find start of information
		lea	(input),a0
.FindStart	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#"=",d0
		bne.b	.FindStart
		move.l	a0,d7

;--------------	find start of offset
.FindComma	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#",",d0
		bne.b	.FindComma
		clr.b	(-1,a0)
		moveq	#STVFORMAT_DEC,d0
		bsr	StringToValue
		move.l	d0,d6

;--------------	allocate new define
		bsr	NewDefine
		tst.l	d0
		beq.b	.InvalidLine
		move.w	d6,(od_Offset,a5)
		lea	(od_Name,a5),a1
		move.l	a1,(LN_NAME,a5)
		movea.l	d7,a0
		moveq	#MAX_DEFINENAME-1,d0
.STRCPY		move.b	(a0)+,(a1)+
		beq.b	.STRCPYEND
		dbra	d0,.STRCPY
.STRCPYEND	moveq	#TRUE,d0
		bra.b	SetDefine_done

		INVALIDLINE
		DONE	SetDefine

***********************************************************************************
		ENTRY	ReadWBArgs,d0-d7/a0-a6
		lea	(TTHStruktur),a3
		move.l	(tth_WBStartup,a3),d0		; WBenchMsg vorhanden?
		beq	ReadWBArgs_done
		tst.l	(arg.rdargs)
		bne	ReadWBArgs_done
		clr.l	(arg.rdargs)

;--------------	normaler Ablauf von Workbench
.vonWorkbench	move.l	d0,a3
		move.l	(sm_NumArgs,a3),d0
		move.l	(sm_ArgList,a3),a3
		cmpi.l	#1,d0
		beq.b	.DEFSTART
		lea	(wa_SIZEOF,a3),a3

.DEFSTART	move.l	(wa_Lock,a3),d1			; DirLock zeigt auf
		CALL	CurrentDir,<(dosBase)>		; Pfad des Programms
		move.l	(wa_Name,a3),a0
.LeseIcon	CALL	GetDiskObject,<(iconBase)>	; ".info"-Datei lesen
		BRF	d0,ReadWBArgs_done		; Fehler, dann weiter
		move.l	d0,(diskObject)	

;--------------	Tool Types auswerten
		move.l	d0,a3
		cmpi.b	#WBPROJECT,(do_PAD_BYTE-1,a3)
		beq	.USEPROJECT
		move.l	(do_ToolTypes,a3),a3	
		move.l	a3,a0
		lea	(TTScript),a1
		push	a0
		CALL	FindToolType
		pop	a0
		move.l	d0,(argScript)

.READTOOLTYPES	lea	(TTOutput),a1
		push	a0
		CALL	FindToolType
		pop	a0
		move.l	d0,(argOutput)
		lea	(TTPri),a1
		push	a0
		CALL	FindToolType
		pop	a0
		tst.l	d0
		beq.b	.SKIPPRI
		move.l	#TTPri.value,(argPri)
		movea.l	d0,a0
		moveq	#STVFORMAT_DEC,d0
		bsr	StringToValue
		move.l	d0,(TTPri.value)
.SKIPPRI	bra.b	ReadWBArgs_done

.USEPROJECT	push	a3
		lea	(TTHStruktur),a3
		move.l	(tth_WBStartup,a3),a3
		move.l	(sm_ArgList,a3),a3
		lea	(wa_SIZEOF,a3),a3
		move.l	(wa_Name,a3),(argScript)
		pop	a3
		move.l	(do_ToolTypes,a3),a3	
		move.l	a3,a0
		bra.b	.READTOOLTYPES
		DONE	ReadWBArgs

*******************************************************************************
;--------------	print out some warning message
;--------------	
;--------------	=> d1: APTR message
;--------------	   d2: APTR arguments
		ENTRY	ShowWarning,d0-d7/a0-a6
		lea	(easyStruct),a1
		move.l	#es_SIZEOF,(es_StructSize,a1)
		move.l	#snoopyTitle,(es_Title,a1)
		move.l	d1,(es_TextFormat,a1)
		move.l	#snoopyGadform,(es_GadgetFormat,a1)
		CLEAR.L	a0,a2
		movea.l	d2,a3
		CALL	EasyRequestArgs,<(intBase)>
		DONE	ShowWarning

***********************************************************************************
;--------------	
		ENTRY	FindDefine,d1-d7/a0-a6
		movea.l	a0,a4
		lea	(includes),a5
		IFEMPTY	a5,.NotInList
		movea.l	(LH_HEAD,a5),a5
.LOOP		tst.l	(LN_SUCC,a5)	; a5 = current node
		beq.b	.NotInList
		movea.l	a4,a0		; string to find
		movea.l	(LN_NAME,a5),a1	; definition of String
.STRICMP	move.b	(a1)+,d0
		beq.b	.InList
		move.b	(a0)+,d1
		cmp.b	d1,d0
		beq.b	.STRICMP
		movea.l	(LN_SUCC,a5),a5
		bra.b	.LOOP

.InList		cmpi.b	#",",(a0)+
		bne.b	.NotInList
		move.w	(od_Offset,a5),d0
		bra.b	FindDefine_done

.NotInList	moveq	#0,d0
		DONE	FindDefine

***********************************************************************************
;--------------	set new directory for includes
;--------------	
		ENTRY	SetIncdir,d1-d7/a0-a6

;--------------	find start of information
		lea	(input),a0
.FindStart	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#"=",d0
		bne.b	.FindStart
		move.l	a0,d7

;--------------	copy name to incdir Buffer
		lea	(incdirBuffer),a1
		move.w	#256-1,d0
.STRCPY		move.b	(a0)+,(a1)+
		beq.b	.STRCPYEND
		dbra	d0,.STRCPY
.STRCPYEND	moveq	#TRUE,d0
		bra.b	SetIncdir_done

		INVALIDLINE
		DONE	SetIncdir

***********************************************************************************
;--------------	set new directory for includes
;--------------	
		ENTRY	SetMatch,d1-d7/a0-a6

;--------------	find start of information
		lea	(input),a0
.FindStart	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#"=",d0
		bne.b	.FindStart

;--------------	NOTE: since ReadArgs() assumes that boolean variables have to
;--------------	exist always one way or the other, you cannot find out if it
;--------------	has been given on the command line already; this is why I
;--------------	don't bother and give "priority" to a scriptfile "TASKINFO" statement
		bsr	GetBooleanArgument
		move.l	d0,(argMatch)

		moveq	#TRUE,d0
		bra.b	SetMatch_done

		INVALIDLINE
		DONE	SetMatch

***********************************************************************************
;--------------	set new directory for includes
;--------------	
		ENTRY	SetTaskInfo,d1-d7/a0-a6

;--------------	find start of information
		lea	(input),a0
.FindStart	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#"=",d0
		bne.b	.FindStart

;--------------	NOTE: since ReadArgs() assumes that boolean variables have to
;--------------	exist always one way or the other, you cannot find out if it
;--------------	has been given on the command line already; this is why I
;--------------	don't bother and give "priority" to a scriptfile "TASKINFO" statement
		bsr	GetBooleanArgument
		move.l	d0,(argTaskInfo)

		moveq	#TRUE,d0
		bra.b	SetTaskInfo_done

		INVALIDLINE
		DONE	SetTaskInfo

***********************************************************************************
;--------------	set segtracker information
;--------------	
		ENTRY	SetSegTracker,d1-d7/a0-a6

;--------------	find start of information
		lea	(input),a0
.FindStart	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#"=",d0
		bne.b	.FindStart

;--------------	NOTE: since ReadArgs() assumes that boolean variables have to
;--------------	exist always one way or the other, you cannot find out if it
;--------------	has been given on the command line already; this is why I
;--------------	don't bother and give "priority" to a scriptfile "TASKINFO" statement
		bsr	GetBooleanArgument
		move.b	d0,(SegTrackerOn)

		moveq	#TRUE,d0
		bra.b	SetSegTracker_done

		INVALIDLINE
		DONE	SetSegTracker

***********************************************************************************
;--------------	find out about some boolean value
;--------------	
;--------------	=> a0: APTR string to match
;--------------	<= d0: LONG boolean value
		ENTRY	GetBooleanArgument,d1-d7/a0-a6

;--------------	TRUE : starts with 'Y', 'y', 'j' or 'J'
		cmpi.b	#'Y',(a0)
		beq.b	.TRUE
		cmpi.b	#'y',(a0)
		beq.b	.TRUE
		cmpi.b	#'J',(a0)
		beq.b	.TRUE
		cmpi.b	#'j',(a0)
		bne.b	.FALSE
.TRUE		moveq	#TRUE,d0
		bra.b	GetBooleanArgument_done

.FALSE		moveq	#FALSE,d0
		DONE	GetBooleanArgument

***********************************************************************************
;--------------	include a file
;--------------	
		ENTRY	SetInclude,d1-d7/a0-a6

;--------------	find start of information
		lea	(input),a0
.FindStart	move.b	(a0)+,d0
		beq	.InvalidLine
		cmpi.b	#"=",d0
		bne.b	.FindStart
		move.l	a0,d7
		bsr.b	IncludeFile
		moveq	#TRUE,d0
		bra.b	SetInclude_done

		INVALIDLINE
		DONE	SetInclude

***********************************************************************************
;--------------	
;--------------	
;--------------	=> a0: APTR filename
;--------------	<= d0: LONG error
		ENTRY	IncludeFile,d1-d7/a0-a6
		move.l	a0,d7

;--------------	FIRST: try to find file in local directory
		move.l	a0,d1
		move.l	d1,(output.args)
		move.l	#MODE_OLDFILE,d2
		CALL	Open,<(dosBase)>
		move.l	d0,(includehandle)
		bne.b	.FileFound

;--------------	build includefile name
		lea	(incdirBuffer),a1
		lea	(includeName),a2
		STRCPY	a1,a2

;--------------	create filename
		move.l	#includeName,d1
		move.l	d7,d2
		move.l	#256,d3
		CALL	AddPart

;--------------	open file
		move.l	#includeName,d1
		move.l	d1,(output.args)
		move.l	#MODE_OLDFILE,d2
		CALL	Open
		move.l	d0,(includehandle)
		beq.b	.NoFile
.FileFound
;--------------	read all lines one-by-one
.LOOP		move.l	(includehandle),d1
		move.l	#input,d2
		move.l	#256,d3
		CALL	FGets
		tst.l	d0
		beq.b	.DONE
		bsr	ProcessInputInclude
		tst.l	d0
		beq.b	.FAIL
		bra.b	.LOOP

;--------------	FGets() returned NULL; so we have to check if it was EOF or an error
.DONE		CALL	IoErr
		move.l	d0,d1
		beq.b	.ReallyDone

;--------------	it WAS an error, so show it and exit
		bsr	ShowDosError
.FAIL		move.l	(includehandle),d1
		CALL	Close
		bra.b	.QUIT

;--------------	return to sender
.ReallyDone	move.l	(includehandle),d1
		CALL	Close
		moveq	#TRUE,d0
		bra.b	IncludeFile_done

;--------------	some error message
.NoFile		lea	(openinc.err),a0
		bsr	ShowErrorMessage
.QUIT		moveq	#FALSE,d0
		DONE	IncludeFile

***********************************************************************************
;--------------	process current input data line (in 'input' buffer)
;--------------	
;--------------	<= d0: BOOL success
;--------------	
		ENTRY	ProcessInputInclude,d1-d7/a0-a6

;--------------	remove comments and NEWLINE
		lea	(input),a0
		cmpi.b	#COMMENT_LINE,(a0)	; skip if its a comment line
		beq.b	.DONE
.CommentLoop	move.b	(a0)+,d0
		beq.b	.CommentDone		
		cmpi.b	#COMMENT,d0
		beq.b	.CommentFound
		cmpi.b	#"\n",d0
		bne.b	.CommentLoop	
.CommentFound	clr.b	-(a0)
.CommentDone
;--------------	skip the line if it only consists of whitespaces
		lea	(input),a0
.WhitespaceLoop	move.b	(a0)+,d0
		beq.b	.DONE
		cmpi.b	#" ",d0
		beq.b	.WhitespaceLoop
		cmpi.b	#"	",d0
		beq.b	.WhitespaceLoop
.NotWhitespaces
;--------------	see if it is one of the codewords we need 
		lea	(IncludeCodewordTable),a0
.CodewordLoop	tst.l	(a0)
		beq.b	.InvalidLine

;--------------	compare codeword and inputline
		move.l	(a0),a1
		lea	(input),a2
.STRICMP	move.b	(a1)+,d0
		beq.b	.Found
		move.b	(a2)+,d1
		UCASE	d1
		cmp.b	d1,d0
		beq.b	.STRICMP

.NotFound	addq.l	#8,a0
		bra.b	.CodewordLoop		

;--------------	codeword found -> call function !
.Found		tst.l	(4,a0)
		beq.b	.DONE
		move.l	(4,a0),a2
		jsr	a2
		bra.b	ProcessInputInclude_done

.DONE		moveq	#TRUE,d0
		bra.b	ProcessInputInclude_done

;--------------	invalid input line
		INVALIDLINE
		DONE	ProcessInputInclude

***********************************************************************************
;--------------	data area

CodewordTable	dc.l	c.Base,SetBase
		dc.l	c.Watch,SetWatch
		dc.l	c.Hide,SetHide
		dc.l	c.Pri,SetPri
		dc.l	c.Show,SetShow
		dc.l	c.Define,SetDefine
		dc.l	c.Include,SetInclude
		dc.l	c.Incdir,SetIncdir
		dc.l	c.Match,SetMatch
		dc.l	c.TaskInfo,SetTaskInfo
		dc.l	c.SegTracker,SetSegTracker
		dc.l	0

IncludeCodewordTable	; without INCLUDE and INCDIR
		dc.l	c.Define,SetDefine
		dc.l	c.Base,SetBase
		dc.l	c.Watch,SetWatch
		dc.l	c.Hide,SetHide
		dc.l	c.Pri,SetPri
		dc.l	c.Show,SetShow
		dc.l	0

c.Base		dc.b	"BASE",0
c.Watch		dc.b	"WATCH",0
c.Hide		dc.b	"HIDE",0
c.Pri		dc.b	"PRI",0
c.Show		dc.b	"SHOW",0
c.Define	dc.b	"DEFINE",0
c.Include	dc.b	"INCLUDE",0
c.Incdir	dc.b	"INCDIR",0
c.Match		dc.b	"MATCH",0
c.TaskInfo	dc.b	"TASKINFO",0
c.SegTracker	dc.b	"SEGTRACKER",0
		even
		dc.b	0,"$VER:",IDSTRING,0

snoopyTitle	dc.b	'Snoopy ',_VALOF(VERSION),'.',_VALOF(REVISION),' Message',0
snoopyGadform	dc.b	'Ok',0
TIenabled.msg	dc.b	'TaskInfo enabled\n',0
TIdisabled.msg	dc.b	'TaskInfo disabled\n',0
taskinfo.msg	dc.b	'Task %08lx : "%s"',0
taskbcpl.msg	dc.b	'Task %08lx : "%b"',0
hello.msg	dc.b	"Welcome to [1m",IDSTRING,"[0m - written by ",AUTHORSTRING,"\n",0
disableout.msg	dc.b	"[3mOutput disabled - press CTRL+E to enable again. [0m\n",0
enableout.msg	dc.b	"[3mOutput enabled - press CTRL+D to disable. [0m\n",0
window.name	dc.b	"con:0/0/640/150/",IDSTRING,0
intName		dc.b	"intuition.library",0
dosName		dc.b	"dos.library",0
iconName	dc.b	"icon.library",0
taskName	dc.b	"Snoopy likes ULTRAWORLD",0
myport.name	dc.b	PROGRAMSTRING,0
argTemplate	dc.b	"SCRIPT,"
		dc.b	"TASKINFO/S,"
		dc.b	"OUTPUT/K,"
		dc.b	"PRI/N,"
		dc.b	"SHOW/K/M,"
		dc.b	"STICKY/S,"
		dc.b	"MATCH/S" ; on -> EXACT match only
		dc.b	0
TTScript	dc.b	"SCRIPT",0
TTOutput	dc.b	"OUTPUT",0
TTPri		dc.b	"PRI",0
default.script	dc.b	DEFAULTSCRIPT,0
newline.msg	dc.b	"\n",0

;--------------	error messages
openbase.err	dc.b	'Cannot open base for "%s"\n',0
openfile.err	dc.b	'Cannot open input file "%s"\n',0
invalidline.err	dc.b	'Invalid input line : %s\n',0
nobasefnd.err	dc.b	'Cannot find the base specified as %s\n',0
nowindow.err	dc.b	'Cannot open output stream\n',0
nomsgport.err	dc.b	'Cannot open Snoopy message port\n',0
nopatch.err	dc.b	'Cannot patch all of the functions in the script file, aborting\n',0
openinc.err	dc.b	'Cannot open includefile "%s"\n',0
closesnoopy.err	dc.b	10,'*** WARNING *** Something else has patched the vectors Snoopy looks into'
		dc.b	10,'You will have to wait for the other program to finish and try Snoopy again',10,0

;--------------	name of SegTracker semaphore
SegTrackerName	dc.b	"SegTracker",0
SegTrackerMsg	dc.b	"$%08lx - %s : Hunk %ld, Offset $%08lx, SegList $%08lx",0
SegTrackerFail	dc.b	"(Segment not found)",0
SegTrackerOn	dc.b	TRUE

;--------------	for the new BOOLEAN attribute
SuccessMsg	dc.b	"SUCCESS",0
FailureMsg	dc.b	"FAILURE",0
		even

		section	memory,bss

BSS_SECTION
SegTracker	ds.l	1	; SegTracker semaphore or NULL if it doesn't exist
st_SegAddress	ds.l	1
st_SegName	ds.l	1
st_SegHunk	ds.l	1
st_SegOffset	ds.l	1
st_SegList	ds.l	1
TTPri.value	ds.l	1
diskObject	ds.l	1
;--------------	HEY DUDES: I know this is a bit messy, but I couldn't think of
;--------------	anything better for my purpose. Of course, Snoopy will probably
;--------------	miss out one or two calls in "stress situations", but
;--------------	"better safe than sorry".....
recursion	ds.w	1	; if bit15 is 0, then no call is currently active 
mypri		ds.l	1
thistask	ds.l	1	; pointer to this task 
iconBase	ds.l	1
intBase		ds.l	1
dosBase		ds.l	1	; pointer to dos.library base
includehandle	ds.l	1	; handle for the include script file
filehandle	ds.l	1	; handle for the input script file
hides		ds.b	LH_SIZE	; list header for all hidden tasks
bases		ds.b	LH_SIZE	; list header for all library bases
watches		ds.b	LH_SIZE	; list header for all function watches
shows		ds.b	LH_SIZE	; list header for all shows 
includes	ds.b	LH_SIZE	; list header for all includes
input		ds.b	256	; current input line from script file
arg.rdargs	ds.l	1	; structure used by ReadArgs()
argFirst	
argScript	ds.l	1	; name of scriptfile or NULL for defaults
argTaskInfo	ds.l	1	; TRUE if extended task info is to be given
argOutput	ds.l	1	; name of redirected filename or NULL for the window
argPri		ds.l	1	; priority number or NULL
argShow		ds.l	1	; array of tasknames to show or NULL
argSticky	ds.l	1	; KEEP STICKY
argMatch	ds.l	1	; use exact matching
message		ds.l	1	; last message recieved by GetMsg()
myport		ds.l	1	; my global answerport
answersignal	ds.l	1	; the signalmask used for SendMsg()/GetMsg() answers
waitsignals	ds.l	1	; signals to Wait() for
signals		ds.l	1	; signals actually recieved by Wait()
window		ds.l	1	; output handle of CON: window
output.args	ds.l	MAX_OUTPUTARGS
outputactive	ds.b	1
showsactive	ds.b	1
		even
easyStruct	ds.b	es_SIZEOF
incdirBuffer	ds.b	256
includeName	ds.b	256
errorMsgBuffer	ds.b	256
		even
BSS_SIZEOF	equ	*-BSS_SECTION

		end

***********************************************************************************
;--------------	
