[net.micro.amiga] unhunk-ing and relocating Amiga executables

eric@chronon.UUCP (05/03/86)

A while ago in order to get something else done (which hopefully will
be commercially available soon...) I needed a tool that processed
the Amiga "hunk" loadfile format, performing the necessary relocation
and otherwise de-hunking the file.  I did a very quick and very dirty
program that got my job done.  I grabbed the CVT Amiga->ST conversion
program by Landon Dyer which recently floated by, and used parts of it
to make mine clearer.  The result, "unhunk", follows.

Features:
	1) Collects code, data, and bss hunks together
	2) Allows individual specification of code, data, and bss origins
	   (which default to text at 0, data immediately following, bss
	   after that, with data & bss rounded to next longword)
	3) Generates binary file with format reminiscent of a.out
	4) Output easily processed by separate program to produce "S-records"
	   suitable for downloading to PROM programmer or development system


In response to requests at the the last BADGE (Bay area Amiga
Developers' Group [E], talk about reaching for an acronym!) I have
added the capability to independently set the origins of the text,
data, and bss segments.  This makes it possible to use the Amiga C
compiler, assembler, and linker to generate 68000 code which may be
burned into ROM/PROM, turning the Amiga into a 68000 cross-development
system (of course, the target 68000 system can't make use of any
Amiga-specific goodies, but generic C code short of Amiga-specific
goodies (or even stdio) could be OK).  I whipped up a program which
takes the output of 'unhunk' and generates Motorola-style S-records,
such as are accepted by many PROM programmers.  This program (dl.c) can
be used as a model for downloading other formats, such as Intel-style
':'-records.

All the usual caveats apply to generating ROMable code, including
avoidance of initialized data...  Basically, to do this correctly means
NEVER using initialized data in your code, ALWAYS specifically initializing
variables to constants in the code, and origining the DATA segment with
your CODE in ROM; you want the DATA segment to have compiler-generated
constants, and NONE of your variables, which should all be in the BSS
segment which you point at RAM.

I have tested this package only with the Lattice 3.03 C compiler;
as far as I know I have avoided dependencies on that compiler (size of
ints and such), but I am using some runtime library routines which may
not be supported by Aztec C (string to decimal/hex conversion, for
example).  As it happens, I would be delighted to discover that the
Manx compiler runtime routine correctly converts an ASCII string
to binary using hexadecimal/decimal/octal conversion, as the Lattice
strtol() is supposed to...

Following are 10 files:
	unhunk.c
	dohunk.c
	convert.c
	binfio.c
	longio.c
	convert.h
	hunk.h
	bin.out.h
	dl.c
	dbugstubs.h

The files convert.c, binfio.c, longio.c, and convert.h are adapted
from Landon Dyer's CVT posting a couple weeks ago.  The binary file
format is defined in bin.out.h, and the separate program in dl.c can
be used to translate that binary file into ASCII S-records for downloading.

Have fun!
----------Cut here--------------------------snip,snip---------->%--
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	bin.out.h
#	binfio.c
#	convert.c
#	convert.h
#	dbugstubs.h
#	dl.c
#	dohunk.c
#	hunk.h
#	longio.c
#	unhunk.c
# This archive created: Thu May  1 20:34:35 1986
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'bin.out.h'" '(1008 characters)'
if test -f 'bin.out.h'
then
	echo shar: "will not over-write existing file 'bin.out.h'"
else
cat << \Stunky!Fluff > 'bin.out.h'
/*
 *		bin.out.h      12 Mar 86    edb
 *      definition of simple memory-image file format similar
 *      in spirit to a.out on UNIX systems
 *		Copyright 1986 Eric D. Black
 */


/*
 * This header is at the very beginning of the file
 */

struct bin {
	long	b_magic;	/* magic number, defined below */
	long	b_text;		/* size of text segment in bytes */
	long	b_data;		/* size of data segment in bytes */
	long	b_bss;		/* size of bss segment in bytes */
	long	b_txorg;	/* base address of text segment in memory */
	long	b_dtorg;	/* base address of data segment in memory */
	long	b_bsorg;	/* base address of bss segment in memory */
	long	b_entry;	/* entry point offset in text segment */
	long	b_rsrv[8];	/* reserved for expansion */
};


/*
 * b_text bytes of text segment follow, then b_data bytes
 * of initialized data
 * If the data segment has to be rounded up to a longword boundary,
 * the 1-3 bytes of pad must have been added into the b_text byte count!
 */

#define BMAGIC 0407		/* why not? */
Stunky!Fluff
if test 1008 -ne "`wc -c < 'bin.out.h'`"
then
	echo shar: "error transmitting 'bin.out.h'" '(should have been 1008 characters)'
fi
fi
echo shar: "extracting 'binfio.c'" '(1260 characters)'
if test -f 'binfio.c'
then
	echo shar: "will not over-write existing file 'binfio.c'"
else
cat << \Stunky!Fluff > 'binfio.c'
/*
 * binfio.h     Copyright 1985   Landon M. Dyer
 *
 * Minor mods for Amiga, DBUG macros    19Apr86  edb
 */

#include <stdio.h>
#include "convert.h"

#ifdef DBUG
#include <local/dbug.h>
#else
#include "dbugstubs.h"
#endif

#define READ    0
#define WRITE   1

ebinopen(name, mode)
char *name;
int mode;
{
        int fn;

		DBUG_ENTER("ebinopen");

        if((fn = binopen(name, mode)) != -1)
			DBUG_RETURN(fn);
        fprintf(stderr, "Cannot %s: %s\n",
                mode == 1 ? "create" : "open",
                name);
        exit(1);
		/*NOTREACHED*/
		DBUG_RETURN(-1);
}


binopen(name, mode)
char *name;
int mode;
{
		int retval;

		DBUG_ENTER("binopen");
#if MACHINE == VAXVMS
        if(mode == WRITE)
			retval = creat(name, 0666);
        else
			retval = open(name, mode);
#endif

#if MACHINE == MSDOS
#define UNCOOKED 0x8000         /* pure binary i/o */
        if(mode == WRITE)
			retval = creat(name, 0666 | UNCOOKED);
        else
			retval = open(name, mode | UNCOOKED);
#endif

#if MACHINE == Amiga
		if(mode == WRITE)
			retval = creat(name, 0666);
		else
			retval = open(name, mode);
#endif

#if MACHINE == UNIX42
))))) force-compiler-error
#endif

#if MACHINE == SYSV
))))) force-compiler-error
#endif

		DBUG_RETURN(retval);
}
Stunky!Fluff
if test 1260 -ne "`wc -c < 'binfio.c'`"
then
	echo shar: "error transmitting 'binfio.c'" '(should have been 1260 characters)'
