// (c) 1991-2007 Electronic Arts Inc.

const char *SPIT_history[] =
{
"------------------------------------------------------------------",
"                                                                  ",
"                            XD v1.71                              ",
"                                                                  ",
"                     by FrANK G. Barchard, EAC                    ",
"                                                                  ",
"                    Main program - Sep 29, 2002                   ",
"                                                                  ",
"------------------------------------------------------------------",
"                                                                  ",
" Version Date   History:                                          ",
" ------- ------ --------                                          ",
"    1.00 910131 spit version of hex dump                          ",
"    1.01 910204 c 0x00 table format                               ",
"    1.10 910205 byte/word/long format                             ",
"    1.20 910211 write to file                                     ",
"    1.21 910215 fix up doc/.bit files                             ",
"    1.22 910222 remove separators from end of line                ",
"    1.23 910224 tolower/toupper                                   ",
"    1.24 910227 auto type                                         ",
"    1.25 910328 close files bug fix                               ",
"    1.26 910401 two column usage/auto opts environment var        ",
"    1.28 910523 default to hex, not auto                          ",
"    1.29 910529 aztec style options list                          ",
"    1.30 910613 load error message                                ",
"    1.31 910613 more formats                                      ",
"    1.33 910710 -t0-3 most popular types                          ",
"    1.34 911119 use native cr/lf chars                            ",
"    1.35 920602 spit 2.0 interface                                ",
"    1.36 920914 spit 2.0 goblet version/fix option parsing        ",
"    1.37 920921 CR/LF tranlated for native output                 ",
"    1.38 930211 pc hex format 0ffffh                              ",
"    1.39 930212 alloc maxline+2 to allow for null terminator      ",
"    1.40 930825 CR/CR/LF supported for jive                       ",
"    1.41 930825 -n linelen for text output line length(default 76)",
"    1.42 930826 -n removed, use -b.  text is line based now       ",
"    1.43 930913 use new custom sprintfb which support %b binary   ",
"    1.44 931020 text output don't strip \b                        ",
"    1.45 931021 bump max bytes per line to 512                    ",
"    1.46 931028 text allow mac special characters for make files  ",
"    1.47 931028 text file type for output, except on PC           ",
"    1.48 931105 default destination is to overwrite source        ",
"    1.49 931130 spin cursor more often on Mac                     ",
"    1.50 931130 spin every 8th character and before fflush        ",
"    1.51 940301 wait after page/x in extension for output again   ",
"    1.52 940609 bumped bytes per line to 2048                     ",
"    1.53 941011 DCD &hex for 3DO                                  ",
"    1.54 941011 bumped -s and -l to 2 billion max                 ",
"    1.55 950830 bumped -s and -l to unlimited                     ",
"    1.56 951010 gimex file io                                     ",
"    1.57 951011 removed mkdir which Mac doesnt have               ",
"    1.58 951116 only load range of file requested                 ",
"    1.59 951130 output to screen use native \n                    ",
"    1.60 960216 dont close stdout after first file, verbose logic ",
"    1.61 981029 removed Aztec support                             ",
"    1.62 990719 -0x option for -t21                               ",
"    1.63 000201 -h for 128 byte header dumps                      ",
"    1.64 000817 banner default is on                              ",
"    1.65 001205 64 bit fileio                                     ",
"    1.66 010517 -h clip to filesize                               ",
"    1.67 011029 -0x bigendian                                     ",
"    1.68 011122 -0x do 16 bytes                                   ",
"    1.69 020610 -help fixed and -opt? implemented                 ",
"    1.70 020723 -a1 default                                       ",
"    1.71 020929 -w turn off prints, not open                      ",
"                                                                  ",
"------------------------------------------------------------------",
"\0"
};

/****************************************************************/
/*  Spit Setup                                                  */
/****************************************************************/

#include    "spit.h"
#include    <math.h>
#include    <stdarg.h>

const char TextVersion[]="1.71 (Samba) 2007.12.4";
#define TOOL_VERSION 171
#define TOOL_NAME "xd"

char *OPTformat0;
char *OPTformat1;
char *OPTformat2;
char *OPTformat3;
char *OPTformat4;
int OPTintel;
int OPTalign;
int OPTtype;
int OPTbytesperline;
int OPTremovebytes;
GPOS OPTstart;
GPOS OPTlen;
int OPTexpandtabs;
int OPTxlat[256];

/****************************************************************/
/*  Defines                                                     */
/****************************************************************/

#define MAXBYTESPERLINE 2048

static int SPIT_writestr(char *str,FILE *g)
{
    if (OPTwrite)
    {
        if (g==stdout)
        {
            char *nl;
            if (strlen(str)>=strlen(SPITNL))
            {
                nl = str+strlen(str)-2;
                if (!strcmp(nl,SPITNL))
                    strcpy(nl,"\n");
            }
        }

        return(fwrite(str,1,strlen(str),g));
    }
    return 0;
}


#if defined(_MSC_VER) || defined(__WATCOMC__)
#define FBOPENTW(f)             fopen(f,"wb")
#else
#define FBOPENTW(f)             fopen(f,"w")
#endif

static FILE *XDopenwt(const char *fname)
{
    FILE *fhdl = stdout;      /* file handle for console */

    if (OPTwrite)
    {
        if (stricmp(fname,"stdout:"))
        {
            fhdl = FBOPENTW(fname);
        }
    }
    return(fhdl);
}



static char *SPIT_loadfilerange(SPITMEM *mem, const char *fname, GPOS start, GPOS len, int verbose)
{
    GPOS     flen;
    GSTREAM *fhdl;
    char     statbuf[SPITMAXLINE];
    int ok;

    flen = 0;
    mem->ptr = 0;

    printf(SPIT_loadstr(statbuf,fname,verbose));
    SPIT_flush();

    fhdl = gopen(fname);

    if (fhdl)
    {
        flen = glen(fhdl);
        if (flen)
        {
            if (start<0)
                OPTstart = start = flen+start;

            gseek(fhdl,start);
            flen -= start;
            if (len)
                flen = gmin(flen,len);
            flen = gmax(0,flen);

            SPIT_alloc(mem, (int) (flen+1));
            if (mem->ptr)
            {
                mem->len = (int)flen;
                *(mem->ptr+flen) = '\0';
                ok = gread(fhdl,mem->ptr, (int)flen);
                gclose(fhdl);
                if (!ok)
                {
                    SPIT_free(mem);
                }
            }
        }
    }

    if (!mem->ptr)
    {
        if (verbose)
            printf("SPIT_loadfilev - COULD NOT READ FILE '%s'\n", fname);
        SPIT_flush();
    }

    return(mem->ptr);
}


/****************************************************************/
/*  vsprintfb                                                   */
/****************************************************************/

