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

const char *SPIT_history[] =
{
"------------------------------------------------------------------",
"                                                                  ",
"                             XL v1.26                             ",
"                                                                  ",
"                     by FrANK G. Barchard, EAC                    ",
"                                                                  ",
"                    Main program - Apr 07, 2000                   ",
"                                                                  ",
"------------------------------------------------------------------",
"                                                                  ",
" Version Date   History:                                          ",
" ------- ------ --------                                          ",
"    1.00 920613 add constant to all bytes in file                 ",
"    1.10 920617 azm sym numerical expression parser               ",
"    1.11 920617 expression for last arg                           ",
"    1.12 920618 print error message for expression                ",
"    1.13 920619 i and x1 symbols added, -l, -c options            ",
"    1.14 920619 if expression                                     ",
"    1.15 920624 source file optional                              ",
"    1.16 920625 prescale and offset x                             ",
"    1.17 920628 source offset and -len                            ",
"    1.18 920708 turn off clipping/y output vars                   ",
"    1.19 920820 -f5 (/12) & -f6 (/16) filtering formulas          ",
"    1.20 920919 2048 byte expressions/-l determines len           ",
"    1.21 920914 spit 2.0                                          ",
"    1.22 920923 changed __y1 var to _y1 for MSC 7                 ",
"    1.23 930527 don't flip sign for -f option                     ",
"    1.24 930528 (signed char) for Watcom/-f expressions changed   ",
"    1.25 940120 -cub for unsigned in doc                          ",
"    1.26 000407 ranger API for constrained ranges/expressions     ",
"                                                                  ",
"------------------------------------------------------------------",
"\0"
};

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

#include    "spit.h"
#include    "expr.h"
#include    "ranger.h"

const char TextVersion[]="1.26 (Samba) 2007.12.4";
#define TOOL_VERSION 126
#define TOOL_NAME "xl"

#define Byte 1
#define Word 2
#define Long 4

int OPTmulamt;
int OPTdivamt;
int OPTaddamt;
int OPTandamt;
int OPToramt;
int OPTeoramt;
int  OPTclip;
int OPTmaxamt;
int OPTminamt;
int OPTsteprate;
int OPTstart;
int OPTlen;
int OPToffset;
int  OPTsignext;
int  OPTsize;
EXPR *expr=0;

#define MAXEXPRESS  2048
char IFExpress[MAXEXPRESS];      /* conditional expression */
char Express[MAXEXPRESS];        /* expression to apply to file */

#define SPIT_ptrdif(s,d) (int)((char *)(d)-(char *)(s))


/****************************************************************/
/*  Application Variables                                       */
/****************************************************************/

/*
;
; ABSTRACT
;
; xl - translate a binary file
;
; SUMMARY
;
; xl -options [files] [if(<expression>)] (<expression>)
;     x - next byte from file, expressed as signed or unsigned int
;         int, depending on -e option.  The default is unsigned
;     u - next byte from file, expressed as an unsigned int in the
;         range 0 to 255
;     -cb       byte sized (default)
;     -csb       '    '    with clipping to signed byte values
;     -csb       '    '    with clipping to unsigned byte values
;     -cw       word sized
;     -csw       '    '    with clipping to signed word values
;     -csw       '    '    with clipping to unsigned word values
;     -cl       int sized
;     -csl       '    '    with clipping to signed int values
;     -csl       '    '    with clipping to unsigned int values
;     -e0       unsigned bytes for source
;     -e0       unsigned bytes for source
;     -e1       sign extend bytes for source
;     -f0       no formula
;     -f1       formula ((x3/4+x2/4+x1/4+x)+1)/2*2 (dac packs)
;     -f2       formula ((x3/4+x2/4+x1/4+x)+2)/4*4
;     -f3       formula ((x3/4+x2/4+x1/4+x)+3)/6*6
;     -f4       formula ((x3/4+x2/4+x1/4+x)+4)/8*8
;     -f5       formula ((x3/4+x2/4+x1/4+x)+6)/12*12
;     -f6       formula ((x3/4+x2/4+x1/4+x)+8)/16*16
;     -l<n>     dump n bytes
;     -o<n>     offset source (ie 1 would take a byte out of dest)
;     -r<n>     step rate (default is 0x00010000)
;     -s<n>     start at byte n
;     -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)
;     -x<exp>   enter expression for each byte
;     -*<n>     pre mult(in order of operations)
;     -/<n>      '  div
;     -+<n>      '  add
;     --<n>      '  sub
;     -&<n>      '  and
;     -|<n>      '  or
;     -^<n>      '  eor
;     -><n>     min clipping
;     -<<n>     max clipping
;     @file     response file, containing a list of options and files
;     =file     specify a output file ie xl source=dest
;
;
; DESCRIPTION
;
; XL translates binary files using an algebraic expression that you
; specify.  The expression is interpreted using the expression
; evalutator from AZM, with 3 reserved symbols available.
;   s - next byte from file, expressed as a sign extended int in the
;       range -128 to 127
;   u - next byte from file, expressed as an unsigned int in the
;       range 0 to 255
;   x - next byte from file, expressed as signed or unsigned int
;         int, depending on -e option.  The default is unsigned
;
; RETURNS
;
; no return code
;
; SEE ALSO
;
; xd, azm, Spit
;
; SAMPLE OUTPUT
;
; >xl file1=file2 if(i>16) (i+1)
;
;   XLate v1.17 (waffle) (c) 1992 FrANK Barchard, EAC
;   file1: Reading, Translating, Writing, 24614->24614 (0.0%)
;
; END ABSTRACT
;
*/

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

