CALLDOS	MACRO
	move.l	DosBase(pc),a6
	jsr	_LVO\1(a6)
	ENDM

CALLEXEC MACRO
	move.l	$4.w,a6
	jsr	_LVO\1(a6)
	ENDM

	include	"df0:include/exec/exec_lib.i"
	include	"df0:include/dos/dos.i"
	include	"df0:include/dos/doshunks.i"
	include	"df0:include/dos/dos_lib.i"

	move.l	sp,StartStack		save initial sp for quick exit

	clr.b	-1(a0,d0.l)		Null terminate command line
	move.l	a0,-(sp)		Save CLI command

	lea	DosName(pc),a1		open dos.library
	CALLEXEC OldOpenLibrary
	tst.l	d0
	beq.s	NoDos
	move.l	d0,DosBase

	CALLDOS	Output			Get CLI output file handle
	move.l	d0,HandleOut

	move.l	(sp)+,a0
	bsr	ParseCLI		CLI call, so parse command line
	beq.s	exit			Bad CLI command ?

	bsr	_main

exit	move.l	FileHandle(pc),d0	Check for open file
	beq.s	.NoCloseFile

	move.l	FileHandle(pc),d1	Free read access on file
	CALLDOS	Close
	clr.l	FileHandle

.NoCloseFile
	move.l	DosBase(pc),a1		Close dos.library
	CALLEXEC CloseLibrary

NoDos	move.l	StartStack(pc),sp
	moveq	#0,d0
	rts


_main	move.l	d0,FileName
	lea	Title(pc),a0
	bsr	printf

	move.l	FileName(pc),d1		Get size of input file
	move.l	#MODE_OLDFILE,d2
	CALLDOS	Open
	move.l	d0,FileHandle
	beq	ErrNoFile
	move.l	d0,d1
	moveq	#OFFSET_END,d3
	moveq	#0,d2
	CALLDOS	Seek		Seek to end of file
	move.l	FileHandle(pc),d1
	moveq	#0,d2
	moveq	#OFFSET_BEGINNING,d3
	CALLDOS	Seek		Seek to beginning of file + retrun file length
	move.l	d0,FileSize


NewHunk	clr.l	HunkNumber
HunkEnd	clr.b	SameHunk

NextHunk
	move.l	FilePos(pc),d0		Check for end of file
	cmp.l	FileSize(pc),d0
	bcc	FileEnd

	bsr	ReadLong
	move.l	d0,d7			save hunk type for later

	move.b	SameHunk(pc),d1
	bne.s	.NoForceMem

	cmp.w	#HUNK_HEADER,d0
	beq.s	.NoForceMem
	cmp.w	#HUNK_UNIT,d0
	beq.s	.NoForceMem
	cmp.w	#HUNK_BREAK,d0
	beq.s	.NoForceMem

	move.l	sp,Stack

	swap	d0
	and.l	#$ffff,d0
	lea	ToChipMsg(pc),a0	check for hunk forced to memory type
	cmp.w	#$4000,d0
	beq.s	.DispHunk
	lea	ToFastMsg(pc),a0
	cmp.w	#$8000,d0
	beq.s	.DispHunk
	lea	BlankMsg(pc),a0	
	tst.w	d0
	beq.s	.DispHunk
	move.l	d0,-(sp)		unknown hunk, so display type
	lea	ForceMsg(pc),a0	
.DispHunk

	move.l	a0,-(sp)		disp 'Hunk 0:' file postion, mem type
	move.l	FilePos(pc),-(sp)
	move.l	HunkNumber(pc),-(sp)
	lea	HunkMsg(pc),a0
	bsr	printf
	move.l	Stack(pc),sp		correct stack

	addq.l	#1,HunkNumber
	st	SameHunk		set new hunk flag

.NoForceMem
	move.l	d7,d0			parse file on hunk type
	cmp.w	#HUNK_UNIT,d0
	beq	HunkUnit
	cmp.w	#HUNK_NAME,d0
	beq	HunkName
	cmp.w	#HUNK_CODE,d0
	beq	HunkCode
	cmp.w	#HUNK_DATA,d0
	beq	HunkData
	cmp.w	#HUNK_BSS,d0
	beq	HunkBss
	cmp.w	#HUNK_RELOC32,d0
	beq	HunkReloc32
	cmp.w	#HUNK_RELOC16,d0
	beq	HunkReloc16
	cmp.w	#HUNK_RELOC8,d0
	beq	HunkReloc8
	cmp.w	#HUNK_EXT,d0
	beq	HunkExt
	cmp.w	#HUNK_SYMBOL,d0
	beq	HunkSymbol
	cmp.w	#HUNK_DEBUG,d0
	beq	HunkDebug
	cmp.w	#HUNK_END,d0
	beq	HunkEnd
	cmp.w	#HUNK_HEADER,d0
	beq	HunkHeader
	cmp.w	#HUNK_OVERLAY,d0
	beq	HunkOverlay
	cmp.w	#HUNK_BREAK,d0
	beq	HunkBreak

	lea	BadHunkMsg(pc),a0	Not an object or executable
	move.l	FilePos(pc),-(sp)	file offset
	move.l	d0,-(sp)		bad HUNK id
	bsr	printf
	bra	exit