#define MAXBUF      (2048+2)
#define PUTC(ch) *d++=ch
#define todigit(c)  ((c) - '0')

#if defined(_MSC_VER) || defined(__WATCOMC__)
#define ARG(basetype) longarg = modflags&LONGINT ? va_arg(argp,long basetype) : \
        modflags&SHORTINT ? (short basetype)va_arg(argp,short basetype) : va_arg(argp,int)
#else
#define ARG(basetype) longarg = va_arg(argp,int)
#endif

#define LONGINT     0x01        /* int integer */
#define SHORTINT    0x02        /* short integer */
#define LADJUST     0x04        /* left adjustment */
#define ZEROPAD     0x08        /* zero (as opposed to blank) pad */
#define ALT         0x10        /* alternate form */
#define HEXPREFIX   0x20        /* add 0x or 0X prefix */

/*

 extension ideas:

 %c print shape ids 1-4 chars
 %lc print shape int ids 1-4 chars
 %4c pad id

 %f for fixed point (normally used for float)
 %F modifier for far pointers and string

 extension done:

 %b for binary

*/

static void  vsprintfb(char *d, char *format, va_list argp)
{
    int ch;                 /* character from format */
    int n;                  /* random handy integer */
    char *t;                /* buffer pointer */
    unsigned int longarg;  /* integer arguments %[diouxX] */
    int digbase;            /* digbase for [diouxX] conversion */
    int dprec;              /* decimal precision in [diouxX] */
    int fieldsz;            /* field size expanded by sign, etc */
    int modflags;           /* modflags as above */
    int prec;               /* precision from format (%.3d), or -1 */
    int realsz;             /* field size expanded by decimal precision */
    int fieldsize;          /* fieldsize of converted field or string */
    int fieldwidth;         /* fieldwidth from format (%8d), or 0 */
    char sign;              /* sign prefix (' ', '+', '-', or \0) */
    char *digs;             /* digits for [diouxX] conversion */
    char buf[MAXBUF];       /* space for %c, %[diouxX], %[eEfgG] */

    digs = "0123456789abcdef";
    for (;; ++format)
    {
        ch = *format;
        while (ch && (ch!='%'))
        {
            PUTC((unsigned char)ch);
            ch = *++format;
        }

        if (!ch)
            goto done;

        modflags = 0; dprec = 0; fieldwidth = 0;
        prec = -1;
        sign = '\0';


rflag:
        switch (*++format)
        {
            case ' ':   /* space for sign */
                if (!sign)
                    sign = ' ';
                goto rflag;

            case '#':   /* octal and hex prefix */
                modflags |= ALT;
                goto rflag;

            case '*':   /* use argment for field width */
                if ((fieldwidth = va_arg(argp, int)) >= 0)
                    goto rflag;
                fieldwidth = -fieldwidth;
                /* drop into... */

            case '-':   /* left adjust */
                modflags |= LADJUST;
                goto rflag;

            case '+':   /* print + for positive numbers */
                sign = '+';
                goto rflag;

            case '.':   /* field precision */
                if (*++format == '*')
                    n = va_arg(argp, int);
                else
                {
                    n = 0;
                    while (isdigit(*format))
                        n = 10 * n + todigit(*format++);
                    --format;
                }
                prec = n < 0 ? -1 : n;
                goto rflag;

            case '0':   /* zero pad */
                modflags |= ZEROPAD;
                goto rflag;

            case '1': case '2': case '3': case '4':     /* field width */
            case '5': case '6': case '7': case '8': case '9':
                n = 0;
                do
                {
                    n = 10 * n + todigit(*format);
                } while (isdigit(*++format));

                fieldwidth = n;
                --format;
                goto rflag;

            case 'h':   /* short int arg */
                modflags |= SHORTINT;
                goto rflag;

            case 'l':   /* int int arg */
                modflags |= LONGINT;
                goto rflag;

            case 'c':   /* character arg */
                *(t = buf) = (unsigned char) (va_arg(argp, int));
                fieldsize = 1;
                sign = '\0';
                goto pforw;

            case 'D':   /* int decimal arg */
                modflags |= LONGINT;
                /*drop into...*/

            case 'd':   /* decimal integer */
            case 'i':   /* integer */
                ARG(int);
                if ((int)longarg < 0)
                {
                    longarg = (unsigned int) -(int)longarg;
                    sign = '-';
                }
                digbase = 10;
                goto number;

            case 'O':   /* int octal arg */
                modflags |= LONGINT;
                /*drop into...*/

            case 'o':   /* octal arg */
                ARG(unsigned);
                digbase = 8;
                goto nosign;

            case 'b':   /* binary arg */
                ARG(unsigned);
                digbase = 2;
                goto nosign;

            case 'p':   /* pointer arg */
                longarg = (unsigned int)(intptr_t)va_arg(argp, void *);
                digbase = 16;
                goto nosign;

            case 's':   /* string arg */
                t = (char *) va_arg(argp, char *);
                if (!t)
                    t = "null";
                if (prec>=0)
                {
                    for (fieldsize=0; fieldsize<prec && t[fieldsize]; ++fieldsize)
                        ;
                }
                else
                    fieldsize = strlen(t);
                sign = '\0';
                goto pforw;

            case 'U':   /* int unsigned int */
                modflags |= LONGINT;
                /*drop into...*/
            case 'u':   /* unsigned int */
                ARG(unsigned);
                digbase = 10;
                goto nosign;

            case 'X':   /* upper case hex arg */
                digs = "0123456789ABCDEF";
                /* drop into... */
            case 'x':   /* hex arg */
                ARG(unsigned);
                digbase = 16;
                /* leading 0x/X only if non-zero */
                if (modflags & ALT && longarg != 0)
                    modflags |= HEXPREFIX;


                /* unsigned conversions */
nosign:         sign = '\0';
number:         if ((dprec = prec) >= 0)
                    modflags &= ~ZEROPAD;

                t = buf + MAXBUF;
                if (longarg != 0 || prec != 0)
                {
                    do
                    {
                        *--t = digs[longarg % digbase];
                        longarg /= digbase;
                    } while (longarg);

                    digs = "0123456789abcdef";
                    if (modflags & ALT && digbase == 8 && *t != '0')
                        *--t = '0'; /* octal leading 0 */
                }
                fieldsize = (int)(buf + MAXBUF - t);

pforw:          fieldsz = fieldsize;
                if (sign)
                    fieldsz++;
                if (modflags & HEXPREFIX)
                    fieldsz += 2;
                realsz = dprec > fieldsz ? dprec : fieldsz;

                /* right-adjusting blank padding */
                if ((modflags & (LADJUST|ZEROPAD)) == 0 && fieldwidth)
                    for (n = realsz; n < fieldwidth; n++)
                        PUTC(' ');

                /* prefix */
                if (sign)
                    PUTC(sign);
                if (modflags & HEXPREFIX)
                {
                    PUTC('0');
                    PUTC((char)*format);
                }

                /* right-adjusting zero padding */
                if ((modflags & (LADJUST|ZEROPAD)) == ZEROPAD)
                    for (n = realsz; n < fieldwidth; n++)
                        PUTC('0');
                /* leading zeroes from decimal precision */
                for (n = fieldsz; n < dprec; n++)
                    PUTC('0');

                /* the string or number proper */
                n = fieldsize;
                while (--n >= 0)
                    PUTC(*t++);

                /* left-adjusting padding (always blank) */
                if (modflags & LADJUST)
                    for (n = realsz; n < fieldwidth; n++)
                        PUTC(' ');
                break;

            case '\0':  /* "%?" prints ?, unless ? is NULL */
                goto done;

            default:
                PUTC((char)*format);
        }
    }
done:
    PUTC(0);    /* null terminate */
    return;
}