void SPIT_reset(void)
{
    OPTextrule = "";
    OPTmulamt = 1L;
    OPTdivamt = 1L;
    OPTaddamt = 0L;
    OPTandamt = -1L;
    OPToramt =  0L;
    OPTeoramt = 0L;
    OPTclip = SPITNO;
    OPTminamt = 0x80000000L;
    OPTmaxamt = 0x7fffffffL;
    OPTsteprate = 0x00010000L;
    OPTstart = 0L;
    OPTlen = 0L;
    OPToffset = 0L;
    OPTsize = Byte;
    OPTsignext = 1;

    EXPR_set(expr,"s",0);
    EXPR_set(expr,"u",0);
    EXPR_set(expr,"x",0);
    EXPR_set(expr,"a",0);
    EXPR_set(expr,"b",0);
    EXPR_set(expr,"c",0);
    EXPR_set(expr,"x1",0);
    EXPR_set(expr,"x2",0);
    EXPR_set(expr,"x3",0);
    EXPR_set(expr,"x4",0);
    EXPR_set(expr,"x5",0);
    EXPR_set(expr,"x6",0);
    EXPR_set(expr,"x7",0);
    EXPR_set(expr,"x8",0);
    EXPR_set(expr,"y1",0);
    EXPR_set(expr,"y2",0);
    EXPR_set(expr,"y3",0);
    EXPR_set(expr,"y4",0);
    EXPR_set(expr,"y5",0);
    EXPR_set(expr,"y6",0);
    EXPR_set(expr,"y7",0);
    EXPR_set(expr,"y8",0);
    EXPR_set(expr,"i", 0);
    EXPR_set(expr,"len",0);
}