fi
fi
echo shar: "extracting 'convert.c'" '(12492 characters)'
if test -f 'convert.c'
then
	echo shar: "will not over-write existing file 'convert.c'"
else
cat << \Stunky!Fluff > 'convert.c'
/*
 * convert.c - convert AmigaDOS "hunk"-format load file to
 *             memory image similar to a.out format
 *             Based on CVT Amiga->ST program
 *             which is Copyright (C) 1985 Landon M. Dyer.
 *
 *             Changes to CVT and everything new is Copyright 1986
 *             by Eric D. Black.  Permission is given to redistribute
 *             this program and its source code subject to the
 *             restrictions given in the file "unhunk.c"
 *
 */

#include <stdio.h>
#include "convert.h"
#include "hunk.h"
#include "bin.out.h"

#ifdef DBUG
#include <local/dbug.h>
#else
#include "dbugstubs.h"
#endif


Hinfo *ahinfo();


/* hunk information */
Hinfo **hunk;           /* -> vector of ptrs to Hinfo structs */
Hinfo *firsthunk;       /* -> first hunk */
int nhunks;             /* #hunks in input file */
int curhunk;            /* current hunk# */
int hvalid;             /* state variable (to bump curhunk) */
long filpos;            /* position in input file */
long siz[3];            /* segment sizes */
long maxhunk;			/* size of biggest hunk found */
char *hunkbuf;			/* ptr to buffer for doing hunk relocation */
int curtype;			/* current hunk type: 0=Code, 1=Data, 2=BSS */
char *secname[] = {
	"CODE", "DATA", "BSS "
	};

/*
 * Macro to bump address up to next longword boundary
 */
#define ROUNDLONG(a) ((a + 3) & 0xfffffffc);


/*
 * Convert AMIG* binary loadfile to memory image file similar to a.out
 */
convert(ifd, ofd)
int ifd, ofd;
{
	DBUG_ENTER("convert");

    /* init globals */
    hunk = (Hinfo **)NULL;
    firsthunk = (Hinfo *)NULL;
    hvalid = nhunks = 0;
	curhunk = -1;
    filpos = 0L;
	maxhunk = 0L;

    pass1(ifd);			/* gather info on hunks, see what we have to do */
    if (curhunk < nhunks)
        panic("Bugcheck: not enough hunks in input body.");

    bind();				/* decide where each hunk will go */
    output(ifd, ofd);	/* spit out hunks in desired order */
    release();			/* free memory */

	DBUG_RETURN(0);
}


/*
 * Parse hunks in AMIG* binary loadfile,
 * gather information about it.
 *
 * Add error checks, handle symbol records   19Apr86 edb
 * Handle extra HUNK_ENDs which alink sometimes produces  20Apr86 edb
 */
pass1(ifd)
int ifd;
{
    long lw;
    Hinfo *h;

	DBUG_ENTER("pass1");

    for(;;)
    {
        if (readlong(ifd, &lw) == EOF) {
			DBUG_3("hunk", "Got EOF", 0);
            break;
		}

        switch ((int)lw)
        {
            case HUNK_UNIT:
            case HUNK_NAME:
                DBUG_3("hunk","%s",(lw==HUNK_UNIT)?"HUNK_UNIT":"HUNK_NAME");
                getlong(ifd, &lw);
                skip(ifd, lw);
                break;

            case HUNK_CODE:
				DBUG_2("hunk", "HUNK_CODE");
                chkhunk();
				curtype = TEXT;
                h = hunk[curhunk];
                getlong(ifd, &lw);              /* get size (in longs) */
				if (lw != h->hsize) {
					fprintf(stderr,
					    "Code hunk %d size %ld doesn't match header (%ld)\n",
						h->hunkno, lw, h->hsize);
					errflg++;
				}
                lw *= 4;
				if (maxhunk < lw) {
					maxhunk = lw;
					DBUG_3("hunk", "maxhunk=%ld", maxhunk);
				}
                h->hsize = lw;
                h->hpos = filpos;
                h->htype = TEXT;
                skip(ifd, lw);
				if (printing)
					printf("Hunk %d, type %s, size %ld\n",
						h->hunkno, secname[h->htype], h->hsize);
                DBUG_EXECUTE("dump", dumphinfo(h); );
                break;

            case HUNK_DATA:
				DBUG_2("hunk", "HUNK_DATA");
                chkhunk();
				curtype = DATA;
                h = hunk[curhunk];
                getlong(ifd, &lw);              /* get size (in longs) */
				if (lw != h->hsize) {
					fprintf(stderr,
					    "Data hunk %d size %ld doesn't match header (%ld)\n",
						h->hunkno, lw, h->hsize);
					errflg++;
				}
                lw *= 4;
				if (maxhunk < lw) {
					maxhunk = lw;
					DBUG_3("hunk", "maxhunk=%ld", maxhunk);
				}
                h->hsize = lw;
                h->hpos = filpos;
                h->htype = DATA;
                skip(ifd, lw);
				if (printing)
					printf("Hunk %d, type %s, size %ld\n",
						h->hunkno, secname[h->htype], h->hsize);
                DBUG_EXECUTE("dump", dumphinfo(h); );
                break;

            case HUNK_BSS:
				DBUG_2("hunk", "HUNK_BSS");
                chkhunk();
				curtype = BSS;
                h = hunk[curhunk];
                getlong(ifd, &lw);              /* get size (in longs) */
				if (lw != h->hsize) {
					fprintf(stderr,
					    "BSS hunk %d size %ld doesn't match header (%ld)\n",
						h->hunkno, lw, h->hsize);
					errflg++;
				}
                h->hsize = lw * 4;
                h->htype = BSS;
				if (printing)
					printf("Hunk %d, type %s, size %ld\n",
						h->hunkno, secname[h->htype], h->hsize);
                DBUG_EXECUTE("dump", dumphinfo(h); );
                break;

            case HUNK_RELOC32:
				DBUG_2("hunk", "HUNK_RELOC32");
                h = hunk[curhunk];
				if (!h->hrel) {
					h->hrel = filpos;
					DBUG_4("hunk", "hunk %d relinfo at %ld",curhunk,filpos);
				}
				for (;;) {				/* skip past reloc records */
					getlong(ifd, &lw);	/* # of offsets */
					DBUG_3("hunk", "%ld offsets", lw);
					if (!lw)
						break;			/* done */
					skip(ifd, (lw+1) * 4);
				}
                break;

            case HUNK_RELOC16:
				DBUG_2("hunk", "HUNK_RELOC16");
                panic("16-bit relocation not supported.");
                break;

            case HUNK_RELOC8:
				DBUG_2("hunk", "HUNK_RELOC8");
                panic("8-bit relocation not supported.");
                break;

            case HUNK_EXT:
				DBUG_2("hunk", "HUNK_EXT");
                panic("External symbols not supported.");
                break;

            case HUNK_SYMBOL:		/* ignore symbol records */
				DBUG_2("hunk", "HUNK_SYMBOL");
				do {
					getlong(ifd, &lw);
					DBUG_3("hunk", "typ/namlen=0x%lx", lw);
					if (lw)
						skip(ifd, ((lw & 0xffffffL) + 1) * 4);
				} while (lw);
                break;

            case HUNK_DEBUG:		/* ignore debug records */
				DBUG_2("hunk", "HUNK_DEBUG");
                getlong(ifd, &lw);      /* get size (in longs) */
                lw *= 4;
                skip(ifd, lw);
                break;

            case HUNK_END:
				DBUG_2("hunk", "HUNK_END");
                if (hvalid) {
                    hvalid = 0;
                    DBUG_3("dump", "end of hunk %d\n", curhunk);
				} else
					printf("Extra HUNK_END for %s hunk %d, ignored\n",
						(curtype>=0 && curtype<=2) ? secname[curtype]:"???",
						curhunk);
                break;

            case HUNK_HEADER:
				DBUG_2("hunk", "HUNK_HEADER");
                header(ifd);
                break;

            case HUNK_OVERLAY:
				DBUG_2("hunk", "HUNK_OVERLAY");
                panic("Overlays not supported.");
                break;

            case HUNK_BREAK:
				DBUG_2("hunk", "HUNK_BREAK");
                panic("Breaks (overlays) not supported.");
                break;

			default:
				DBUG_3("hunk", "Unknown hunk type: 0x%lx", lw);
				panic("Out of phase, lost in space...");
        }
    }
	curhunk++;			/* boundary adjustment */
	DBUG_4("hunk","%d hunks expected, %d found", nhunks, curhunk);
	DBUG_RETURN(0);
}