void  sprintfb(char *buf, char *format, ...)
{
    va_list arglist;

    va_start(arglist, format);
    vsprintfb(buf, format, arglist);
    va_end(arglist);
}

/****************************************************************/
/*  Application                                                 */
/****************************************************************/

static char        buf0[MAXBUF];
static char        buf1[MAXBUF];
static char        buf2[MAXBUF];
static char        buf3[MAXBUF];
static char        buf4[MAXBUF];

static int xdump(char *dumpbuf,GPOS start,GPOS dumplen,const char *fname)
{
    char *lineptr;
    char *bend;
    char *aend;
    char *bstart;
    char prchar;
    int i;
    int ii;
    int j;
    int ok;
    GPOS offset;
    GPOS alignlen;
    int tv;
    int bytesinline;
    int fullbytesinline;
    unsigned int ltv;
    int written;
    int totalwritten;
    FILE *fhdl;
    char vstr[MAXBYTESPERLINE+2];
    char tempstr[MAXBYTESPERLINE+2];
    char fline[MAXBYTESPERLINE*2+2];

    alignlen = (int)OPTalign;
    offset = start&-alignlen;
    alignlen = (dumplen+alignlen-1)&-alignlen;

    lineptr = dumpbuf;/*+offset; */
    bstart = dumpbuf;/*+start; */
    bend = bstart+dumplen;
    aend = bstart+alignlen;

    totalwritten = 0L;
    ok = SPITYES;
    fhdl = XDopenwt(fname);

    while (lineptr<aend)
    {
        sprintfb(fline, OPTformat0, offset, offset);        /* print offset */

        /* print formatted values */

        bytesinline = OPTbytesperline;
        fullbytesinline = OPTbytesperline;

        if (!strcmp(OPTformat1,"%c"))
        {
            for (i=0; i<MAXBYTESPERLINE; ++i)
            {
                if (lineptr[i]==(char)10 || lineptr[i]==(char)13)
                    break;
            }
            bytesinline = i+1;
            if (lineptr[i]==(char)10)
            {
                if (lineptr[i+1]==(char)13)
                    ++bytesinline;
            }
            else if (lineptr[i]==(char)13)
            {
                if (lineptr[i+1]==(char)13 && lineptr[i+2]==(char)10)
                    bytesinline += 2;
                else if (lineptr[i+1]==(char)10)
                    ++bytesinline;
            }
            fullbytesinline = bytesinline;
            if (bytesinline > OPTbytesperline)
                bytesinline = OPTbytesperline;
        }

        for (i=0; i<bytesinline; ++i)
        {
            ii = i^OPTintel;
            tv = OPTxlat[(unsigned int) lineptr[ii] & 255];

            if (tv>=0)
            {
                sprintfb(vstr, OPTformat1, tv, tv);

                if (OPTformat2[0])
                {
                    if ((i&1)==1)
                    {
                        tv += (OPTxlat[(int) lineptr[(i-1)^OPTintel]  & 255] << 8);
                        sprintfb(tempstr, OPTformat2, tv, tv);
                        strcat(vstr,tempstr);
                    }
                }

                if (OPTformat3[0])
                {
                    if ((i&3)==3)
                    {
                        ltv = (int) tv;
                        ltv += ((int)OPTxlat[(int) lineptr[(i-1)^OPTintel]  & 255] << 8);
                        ltv += ((int)OPTxlat[(int) lineptr[(i-2)^OPTintel]  & 255] << 16);
                        ltv += ((int)OPTxlat[(int) lineptr[(i-3)^OPTintel]  & 255] << 24);
                        if (OPTintel)
                            ltv = ((ltv>>16)&0x0000ffff) + ((ltv<<16)&0xffff0000);
                        sprintfb(tempstr, OPTformat3, ltv, ltv);
                        strcat(vstr,tempstr);
                    }
                }

                /* blank it out if its out of range */

                if ((lineptr+ii<bstart) || (lineptr+ii>=bend))
                {
                    if (lineptr+ii>=aend)
                        vstr[0]='\0';
                    else
                    {
                        for (j=0; vstr[j]; ++j)
                            vstr[j] = ' ';
                    }
                }
                strcat(fline, vstr);
            }
            if (!(i&1))
                SPIT_flush();   /* to make cursor spin on Mac */
        }

        /* expand tabs */

#if 0
        if (OPTexpandtabs)
        {
            strcpy(tempstr, vstr);
            for (i=0; i<bytesinline; ++i)
            {
            }
        }
#endif

        /* convert CR/LFs to native format */

        strcpy(tempstr, fline);
        j = 0;
        i = 0;
        while (tempstr[i])
        {
            if (tempstr[i]==(char)10)
            {
                ++i;
                strcpy(fline+j, SPITNL);
                j += strlen(SPITNL);
                if (tempstr[i]==(char)13)
                    ++i;
            }
            else
                if (tempstr[i]==(char)13)
                {
                    ++i;
                    strcpy(fline+j, SPITNL);
                    j += strlen(SPITNL);
                    if (tempstr[i]==(char)10)
                        ++i;
                    else if (tempstr[i]==(char)13 && tempstr[i+1]==(char)10)
                        i += 2;
                }
                else
                    fline[j++] = tempstr[i++];
        }
        fline[j] = (char) '\0';

        /* remove separators from end of line */

        if (OPTremovebytes)
        {
            i = (int) (strlen(fline))-1;
            while (i>0)
            {
                if (fline[i]==(char)' ' || fline[i]==(char)'\t' || fline[i]==(char)',')
                {
                    fline[i]='\0';
                    --i;
                }
                else
                    i = 0;
            }
        }

        /* format ASC bytes */

        if (OPTformat4[0]!=(char)'\\')
        {
            if (OPTformat4[0]!=(char)'\0')
            {
                for (i=0; i<bytesinline; ++i)
                {
                    prchar = (char) (OPTxlat[(int) lineptr[i^OPTintel]  & 255]);

                    if ((lineptr+i<bstart) || (lineptr+i>=bend))
                    {
                        if (lineptr+i<aend)
                            prchar = ' ';
                    }
                    else
                    {
                        prchar = (unsigned char) (prchar&(char)127);
                        if ((unsigned char)prchar<(unsigned char)' ')
                            prchar = '.';
                        if (prchar>'z')
                            prchar = '.';
                    }
                    tempstr[i] = prchar;
                }
                tempstr[i] = '\0';

                /* print ascii values */

                sprintfb(vstr, OPTformat4, tempstr, tempstr);

                strcat(fline, vstr);
            }
            strcat(fline,SPITNL);
        }
        if (fullbytesinline!=bytesinline)
            strcat(fline,SPITNL);

        written = SPIT_writestr(fline, fhdl);
        SPIT_flush();

        totalwritten += written;
        if (!written)
        {
            ok = SPITNO;
            lineptr = aend;
        }

        lineptr += fullbytesinline;
        offset += fullbytesinline;
    }

    if (fhdl && fhdl!=stdout)
        fclose(fhdl);

    if (!ok)
        totalwritten = 0L;
    return(totalwritten);
}