void SPIT_usage(const char *prgname, const char *envname, const char *urlname, int utype)
{
    printf("XLate v%s ",TextVersion);
    printf("(c) 1992 FrANK Barchard, EAC\n");

    if (utype>=3)
    {
            puts("");
          printf("VERSION: %s v%s, Spit v%.2f\n",SPIT_MACHINE,TextVersion,(float)SPIT_VERSION/100.0f);
            puts("SUMMARY: XL translates a binary file with an expression");
          printf("         SPIT environment variable is %s\n",envname);
            puts("");
            puts("EXPRESSION VARIABLES:");
            puts("    inlen     length of input file");
            puts("    s         signed source value");
            puts("    u         unsigned source value");
            puts("    x         source value signed based on -e option (signed default)");
            puts("    a         1/2 source + 1/2 a");
            puts("    b         1/4 source + 3/4 b");
            puts("    c         1/8 source + 7/8 c");
            puts("    x1        source[-1]");
            puts("    x2        source[-2]");
            puts("    x3        source[-3]");
            puts("    x4        source[-4]");
            puts("    x5        source[-5]");
            puts("    x6        source[-6]");
            puts("    x7        source[-7]");
            puts("    x8        source[-8]");
            puts("    y1        dest[-1]");
            puts("    y2        dest[-2]");
            puts("    y3        dest[-3]");
            puts("    y4        dest[-4]");
            puts("    y5        dest[-5]");
            puts("    y6        dest[-6]");
            puts("    y7        dest[-7]");
            puts("    y8        dest[-8]");
            puts("    i         index into file");
            puts("    len       length of source file");
            puts("");
    }
    if (utype)
        printf("USAGE: %s -options [files] [if(<expression>)] (<expression>)\n", prgname);

    switch (utype)
    {
        case 0:
        case 1:
            break;

        case 2:
            puts("    -c clip and size             -r step rate");
            puts("    -e extend sign               -s start byte");
            puts("    -f formulas builtin          -v verbose");
            puts("    -l len (bytes to dump)       -w write file");
            puts("    -o offset                    -x expression");
            puts("    -> min                       -< max");
            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:
            puts("    @file     response file, containing a list of options and files");
          printf("    =file     specify a output file ie %s source=dest\n", prgname);
            puts("    -cb       byte sized (default)");
            puts("    -csb       '    '    with clipping to signed byte values");
            puts("    -cub       '    '    with clipping to unsigned byte values");
            puts("    -cw       word sized");
            puts("    -csw       '    '    with clipping to signed word values");
            puts("    -cuw       '    '    with clipping to unsigned word values");
            puts("    -cl       int sized");
            puts("    -csl       '    '    with clipping to signed int values");
            puts("    -cul       '    '    with clipping to unsigned int values");
            puts("    -e0       unsigned bytes for source");
            puts("    -e1       sign extend bytes for source");
            puts("    -f0       no formula");
            puts("    -f1       formula ((x3/4+x2/4+x1/4+x)*4/7+1)/2*2 (dac packs)");
            puts("    -f2       formula ((x3/4+x2/4+x1/4+x)*4/7+2)/4*4");
            puts("    -f3       formula ((x3/4+x2/4+x1/4+x)*4/7+3)/6*6");
            puts("    -f4       formula ((x3/4+x2/4+x1/4+x)*4/7+4)/8*8");
            puts("    -f5       formula ((x3/4+x2/4+x1/4+x)*4/7+6)/12*12");
            puts("    -f6       formula ((x3/4+x2/4+x1/4+x)*4/7+8)/16*16");
            puts("    -l<n>     dump n bytes");
            puts("    -o<n>     offset source (ie 1 would take a byte out of dest)");
            puts("    -r<n>     step rate (default is 0x00010000)");
            puts("    -s<n>     start at byte n");
            puts("    -nologo   disable banner");
            puts("    -v0       no console output");
            puts("    -v1       prints source file name and errors");
            puts("    -v2       status line for each file (default)");
            puts("    -v3       additional info");
            puts("    -w0       don't output file");
            puts("    -w1       output to file (default)");
            puts("    -x<exp>   enter expression for each byte");
            puts("    -*<n>     pre mult(in order of operations)");
            puts("    -/<n>      '  div");
            puts("    -+<n>      '  add");
            puts("    --<n>      '  sub");
            puts("    -&<n>      '  and");
            puts("    -|<n>      '  or");
            puts("    -^<n>      '  eor");
            puts("    -><n>     min clipping");
            puts("    -<<n>     max clipping");
            break;

        default:
            break;
    }
}

