[mod.mac.sources] DeskCheck Source

macintosh@felix.UUCP (03/12/87)

[DeskCheck Source]

[Moderator's Note:  See the mod.mac.binaries posting for a description of
DeskCheck and the binary application.  The source is presented here in
ascii form so that people with or without Macs can take a look at it.]

---
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	DeskCheck/DeskCheck.asm
#	DeskCheck/FCensus.asm
sed 's/^X//' << 'SHAR_EOF' > DeskCheck/DeskCheck.asm
X
XDebug	equ	0		; make non-zero for debugging
X
X	String_Format	0	; no string padding
X
X
X;	DeskCheck.asm: Find out whether everyone's bundle is legit.
X;	Ephraim Vishniac / P.O. Box 1357 / East Arlington, MA 02174
X;	This program is in the public domain.
X
X;
X
X	Include	Traps.D
X	Include	SysEquX.D
X	Include	FSEqu.D
X	Include	ToolEqu.D
X	Include	SysErr.D
X	Include	PackMacs.Txt
X
X;	Our Macros
X
XMACRO	DoAlert		AlertNumber =
X	IF Debug
X	_Debugger
X	ENDIF
X	; Alert (AlertNumber:INT, NIL:ProcPtr) : INT;
X	clr.w		-(sp)			; space for result
X	move.w		#{AlertNumber},-(sp)	; alert number
X	clr.l		-(sp)			; NIL filter
X	_Alert
X	move.w		(sp)+,d0		; d0 = button hit
X	cmp.w		#OKitem,d0		; standard test
X	|
X
XMACRO	DebugPoint =
X	IF Debug
X	_Debugger
X	ENDIF
X	|
X
XMACRO	UseUs =
X	move.w		OurMap(a5),CurMap	; make ours the current map
X	|
X
XMACRO	UseThem =
X	move.w		TheirMap(a5),CurMap	; make theirs the current map
X	|
X
XMACRO	SetParamText =
X	move.l	ParamZero(a5),-(sp)	; push our paramtext pointers
X	move.l	ParamOne(a5),-(sp)
X	move.l	ParamTwo(a5),-(sp)
X	move.l	ParamThree(a5),-(sp)
X	_ParamText
X	|
X
Xmacro   DNAME   Name =
X        dc.b    '{Name|0:8}'
X	.align	2
X	|
X
X
X;	Our alerts
X
XGreeting	equ	128	; say hello
XFarewell	equ	129	; say goodbye
XSetVolFailed	equ	130	; couldn't SetVol
XOpenResFailed	equ	131	; couldn't OpenResFile
XBundleBitClear	equ	132	; has bundles, but no bundle bit
XNumberOfTypes	equ	133	; bundles has unusual number of types
XNoSigResource	equ	134	; couldn't load signature resource
XNovelType	equ	135	; neither ICN#, nor FREF
XMissingBundle	equ	136	; bundle is too short
XExcessBundle	equ	137	; bundle runs too long
XFunnyIcon	equ	138	; ICN# isn't 256 bytes
XSmallFREF	equ	139	; FREF is less than six bytes
XBigFREF		equ	140	; FREF is more than 262 bytes
XMissingResource	equ	141	; can't find some bundled resource
XDoVolumeAlert	equ	142	; should we do this volume?
XNoIcons		equ	143	; no ICN# list in bundle
XNoFREFs		equ	144	; no FREF list in bundle
XBadLocalID	equ	145	; local ID unresolved
XOrphanType	equ	146	; no FREF with this file type
XOrphanCreator	equ	147	; no BNDL with matching signature
X
X
X;	Our dialogs
X
XCurrentFile	equ	150
X
X;	Other miscellaneous equates
X
XOKitem		equ	1	; Item number for OK button
XQuitItem	equ	2	; Item number for Quit button
X
X;	Our globals
X
XOurMap		ds.w	1	; a word from our sponsor
XTheirMap	ds.w	1	; equal time for the other guy
XDialogPtr	ds.l	1	; current dialog
XOtherBNDLs	ds.w	1	; 'background count' of BNDL resources
XParamZero	ds.l	1	; our param zero text pointer
XParamOne	ds.l	1	; our param one text pointer
XParamTwo	ds.l	1	; our param two text pointer
XParamThree	ds.l	1	; our param three text pointer
XFileType	ds.l	1	; File Type of current file
XFileCreator	ds.l	1	; File Creator of current file
XTypeMatch	ds.b	1	; flag for file type matched
XCreatorMatch	ds.b	1	; flag for file creator matched
X
X	XDef	FCensus
X
XDeskCheck
X;------------------------------- Init Managers ----------------------------
X
X	pea	-4(A5)			; Quickdraw's global area
X	_InitGraf			; Init Quickdraw
X	_InitFonts			; Init Font Manager
X	move.l	#$FFFF,D0		; Flush all events
X	_FlushEvents
X	_InitWindows			; Init Window Manager
X	_InitMenus			; Init Menu Manager
X	_TEInit				; Init Text Edit
X	clr.l	-(SP)			; No restart procedure
X	_InitDialogs			; Init Dialog Manager
X	_InitCursor			; Turn on arrow cursor
X
X;------------------------------- Init Globals -----------------------------
X	move.w	CurMap,OurMap(a5)	; record our resource refnum
X
X	; we need to discount bundles in our file and the system
X	clr.w	-(sp)
X	move.l	#'BNDL',-(sp)		; How many bundles?
X	_CountResources
X	move.w	(sp)+,OtherBNDLs(a5)	; save for later
X
X	clr.l	ParamZero(a5)		; clear our param text pointers
X	clr.l	ParamOne(a5)
X	clr.l	ParamTwo(a5)
X	clr.l	ParamThree(a5)
X
X;-------------------------------Desk Check---------------------------------
X;	Just do a census of all files on all volumes, running them
X;	through our bundle checker.
X
X	DoAlert	Greeting		; say hello
X	bne	SayByeBye		; if not OK, split
X	
X	DebugPoint
X
X	jsr	CheckAllVols		; else test all volumes
X	DoAlert	FareWell		; say goodbye
XSayByeBye
X	_ExitToShell
X
X
X;	CheckAllVols: Check each mounted volume
X
XCAVinfo		equ	-ioVQElSize	; a handy parm block
XVolumeName	equ	CAVinfo-256	; name of current volume
XLastLocal	set	VolumeName
X
XCheckAllVols
X	link	a6,#LastLocal
X	lea	CAVinfo(a6),a0		; a0 = parm block
X	clr.l	ioCompletion(a0)	; no completion routine
X	lea	VolumeName(a6),a1	; storage for volume name
X	move.l	a1,ioFileName(a0)	; set in parm block
X	clr.w	ioVolIndex(a0)		; clear index
X@0	lea	CAVinfo(a6),a0		; a0 = parm block
X	clr.l	VolumeName(a6)		; no volname yet
X	add.w	#1,ioVolIndex(a0)	; advance to next volume
X	_GetVolInfo
X	cmp.w	#nsvErr,d0		; out of volumes?
X	beq	@1			; exit if so
X	move.l	ioFileName(a0),ParamZero(a5)	; set param text zero
X	SetParamText
X	DoAlert	DoVolumeAlert		; should we do this one?
X	bne	@0
X	lea	CAVinfo(a6),a0		; a0 = parm block
X	jsr	CheckOneVol		; else check this volume
X	bra	@0			; and loop back
X@1	clr.l	ParamZero(a5)
X	unlk	a6
X	rts
X	DName	CHECKALLVOLS
X
X;	CheckOneVol: Survey a single volume
X;	Entry:	a0 = _GetVolInfo poop on the volume to check
X
XTheItemType	set	-2		; Dialog item type
XTheItem		set	TheItemType-4	; Dialog item handle
XTheBox		set	TheItem-8	; Dialog item box
XLastLocal	set	TheBox
X
XCheckOneVol
X	link	a6,#LastLocal
X	move.w	ioVRefNum(a0),-(sp)	; save volume reference number
X	move.l	ioFileName(a0),-(sp)	; save volume name pointer
X
X	clr.l	-(sp)			; space for result
X	move.w	#CurrentFile,-(sp)	; dialog number
X	clr.l	-(sp)			; take what we get
X	move.l	#-1,-(sp)		; put this window in front
X	_GetNewDialog			; Pop the question
X	move.l	(sp),DialogPtr(a5)	; save the dialog pointer
X	_SetPort			; make ours the current port
X	move.l	DialogPtr(a5),-(sp)
X	_DrawDialog			; force complete dialog drawing
X
X	move.l	DialogPtr(a5),-(sp)
X	move.w	#4,-(sp)		; item number 4
X	pea	TheItemType(a6)		; storage for item type
X	pea	TheItem(a6)		; storage for item handle
X	pea	TheBox(a6)		; storage for item box
X	_GetDItem
X	move.l	(sp)+,a1		; file name pointer
X	move.l	TheItem(a6),-(sp)	; item handle
X	move.l	a1,-(sp)		; point to file name
X	_SetIText			; set file name in dialog
X
X	move.l	#2,-(sp)		; root directory
X	pea	CheckOneFile		; our file inspector
X	jsr	FCensus			; scan everything
X
X	move.l	DialogPtr(a5),-(sp)	; push the dialog pointer
X	_DisposDialog			; and kill the dialog
X
X	unlk	a6
X	rts
X	DName	CHECKONEVOL
X
X;	CheckOneFile(ParamBlock:ParmBlkPtr; dirID:longint):boolean
X;	Do the actual tests on a given file.
X;	A6 offsets
XOldA6		set	0
XReturnAddr	set	OldA6+4
XDirID		set	ReturnAddr+4	; directory ID
XFileInfo	set	DirID+4		; param block from _GetFileInfo
XReturnValue	set	FileInfo+4	; return value (0 = continue)
XArgsSz		set	ReturnValue-DirID
X;
XParmBlk		set	OldA6-ioHVQElSize	; local parm block
XErrString	set	ParmBlk-32	; Str31 for error codes
XTheItemType	set	ErrString-2	; Dialog item type
XTheItem		set	TheItemType-4	; Dialog item handle
XTheBox		set	TheItem-8	; Dialog item box
XLastLocal	set	TheBox
X
XCheckOneFile
X	link	a6,#LastLocal
X	clr.w	ReturnValue(a6)		; always continue search
X	
X	move.l	DialogPtr(a5),-(sp)
X	move.w	#2,-(sp)		; item number 2
X	pea	TheItemType(a6)		; storage for item type
X	pea	TheItem(a6)		; storage for item handle
X	pea	TheBox(a6)		; storage for item box
X	_GetDItem
X	move.l	TheItem(a6),-(sp)	; item handle
X	move.l	FileInfo(a6),a1		; point to GetFileInfo stuff
X	move.l	ioFileName(a1),-(sp)	; point to file name
X	_SetIText			; set file name in dialog
X
X	; is there a resource fork?
X	move.l	FileInfo(a6),a1		; point to _GetFileInfo stuff
X	tst.l	ioFlRLgLen(a1)		; is there a resource fork?
X	beq	@9			; skip if not
X
X	lea	ParmBlk(a6),a0		; point to parm block
X	clr.l	ioCompletion(a0)
X	clr.l	ioFileName(a0)
X	move.w	ioVRefNum(a1),ioVRefNum(a0) ; volume from file info
X	move.l	DirID(a6),ioWDDirID(a0)	; directory ID from file info
X	tst	FSFCBLen		; HFS running?
X	bmi	@0			; branch if not
X	_HSetVol			; HFS, set volume and directory
X	bra	@1
X@0	_SetVol				; MFS, just set volume
X@1	move.w	ioResult(a0),d0		; did it work?
X	beq	@2			; skip if vol ok
X
X	ext.l	d0
X	lea	ErrString(a6),a0
X	move.l	a0,ParamZero(a5)	; move to param text ptrs
X	_NumToString
X	SetParamText
X	DoAlert	SetVolFailed
X	bra	@9
X
X@2	move.l	FileInfo(a6),a1		; point to _GetFileInfo stuff
X	clr.w	-(sp)			; for _OpenResFile result
X	move.l	ioFileName(a1),-(sp)	; push given file name
X	move.b	#0,ResLoad		; don't load resources
X	_OpenResFile			; give it a shot
X	move.b	#-1,ResLoad		; do load resources
X	move.w	(sp)+,d0		; pop reference number
X	bpl	@3			; skip if reasonable number
X
X	move.w	ResErr,d0		; get the error code
X	ext.l	d0
X	lea	ErrString(a6),a0
X	move.l	a0,ParamZero(a5)	; move to param text ptrs
X	_NumToString
X	SetParamText
X	UseUs				; do we need this?
X	DoAlert	OpenResFailed
X	bra	@9
X
X	; While the other file is open, we have to bracket our
X	; alerts and stuff with 'UseUs' - 'UseThem'
X
X@3	cmp.w	SysMap,d0		; did we just open the system?
X	beq	@9			; skip ahead if so
X	cmp.w	OurMap(a5),d0		; is it us?
X	beq	@9			; skip ahead if so
X	move.w	d0,TheirMap(a5)		; refnum of file under test
X
X	; Here's where we actually examine the file contents...
X
X	; Does this bozo have a bundle?
X	clr.w	-(sp)
X	move.l	#'BNDL',-(sp)		; How many bundles?
X	_CountResources
X	move.w	(sp)+,d3		; well?
X	cmp.w	OtherBNDLs(a5),d3	; discount other bundles
X	beq	@5			; skip if no more, close it up
X
X	move.l	FileInfo(a6),a1		; point to _GetFileInfo stuff
X	move.l	ioFlUsrWds+fdType(a1),FileType(a5)	; save file type
X	move.l	ioFlUsrWds+fdCreator(a1),FileCreator(a5) ; ditto creator
X	clr.b	TypeMatch(a5)		; no matches yet
X	clr.b	CreatorMatch(a5)
X
X	move.w	ioFlUsrWds+fdFlags(a1),d0 ; d0 = file flags
X	btst	#fHasBundle,d0		; test bundle bit
X	bne	@4			; skip if set, that makes sense
X
X	move.w	D3,D0
X	sub.w	OtherBNDLs(a5),D0
X	ext.l	d0
X	lea	ErrString(a6),a0
X	move.l	a0,ParamZero(a5)	; move to param text ptrs
X	_NumToString
X	SetParamText
X	UseUs
X	DoAlert	BundleBitClear
X	UseThem
X
X@4	move.w	D3,D0			; retrieve number of bundles
X	jsr	TestBundles		; else go test the bundles
X	tst.b	TypeMatch(a5)		; found FREF with our Type?
X	bne	@6			; skip if so
X
X	lea	ErrString+1(a6),a0	; fudge alignment of string
X	move.l	a0,ParamZero(a5)	; it's param text zero
X	move.b	#4,(a0)+		; set string length
X	move.l	FileType(a5),(a0)	; and string contents
X	SetParamText	
X	UseUs
X	DoAlert	OrphanType
X	UseThem
X@6	tst.b	CreatorMatch(a5)	; found BNDL with our Creator?
X	bne	@5			; skip if so
X
X	lea	ErrString+1(a6),a0	; fudge alignment of string
X	move.l	a0,ParamZero(a5)	; it's param text zero
X	move.b	#4,(a0)+		; set string length
X	move.l	FileCreator(a5),(a0)	; and string contents
X	SetParamText	
X	UseUs
X	DoAlert	OrphanCreator
X	UseThem
X
X	; Here's where we close up the file
X@5	move.w	TheirMap(a5),-(sp)	; retrieve test file refnum
X	_CloseResFile			; and close it up
X
X	move.w	CurMap,d0		; check the current map
X	cmp.w	OurMap(a5),d0		; is it us?
X	beq	@9			; skip if so, we're good
X	DebugPoint
X
X	; so much for this file.  Restore default volume
X@9	UseUs				; in case we opened the System...
X	clr.l	ParamZero(a5)		; the string storage is gone
X	unlk	a6
X	move.l	(sp)+,a0		; a0 = return address
X	lea	ArgsSz(sp),sp		; pop arguments
X	jmp	(a0)			; return
X	DName	CHECKONEFILE
X
X;	TestBundles: Test all the bundles of the current resource file
X;	d0 = number of BNDL available
X;	We only need to check ones native to the top map [TheirMap(a5)]
X
XOldA6		set	0
XReturnAddr	set	OldA6+4
X
XResIndex	set	OldA6-2		; current resource index
XBNDLHandle	set	ResIndex-4	; handle to current bundle
XLastLocal	set	BNDLHandle
X
X
XTestBundles
X	link	a6,#LastLocal
X	move.w	d0,ResIndex(a6)		; resources to check
X
X@0	clr.l	-(sp)
X	move.l	#'BNDL',-(sp)		; resource type
X	move.w	ResIndex(a6),-(sp)	; resource index
X	_GetIndResource			; get the bundle
X	move.l	(sp)+,BNDLHandle(a6)	; save handle
X	
X	; is it one that we want?
X	clr.w	-(sp)
X	move.l	BNDLHandle(a6),-(sp)	; current bundle
X	_HomeResFile
X	move.w	(sp)+,d0
X	cmp.w	TheirMap(a5),d0		; is it theirs?
X	bne	@1			; skip if not
X
X	move.l	BNDLHandle(a6),a0	; get the bundle handle
X	_HNoPurge			; make it unpurgeable
X	move.l	BNDLHandle(a6),a0	; get the bundle handle
X	_HLock				; lock it down
X
X	move.l	BNDLHandle(a6),a0	; get the bundle handle
X	jsr	TestOneBundle		; and check it out
X
X@1	sub.w	#1,ResIndex(a6)		; decrement resource index
X	bne	@0			; and try again
X
X	unlk	a6
X	rts
X	DName	TESTBUNDLES
X
X;	TestOneBundle: Examine one BNDL for validity, sanity, etc.
X;	a0 = handle to the bundle
X
XOldA6		set	0
XReturnAddr	set	OldA6+4
X
XBNDLHandle	set	OldA6-4		; handle to current bundle
XBundleIDStr	set	BNDLHandle-32	; Str31 for resource ID
XBundleSize	set	BundleIDStr-4	; size of bundle
XBundleID	set	BundleSize-2	; bundle's resource ID
XBundleType	set	BundleID-4	; bundle's resource type
XBundleName	set	BundleType-256	; bundle's resource name
XOtherString	set	BundleName-32	; for other stuff
XICNlist		set	OtherString-4	; pointer to ICN# list
XFREFlist	set	ICNlist-4	; pointer to FREF list
XLastLocal	set	FREFlist
X
XTestOneBundle
X	link	a6,#LastLocal
X	movem.l	d2-d5/a2-a4,-(sp)	; save some registers
X	clr.l	ICNlist(a6)		; clear list pointers
X	clr.l	FREFlist(a6)
X
X	move.l	a0,BNDLHandle(a6)	; store bundle handle for later
X	move.l	(a0),a4			; a4 = bundle pointer
X
X	move.l	a0,-(sp)		; push handle
X	pea	BundleID(a6)		; pointer to resource ID var
X	pea	BundleType(a6)		; pointer to resource type var
X	pea	BundleName(a6)		; pointer to resource name var
X	_GetResInfo
X
X	lea	BundleIDStr(a6),a0	; string for bundle's res ID
X	move.l	a0,ParamZero(a5)	; save for use in ParamText
X	move.w	BundleID(a6),d0		; get the resource ID
X	ext.l	d0
X	_NumToString
X	SetParamText
X
X	; Examine the bundle for size-wise sanity
X	clr.l	-(sp)
X	move.l	BNDLHandle(a6),-(sp)
X	_SizeRsrc			; how big is it?
X	move.l	(sp)+,D4		; save for later
X	move.l	D4,BundleSize(a6)	; might need original figure...
X	sub.w	#8,D4			; at least minimum length?
X	bmi	@5			; branch if not
X	move.l	(a4),D0			; D0 = signature type
X	move.w	4(a4),d1		; D1 = signature ID
X	jsr	TestSignature		; check it out!
X
X	move.w	6(a4),d3		; D3 = # types - 1
X	cmp.w	#1,D3			; usual number?
X	beq	@0			; skip if so
X	move.w	d3,d0
X	add.w	#1,d0			; actual number of types
X	lea	OtherString(a6),a0	; other string
X	move.l	a0,ParamOne(a5)
X	ext.l	d0
X	_NumToString
X	SetParamText
X	UseUs
X	DoAlert	NumberOfTypes
X	UseThem
X@0	lea	8(a4),a4		; a4 = header of first resource list
X
X@1	sub.w	#6,D4			; length of list header
X	bmi	@5			; skip out if too short
X	cmpi.l	#'ICN#',(a4)		; icons?
X	bne	@6			; skip if not, try something else
X	move.l	a4,ICNlist(a6)		; save ICN# list pointer
X	bra	@2			; and go check the list
X@6	cmpi.l	#'FREF',(a4)		; file references?
X	bne	@7			; skip if not, it's something weird
X	move.l	a4,FREFlist(a6)		; save FREF list pointer
X	bra	@2			; and go check the list
X@7	lea	OtherString(a6),a0	; point to other string
X	move.w	#4,(a0)
X	move.l	(a4),2(a0)		; fill in resource type
X	lea	1(a0),a0		; use odd-aligned string
X	move.l	a0,ParamOne(a5)
X	SetParamText
X	UseUs
X	DoAlert	NovelType
X	UseThem
X@2	move.w	4(a4),d2		; resources - 1 of this type
X	lea	6(a4),a3		; a3 = start of resource list
X@3	sub.w	#4,d4			; size of list item
X	bmi	@5			; skip out if too short
X	move.l	(a4),D0			; resource type
X	move.w	2(a3),D1		; resource ID
X	jsr	TestOneResource		; test it!
X	lea	4(a3),a3		; next item in list
X	dbra	d2,@3			; collect them all
X	move.l	a3,a4			; next list
X	dbra	d3,@1			; collect all of those, too
X	tst.w	d4			; All used up?
X	beq	@4			; skip if so, that's just right
X	; The bundle runs on longer than expected
X	UseUs
X	DoAlert	ExcessBundle
X	UseThem
X@4	move.l	ICNlist(a6),a0		; pick up ICN# and FREF pointers
X	move.l	FREFlist(a6),a1
X	jsr	TestLocalIDs
X
X	clr.l	ParamZero(a5)
X	clr.l	ParamOne(a5)
X	movem.l	(sp)+,d2-d5/a2-a4	; restore some registers
X	unlk	a6
X	rts
X	DName	TESTONEBUNDLE
X
X@5	UseUs
X	DoAlert	MissingBundle
X	UseThem
X	bra	@4
X
X
X;	TestSignature: Does the 'signature' resource exist?
X;	D0 = resource type
X;	D1.w = resource ID
X
XOldA6		set	0
XReturnAddr	set	OldA6+4
X
XSigType		set	OldA6-4		; type of signature resource
XTypeStr		set	SigType-1	; for type string
XFillerOne	set	TypeStr-1	; restore alignment
XSigID		set	FillerOne-2	; resource ID for signature
XIDString	set	SigID-32	; Str31 for resource ID
X
XLastLocal	set	IDString
X
XTestSignature
X	link	a6,#LastLocal
X	move.l	d0,SigType(a6)		; save signature's resource type
X	move.w	d1,SigID(a6)		; save resource ID
X	cmp.l	FileCreator(a5),d0	; FREF matches creator?
X	seq	d0
X	or.b	d0,CreatorMatch(a5)	; set match flag if so
X
X	clr.l	-(sp)
X	move.l	SigType(a6),-(sp)	; resource type
X	move.w	SigID(a6),-(sp)		; resource ID
X	_GetResource			; Fetch!
X	move.l	(sp)+,d0		; pop the handle
X	beq	@2			; problem if NIL
X	tst.w	ResErr			; something wrong?
X	bne	@2			; skip if so
X	clr.w	-(sp)			; check home file of resource
X	move.l	d0,-(sp)
X	_HomeResFile
X	move.w	(sp)+,d0		; pop res file reference
X	cmp.w	TheirMap(a5),d0		; right file?
X	beq	@0			; branch if so, it's good
X
X@2	move.b	#4,TypeStr(a6)		; set resource type string
X	lea	TypeStr(a6),a0
X	move.l	a0,ParamOne(a5)
X	SetParamText
X
X	move.w	SigID(a6),d0		; d0 = signature's res ID
X	ext.l	d0
X	lea	IDString(a6),a0
X	move.l	a0,ParamTwo(a5)
X	_NumToString
X	SetParamText
X
X	UseUs
X	DoAlert	NoSigResource
X	UseThem
X
X@0	clr.l	ParamOne(a5)
X	clr.l	ParamTwo(a5)
X	unlk	a6
X	rts
X	DName	TESTSIGNATURE
X
X;	TestOneResource: Do a sanity check on one resource.
X;		For all kinds, be sure it exists.
X;		For ICN# and FREF, do some other stuff
X;	D0 = resource type
X;	D1.W = resource ID
X
XOldA6		set	0
XReturnAddr	set	OldA6+4
X
XResHandle	set	OldA6-4		; handle to current resource
XResType		set	ResHandle-4	; resource type
XResTypeStr	set	ResType-1	; for using above as string
XFillerOne	set	ResTypeStr-1	; restore alignment
XResID		set	FillerOne-2	; resource ID
XResIDStr	set	ResID-32	; Str31 for resource ID
XResSize		set	ResIDStr-4	; size of resource
XSizeString	set	ResSize-32	; Str31 for resource size
XLastLocal	set	SizeString
X
XTestOneResource
X	link	a6,#LastLocal
X	movem.l	d2-d5/a2-a4,-(sp)	; save some registers
X
X	move.l	d0,ResType(a6)
X	move.w	d1,ResID(a6)
X
X	move.b	#4,ResTypeStr(a6)	; build type string
X	lea	ResTypeStr(a6),a0
X	move.l	a0,ParamOne(a5)		; set indirect pointer
X
X	move.w	ResID(a6),d0		; resource ID
X	lea	ResIDStr(a6),a0		; ID string
X	move.l	a0,ParamTwo(a5)
X	ext.l	d0
X	_NumToString
X	SetParamText
X
X	clr.l	-(sp)
X	move.l	ResType(a6),-(sp)	; resource type
X	move.w	ResID(a6),-(sp)		; resource ID
X	_GetResource			; Fetch!
X	move.l	(sp)+,ResHandle(a6)	; save the handle
X	tst.l	ResHandle(a6)		; NIL handle?
X	beq	@4			; error if so, resource is missing
X	tst.w	ResErr			; something wrong?
X	bne	@4			; skip if so
X	clr.w	-(sp)			; else check home resource file
X	move.l	ResHandle(a6),-(sp)
X	_HomeResFile
X	move.w	(sp)+,d0		; pop res file ref
X	cmp.w	TheirMap(a5),d0		; right file?
X	beq	@0			; branch if so, we'll take it
X
X@4	UseUs
X	DoAlert	MissingResource
X	UseThem
X	bra	@9
X@0	clr.l	-(sp)
X	move.l	ResHandle(a6),-(sp)
X	_SizeRsrc			; How big is this sucker?
X	move.l	(sp)+,ResSize(a6)	; save for later testing
X
X	move.l	ResSize(a6),d0		; set up length string
X	lea	SizeString(a6),a0
X	move.l	a0,ParamThree(a5)
X	_NumToString
X	SetParamText
X
X	move.l	ResType(a6),d0		; d0 = resource type
X	cmpi.l	#'ICN#',d0		; Icon list?
X	bne	@2			; skip if not
X	
X	move.l	ResSize(a6),d0		; check resource size
X	cmp.l	#256,d0			; must be 256 bytes
X	beq	@9			; exit if so, it's good
X	UseUs
X	DoAlert	FunnyIcon
X	UseThem
X	bra	@9
X@2	cmpi.l	#'FREF',d0		; FREF?
X	bne	@9			; exit if not, we don't care
X	move.l	ResSize(a6),d0		; check resource size
X	cmpi.l	#6,d0			; reasonable size?
X	bcc	@3			; branch if minimum or more
X	UseUs
X	DoAlert	SmallFREF		; the FREF is too small
X	UseThem
X	bra	@9
X@3	cmpi.l	#263,d0			; not too big?
X	bcs	@9			; branch if in bounds
X	UseUs
X	DoAlert	BigFREF
X	UseThem
X
X@9	clr.l	ParamOne(a5)
X	clr.l	ParamTwo(a5)
X	clr.l	ParamThree(a5)
X	movem.l	(sp)+,d2-d5/a2-a4	; restore some registers
X	unlk	a6
X	rts
X	DName	TESTONERESOURCE
X
X;	TestLocalIDs: See if the local IDs referred to by the FREFs are
X;			resolved in the ICN# list.
X;	a0 = ptr to ICN# list from bundle
X;	a1 = ptr to FREF list from bundle
X
XFREFIDStr	set	-32		; Str31 for FREF ID #
XLocalIDStr	set	FREFIDStr-32	; Str31 for local ID #
XFREFHandle	set	LocalIDStr-4	; handle of current FREF
XLastLocal	set	FREFHandle
X
XTestLocalIDs
X	link	a6,#LastLocal		; some local storage
X	movem.l	a2-a4/d2-d4,-(sp)	; save some regs
X	
X	move.l	a0,d0			; is there an ICN# list?
X	bne	@0			; skip if so
X	UseUs
X	DoAlert	NoIcons
X	UseThem
X	bra	@9
X@0	move.l	a1,d0			; is there an FREF list?
X	bne	@1			; skip if so
X	UseUs
X	DoAlert	NoFREFs
X	UseThem
X	bra	@9
X@1	move.l	a0,a4			; a4 = ICN# list pointer
X	move.w	4(a1),d4		; d4 = # FREFs - 1
X	lea	6(a1),a3		; a3 = first FREF item
X@2	clr.l	-(sp)
X	move.l	#'FREF',-(sp)
X	move.w	2(a3),-(sp)
X	_GetResource			; get the FREF
X	move.l	(sp)+,d0		; pop the handle
X	beq	@5			; skip if NIL handle
X	tst.w	ResErr
X	bne	@5			; skip if resource error
X	move.l	d0,FREFHandle(a6)	; save FREF handle
X	clr.w	-(sp)			; check home res file
X	move.l	d0,-(sp)
X	_HomeResFile
X	move.w	(sp)+,d0		; pop home res file
X	cmp.w	TheirMap(a5),d0		; from a good home?
X	bne	@5			; exit if not
X
X	move.l	FREFHandle(a6),a0	; a0 = FREF handle
X	move.l	(a0),a0			; a0 = FREF pointer
X
X	move.l	(a0),d0			; d0 = file type from FREF
X	cmp.l	FileType(a5),d0		; match our file type?
X	seq	d0
X	or.b	d0,TypeMatch(a5)	; set type match flag if so
X
X	move.w	4(a0),d0		; d0 = local ID from FREF
X	move.w	4(a4),d3		; d3 = # ICN#s - 1
X	lea	6(a4),a2		; a2 = first ICN# item
X@3	cmp.w	(a2),d0			; local IDs match?
X	beq	@5			; skip if so, test next FREF
X	lea	4(a2),a2		; else move to next ICN# item
X	dbra	d3,@3			; search through ICN# list
X
X	; If we fall out, we have an unsatisfied local ID in d0
X
X	ext.l	d0
X	lea	LocalIDStr(a6),a0	; string for local resource ID
X	move.l	a0,ParamTwo(a5)
X	_NumToString
X	move.w	2(a3),d0		; FREF resource ID
X	ext.l	d0
X	lea	FREFIDStr(a6),a0	; string for FREF resource ID
X	move.l	a0,ParamOne(a5)
X	_NumToString
X	SetParamText
X	UseUs
X	DoAlert	BadLocalID
X	UseThem
X	clr.l	ParamOne(a5)
X	clr.l	ParamTwo(a5)
X@5	lea	4(a3),a3		; next FREF item in list
X	dbra	d4,@2			; test entire FREF list
X@9	movem.l	(sp)+,a2-a4/d2-d4	; restore registers
X	unlk	a6
X	rts
X	DName	TESTLOCALIDS
X
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > DeskCheck/FCensus.asm
X
X;	FCensus: HFS/MSF file census routine from Feb '86 MacTutor
X;	Provides info on each file on a volume, whether MFS or HFS.
X
X;	Proc FCensus(vRefNum:integer; DirID:longint; Inspector:ProcPtr);
X
X;	vRefNum: volume reference number (or drive number) of volume
X
X;	dirID: ID of directory to start.  Root dir = 2.
X
X;	Inspector: user-supplied function
X;		MyInspector(ParamBlock:ParmBlkPtr; dirID:longint):boolean
X;		ParamBlock is a GetFileInfo block
X;		dirID is the ID of the file's directory
X;		If returned value = True, search ends.
X;		If returned value = False, search continues.
X
X	Include	Traps.D
X	Include	SysEquX.D
X	Include	FSEqu.D
X	Include	SysErr.D
X		
X		.MACRO _TFSCORE
X		IF '%1' <> ''
X		LEA    %1,A0
X		ENDIF
X		IF '%3' = ''
X		DC.W   $A200+%2
X		ENDIF
X		IF '%3' = 'REGS'
X		DC.W   $A300+%2
X		ENDIF
X		IF '%3' = 'ASYNC'
X		DC.W   $A600+%2
X		ENDIF
X		IF '%3' = 'SYS'
X		DC.W   $A600+%2
X		ENDIF
X		IF '%3' = 'IMMED'
X		DC.W   $A200+%2
X		ENDIF
X		.ENDM
X
X
X		.MACRO _GetCatInfo 
X		MOVEQ		#9,D0
X		_TFSCore	%1,96,%2
X		.ENDM
X
X
X;	A6 offsets
XOldA6		set	0
XReturnAddr	set	OldA6+4
XInspec		set	ReturnAddr+4
XDirID		set	Inspec+4
XvRefNum		set	DirID+4
XArgsSz		set	vRefNum+2-Inspec
X;
XParmBlk		set	OldA6-ioHVQElSize	; local parm block
XNameStr		set	ParmBlk-256		; Str255 buffer
XIndex		set	NameStr-2		; directory index
X
X	XRef	FCensus
X
XFCensus
X	Link	a6,#Index
X	clr.l	-(sp)			; sentinel for end of DirID list
XNextDir
X	clr	Index(a6)		; init index = 0
XNextFile
X	lea	ParmBlk(a6),a0		; a0 = parm block pointer
X	clr.l	ioCompletion(a0)
X	clr.l	ioFileName(a0)
X	move	vRefNum(a6),ioVRefNum(a0)	; set volume
X	move.l	dirID(a6),ioDirID(a0)	; set directory ID
X	lea	NameStr(a6),a1		; a1 = name string buffer pointer
X	move.l	a1,ioFileName(a0)	; set file name pointer
X	addq	#1,Index(a6)		; advance index
X	move	Index(a6),ioFDirIndex(a0)	; set index
X	tst	FSFCBLen		; HFS running?
X	bmi.s	@0			; branch if not
X	_GetCatInfo
X	bra.s	@1
X@0	_GetFileInfo			; MFS, get partial story
X@1	beq.s	NodeKind		; no error, check things out
X	cmp	#fnfErr,d0		; end of directory?
X	bne.s	FCExit			; no, unexpected problem
X	move.l	(sp)+,dirID(a6)		; pop next directory off stack
X	bne.s	NextDir			; branch if there is one
X	bra.s	FCExit			; branch if there isn't one
XNodeKind
X	btst	#ioDirFlg,ioFlAttrib(a0)	; directory?
X	beq.s	CallInspec		; a file, call Inspector
X	move.l	ioDirID(a0),-(sp)	; directory, push on stack
X	bra.s	NextFile		; look for next file
XCallInspec
X	clr	-(sp)			; for returned value
X	pea	ParmBlk(a6)		; param block for inspector
X	move.l	dirID(a6),-(sp)		; pass dirID
X	move.l	Inspec(a6),a0		; address of user function
X	jsr	(a0)			; call inspector
X	tst.b	(sp)+			; time to quit?
X	beq.s	NextFile		; no, keep going
XFCExit
X	unlk	a6
X	move.l	(sp)+,a0		; a0 = return address
X	lea	ArgsSz(sp),sp		; pop arguments
X	jmp	(a0)			; return
X	dc.b	'FCensus'
X	.align	2
SHAR_EOF
exit
---