#if 0
/*
;
; ABSTRACT
;
; xd - hex dumps files with flexible output formats
;
; SUMMARY
;
; xd -options [files]
;     @file     response file, containing a list of options and files
;     =file     specify a output file ie xd source=dest
;     -a<n>     align to n bytes
;     -b<n>     bytes per line
;     -e0       output tabs
;     -e<n>     expand tabs to n spaces (default 4)
;     -i0       motorola format
;     -i1       intel swap high and low byte
;     -h        quick header dump of 128 bytes
;     -s<n>     start at byte n
;     -s-<n>    start at end of file-n
;     -l<n>     dump n bytes
;     -o0,<s>   printf control string for int offset
;     -o1,<s>   printf control string for int every byte
;     -o2,<s>   printf control string for int every word
;     -o3,<s>   printf control string for int every int
;     -o4,<s>   printf control string for ascii string
;     -o4,"\"   suppress new lines
;     -eol0     include separators at end of line
;     -eol1     remove separators at end of line
;     -t0       auto select hex(-t1) or text(-t2)
;     -t1       hex int/ascii dump, 16 bpl (default)
;     -t2       text with translation
;     -t3       $hex word tbl with tab, 16 bpl
;     -t4       hex int/ascii dump, 16 bpl
;     -t5        '  word  '     '     '
;     -t6        '  byte  '     '     '
;     -t7       dec int dump, 16 bpl
;     -t8        '  word  '     '
;     -t9        '  byte  '     '
;     -t10      oct int dump, 16 bpl
;     -t11       '  word  '     '
;     -t12       '  byte  '     '
;     -t13      $hex int tbl with tab, 16 bpl
;     -t14       '   word  '             '
;     -t15       '   byte  '             '
;     -t16      dec int tbl with tab, 16 bpl
;     -t17       '  word  '            '
;     -t18       '  byte  '            '
;     -t19      0x hex int tbl with tab, 16 bpl
;     -t20       '     word  '             '
;     -t21 -0x   '     byte  '            8 bpl
;     -t22      dl $hex int tbl, 16 bpl
;     -t23      dw  '   word  '    '
;     -t24      db  '   byte  '    '
;     -t25      dl $hex int tbl, 8 bpl
;     -t26      dw  '   word  '    '
;     -t27      db  '   byte  '    '
;     -t28      dl $hex int tbl, 4 bpl
;     -t29      dw  '   word  '    '
;     -t30      db  '   byte  '    '
;     -t31      dl dec int tbl, 16 bpl
;     -t32      dw  '  word  '    '
;     -t33      db  '  byte  '    '
;     -t34      dl dec int tbl, 8 bpl
;     -t35      dw  '  word  '    '
;     -t36      db  '  byte  '    '
;     -t37      dl dec int tbl, 4 bpl
;     -t38      dw  '  word  '    '
;     -t39      db  '  byte  '    '
;     -t40      dc.l $hex int tbl, 16 bpl
;     -t41      dc.w  '   word  '    '
;     -t42      dc.b  '   byte  '    '
;     -t43      dc.l $hex int tbl, 8 bpl
;     -t44      dc.w  '   word  '    '
;     -t45      dc.b  '   byte  '    '
;     -t46      dc.l $hex int tbl, 4 bpl
;     -t47      dc.w  '   word  '    '
;     -t48      dc.b  '   byte  '    '
;     -t49      dc.l dec int tbl, 16 bpl
;     -t50      dc.w '   word  '    '
;     -t51      dc.b '   byte  '    '
;     -t52      dc.l dec int tbl, 8 bpl
;     -t53      dc.w '   word  '    '
;     -t54      dc.b '   byte  '    '
;     -t55      dc.l dec int tbl, 4 bpl
;     -t56      dc.w '   word  '    '
;     -t57      dc.b '   byte  '    '
;     -t58      text with no translation
;     -t59       '   lower case
;     -t60       '   upper case
;     -t61      dl 0aah intel hex int tbl, 16 bpl
;     -t62      dw  '    '     '  word  '    '
;     -t63      db  '    '     '  byte  '    '
;     -t64      binary bytes w/offset, 8 bpl
;     -t65       '     words  '         '
;     -t66       '     longs  '         '
;     -t67      DCD  &hex int tbl, 16 bpl
;     -t68      DCW   '   word  '    '
;     -t69      DCB   '   byte  '    '
;     -nologo   disable banner
;     -v0       no console output
;     -v1       prints source file name and errors
;     -v2       status line for each file (default)
;     -v3       additional info
;     -w0       don't output file
;     -w1       output to file (default)
;     -r        recurse subdirectories
;     -x<n>,<m> translate character n to m (ie -x65,97)
;
; DESCRIPTION
;
; XD dumps files in hex by default, but can also output
; in decimal, octal or ascii.
;
; The advanced user may specify printf-style formatting strings,
; although many formats are built in.
;
; Some formats are suitable for tables in C or assemble, while
; others are for display purposes only.  Character translation
; also optional, allowing any characters to be translated to
; other characters.  Output can be written to files, allowing
; easy batch processing applications.
;
; RETURNS
;
; no return code
;
; SEE ALSO
;
; hd, HexEdit(Mac), Spit
;
; SAMPLE OUTPUT
;
; >xd jet.dat -l64
;
;   00000: 000067ce 00032170 616c6a65 74626a65  ..gN..!paljetbje
;   00010: 74730000 00000000 00400000 1f203000  ts.......@... 0.
;   00020: 0100598a 668a0000 00008d8a 9a8a0000  ..Y.f...........
;   00030: 00153f3f 15151518 18182a2a 2a1f1f1f  ..??......***...
;
; END ABSTRACT
;
*/
#endif