FileEnd	lea	EndUnit(pc),a0
	bra	printf

HunkUnit
	lea	HunkUnitMsg(pc),a0
	bra.s	GetName

HunkName
	lea	HunkNameMsg(pc),a0
GetName	bsr	ReadLong
	bsr	ReadD0Longs
	pea	DiskBuffer(pc)
	move.l	a0,-(sp)
	lea	NameMsg(pc),a0
	bsr	printf
	addq.w	#8,sp
	bra	NextHunk

HunkUnitMsg	dc.b	"Progam Unit",0
HunkNameMsg	dc.b	"	Hunk Name",0
CodeMsg		dc.b	"Code",0
DataMsg		dc.b	"Data",0
BssMsg		dc.b	"Bss",0
DebugMsg	dc.b	"Debug",0
	even
HunkDebug
	lea	DebugMsg(pc),a0
	bra.s	HunkCodeData
HunkCode
	lea	CodeMsg(pc),a0
	bra.s	HunkCodeData
HunkData
	lea	DataMsg(pc),a0
HunkCodeData
	bsr	ReadLong
	bsr	SkipD0Longs
BssBit	lsl.l	#2,d0
	move.l	d0,-(sp)
	move.l	a0,-(sp)
	lea	HunkCodeDataMsg(pc),a0
	bsr	printf
	addq.w	#8,sp
	bra	NextHunk

HunkBss	lea	BssMsg(pc),a0
	bsr	ReadLong
	bra.s	BssBit

HunkReloc8
	lea	HunkReloc8Msg(pc),a4
	bra.s	RelocJn
HunkReloc16
	lea	HunkReloc16Msg(pc),a4
	bra.s	RelocJn
HunkReloc32
	lea	HunkReloc32Msg(pc),a4
RelocJn	bsr	ReadLong
	move.l	d0,d1
	beq	NextHunk
	bsr	ReadLong
	move.l	d1,-(sp)		d1 = number of relocs
	move.l	d0,-(sp)		d0 = reference section
	move.l	a4,-(sp)
	lea	HunkRelocMsg(pc),a0
	bsr	printf
	lea	8(sp),sp

	move.l	(sp)+,d0		advance past reloc section
	bsr	SkipD0Longs
	bra.s	HunkReloc32

HunkSymbol
	lea	HunkSymbolMsg(pc),a0
	bra.s	SymCont

HunkExt	lea	HunkExtMsg(pc),a0
SymCont	bsr	printf

NxSymbol
	bsr	ReadLong
	move.l	d0,d1
	beq	NextHunk
	rol.l	#8,d1			d1 = symbol type
	and.l	#$ffffff,d0		d0 = symbol length
	bsr	ReadD0Longs		read symbol name

	cmp.b	#EXT_RES+1,d1
	bcs.s	ExtDefinition
	cmp.b	#EXT_COMMON,d1
	beq.s	ExtCommon
	bsr	ReadLong
	bsr	SkipD0Longs

	move.b	ShowSymbols(pc),d2	display symbol ?
	beq.s	NxSymbol

	moveq	#32,d2			assume 32 bit reference
	cmp.b	#EXT_REF32,d1
	beq.s	.GotSiz
	moveq	#16,d2			assume 16 bit reference
	cmp.b	#EXT_REF16,d1
	beq.s	.GotSiz
	moveq	#8,d2			must be 8 bit reference
.GotSiz	pea	DiskBuffer(pc)		yes
	move.l	d2,-(sp)
	move.l	d0,-(sp)
	lea	ExtRefMsg(pc),a0
	bsr	printf
	lea	12(sp),sp
	bra.s	NxSymbol

ExtCommon
	bsr	ReadLong
	move.l	d0,-(sp)		Size of common block
	bsr	ReadLong
	move.l	d0,-(sp)		Count of references
	bsr	SkipD0Longs
	pea	DiskBuffer(pc)		Symbol name

	lea	ExtCommonMsg(pc),a0
	move.b	ShowSymbols(pc),d0
	beq.s	.NoSyms
	bsr	printf