char *SPIT_opt(const char *optptr)
{
    const char *s;
    char optchar;
    int  optval;

    s = optptr;
    optchar = (char)(*s++|(char)' ');
    switch (optchar)
    {
        case 'x':                               /* general expression */
            s = SPIT_getstropt( Express,s, "expression", ",", SPITNO, MAXEXPRESS);
            break;

        case '*':
            s = SPIT_getopt( &OPTmulamt,s, "mul amount", (int) 0x80000000, (int) 0x7fffffff);
            break;

        case '/':
            s = SPIT_getopt( &OPTdivamt,s, "div amount", (int) 0x80000000, (int) 0x7fffffff);
            break;

        case '+':
        case 'a':
            s = SPIT_getopt( &OPTaddamt,s, "add amount", (int) 0x80000000, (int) 0x7fffffff);
            break;

        case '-':
            s = SPIT_getopt( &OPTaddamt,s, "add amount", (int) 0x80000000, (int) 0x7fffffff);
            OPTaddamt = -OPTaddamt;
            break;

        case '&':
            s = SPIT_getopt( &OPTandamt,s, "and amount", (int) 0x80000000, (int) 0x7fffffff);
            break;

        case '|':
            s = SPIT_getopt( &OPToramt,s,  "or amount",  (int) 0x80000000, (int) 0x7fffffff);
            break;

        case '^':
            s = SPIT_getopt( &OPTeoramt,s, "eor amount", (int) 0x80000000, (int) 0x7fffffff);
            break;

        case '<':
            OPTclip = SPITYES;
            s = SPIT_getopt( &OPTmaxamt,s, "max amount", (int) 0x80000000, (int) 0x7fffffff);
            break;

        case '>':
            OPTclip = SPITYES;
            s = SPIT_getopt( &OPTminamt,s, "min amount", (int) 0x80000000, (int) 0x7fffffff);
            break;

        case 'c':
            optchar = (char)(*s++|(char)' ');
            optval = 0;
            OPTclip = SPITNO;
            if (optchar==(char)'s')
            {
                optval = 1;
                OPTsignext = 1;
                optchar = (char)(*s++|(char)' ');
            }
            else
            {
                if (optchar==(char)'u')
                {
                    optval = 2;
                    OPTsignext = 0;
                    optchar = (char)(*s++|(char)' ');
                }
            }

            if (optchar==(char)'b' || (unsigned char)optchar<=(unsigned char)' ')
            {
                if ((unsigned char)optchar<=(unsigned char)' ')
                    --s;
                OPTsize = Byte;
                if (optval)
                {
                    OPTclip = SPITYES;
                    if (optval==1)
                    {
                        OPTminamt = 0xffffff80L;
                        OPTmaxamt = 0x0000007fL;
                    }
                    else
                    {
                        OPTminamt = 0x00000000L;
                        OPTmaxamt = 0x000000ffL;
                    }
                }
            }
            else
            {
                if (optchar==(char)'w')
                {
                    OPTsize = Word;
                    if (optval)
                    {
                        OPTclip = SPITYES;
                        if (optval==1)
                        {
                            OPTminamt = 0xffff8000L;
                            OPTmaxamt = 0x00007fffL;
                        }
                        else
                        {
                            OPTminamt = 0x00000000L;
                            OPTmaxamt = 0x0000ffffL;
                        }
                    }
                }
                else
                {
                    if (optchar==(char)'l')
                    {
                        OPTsize = Long;
                        if (optval)
                        {
                            OPTclip = SPITYES;
                            OPTminamt = 0x80000000L;
                            OPTmaxamt = 0x7fffffffL;
                        }
                    }
                    else
                    {
                        if (OPTverbose)
                            puts("Error: illegal clip option");
                    }
                }
            }
            break;

        case 'e':
            s = SPIT_getopt( &OPTsignext,s, "extend sign", 0, 1);
            break;

        case 'f':
            optval = 0;
            s = SPIT_getopt( &optval,s, "formula number", 0, 6);
            switch (optval)
            {
                case 0:
                    OPTsize = Byte;
                    OPTclip = SPITYES;
                    OPTminamt = 0x80000000L;
                    OPTmaxamt = 0x7fffffffL;
                    OPTsignext = 1;
                    OPTaddamt = 0;
                    Express[0] = '\0';
                    break;

                case 1:
                    OPTsize = Byte;
                    OPTclip = SPITYES;
                    OPTminamt = 0xffffff80L;
                    OPTmaxamt = 0x0000007fL;
                    OPTsignext = 1;
                    OPTaddamt = 0;
                    strcpy(Express, "((x3/4+x2/4+x1/4+x)*4/7+1)/2*2");
                    break;

                case 2:
                    OPTsize = Byte;
                    OPTclip = SPITYES;
                    OPTminamt = 0xffffff80L;
                    OPTmaxamt = 0x0000007fL;
                    OPTsignext = 1;
                    OPTaddamt = 0;
                    strcpy(Express, "((x3/4+x2/4+x1/4+x)*4/7+2)/4*4");
                    break;

                case 3:
                    OPTsize = Byte;
                    OPTclip = SPITYES;
                    OPTminamt = 0xffffff80L;
                    OPTmaxamt = 0x0000007fL;
                    OPTsignext = 1;
                    OPTaddamt = 0;
                    strcpy(Express, "((x3/4+x2/4+x1/4+x)*4/7+3)/6*6");
                    break;

                case 4:
                    OPTsize = Byte;
                    OPTclip = SPITYES;
                    OPTminamt = 0xffffff80L;
                    OPTmaxamt = 0x0000007fL;
                    OPTsignext = 1;
                    OPTaddamt = 0;
                    strcpy(Express, "((x3/4+x2/4+x1/4+x)*4/7+4)/8*8");
                    break;

                case 5:
                    OPTsize = Byte;
                    OPTclip = SPITYES;
                    OPTminamt = 0xffffff80L;
                    OPTmaxamt = 0x0000007fL;
                    OPTsignext = 1;
                    OPTaddamt = 0;
                    strcpy(Express, "((x3/4+x2/4+x1/4+x)*4/7+6)/12*12");
                    break;

                case 6:
                    OPTsize = Byte;
                    OPTclip = SPITYES;
                    OPTminamt = 0xffffff80L;
                    OPTmaxamt = 0x0000007fL;
                    OPTsignext = 1;
                    OPTaddamt = 0;
                    strcpy(Express, "((x3/4+x2/4+x1/4+x)*4/7+8)/16*16");
                    break;
            }
            break;

        case 'r':
            s = SPIT_getopt( &OPTsteprate,s, "step rate", (int) 0x00008000, (int) 0x00100000);
            break;

        case 's':
            s = SPIT_getopt( &OPTstart,s, "start", 0L, 8388600L);
            break;

        case 'l':
            s = SPIT_getopt( &OPTlen,s, "len", (int) 0x80000000, (int) 0x7fffffff);
            break;

        case 'o':
            s = SPIT_getopt( &OPToffset,s, "offset", (int) 0x80000000, (int) 0x7fffffff);
            break;

        default:
            s = 0;
            break;
    }
    return((char *)s);
}