/****************************************************************/
/*  SPIT Routines                                               */
/****************************************************************/

void SPIT_reset(void)
{
    int  i;

    OPTwrite = 1;
    OPTbanner = 1;
    OPTextrule = "";
    OPTformat0 = "%05lx: ";
    OPTformat1 = "%02x";
    OPTformat2 = "";
    OPTformat3 = " ";
    OPTformat4 = " %s";
    OPTintel = 0;
    OPTalign = 1;
    OPTbytesperline = 16;
    OPTremovebytes = 0;
    OPTtype = 1;
    OPTstart = 0L;
    OPTlen = 0L;
    OPTexpandtabs = 4;

    for (i=0; i<256; ++i)
        OPTxlat[i] = i;

    return;
}

char *optionhelp[]=
{
    "    @file     response file, containing a list of options and files\n",
    "    =file     specify a output file ie source=dest\n",
    "    -a<n>     align to n bytes\n",
    "    -b<n>     bytes per line\n",
    "    -e0       output tabs\n",
    "    -e<n>     expand tabs to n spaces (default 4)\n",
    "    -i0       motorola format\n",
    "    -i1       intel swap high and low byte\n",
    "    -h        quick header dump of 128 bytes\n",
    "    -s<n>     start at byte n\n",
    "    -s-<n>    start at end of file-n\n",
    "    -l<n>     dump n bytes\n",
    "    -o0,<s>   printf control string for int offset\n",
    "    -o1,<s>   printf control string for int every byte\n",
    "    -o2,<s>   printf control string for int every word\n",
    "    -o3,<s>   printf control string for int every int\n",
    "    -o4,<s>   printf control string for ascii string\n",
    "    -o4,\42\\\42   suppress new lines\n",
    "    -eol0     include separators at end of line\n",
    "    -eol1     remove separators at end of line\n",
    "    -t0       auto select hex(-t1) or text(-t2)\n",
    "    -t1       hex int/ascii dump, 16 bpl (default)\n",
    "    -t2       text with translation\n",
    "    -t3       $hex word tbl with tab, 16 bpl\n",
    "    -t4       hex int/ascii dump, 16 bpl\n",
    "    -t5        '  word  '     '     '\n",
    "    -t6        '  byte  '     '     '\n",
    "    -t7       dec int dump, 16 bpl\n",
    "    -t8        '  word  '     '\n",
    "    -t9        '  byte  '     '\n",
    "    -t10      oct int dump, 16 bpl\n",
    "    -t11       '  word  '     '\n",
    "    -t12       '  byte  '     '\n",
    "    -t13      $hex int tbl with tab, 16 bpl\n",
    "    -t14       '   word  '             '\n",
    "    -t15       '   byte  '             '\n",
    "    -t16      dec int tbl with tab, 16 bpl\n",
    "    -t17       '  word  '            '\n",
    "    -t18       '  byte  '            '\n",
    "    -t19      0x hex int tbl with tab, 16 bpl\n",
    "    -t20       '     word  '             '\n",
    "    -t21 -0x   '     byte  '            8 bpl\n",
    "    -t22      dl $hex int tbl, 16 bpl\n",
    "    -t23      dw  '   word  '    '\n",
    "    -t24      db  '   byte  '    '\n",
    "    -t25      dl $hex int tbl, 8 bpl\n",
    "    -t26      dw  '   word  '    '\n",
    "    -t27      db  '   byte  '    '\n",
    "    -t28      dl $hex int tbl, 4 bpl\n",
    "    -t29      dw  '   word  '    '\n",
    "    -t30      db  '   byte  '    '\n",
    "    -t31      dl dec int tbl, 16 bpl\n",
    "    -t32      dw  '  word  '    '\n",
    "    -t33      db  '  byte  '    '\n",
    "    -t34      dl dec int tbl, 8 bpl\n",
    "    -t35      dw  '  word  '    '\n",
    "    -t36      db  '  byte  '    '\n",
    "    -t37      dl dec int tbl, 4 bpl\n",
    "    -t38      dw  '  word  '    '\n",
    "    -t39      db  '  byte  '    '\n",
    "    -t40      dc.l $hex int tbl, 16 bpl\n",
    "    -t41      dc.w  '   word  '    '\n",
    "    -t42      dc.b  '   byte  '    '\n",
    "    -t43      dc.l $hex int tbl, 8 bpl\n",
    "    -t44      dc.w  '   word  '    '\n",
    "    -t45      dc.b  '   byte  '    '\n",
    "    -t46      dc.l $hex int tbl, 4 bpl\n",
    "    -t47      dc.w  '   word  '    '\n",
    "    -t48      dc.b  '   byte  '    '\n",
    "    -t49      dc.l dec int tbl, 16 bpl\n",
    "    -t50      dc.w '   word  '    '\n",
    "    -t51      dc.b '   byte  '    '\n",
    "    -t52      dc.l dec int tbl, 8 bpl\n",
    "    -t53      dc.w '   word  '    '\n",
    "    -t54      dc.b '   byte  '    '\n",
    "    -t55      dc.l dec int tbl, 4 bpl\n",
    "    -t56      dc.w '   word  '    '\n",
    "    -t57      dc.b '   byte  '    '\n",
    "    -t58      text with no translation\n",
    "    -t59       '   lower case\n",
    "    -t60       '   upper case\n",
    "    -t61      dl 0aah intel hex int tbl, 16 bpl\n",
    "    -t62      dw  '    '     '  word  '    '   \n",
    "    -t63      db  '    '     '  byte  '    '   \n",
    "    -t64      binary bytes w/offset, 8 bpl\n",
    "    -t65       '     words  '         '\n",
    "    -t66       '     longs  '         '\n",
    "    -t67      DCD  &hex int tbl, 16 bpl\n",
    "    -t68      DCW   '   word  '    '\n",
    "    -t69      DCB   '   byte  '    '\n",
    "    -nologo   disable banner\n",
    "    -v0       no console output\n",
    "    -v1       prints source file name and errors\n",
    "    -v2       status line for each file (default)\n",
    "    -v3       additional info\n",
    "    -w0       don't output file\n",
    "    -w1       output to file (default)\n",
    "    -r        recurse subdirectories\n",
    "    -x<n>,<m> translate character n to m (ie -x65,97)\n",
    "\n",
    "RANGE SYNTAX:\n"
    "    [[!][<start>][..][<end>][+=<step>][,]]*\n"
    "    ie -f             all frames\n"
    "       -f5            frame 5\n"
    "       -f5..9         frames 5..9 inclusive\n"
    "       -f!10          all frames except\n"
    "       -f5,7,9        frames 5,7 and 9\n"
    "       -f10..98+=2    even frames in range between 10 and 98\n",
    "\n",
    0,
};