/*
 * Sanity check about hunk adjacency (which may not be a
 * problem) and hunk number range.
 *
 * Remove panic for (presumably) missing HUNK_END   23Apr86  edb
 */
chkhunk()
{
	DBUG_ENTER("chkhunk");
#if 0
    if (hvalid)
        panic("Bugcheck: two adjacent hunks w/o HUNK_END!");
#endif
	curhunk++;		/* bump hunk# here in case of extra HUNK_ENDs */
    if (curhunk >= nhunks)
        panic("Bugcheck: too many hunks!");
    hvalid = 1;
	DBUG_RETURN(0);
}


/*
 * Read hunk header,
 * get info for global vars.
 *
 */
header(fd)
int fd;
{
    long lw;
    long htabsize, firsthunk, lasthunk;
    unsigned int j;

	DBUG_ENTER("header");

    /*
     * Skip library names.
     */
    for (;;)
    {
        getlong(fd, &lw);
		DBUG_3("hunk", "namlen=%d", lw);
        if (!lw) break;
        skip(fd, lw*4);
    }

    /* more random header info */
    getlong(fd, &htabsize);
    getlong(fd, &firsthunk);
    getlong(fd, &lasthunk);
    DBUG_5("hunk", "htabsize = %ld\nfirsthunk = %ld\nlasthunk = %ld\n", htabsize, firsthunk, lasthunk);

    /* alloc space for hunk database */
    nhunks = (unsigned)(lasthunk - firsthunk + 1);
	j = nhunks * sizeof(*hunk);
	DBUG_4("mem", "grabbing %ld bytes for %d hunks", j, nhunks);
    hunk = (Hinfo **)malloc(j);
    if (hunk == NULL)
        allerr();

    for (j = 0; j < nhunks; ++j)
    {
        hunk[j] = ahinfo(j);
        hunk[j]->hunkno = j;
        getlong(fd, &hunk[j]->hsize);
        DBUG_5("dump", "%d hsize = %ld ($%lx)\n", j, hunk[j]->hsize, hunk[j]->hsize);
    }

	DBUG_RETURN(0);
}


/*
 * Compute hunk order and starting addresses.
 * 
 * Changed for unhunk  19Apr86  edb
 * We have three bases to work with: text, data, bss;
 * each may be specified individually, otherwise text is assumed to
 * start at zero, data immediately follows text (padded to longword),
 * and bss immediately follows data (padded to longword).
 */
bind()
{
    int typ, hnk;
    long addr;
    Hinfo *hptr;

	DBUG_ENTER("bind");

    hptr = firsthunk;
	if (printing)
		printf("Assigning hunk load addresses:\n");
    for (typ = TEXT; typ <= BSS; ++typ) {	/* text, then data, then bss */
    	addr = origin[typ];
        siz[typ] = 0L;
        for (hnk = 0; hnk < nhunks; ++hnk)
            if (hunk[hnk]->htype == typ) {
                if (firsthunk == (Hinfo *)NULL)
                    hptr = firsthunk = hunk[hnk];
                    else {			/* list of each type in order found */
                        hptr->hnext = hunk[hnk];
                        hptr = hunk[hnk];
                    }
                siz[typ] += hptr->hsize;
                hptr->haddr = addr;
                addr += hptr->hsize;
				if(printing)
					printf("Hunk %d (%s) load address 0x%lx\n",
						hnk, secname[hptr->htype], hptr->haddr);
                DBUG_5("dump", "%s hunk[%d]->haddr = $%lx\n",secname[typ],hnk,hptr->haddr);
            }
		/*
		 * if not otherwise specified, round data and bss segments
		 * each up to longword boundary
		 */
		if (!orgspec[DATA]) {
			/*
			 * charge pad bytes to text segment
			 */
			siz[TEXT] = ROUNDLONG(siz[TEXT]);
			origin[DATA] = origin[TEXT] + siz[TEXT];
		}
		if (!orgspec[BSS]) {
			siz[DATA] = ROUNDLONG(siz[DATA]);
			origin[BSS] = origin[DATA] + siz[DATA];
		}

    }

	printf("Section    Origin      Size(bytes)\n");
	for(typ=TEXT; typ<=BSS; typ++)
		printf(" %s      0x%-6lx      %ld (0x%lx)\n",
			secname[typ], origin[typ], siz[typ], siz[typ]);

	DBUG_RETURN(0);
}



/*
 * Allocate (and initialize) a Hinfo node.
 *
 * use hrel as filepos to re-read reloc info  20Apr86 edb
 */
Hinfo *ahinfo(hnum)
int hnum;
{
    Hinfo *h;

	DBUG_ENTER("ahinfo");

    if (hnum >= nhunks)
        panic("curhunk >= nhunks, too many hunks!");

	DBUG_4("mem","malloc'ing %d bytes for hunk %d",sizeof(Hinfo),hnum);
    if ((h = (Hinfo *)malloc(sizeof(Hinfo))) == NULL)
        allerr();
    h->hsize = 0L;
    h->hpos = 0L;
    h->haddr = 0L;
    h->hrsize = 0L;
    h->htype = -1;
    h->hrel = 0L;
    h->hnext = (Hinfo *)NULL;

    DBUG_RETURN(h);
}