.NoSyms	lea	12(sp),sp
	bra.s	NxSymbol

ExtDefinition
	bsr	ReadLong
	move.b	ShowSymbols(pc),d1	Show symbol ?
	beq	NxSymbol

	move.l	d0,-(sp)		Symbol value
	pea	DiskBuffer(pc)
	lea	ExtDefintionMsg(pc),a0
	bsr	printf
	addq.w	#8,sp
	bra	NxSymbol


HunkHeader
	lea	HunkHeaderMsg(pc),a0
	bsr	printf
.NxLib	bsr	ReadLong
	tst.l	d0
	beq.s	.EndLibs
	bsr	ReadD0Longs
	pea	DiskBuffer(pc)
	lea	LibNameMsg(pc),a0
	bsr	printf
	addq.w	#4,sp
	bra.s	.NxLib

.EndLibs
	bsr	ReadLong
	move.l	d0,-(sp)
	lea	TableMsg(pc),a0
	bsr	printf
	bsr	ReadLong
	move.l	d0,HunkNumber
	bsr	ReadLong
	move.l	d0,-(sp)		d0 = Last hunk number

	sub.l	HunkNumber(pc),d0
	addq.l	#1,d0			d0 = number of hunks

	bsr	SkipD0Longs

	move.l	HunkNumber(pc),-(sp)
	lea	TableRange(pc),a0
	bsr	printf
	lea	12(sp),sp
	bra	NextHunk

HunkOverlay
	bsr	ReadLong
	move.l	d0,d1
	bsr	ReadLong
	subq.l	#2,d0
	move.l	d0,-(sp)
	move.l	d1,-(sp)
	move.l	d1,d0
	bsr	SkipD0Longs
	lea	HunkOverlayMsg(pc),a0
	bsr	printf
	addq.w	#8,sp
	bra	NewHunk

HunkBreak
	lea	HunkBreakMsg(pc),a0
	bsr	printf
	bra	NewHunk

************	Execute given CLI commands (a0) = line to parse
* ParseCLI *
************	returns d0=ptr to command name. d0=0, bad CLI command
ParseCLI
	move.l	a0,a1

.NxChr	move.b	(a1)+,d0		Parse CLI command
	beq.s	BadCLI
	cmp.b	#" ",d0			Ignore spaces
	beq.s	.NxChr
	cmp.b	#"	",d0
	beq.s	.NxChr
	cmp.b	#"-",d0
	beq.s	.Option
	lea	-1(a1),a0		a0 = start of filename

.ToEnd	move.b	(a1)+,d0		search for next space & null terminate
	beq.s	.EndTx
	cmp.b	#" ",d0
	beq.s	.EndTx
	cmp.b	#"	",d0
	bne.s	.ToEnd
.EndTx	clr.b	-(a1)
	move.l	a0,d0
	rts

.Option	move.b	(a1)+,d0
	cmp.b	#" ",d0
	beq.s	.NxChr
	cmp.b	#"	",d0
	beq.s	.NxChr
	cmp.b	#"s",d0
	bne.s	BadCLI
	st	ShowSymbols
	bra.s	.Option

UnknownOpt
	move.l	d0,-(sp)
	lea	BadOptMsg(pc),a0
	bsr	printf
	addq.w	#4,sp
BadCLI	lea	BadCLIMsg(pc),a0
	bsr	printf

	moveq	#0,d0			exit - error
	rts

**************	Check whether ctrl + C has been hit - quits program if so
* CheckCTRLc *
**************
CheckCTRLc
	move.l	a0,-(sp)
	moveq	#0,d0
	moveq	#0,d1
	CALLEXEC SetSignal
	and.l	#SIGBREAKF_CTRL_C,d0
	bne.s	.CTRLcHit
	move.l	(sp)+,a0
	rts
.CTRLcHit
	bsr.s	ResetCTRLc
	lea	BreakMsg(pc),a0
	bsr	print
	bra	exit

**************	Reset the CTRL + C pressed flag
* ResetCTRLc *
**************
ResetCTRLc
	moveq	#0,d0
	move.l	#SIGBREAKF_CTRL_C,d1
	CALLEXEC SetSignal
	rts

*********  Sends string (a0), (a3-a0-1) bytes long to the screen
* Write *
*********
Write	move.l	a0,d2
	move.l	a3,d3
	sub.l	a0,d3
	subq.l	#1,d3
	move.l	HandleOut(pc),d1
	CALLDOS	Write
	rts