int main(int argc, char **argv)
{
    int  i;
    char *s;
    char *d;
    int dacc;
    char *send;
    int dumplen;
    int ifl;
    int l;
    int ls;
    int lu;
    struct SPITMEM infile;
    struct SPITMEM outfile;
    char statbuf[SPITMAXLINE];
    RANGER *r;

    expr = EXPR_open();

    IFExpress[0] = '\0';
    Express[0] = '\0';

    if (argc>2)
    {
/*        if (argv[argc-1][0]==(char)'(' && !IsSingle(argv[argc-1])) */
        {
            strcpy(Express, argv[argc-1]);
            --argc;
        }
    }
#if 0
    if (argc>2)
    {
        if (((argv[argc-1][0]|(char)' ')==(char)'i') && ((argv[argc-1][1]|(char)' ')==(char)'f') && ((argv[argc-1][2])==(char)'('))
        {
            if (!IsSingle(&argv[argc-1][2]))
            {
                strcpy(IFExpress, &argv[argc-1][2]);
                --argc;
            }
        }
    }
#endif

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

    for (i=0; i<SPITargnum; ++i)
    {
        r = RANGER_open(expr,Express,0.0,4294967295.0);  // min/max mostly ignored
        if (OPTverbose>=5)
            printf("applying expression %s\n",Express);

        infile.ptr = (char *) 0;
        infile.len = 0L;
        if (SPITsargv[i][0])
        {
            if (!SPIT_loadfile(&infile, SPITsargv[i]))
                infile.len = -1L;
        }

        if (infile.len>=0)
        {
            if (OPTsteprate==0x00010000L)
                dumplen = infile.len+OPTlen+50000L;
            else
                dumplen = (infile.len+OPTlen)*2+50000L;

            if (SPIT_alloc(&outfile, dumplen))
            {
                if (OPTverbose>=3)
                {   printf("Translating, ");
                        SPIT_flush();
                }

                dumplen = infile.len;
                if (OPTstart+dumplen>infile.len)
                    dumplen = infile.len-OPTstart;

                if (OPTlen)
                {
                    if (OPTlen<0L)
                        dumplen = dumplen+OPTlen;
                    else
                        dumplen = OPTlen;
                }

/********************************************************************/
/*  Define Rne Reserved Symbols                                     */
/********************************************************************/

                /* copy start of file */

                s = infile.ptr+OPToffset;
                d = outfile.ptr;
                send = s+OPTstart;
                if (infile.ptr)
                {
                    while (s<send)
                    {
                        *d++ = *s++;
                    }
                }
                else
                {
                    while (s<send)
                    {
                        *d++ = '\0';
                        ++s;
                    }
                }

                dacc = 0L;

                /* translate range of file */

                EXPR_set(expr,"len",infile.len);
                ifl = 1;
                lu = 0;

                send = s+dumplen;
                while (s<send)
                {
                    if (infile.ptr)
                        lu = (int) ggetm(s, OPTsize);
                    s += OPTsize;
                    if (OPTsize==Byte)
                    {
                        ls = (int) ((signed char) lu);
                    }
                    else
                    {
                        if (OPTsize==Word)
                        {
                            ls = (int) ((short) lu);
                        }
                        else
                        {
                            ls = lu;
                        }
                    }
                    l = lu;
                    if (OPTsignext)
                    {
                        l = ls;
                    }

                    l = l * OPTmulamt;
                    l = l / OPTdivamt;
                    l = l + OPTaddamt;
                    l = l & OPTandamt;
                    l = l | OPToramt;
                    l = l ^ OPTeoramt;

                    EXPR_set(expr,"a", (EXPR_get(expr,"a")   + EXPR_get(expr,"x"))/2);
                    EXPR_set(expr,"b", (EXPR_get(expr,"b")*3 + EXPR_get(expr,"x"))/4);
                    EXPR_set(expr,"c", (EXPR_get(expr,"c")*7 + EXPR_get(expr,"x"))/8);
                    EXPR_set(expr,"x8", EXPR_get(expr,"x7"));
                    EXPR_set(expr,"x7", EXPR_get(expr,"x6"));
                    EXPR_set(expr,"x6", EXPR_get(expr,"x5"));
                    EXPR_set(expr,"x5", EXPR_get(expr,"x4"));
                    EXPR_set(expr,"x4", EXPR_get(expr,"x3"));
                    EXPR_set(expr,"x3", EXPR_get(expr,"x2"));
                    EXPR_set(expr,"x2", EXPR_get(expr,"x1"));
                    EXPR_set(expr,"x1", EXPR_get(expr,"x"));
                    EXPR_set(expr,"s", ls);
                    EXPR_set(expr,"u", lu);
                    EXPR_set(expr,"x", l);
                    EXPR_set(expr,"i", SPIT_ptrdif(outfile.ptr, d)/OPTsize);

                    if (IFExpress[0])
                    {
                        ifl = (int)EXPR_get(expr,IFExpress);
                    }

                    if (ifl)
                    {
                        if (Express[0])
                        {
//                            l = (int)EXPR_get(expr,Express);
                            l = (int) RANGER_closest(r, (double) l, RANGER_ROUND_CLOSEST);
                        }

                        if (OPTclip)
                        {
                            if (l > OPTmaxamt)
                                l = OPTmaxamt;

                            if (l < OPTminamt)
                                l = OPTminamt;
                        }
                    }
                    else
                    {
                        l = ls;                     /* revert to old value */
                    }

                    gputm(d, (unsigned int) l, OPTsize);

                    EXPR_set(expr,"y8", EXPR_get(expr,"y7"));
                    EXPR_set(expr,"y7", EXPR_get(expr,"y6"));
                    EXPR_set(expr,"y6", EXPR_get(expr,"y5"));
                    EXPR_set(expr,"y5", EXPR_get(expr,"y4"));
                    EXPR_set(expr,"y4", EXPR_get(expr,"y3"));
                    EXPR_set(expr,"y3", EXPR_get(expr,"y2"));
                    EXPR_set(expr,"y2", EXPR_get(expr,"y1"));
                    EXPR_set(expr,"y1", l);

                    dacc += OPTsteprate;
                    d += (dacc>>16)*OPTsize;
                    dacc = dacc & 0x0000ffffL;
/*                    EXPR_set(expr,"i",EXPR_get(expr,"i")); */
                }

                /* copy end of file */

                send = infile.ptr+infile.len;

                if (infile.ptr)
                {
                    while (s<send)
                    {
                        *d++ = *s++;
                    }
                }
                else
                {
                    while (s<send)
                    {
                        *d++ = '\0';
                        ++s;
                    }
                }

                outfile.len = dumplen;

                SPIT_savefile(&outfile, SPITdargv[i]);

                SPIT_free(&outfile);

                /* print some stats */

                if (OPTverbose>=3)
                {
                    SPIT_percentstr(statbuf, infile.len, outfile.len);
                    printf("%ld->%ld (%s)\n", infile.len, outfile.len, statbuf);
                    SPIT_flush();
                }
            }
            else
            {
                if (OPTverbose>=2)
                    printf("ERROR could not allocate pack buffer\n");
            }
            if (infile.ptr)
                SPIT_free(&infile);
        }
        RANGER_close(r);
    }
    if (OPTverbose==1)
        puts("");

    EXPR_close(expr);

    return(0);
}