/*
 * Release memory used by hunk database.
 */
release()
{
    int i;

	DBUG_ENTER("release");

    for (i = 0; i < nhunks; ++i)
    {
		DBUG_3("mem", "freeing node at 0x%x", hunk[i]);
        free(hunk[i]);
    }
	DBUG_2("mem", "freeing hunk");
    free(hunk);
	DBUG_RETURN(0);
}


/*
 * Skip some of the input file
 */
skip(fd, count)
int fd;
long count;
{
	DBUG_ENTER("skip");
	DBUG_3("hunk", "skipping %ld bytes", count);
    filpos += count;
    lseek(fd, count, 1);
	DBUG_RETURN(0);
}


/*
 * Out of memory (malloc() didn't work);
 * complain and die.
 */
allerr()
{
	DBUG_ENTER("allerr");
    panic("Allocation failure, heap exhausted, I give up!\n");
	/*NOTREACHED*/
	DBUG_RETURN(0);
}


/*
 * Print information about an Hinfo node.
 */
dumphinfo(h)
Hinfo *h;
{
	DBUG_ENTER("dumphinfo");
    printf("hsize = %ld ($%lx), hpos = %ld, haddr = %ld ($%lx)\n",
                h->hsize, h->hsize, h->hpos, h->haddr, h->haddr);
    printf("htype = %s ", secname[h->htype]);
    printf("hrel = %ld, hnext = $%lx\n",
                h->hrel, (long)h->hnext);
	DBUG_RETURN(0);
}

/* cvt2long() moved to longio.c to help localize machine dependencies  edb*/
Stunky!Fluff
if test 12492 -ne "`wc -c < 'convert.c'`"
then
	echo shar: "error transmitting 'convert.c'" '(should have been 12492 characters)'
fi
fi
echo shar: "extracting 'convert.h'" '(1644 characters)'
if test -f 'convert.h'
then
	echo shar: "will not over-write existing file 'convert.h'"
else
cat << \Stunky!Fluff > 'convert.h'
/* convert.h    19 Apr 86    edb */

/* 
 * Copyright (C) 1986 by Eric D. Black and 1985 Landon M. Dyer.
 * Based on the CVT Amiga->ST conversion program by Landon Dyer.
 * Permission is granted to redistribute this program and its
 * source code subject to the restrictions given in the file "unhunk.c"
 */

#define BUFFERSIZE      0x4000
#define OK              0
#define ERROR           (-1)

#define MSDOS   1
#define VAXVMS  2
#define UNIX42  3
#define SYSV    4
#define Amiga	5

/* type of machine doing the conversion; target is always assumed
 * to be 68000 processor, source is assumed to be AmigaDOS hunk-format
 * 68000 code...
 */
#define MACHINE Amiga


/*
 * Hunk types.
 */
#define TEXT    0
#define DATA    1
#define BSS     2

extern long origin[];		/* origin for each type */
extern int orgspec[];		/* origin for each type specified on cmd line */
extern long entrypnt;		/* entry point specified on cmd line */
extern int printing;		/* !=0 if printing extra messages */extern int errflg;			/* count of errors/inconsistencies found */


/*
 * Information about hunks:
 *
 * hrel is now filepos of start of reloc info for hunk   20Apr86 edb
 */
#define Hinfo   struct hinfo
Hinfo {
    long	hsize;			/* hunk size (bytes) */
    long	hpos;			/* position of hunk info in file (or -1L) */
    long	haddr;			/* starting address of hunk */
    long	hrsize;			/* size of relocation information (bytes) */
    int		htype;			/* hunk type (TEXT, DATA, BSS, or -1) */
    int		hunkno;			/* hunk number */
    long	hrel;			/* filepos of start of reloc info for hunk */
    Hinfo	*hnext;			/* -> next hunk in order of saddr (or NULL) */
};
Stunky!Fluff
if test 1644 -ne "`wc -c < 'convert.h'`"
then
	echo shar: "error transmitting 'convert.h'" '(should have been 1644 characters)'
fi
fi
echo shar: "extracting 'dbugstubs.h'" '(1396 characters)'
if test -f 'dbugstubs.h'
then
	echo shar: "will not over-write existing file 'dbugstubs.h'"
else
cat << \Stunky!Fluff > 'dbugstubs.h'

/*
 *  dbugstubs.h   -  derived from dbug.h by Fred Fish
 *
 *  everything real has been deleted, only the stubs remain...  edb
 */


/************************************************************************
 *									*
 *			Copyright (c) 1984, Fred Fish			*
 *			    All Rights Reserved				*
 *									*
 *	This software and/or documentation is released into the		*
 *	public domain for personal, non-commercial use only.		*
 *	Limited rights to use, modify, and redistribute are hereby	*
 *	granted for non-commercial purposes, provided that all		*
 *	copyright notices remain intact and all changes are clearly	*
 *	documented.  The author makes no warranty of any kind with	*
 *	respect to this product and explicitly disclaims any implied	*
 *	warranties of merchantability or fitness for any particular	*
 *	purpose.							*
 *									*
 ************************************************************************
 */

#    define DBUG_ENTER(a1)
#    define DBUG_RETURN(a1) return(a1)
#    define DBUG_VOID_RETURN return
#    define DBUG_EXECUTE(keyword,a1)
#    define DBUG_2(keyword,format)
#    define DBUG_3(keyword,format,a1)
#    define DBUG_4(keyword,format,a1,a2)
#    define DBUG_5(keyword,format,a1,a2,a3)
#    define DBUG_PUSH(a1)
#    define DBUG_POP()
#    define DBUG_PROCESS(a1)
#    define DBUG_FILE (stderr)
#    define DBUG_SETJMP setjmp
#    define DBUG_LONGJMP longjmp
Stunky!Fluff
if test 1396 -ne "`wc -c < 'dbugstubs.h'`"
then
	echo shar: "error transmitting 'dbugstubs.h'" '(should have been 1396 characters)'
fi
fi
echo shar: "extracting 'dl.c'" '(5812 characters)'
if test -f 'dl.c'
then
	echo shar: "will not over-write existing file 'dl.c'"
else
cat << \Stunky!Fluff > 'dl.c'
/*
 * dl.c
 *
 * Convert bin.out file to Motorola S-record text file
 * Copyright (c) 1986  Eric D. Black
 *
 * Usage:
 *		dl [-o oooooo] [-e eeeeee]  binfile [srecfile]
 * where
 *		oooooo is an offset added to to the address of every S-record
 *             (no relocation of addresses in code is done)
 *		eeeeee is the entry point (overrides any found in binfile)
 *		binfile is the binary file in bin.out format
 *		srecfile is the text file to receive S-records, stdout by default
 * addresses oooooo and eeeeee may be in hexadecimal (leading "0x"),
 * octal (leading "0"), otherwise decimal
 */