void SPIT_usage(const char *prgname, const char *envname, const char *urlname, int utype)
{
    char **hlp;

    printf("XDump v%s by FrANK Barchard, EAC\n",TextVersion);
    if (utype)
        printf("USAGE: %s -options [files]\n", prgname);

    switch (utype)
    {
        case 2:
            puts("    -a alignment                 -eol remove eoln separators");
            puts("    -e expand tabs               -t type of output");
            puts("    -b bytes per line            -s start byte");
            puts("    -i intel swap                -v verbose");
            puts("    -l len (bytes to dump)       -w write file");
            puts("    -o output format strings     -x translate characters");
            puts("    -r recurse subdirectories");
            puts("     @ response file              = output file");
          printf("type '%s -h' for more help\n", prgname);
          printf("type '%s -help' for web page (%s)\n", prgname, urlname);
            break;

        case 3:
          printf("VERSION: %s v%s, Spit v%.2f\n",SPIT_MACHINE,TextVersion,(float)SPIT_VERSION/100.0f);
            puts("SUMMARY: XD dumps a file in Hex, Decimal or Octal with ASCII");
            puts("         as a text file, with optional translation.");
          printf("         SPIT environment variable is %s\n",envname);
            puts("");

            hlp = optionhelp;
            while (*hlp)
            {
                printf("%s",*hlp);
                ++hlp;
            }
            break;

         case 4:
            puts("");
            {
                hlp = optionhelp;
                while (*hlp)
                {
                    if (SPIT_strstr(*hlp,envname))
                        printf("%s",*hlp);
                    ++hlp;
                }
                puts("");
            }
            break;

        default:
            break;
    }
}