************ writes character d0 to screen
* printchr *
************
printchr
	move.l	a3,-(sp)
	lea	PrintBuffer(pc),a0
	move.l	a0,a3
	move.b	d0,(a3)+
	clr.b	(a3)+
	bsr	Write
	move.l	(sp)+,a3
	rts

************ converts d0 to hexadecimal ascii chars & displays them
* printhex *
************
printhex
	moveq	#0,d3		d3 = 0, ignore leading spaces
	move.l	a3,-(sp)
	lea	PrintBuffer(pc),a0
	move.l	a0,a3
	moveq	#7,d1
.DoHex	rol.l	#4,d0
	move.l	d0,d2
	and.l	#$f,d2
	bne.s	.PrtChr
	tst.w	d3		got a zero to print, so check if leading 0
	beq.s	.NoChr
.PrtChr	moveq	#-1,d3
	move.b	Hex2Ascii(pc,d2.w),(a3)+
.NoChr	dbra	d1,.DoHex

	tst.w	d3		check for number = 0
	bne.s	.NumNot0
	move.b	#"0",(a3)+
.NumNot0
	clr.b	(a3)+
	bsr.s	Write
	move.l	(sp)+,a3
	rts
Hex2Ascii	dc.b	"0123456789ABCDEF"
PrintBuffer	ds.b	20

nums	dc.l	100000000,10000000,1000000,100000,10000,1000,100,10,1,-1

************	writes number d0 to screen leading zeros are omitted
* printdec *
************
printdec
	movem.l	a3/d6/d7,-(sp)
	lea	PrintBuffer(pc),a3

	moveq	#0,d7			d7 = 1, include zeros
	lea	nums(pc),a0

NextDivisor
	move.l	(a0)+,d1
	bmi.s	NumberDone

	moveq	#"0",d6
CompareAgain
	cmp.l	d1,d0
	blt.s	NoSubtract
	addq.w	#1,d6
	sub.l	d1,d0
	moveq	#1,d7
	bra.s	CompareAgain
NoSubtract
	tst.w	d7
	beq.s	NextDivisor
	move.b	d6,(a3)+		Add digit to display buffer
	bra.s	NextDivisor
NumberDone
	tst.w	d7
	bne.s	NumberNot0
	move.b	#"0",(a3)+
NumberNot0
	clr.b	(a3)+
	lea	PrintBuffer(pc),a0
	bsr	Write
	movem.l	(sp)+,a3/d6/d7
	rts

NumberBuffer	ds.b	10


**********  writes string (a0) to screen. Parameters need to be pushed onto
* printf * the stack in the reverse order of usage
**********
printf	bsr	CheckCTRLc
	lea	4(a7),a4	a4 points to first parameter
print	move.l	a0,a3
.ScanTx	move.b	(a3)+,d0	search for end of line, or parameter
	beq	Write
	cmp.b	#"%",d0
	bne.s	.ScanTx
	bsr	Write
	move.b	(a3)+,d0	d0 = printf parameter command
	move.l	a3,a0
	cmp.b	#"%",d0
	bne.s	.NotPct
	subq.w	#1,a0
	bra.s	.ScanTx
.NotPct	cmp.b	#"c",d0
	bne.s	.NotChr
	move.l	(a4)+,d0	%c - write character to screen
	bsr	printchr
	move.l	a3,a0
	bra.s	.ScanTx
.NotChr	cmp.b	#"d",d0
	bne.s	.NotDec
	move.l	(a4)+,d0	%d - write decimal number to screen
	bsr	printdec
	move.l	a3,a0
	bra.s	.ScanTx
.NotDec	cmp.b	#"s",d0
	bne.s	.NotStr
	move.l	a3,-(sp)	%s - write string to screen
	move.l	(a4)+,a0
	bsr	print
	move.l	(sp)+,a3
	move.l	a3,a0
	bra.s	.ScanTx
.NotStr	cmp.b	#"x",d0		%x - write hexadecimal
	bne	Write
	move.l	(a4)+,d0
	bsr	printhex
	move.l	a3,a0
	bra.s	.ScanTx

ErrNoFile
	lea	NoFileMsg(pc),a0
	move.l	FileName(pc),-(sp)
	bsr	printf
	addq.w	#4,sp
	bra	exit
ErrNoMem
	lea	NoMemMsg(pc),a0
ErrJn	bsr	printf
	bra	exit

ErrRead	lea	BadReadMsg(pc),a0
	bra.s	ErrJn