/*
 * Permission is given to distribute these files and the code they
 * generate, and to modify and/or extend them, providing that:
 *     1) All copyright notices remain intact (you may copyright your
 *        specific changes)
 *     2) All source code accompanies any distribution, including any
 *        changes and/or enhancements you may have made
 *     3) Any changes you make are clearly indicated
 *     4) No direct profit results from that distribution (i.e. you
 *        may not sell this program or anything derived from it, but
 *        you may include it at no charge on a system you sell for profit),
 *        and you may give it away
 *
 */

#include <stdio.h>
#include "bin.out.h"

extern char getopt();
extern char *optarg;
extern int optind;

extern int Enable_Abort;

FILE *infile;
FILE *outfile;

int eflag = 0;
int oflag = 0;
int entrypt = 0;
int offset = 0;

main(argc,argv)
int argc;
char *argv[];
{
char c;

	/*
	 * Process command line using getopt(3)
	 */
    if(argc<2) {
        fprintf(stderr,"Usage: dl [-e xxxx] infile [outfile]\n");
        exit(1);
    }
	while ((c = getopt(argc, argv, "e:o:")) != EOF) {
		switch(c) {
			case 'e':
					entrypt = getnum(optarg);
					eflag++;
					break;
			case 'o':
					offset = getnum(optarg);
					oflag++;
					break;
			default:
					exit(1);	/* error msg is printed by getopt */
		}
	}
	argv += optind;
	argc -= optind;

	/*
	 * Get input, output file names
	 */
    if((infile=fopen(argv[0],"r"))==NULL) {   /* open infile */
       fprintf(stderr,"dl: Can't open %s\n",argv[0]);
       exit(1);
    }
	if (argc>1) {
        if ((outfile = fopen(argv[1],"w")) == NULL) {
                fprintf(stderr,"dl: Can't open %s\n",argv[1]);
                exit(1);
        }
    } else
		outfile = stdout;

	Enable_Abort = 1;

	dofile();

	fclose(infile);
	fclose(outfile);
}

/*
 * Translate input bin.out file to ASCII S-records in output file
 */

#define RECSIZE 32              /* Size of Motorola S-type records */

dofile()
{
struct bin binhdr;
int Saddr;

	/*
	 * get header info
	 */
    if(fread(&binhdr, sizeof(struct bin),1,infile) != 1) {
        fprintf(stderr,"dl: error reading input file\n");
        exit(1);
    }
    if(binhdr.b_magic != BMAGIC) {              /* check magic number */
         fprintf(stderr,"dl: input not proper b.out file\n"); 
         exit(1);
    }

    /*
     * Entry point is:
     *   1) as specified on command line, or
     *   2) as found in input bin.out header (plus offset), or
     *   3) start of text segment (plus offset)
     */
    if (!eflag) {
        entrypt = binhdr.b_entry ? binhdr.b_entry : binhdr.b_text;
		entrypt += offset;
	}

    Saddr = offset;

    /*
     * Output records for TEXT portion
     */
    outbin(infile,Saddr,binhdr.b_text);
    Saddr += binhdr.b_text;    /* adjust output address */

    /*
     * Output records for DATA segment
     */
    outbin(infile,Saddr,binhdr.b_data);
    Saddr += binhdr.b_data;    /* adjust output address */

    /*
     * Output entry point: as in file header,
     * else default to start address
     */
    print_s_rec(7,0,0,entrypt);
}


int checksum;

/*
 * print out one S record of given type
 */
print_s_rec(type,buffer,Dcount,addr)
char *buffer;
int Dcount, addr;
{
         fprintf(outfile,"S%d",type);
	     checksum = 0;
         checkout((char) Dcount+5);
         checkout((char) (addr>>24));
         checkout((char) (addr>>16));
         checkout((char) (addr>>8));
         checkout((char) addr);
         while (Dcount--)
		 	checkout(*buffer++);
         puthex(~(checksum & 0XFF)); 
         fprintf(outfile,"\n");
}

/*
 * output byte as two hex chars, keeping running checksum
 */

checkout(c)
char c;
{
	checksum += c;
	puthex(c);
}


#define hex(c) c>9 ? c+0X37 : c+0X30  /* macro for hex convert */

/*
 * print byte as two hex chars
 */
puthex(b)
char b;
{
char c1,c2;

    c1=(b>>4) & 0XF; c2=b & 0XF;
    c1=hex(c1); c2=hex(c2);
    fprintf(outfile,"%c%c",c1,c2);
}

/*
 * put out records from a buffer, using addr as starting S-record
 * address, for size bytes
 */
outbuf(buffer,addr,size)
char *buffer;
int addr, size;
{
int count,                      /* counts total number of bytes processed*/
    Dcount;                     /* number of bytes in current record */

    for(count=0; count<size; count += RECSIZE) {
        Dcount= (size-count<RECSIZE) ? size-count : RECSIZE;
        print_s_rec(3,buffer,Dcount,addr);
        buffer += Dcount;
        addr += Dcount;
    }
}

/*
 * put out records from a file, reading from current filepos for size bytes,
 * using addr as starting S-record address, for size bytes
 */
outbin(file,addr,size)
FILE *file;
int addr, size;
{
int count,                      /* counts total number of bytes processed*/
    Dcount;                     /* number of bytes in current record */
char buffer[RECSIZE];           /* buffer for data */

    for(count=0; count<size; count += RECSIZE) {
        Dcount= (size-count<RECSIZE) ? size-count : RECSIZE;
        if(fread(buffer,Dcount,1,file) != 1) {
            fprintf(stderr,"Input read error\n");
			exit(1);
		}
        print_s_rec(3,buffer,Dcount,addr);
        addr += Dcount;
    }
}
Stunky!Fluff
if test 5812 -ne "`wc -c < 'dl.c'`"
then
	echo shar: "error transmitting 'dl.c'" '(should have been 5812 characters)'
fi
fi
echo shar: "extracting 'dohunk.c'" '(4430 characters)'
if test -f 'dohunk.c'
then
	echo shar: "will not over-write existing file 'dohunk.c'"
else
cat << \Stunky!Fluff > 'dohunk.c'
/*
 * dohunk.c -  Do hunk output & relocation for unhunk program.
 *             Copyright 1986 by Eric D. Black.
 *			   Permission is given to redistribute this program
 *			   and its source code subject to the
 *             restrictions given in the file "unhunk.c"
 *
 */

#include <stdio.h>
#include "convert.h"
#include "hunk.h"
#include "bin.out.h"

#ifdef DBUG
#include <local/dbug.h>
#else
#include "dbugstubs.h"
#endif