char *SPIT_opt(const char *optptr)
{
    const char *d=NULL;
    int  optstate;
    int  i;

    switch (*optptr|(char)' ')
    {
        case 'a':
            d = SPIT_getopt( &OPTalign,optptr+1, "alignment", 0, MAXBYTESPERLINE);
            break;

        case 'b':
            d = SPIT_getopt( &OPTbytesperline,optptr+1, "bytesperline", 0, MAXBYTESPERLINE);
            break;

        case 'e':
            if (strnicmp(optptr, "eol", 3))
                d = SPIT_getopt( &OPTremovebytes,optptr+1, "expand tabs", 0, 1);
            else
                d = SPIT_getopt( &OPTexpandtabs,optptr+1, "expand tabs", 0, 16);
            break;

        case 'h':
            if (!strnicmp(optptr, "help", 4))
                break;
            OPTlen = 256;
            d = optptr+1;
            break;

        case 'i':
            d = SPIT_getopt( &OPTintel,optptr+1, "intel", 0, 1);
            break;

        case 'l':
        {
            int l=(int)OPTlen;
            d = SPIT_getopt( &l,optptr+1, "len", 0x80000000, 0x7fffffff);
            OPTlen = (GPOS) l;
            break;
        }

        case 's':
        {
            int l=(int)OPTstart;
            d = SPIT_getopt( &l,optptr+1, "start", 0x80000000, 0x7fffffff);
            OPTstart = (GPOS) l;
            break;
        }

        case 'o':
            optstate = 0;
            if (OPTtype==0)
                OPTtype = 1;

            d = SPIT_getopt( &optstate,optptr+1, "outformat", 0, 4);
            d = SPIT_nextfield(d);
            switch (optstate)
            {
                case 0:
                    strcpy(buf0,OPTformat0);
                    OPTformat0 = buf0;
                    d = SPIT_getstropt( buf0,d, "int offset format", "", SPITYES, 2048);
                    break;

                case 1:
                    strcpy(buf1,OPTformat1);
                    OPTformat1 = buf1;
                    d = SPIT_getstropt( buf1,d, "int every byte format", "", SPITYES, 2048);
                    break;

                case 2:
                    strcpy(buf2,OPTformat2);
                    OPTformat2 = buf2;
                    d = SPIT_getstropt( buf2,d, "int every word format", "", SPITYES, 2048);
                    break;

                case 3:
                    strcpy(buf3,OPTformat3);
                    OPTformat3 = buf3;
                    d = SPIT_getstropt( buf3,d, "int every int format", "", SPITYES, 2048);
                    break;

                case 4:
                    strcpy(buf4,OPTformat4);
                    OPTformat4 = buf4;
                    d = SPIT_getstropt( buf4,d, "ascii string format", "", SPITYES, 2048);
                    break;
            }
            break;

        case '0':
            if (!strnicmp(optptr,"0x00000000",10))
            {
                d = optptr+10;
                OPTalign = 1;
                OPTintel = 1;
                OPTbytesperline = 16;
                OPTremovebytes = 0;
                OPTformat0 = "  ";
                OPTformat1 = "";
                OPTformat2 = "";
                OPTformat3 = "0x%08lx,";
                OPTformat4 = "";
            }
            else if (!strnicmp(optptr,"0x0000",6))
            {
                d = optptr+6;
                OPTalign = 1;
                OPTintel = 1;
                OPTbytesperline = 16;
                OPTremovebytes = 0;
                OPTformat0 = "  ";
                OPTformat1 = "";
                OPTformat2 = "0x%04x,";
                OPTformat3 = "";
                OPTformat4 = "";
            }
            else if (!strnicmp(optptr,"0x00",4))
            {
                d = optptr+4;
                OPTalign = 1;
                OPTintel = 1;
                OPTbytesperline = 16;
                OPTremovebytes = 0;
                OPTformat0 = "  ";
                OPTformat1 = "0x%02x,";
                OPTformat2 = "";
                OPTformat3 = "";
                OPTformat4 = "";
            }
            else if (!strnicmp(optptr,"0x",2))
            {
                d = optptr+2;
                OPTalign = 1;
                OPTintel = 0;
                OPTbytesperline = 16;
                OPTremovebytes = 0;
                OPTformat0 = "  ";
                OPTformat1 = "0x%02x,";
                OPTformat2 = "";
                OPTformat3 = "";
                OPTformat4 = "";
            }
            break;

        case 't':
            for (i=0; i<256; ++i)
                OPTxlat[i] = i;

            d = SPIT_getopt( &OPTtype,optptr+1, "type", 0, 69);
            switch (OPTtype)
            {
                case 0: /* auto */
                    break;

                case 1:
                    OPTalign = 1;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "%05lx: ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%08lx ";
                    OPTformat4 = " %s";
                    break;

                case 2:
                    OPTalign = 1;
                    OPTbytesperline = MAXBYTESPERLINE;
                    OPTremovebytes = 0;
                    OPTformat0 = "";
                    OPTformat1 = "%c";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "\\";
                    for (i=0; i<(int)' '; ++i)
                        OPTxlat[i] = '.';
                    for (i=127; i<256; ++i)
                        OPTxlat[i] = '.';
                    OPTxlat[8] = 8;     /* backspace is ok */
                    OPTxlat[9] = 9;     /* tab is ok */
                    OPTxlat[10] = 10;   /* lf is ok */
                    OPTxlat[13] = 13;

                    OPTxlat[165] = 165; /* $a5 165 bullet */
                    OPTxlat[168] = 168; /* $a8 168 registered trademark */
                    OPTxlat[169] = 169; /* $a9 169 copyright */
                    OPTxlat[170] = 170; /* $aa 170 trademark */
                    OPTxlat[182] = 182; /* $b6 182 line continuation */
                    OPTxlat[196] = 196; /* $c4 196 florin */
                    break;

                case 3:
                    OPTalign = 2;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  ";
                    OPTformat1 = "";
                    OPTformat2 = "$%04x,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 4:
                    OPTalign = 16;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "%05lx: ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%08lx ";
                    OPTformat4 = " %s";
                    break;

                case 5:
                    OPTalign = 2;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  ";
                    OPTformat1 = "";
                    OPTformat2 = "$%04x,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 6:
                    OPTalign = 16;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "%05lx: ";
                    OPTformat1 = "%02x ";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = " %s";
                    break;

                case 7:
                    OPTalign = 16;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "%05lx: ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%10ld ";
                    OPTformat4 = "";
                    break;

                case 8:
                    OPTalign = 16;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "%05lx: ";
                    OPTformat1 = "";
                    OPTformat2 = "%5d ";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 9:
                    OPTalign = 16;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "%05lx: ";
                    OPTformat1 = "%3d ";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 10:
                    OPTalign = 16;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "%08lo: ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%011lo ";
                    OPTformat4 = "";
                    break;

                case 11:
                    OPTalign = 16;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "%08lo: ";
                    OPTformat1 = "";
                    OPTformat2 = "%06o ";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 12:
                    OPTalign = 16;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "%08lo: ";
                    OPTformat1 = "%03o ";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 13:
                    OPTalign = 4;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "$%08lx,";
                    OPTformat4 = "";
                    break;

                case 14:
                    OPTalign = 2;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  ";
                    OPTformat1 = "";
                    OPTformat2 = "$%04x,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 15:
                    OPTalign = 1;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  ";
                    OPTformat1 = "$%02x,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 16:
                    OPTalign = 4;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "  ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%ld,";
                    OPTformat4 = "";
                    break;

                case 17:
                    OPTalign = 2;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "  ";
                    OPTformat1 = "";
                    OPTformat2 = "%d,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 18:
                    OPTalign = 1;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "  ";
                    OPTformat1 = "%d,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 19:
                    OPTalign = 4;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "  ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "0x%08lx,";
                    OPTformat4 = "";
                    break;

                case 20:
                    OPTalign = 2;
                    OPTbytesperline = 16;
                    OPTremovebytes = 0;
                    OPTformat0 = "  ";
                    OPTformat1 = "";
                    OPTformat2 = "0x%04x,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 21:
                    OPTalign = 1;
                    OPTbytesperline = 8;
                    OPTremovebytes = 0;
                    OPTformat0 = "  ";
                    OPTformat1 = "0x%02x,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 22:
                    OPTalign = 4;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dl  ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "$%08lx,";
                    OPTformat4 = "";
                    break;

                case 23:
                    OPTalign = 2;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dw  ";
                    OPTformat1 = "";
                    OPTformat2 = "$%04x,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 24:
                    OPTalign = 1;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  db  ";
                    OPTformat1 = "$%02x,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 25:
                    OPTalign = 4;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dl  ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "$%08lx,";
                    OPTformat4 = "";
                    break;

                case 26:
                    OPTalign = 2;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dw  ";
                    OPTformat1 = "";
                    OPTformat2 = "$%04x,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 27:
                    OPTalign = 1;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  db  ";
                    OPTformat1 = "$%02x,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 28:
                    OPTalign = 4;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dl  ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "$%08lx,";
                    OPTformat4 = "";
                    break;

                case 29:
                    OPTalign = 2;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dw  ";
                    OPTformat1 = "";
                    OPTformat2 = "$%04x,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 30:
                    OPTalign = 1;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  db  ";
                    OPTformat1 = "$%02x,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 31:
                    OPTalign = 4;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dl  ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%ld,";
                    OPTformat4 = "";
                    break;

                case 32:
                    OPTalign = 2;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dw  ";
                    OPTformat1 = "";
                    OPTformat2 = "%d,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 33:
                    OPTalign = 1;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  db  ";
                    OPTformat1 = "%d,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 34:
                    OPTalign = 4;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dl  ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%ld,";
                    OPTformat4 = "";
                    break;

                case 35:
                    OPTalign = 2;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dw  ";
                    OPTformat1 = "";
                    OPTformat2 = "%d,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 36:
                    OPTalign = 1;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  db  ";
                    OPTformat1 = "%d,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 37:
                    OPTalign = 4;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dl  ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%ld,";
                    OPTformat4 = "";
                    break;

                case 38:
                    OPTalign = 2;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dw  ";
                    OPTformat1 = "";
                    OPTformat2 = "%d,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 39:
                    OPTalign = 1;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  db  ";
                    OPTformat1 = "%d,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 40:
                    OPTalign = 4;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.l    ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "$%08lx,";
                    OPTformat4 = "";
                    break;

                case 41:
                    OPTalign = 2;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.w    ";
                    OPTformat1 = "";
                    OPTformat2 = "$%04x,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 42:
                    OPTalign = 1;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.b    ";
                    OPTformat1 = "$%02x,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 43:
                    OPTalign = 4;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.l    ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "$%08lx,";
                    OPTformat4 = "";
                    break;

                case 44:
                    OPTalign = 2;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.w    ";
                    OPTformat1 = "";
                    OPTformat2 = "$%04x,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 45:
                    OPTalign = 1;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.b    ";
                    OPTformat1 = "$%02x,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 46:
                    OPTalign = 4;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.l    ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "$%08lx,";
                    OPTformat4 = "";
                    break;

                case 47:
                    OPTalign = 2;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.w    ";
                    OPTformat1 = "";
                    OPTformat2 = "$%04x,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 48:
                    OPTalign = 1;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.b    ";
                    OPTformat1 = "$%02x,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 49:
                    OPTalign = 4;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.l    ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%ld,";
                    OPTformat4 = "";
                    break;

                case 50:
                    OPTalign = 2;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.w    ";
                    OPTformat1 = "";
                    OPTformat2 = "%d,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 51:
                    OPTalign = 1;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.b    ";
                    OPTformat1 = "%d,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 52:
                    OPTalign = 4;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.l    ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%ld,";
                    OPTformat4 = "";
                    break;

                case 53:
                    OPTalign = 2;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.w    ";
                    OPTformat1 = "";
                    OPTformat2 = "%d,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 54:
                    OPTalign = 1;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.b    ";
                    OPTformat1 = "%d,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 55:
                    OPTalign = 4;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.l    ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%ld,";
                    OPTformat4 = "";
                    break;

                case 56:
                    OPTalign = 2;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.w    ";
                    OPTformat1 = "";
                    OPTformat2 = "%d,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 57:
                    OPTalign = 1;
                    OPTbytesperline = 4;
                    OPTremovebytes = 1;
                    OPTformat0 = "  dc.b    ";
                    OPTformat1 = "%d,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 58:
                    OPTalign = 1;
                    OPTbytesperline = MAXBYTESPERLINE;
                    OPTremovebytes = 0;
                    OPTformat0 = "";
                    OPTformat1 = "%c";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "\\";
                    break;

                case 59:
                    OPTalign = 1;
                    OPTbytesperline = MAXBYTESPERLINE;
                    OPTremovebytes = 0;
                    OPTformat0 = "";
                    OPTformat1 = "%c";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "\\";
                    for (i=(int)'A'; i<=(int)'Z'; ++i)
                        OPTxlat[i] = i+(int)('a'-'A');
                    break;

                case 60:
                    OPTalign = 1;
                    OPTbytesperline = MAXBYTESPERLINE;
                    OPTremovebytes = 0;
                    OPTformat0 = "";
                    OPTformat1 = "%c";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "\\";
                    for (i=(int)'a'; i<=(int)'z'; ++i)
                        OPTxlat[i] = i+(int)('A'-'a');
                    break;

                case 61:
                    OPTalign = 4;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTintel = 1;
                    OPTformat0 = "  dl  ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "0%08lxh,";
                    OPTformat4 = "";
                    break;

                case 62:
                    OPTalign = 2;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTintel = 1;
                    OPTformat0 = "  dw  ";
                    OPTformat1 = "";
                    OPTformat2 = "0%04xh,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 63:
                    OPTalign = 1;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTintel = 1;
                    OPTformat0 = "  db  ";
                    OPTformat1 = "0%02xh,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 64:
                    OPTalign = 8;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "%05lx: ";
                    OPTformat1 = "%08b ";
                    OPTformat2 = "";
                    OPTformat3 = " ";
                    OPTformat4 = "";
                    break;

                case 65:
                    OPTalign = 8;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "%05lx: ";
                    OPTformat1 = "";
                    OPTformat2 = "%016b ";
                    OPTformat3 = " ";
                    OPTformat4 = "";
                    break;

                case 66:
                    OPTalign = 8;
                    OPTbytesperline = 8;
                    OPTremovebytes = 1;
                    OPTformat0 = "%05lx: ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "%032b ";
                    OPTformat4 = "";
                    break;

                case 67:
                    OPTalign = 4;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  DCD     ";
                    OPTformat1 = "";
                    OPTformat2 = "";
                    OPTformat3 = "&%08lx,";
                    OPTformat4 = "";
                    break;

                case 68:
                    OPTalign = 2;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  DCW     ";
                    OPTformat1 = "";
                    OPTformat2 = "&%04x,";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;

                case 69:
                    OPTalign = 1;
                    OPTbytesperline = 16;
                    OPTremovebytes = 1;
                    OPTformat0 = "  DCB     ";
                    OPTformat1 = "&%02x,";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "";
                    break;
            }
            break;

        case 'x':
            optstate = 0;
            d = SPIT_getopt( &optstate,optptr+1, "xlatsource", 0, 255);
            d = SPIT_nextfield(d);
            d = SPIT_getopt( &OPTxlat[optstate],d, "xlatdest", -1, 255);
            break;

        default:
            break;
    }
    return((char *) d);
}