************	Reads in a long word from file, returns (d0)
* ReadLong *
************
ReadLong
	movem.l	d1-d3/a0/a1,-(sp)	save regs
	move.l	FileHandle(pc),d1
	move.l	#.Buffer,d2
	moveq	#4,d3
	CALLDOS	Read
	cmp.l	#4,d0			read in 4 bytes ?
	bne	ErrRead
	move.l	.Buffer(pc),d0
	addq.l	#4,FilePos

	movem.l	(sp)+,d1-d3/a0/a1	restore regs
	rts
.Buffer	dc.l	0

***************	Reads in d0 long word from file, data in DiskBuffer onwards
* ReadD0Longs *
***************
ReadD0Longs
	movem.l	d1-d3/a0/a1,-(sp)	save regs
	lea	DiskBuffer(pc),a0
	lsl.l	#2,d0
	clr.b	0(a0,d0.w)		Null terminate data to read in
	move.l	d0,-(sp)
	add.l	d0,FilePos		advance file position

	move.l	FileHandle(pc),d1
	move.l	#DiskBuffer,d2
	move.l	d0,d3
	CALLDOS	Read
	cmp.l	(sp)+,d0		check number of bytes read in
	bne	ErrRead
	movem.l	(sp)+,d1-d3/a0/a1	restore regs
	rts

***************	Skips D0 long words past current file point
* SkipD0Longs *
***************
SkipD0Longs
	movem.l	d0-d3/a0/a1,-(sp)
	move.l	FileHandle(pc),d1
	move.l	d0,d2
	lsl.l	#2,d2
	add.l	d2,FilePos		advance file position
	moveq	#OFFSET_CURRENT,d3
	CALLDOS	Seek
	cmp.l	#-1,d0
	beq	ErrRead
	movem.l	(sp)+,d0-d3/a0/a1
	rts

Title		dc.b	"Object dump utility V1.0 (C) 1993 Justin Leck",10,10,0
BadOptMsg	dc.b	"Unknown option %c",10,0
BadCLIMsg	dc.b	"USAGE:  Hunk [-s] <executable/object file>",10,10,0
BadReadMsg	dc.b	"Error reading file.",10,10,0
NoFileMsg	dc.b	"Can't read file '%s'.",10,10,0
NoMemMsg	dc.b	"Not enough memory",10,10,0
BreakMsg	dc.b	10,"*** BREAK ***",10,0
DosName		DOSNAME
HunkMsg		dc.b	"Hunk %d:    %x %s",10,0
BadHunkMsg	dc.b	"Funny code: %x @ %x",10,0
ForceMsg	dc.b	"** Hunk forcing type $%x **"
BlankMsg	dc.b	0
ToChipMsg	dc.b	"** Hunk forced to chip memory **",0
ToFastMsg	dc.b	"** Hunk forced to fast memory **",0

NameMsg		dc.b	"%s - <%s>",10,0

HunkCodeDataMsg	dc.b	"	%s block %d bytes long.",10,0
HunkReloc8Msg	dc.b	"8",0
HunkReloc16Msg	dc.b	"16",0
HunkReloc32Msg	dc.b	"32",0
HunkRelocMsg	dc.b	"	Reloc %s for hunk %d with %d refs.",10,0
HunkSymbolMsg	dc.b	"	Symbol table block.",10,0
HunkExtMsg	dc.b	"	External symbol block.",10,0
ExtRefMsg	dc.b	"	  %d %d bit refs of <%s>",10,0
ExtCommonMsg	dc.b	"	  <%s> (%d refs) common size = %d",10,0
ExtDefintionMsg	dc.b	"	  %s = $%x",10,0
EndUnit		dc.b	"End of object dump.",10,0
HunkHeaderMsg	dc.b	"Executable File",10,0
TableMsg	dc.b	"	Table contains %d Hunks",10,0
TableRange	dc.b	"	   First Hunk = %d, Last hunk = %d",10,0
LibNameMsg	dc.b	"	Library - <%s>",10,0
HunkOverlayMsg	dc.b	"Hunk Overlay",10
		dc.b	"	Table size is %d words.",10
		dc.b	"	Max number of overlay table uses is %d",10,0
HunkBreakMsg	dc.b	"Hunk Break",10,0


StartStack	dc.l	0
Stack		dc.l	0	value of stack before a bsr printf
DosBase		dc.l	0
HandleOut	dc.l	0
FileName	dc.l	0
FileHandle	dc.l	0
FilePos		dc.l	0
FileSize	dc.l	0
DiskBuffer	ds.b	256	256 bytes for symbol names etc

HunkNumber	dc.l	0
SameHunk	dc.b	0	0 = new hunk, -1= same hunk number
ShowSymbols	dc.b	0	0 = don't, !=0, show symbols