/* hunk information */
extern Hinfo **hunk;           /* -> vector of ptrs to Hinfo structs */
extern Hinfo *firsthunk;       /* -> first hunk */
extern int nhunks;             /* #hunks in input file */
extern int curhunk;            /* current hunk# */
extern int hvalid;             /* state variable (to bump curhunk) */
extern long filpos;            /* position in input file */
extern long siz[3];            /* segment sizes */
extern long maxhunk;		   /* size of biggest hunk found */

extern long *hunkbuf;          /* -> buffer for doing hunk relocation */
extern char *secname;		   /* "Text", "Data", "BSS" section name strs */


/*
 * Generate memory image file from hunk format load file and
 * information collected into Hinfo structs by 1st pass in convert()
 */
output(ifd, ofd)
int ifd, ofd;
{
	struct bin bin_hd;
	int i;
	Hinfo *hu;

	DBUG_ENTER("output");

	/*
	 * Write header, then hunks to output file in sorted order;
	 * for each hunk, read it into buffer, read relocation
	 * info & do relocation; then write buffer to output file
	 */

	bin_hd.b_magic = BMAGIC;
	bin_hd.b_text = siz[TEXT];
	bin_hd.b_data = siz[DATA];
	bin_hd.b_bss = siz[BSS];
	bin_hd.b_txorg = origin[TEXT];
	bin_hd.b_dtorg = origin[DATA];
	bin_hd.b_bsorg = origin[BSS];
	bin_hd.b_entry = entrypnt;
	for (i=0; i<8; i++)
		bin_hd.b_rsrv[i] = 0;

	if (write(ofd, &bin_hd, sizeof(bin_hd)) != sizeof(bin_hd)) {
		panic("Can't write output file\n");
	}


	DBUG_3("mem","malloc'ing %d bytes for hunkbuf", maxhunk);
    if ((hunkbuf = (long *)malloc((int)maxhunk)) == NULL)
        allerr();

	for (hu = firsthunk; hu != NULL; hu = hu->hnext)
		if (hu->htype == TEXT || hu->htype == DATA) {
			lseek(ifd, hu->hpos, 0);		/* get hunk */
			if (read(ifd, hunkbuf, (int)hu->hsize) != (int)hu->hsize)
				panic("Error reading input file.");
			DBUG_4("rel","hunk %d, %ld bytes", hu->hunkno, (int)hu->hsize);
			/*
			 * relocate hunk in buffer
			 */
			if(hu->hsize) {		/* for nonzero-size hunks */
				reloc(hunkbuf, ifd, hu);	/* relocate hunk */
				if (write(ofd, hunkbuf, (int)hu->hsize) != (int)hu->hsize)
					panic("Error writing output file.");
			} else {
				DBUG_3("rel","hunk %d zero length", hu->hunkno);
			}
		}

	DBUG_2("mem", "freeing hunkbuf");
	free(hunkbuf);

	DBUG_RETURN(0);
}


/*
 * Read relocation records from input hunk file, perform relocation
 * on hunk in buffer
 */
reloc(buffer, fd, hp)
char *buffer;
int fd;	
Hinfo *hp;
{
	long pos;
	long hunksize;
	long numoffset;
	long hunknum;
	long reloffset;
	Hinfo *h;

	DBUG_ENTER("reloc");

	pos = hp->hrel;
	if(pos==0L) {
		DBUG_2("rel", "no relocation info for this hunk");
		DBUG_RETURN(0);
	}
	hunksize = hp->hsize;

	DBUG_4("rel","reloc start filepos %ld, buffer at 0x%lx", pos, buffer);
	lseek(fd, pos, 0);			/* go to 1st relocation record this hunk */
	do {
		getlong(fd, &numoffset);	/* get # of offsets to relocate */
		DBUG_3("rel","%ld offsets", numoffset);
		if (numoffset) {
			getlong(fd, &hunknum);	/* add address of this hunk ... */
			if((int)hunknum > nhunks) {
				printf("Bad hunk # in relocation info: %d, nhunks=%d\n",
					hunknum, nhunks);
				panic("phase error");
			}
			h = hunk[hunknum];
			DBUG_4("rel","  hunk %ld (base=0x%lx)",hunknum,h->haddr);
			while(numoffset--) {
				getlong(fd, &reloffset);	/* ... to word at this offset */
				DBUG_5("rel","  offset 0x%lx (addr 0x%lx) = 0x%lx",reloffset,buffer+reloffset,*(long *)(buffer+reloffset));
				if(reloffset>hunksize-3) {
					fprintf(stderr,
					    "Unreasonable relocation offset 0x%lx in %s hunk %d",
					    reloffset, secname[h->htype], h->hunkno);
					panic("Input file possibly garbled");
				}
				/*
				 * Add base address of specified hunk to the contents of
				 * longword at specified byte offset
				 * (isn't the combination of bytes & longwords clear??)
				 */
				*(long *)(buffer+reloffset) += h->haddr;
				DBUG_3("rel","  new contents = 0x%lx", *(long *)(buffer+reloffset));
			}
		}
	} while (numoffset);

	DBUG_RETURN(0);
}

Stunky!Fluff
if test 4430 -ne "`wc -c < 'dohunk.c'`"
then
	echo shar: "error transmitting 'dohunk.c'" '(should have been 4430 characters)'
fi
fi
echo shar: "extracting 'hunk.h'" '(2605 characters)'
if test -f 'hunk.h'
then
	echo shar: "will not over-write existing file 'hunk.h'"
else
cat << \Stunky!Fluff > 'hunk.h'
/* hunk.h    12 Mar 86   edb */

/*
 * defines for understanding object & load module formats
 * Copyright 1986 Eric D. Black
 */

/*
 * Hunks are blocks of code or data or bss reservations, possibly with
 * blocks of relocation information and symbols, with optional names.
 * Object modules are output of compilers (e.g. *.o files), load modules
 * are similar with all external references resolved.  The program loader
 * uses hunk relocation information to relocate pieces of code and/or
 * data when loaded into memory for execution.
 *
 * Each hunk consists of some number of hunk records, each of which
 * consists of a longword hunk type code, a longword count of data words,
 * and that number of data words.
 */

/*
 * Hunk type codes (decimal, hex equivalent in comments)
 */