int main(int argc,char **argv)
{
    char *s;
    int  i;
    int  j;
    SPITMEM infile;
    char statbuf[SPITMAXLINE];
    int oldverbose;
    GPOS dumplen;
    GPOS outlen;

    SPIT_init(SPIT_reset, SPIT_usage, SPIT_opt, SPIT_history);
    SPIT_parse(argc, argv, TOOL_NAME, TOOL_VERSION);

    oldverbose = OPTverbose;
    {
        if (SPITargnum>1)
            OPTverbose -= 1;
        else
            OPTverbose -= 2;
        if (OPTverbose<0)
            OPTverbose = 0;
    }

    for (i=0; i<SPITargnum; ++i)
    {
        if (OPTverbose>=6)
            printf("file %d of %d %s\n",i,SPITargnum,SPITsargv[i]);
        SPIT_loadfilerange(&infile, SPITsargv[i],OPTstart,OPTlen,OPTverbose);
        if (infile.ptr)
        {
            dumplen = infile.len;

//            int digits=(int) ceil(log10(OPTstart+infile.len));

            const char *outfile = "stdout:";
            if (stricmp(SPITsargv[i],SPITdargv[i]))
                outfile = SPITdargv[i];

            /* auto select output format */

            if (OPTtype==0)
            {
                OPTtype = 2;
                j = (int) dumplen;
                if (j > 3000)
                    j = 3000;
                s = infile.ptr;
                while (j--)
                {
                    if ((unsigned char)*s<(unsigned char)' ' || *s>'~')
                    {
                        if (*s>'~' || ((unsigned char)*s<(unsigned char)' ' && *s!=(char)'\n' && *s!=(char)'\t' && *s!=(char)'\b' && *s!=(char)'\r' && *s!=(char)26))
                        {
                            OPTtype = 1;
                            j = 0;
                        }
                    }
                    ++s;
                }
                if (OPTtype==2)
                {
                    OPTalign = 1;
                    OPTbytesperline = MAXBYTESPERLINE;
                    OPTremovebytes = 0;
                    OPTformat0 = "";
                    OPTformat1 = "%c";
                    OPTformat2 = "";
                    OPTformat3 = "";
                    OPTformat4 = "\\";
                }
            }

            printf("%s",SPIT_savestr(statbuf, outfile,OPTverbose));
            SPIT_flush();

            if (OPTverbose)
                puts("");

            outlen = xdump(infile.ptr, OPTstart, dumplen, outfile);

            if (!outlen)
            {
                if (OPTverbose)
                    printf("ERROR could not write output file\n");
            }

            /* print some stats */

            if (OPTverbose>=3)
            {
                SPIT_percentstr(statbuf, (int)dumplen, (int)outlen);
                printf("%ld->%ld (%s)\n", (int)dumplen, (int)outlen, statbuf);
                SPIT_flush();
            }

            SPIT_free(&infile);
        }
        else
        {
            if (!OPTverbose)
            {
                printf("ERROR could not read file <%s>\n", SPITsargv[i]);
            }
        }
    }
    if (OPTverbose==1)
        puts("");
    OPTverbose = oldverbose;
    return(0);
}