#define HUNK_UNIT		999		/* 3e7  Start of program unit */
#define HUNK_NAME		1000	/* 3e8  Name of a hunk */
#define HUNK_CODE		1001	/* 3e9  Code segment */
#define HUNK_DATA		1002	/* 3ea  Initialized Data segment */
#define HUNK_BSS		1003	/* 3eb  Unitialized Data segment */
#define HUNK_RELOC32	1004	/* 3ec  32-bit relocation list */
#define HUNK_RELOC16	1005	/* 3ed  16-bit PC-relative relocation info */
#define HUNK_RELOC8		1006	/* 3ee  8-bit PC-relative relocation info */
#define HUNK_EXT		1007	/* 3ef  External symbol info */
#define HUNK_SYMBOL		1008	/* 3f0  Symbol table info */
#define HUNK_DEBUG		1009	/* 3f1	Debug data */
#define HUNK_END		1010	/* 3f2  End of this hunk */
#define HUNK_HEADER		1011	/* 3f3  hunk summary info for loader */
#define HUNK_OVERLAY	1013	/* 3f5  overlay table info */
#define HUNK_BREAK		1014	/* 3f6  end of overlay node */


/*
 * External symbol info
 * Each HUNK_EXT record is a null-terminated list of symbol data units;
 * each symbol data unit consists of a type byte, 3-byte symbol length
 * in longwords, symbol name (null-padded if necessary), and data word(s).
 * EXTSYMB has null-terminated list of symbol data units,
 * EXTDEF, EXTABS, EXTRES have 1 longword of data,
 * EXTREF32, EXTREF16, EXTREF8 have longword count and n longwords of data,
 * EXTCOMMON also has longword size of common block before the data count.
 */

#define HUNK_EXTSYMB	0		/* symbol table */
#define HUNK_EXTDEF		1		/* relocatable definition */
#define HUNK_EXTABS		2		/* absolute definition */
#define HUNK_EXTRES		3		/* resident library definition */
#define HUNK_EXTREF32	129		/* 32-bit reference to symbol */
#define HUNK_EXTCOMMON	130		/* 32-bit reference to COMMON */
#define HUNK_EXTREF16	131		/* 16-bit reference to symbol */
#define HUNK_EXTREF8	132		/* 8-bit reference to symbol */
Stunky!Fluff
if test 2605 -ne "`wc -c < 'hunk.h'`"
then
	echo shar: "error transmitting 'hunk.h'" '(should have been 2605 characters)'
fi
fi
echo shar: "extracting 'longio.c'" '(2488 characters)'
if test -f 'longio.c'
then
	echo shar: "will not over-write existing file 'longio.c'"
else
cat << \Stunky!Fluff > 'longio.c'
/*
 *  longio.h       Copyright 1985  Landon M. Dyer
 *
 * Minor mods for Amiga, DBUG macros    19Apr86  edb
 */

#include <stdio.h>
#include "convert.h"

#ifdef DBUG
#include <local/dbug.h>
#else
#include "dbugstubs.h"
#endif

extern long filpos;
extern int printing;
extern char buf[];


/*
 * Get a longword or complain about premature EOF
 *
 */
getlong(fd, p_lw)
int fd;
long *p_lw;
{
	DBUG_ENTER("getlong");
    if (readlong(fd, p_lw) == EOF)
        panic("Premature EOF getting longword");
    DBUG_RETURN(OK);
}


/*
 * Read 68000 longword from file,
 * stuff it into '*p_lw' in the
 * host machine's longword format.
 *
 */
readlong(fd, p_lw)
int fd;
long *p_lw;
{
    char buf[4], *out;

	DBUG_ENTER("readlong");
	DBUG_3("io", "input filepos=%ld", lseek(fd, 0L, 1));
    out = (char *)p_lw;
    if (read(fd, buf, 4) != 4)          /* probably end of file */
        DBUG_RETURN(EOF);

    filpos += 4;
#if MACHINE == MSDOS || MACHINE == VAXVMS
    /*
     * 8086/8088 conversion
     * hh hl lh ll ==> ll lh hl hh
     */
    out[0] = buf[3];
    out[1] = buf[2];
    out[2] = buf[1];
    out[3] = buf[0];
#endif

#if MACHINE == Amiga
    out[0] = buf[0];
    out[1] = buf[1];
    out[2] = buf[2];
    out[3] = buf[3];
#endif
	DBUG_4("io","got 0x%lx, ret=0x%lx", *(long *)buf, *(long *)out);
	DBUG_RETURN(0);
}


/*
 * Write word to file,
 * in 68000 format.
 */
writeword(fd, w)
int fd;
unsigned int w;
{
    char buf[2], *out;

	DBUG_ENTER("writeword");

    out = (char *)&w;
#if MACHINE == MSDOS || MACHINE == VAXVMS
    buf[0] = out[1];
    buf[1] = out[0];
#endif

#if MACHINE == Amiga
    buf[0] = out[0];
    buf[1] = out[1];
#endif
	DBUG_3("io", "out filepos=0x%lx", lseek(fd, 0L, 1));
	DBUG_4("io", "got 0x%x, writing 0x%x", w, *(unsigned short *) out);
    if (write(fd, buf, 2) != 2)
        panic("Write error (word)");

	DBUG_RETURN(0);
}


/*
 * Write longword to file, in
 * 68000 format.
 */
writelong(fd, lw)
int fd;
long lw;
{
    char buf[4], *out;

	DBUG_ENTER("writelong");

    out = (char *)&lw;
#if MACHINE == MSDOS || MACHINE == VAXVMS
    buf[0] = out[3];
    buf[1] = out[2];
    buf[2] = out[1];
    buf[3] = out[0];
#endif

#if MACHINE == Amiga
    buf[0] = out[0];
    buf[1] = out[1];
    buf[2] = out[2];
    buf[3] = out[3];
#endif

	DBUG_3("io", "out filepos=0x%lx", lseek(fd, 0L, 1));
	DBUG_4("io", "got 0x%lx, writing 0x%lx", lw, *(long *) out);
    if (write(fd, buf, 4) != 4)
        panic("Write error (longword)");

	DBUG_RETURN(0);
}

Stunky!Fluff
if test 2488 -ne "`wc -c < 'longio.c'`"
then
	echo shar: "error transmitting 'longio.c'" '(should have been 2488 characters)'
fi
fi
echo shar: "extracting 'unhunk.c'" '(6366 characters)'
if test -f 'unhunk.c'
then
	echo shar: "will not over-write existing file 'unhunk.c'"
else
cat << \Stunky!Fluff > 'unhunk.c'

/* unhunk.c   Copyright (C) 1986   Eric D. Black */

/*
 * UNHUNK -- convert AmigaDOS "hunk"-format load files to
 *           memory image similar to a.out; performs relocation,
 *           allows specification of text, data, and bss origins.
 *           Output suitable for simple processing & downloading
 *           to PROM programmers...
 *
 * Portions of UNHUNK are based on the CVT Amiga->ST conversion
 * program by Landon Dyer; these appear in the files convert.c, binfio.c,
 * longio.c, and convert.h, which are all Copyright 1985 by Landon M. Dyer.
 *
 * Changes to those files, and all other code is Copyright 1986 by
 * Eric D. Black.  Permission is given to distribute these files and
 * the code they generate, and to modify and/or extend them, providing
 * that:
 *     1) All copyright notices remain intact (you may copyright your
 *        specific changes)
 *     2) All source code accompanies any distribution, including any
 *        changes and/or enhancements you may have made
 *     3) Any changes you make are clearly indicated
 *     4) No direct profit results from that distribution (i.e. you
 *        may not sell this program or anything derived from it, but
 *        you may include it at no charge on a system you sell for profit),
 *        and you may give it away
 *
 * Debug macros and routines are from the 'dbug' package by Fred Fish,
 * and are available on his freely redistributable Amiga library disks;
 * these are not included here.  If you have them, and want to
 * compile with the debug code, compile with '-DDBUG'; otherwise the extra
 * debug statements will generate no code
 *
 */

#include <stdio.h>
#include "convert.h"

#ifdef DBUG
#include <local/dbug.h>
#else
#include "dbugstubs.h"
#endif

char *version = "1.0";
char *date = "21-Apr-1986";

#define STRINGSIZ       256
#define READ            0
#define WRITE           1

int orgspec[3] = {0,0,0};	/* text, data, bss origin specified on cmdlin */
int printing = 0;			/* print hunk information */

/*
 * origin of text, data, bss segments, seg types 0-2 defined in convert.h
 */
long origin[3] = { 0,0,0 };

long entrypnt = 0;	/* entry offset in text section */
int errflg = 0;		/* count of errors encountered */

extern int Enable_Abort;	/* set non-zero to enable ^C and ^D abort */


main(argc, argv)
int argc;
char **argv;
{
    int ifd, ofd;
	char c;
	extern char *optarg;
	extern int optind;

	DBUG_ENTER("main");
	DBUG_PROCESS("unhunk");		/* since we get argv[0]="c" (!) */

    /*
     * No instructions:
     * print info about use and
     * exit with bad return code.
	 * (it's not worth making this work from the Workbench...)
     */
    if (argc <= 1) {
	usage();
   	printf("\nUNHUNK Version %s (%s)\n", version, date);
   	printf("This program is copyright (c) 1986 Eric D. Black\n");
	printf("       and (c) 1985 Landon M. Dyer\n");
	printf("It may be freely redistributed to others\n");
   	printf("ONLY if the following conditions are met:\n");
   	printf("\t1. You do not make a profit on it.\n");
   	printf("\t2. If you have the source code, you give that away, too.\n");
   	printf("\t3. You include this notice in the source and object code.\n");
	exit(1);
	}

	/*
	 * Parse command line, using getopt(), public domain goodie from
	 * Henry Spencer, available from almost any USENET site
	 */
	while((c = getopt(argc, argv, "#:t:d:b:D:p")) != EOF) {
		switch(c) {
			case '#':			/* debug package arguments */
					DBUG_PUSH(optarg);
					break;
			case 't':			/* text origin */
					DBUG_3("args", "text origin '%s'", optarg);
					origin[TEXT] = getnum(optarg);
					orgspec[TEXT]++;
					DBUG_3("args", "text origin=0x%x", origin[TEXT]);
					break;
			case 'd':			/* data origin */
					DBUG_3("args", "data origin '%s'", optarg);
					origin[DATA] = getnum(optarg);
					orgspec[DATA]++;
					DBUG_3("args", "data origin=0x%x", origin[DATA]);
					break;
			case 'b':			/* bss origin */
					DBUG_3("args", "bss origin '%s'", optarg);
					origin[BSS] = getnum(optarg);
					orgspec[BSS]++;
					DBUG_3("args", "bss origin=0x%x", origin[BSS]);
					break;
			case 'p':			/* print hunk info */
					printing++;
					break;
			default:
					DBUG_3("args", "bad arg, exit status=5", 0);
					exit(5);	/* error message is printed by getopt */
		}
	}
	argv += optind;				/* skip past flags */
	argc -= optind;

	/*
	 * Since we only use level 1 I/O (except for printf's...), and
	 * only use malloc() to allocate memory, we can go ahead and
	 * enable the Lattice C runtime check for ^C and ^D
	 */
	Enable_Abort++;


    if ((ifd = ebinopen(argv[0], READ)) < 0) {
		printf("Can't open input file: %s\n", argv[0]);
		exit(5);
	}
    if ((ofd = ebinopen(argv[1], WRITE)) < 0) {
		printf("Can't open output file: %s\n", argv[1]);
		exit(5);
	}

	/*
	 * This is where we do the actual work
	 */
    convert(ifd, ofd);

    close(ifd);
    close(ofd);

	printf("Done\n%d errors encountered\n", errflg);
	exit(0);

}	/* end of main */


/*
 * Print info about usage
 */
usage()
{
		DBUG_ENTER("usage");
        printf("\nUsage:\n");
        printf("\tunhunk [-t xxxx] [-d xxxx] [-b xxxx] infile outfile\n");
		printf("\t(both input and output files are REQUIRED)\n");
		DBUG_RETURN(0);
    }


/*
 * Panic and give up.
 */
panic(s)
char *s;
{
	DBUG_ENTER("panic");
    printf("unhunk disaster: %s\nGiving up...\n", s);
    exit(10);

	/* NOTREACHED */
	DBUG_RETURN(0);
}

/*
 * Convert char string to long
 * prefixes understood:  0x (hex), 0 (octal), otherwise decimal
 * leading '-' means 2's complement
 */
long
getnum(str)
char *str;
{
	long num;
	char *foo;
	int negflag;
	extern long strtol();

	DBUG_ENTER("getnum");

	if (*str == '-') {
		DBUG_3("args", "minus sign: '%s'", str);
		negflag = 1;
		str++;
	} else
		negflag = 0;

	DBUG_3("args", "string is: '%s'", str);

#if 0
	/**** this sucks!  strtol() causes an address error guru med! ****/
	DBUG_4("args", "about to call strtol: str='%s', &foo=0x%x", str, &foo);
	num = strtol(str, &foo, 0);
	DBUG_4("args", "got back from strtol, got num=%ld (0x%lx)", num, num);
#else 0
	if (*str == '0') {
		str++;
		if(*str == 'x' || *str == 'X')
			stch_i(++str, &num);
		else
			panic("Can't handle octal args");
	} else
		stcd_i(str, &num);
#endif 0

	if (negflag)
		num = (long) (0 - (int) num);
	DBUG_4("args", "conversion returns %ld (0x%lx)", num, num);

	DBUG_RETURN(num);
}
Stunky!Fluff
if test 6366 -ne "`wc -c < 'unhunk.c'`"
then
	echo shar: "error transmitting 'unhunk.c'" '(should have been 6366 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
Eric Black   "Garbage In, Gospel Out"
UUCP:        {sun,pyramid,hplabs,amdcad}!chronon!eric