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

const char *SPIT_history[] =
{
"------------------------------------------------------------------",
"                                                                  ",
"                            Eapu v1.12                            ",
"                                                                  ",
"                        by FrANK G. Barchard                      ",
"                                                                  ",
"                     Main program - June 12, 2007                 ",
"                                                                  ",
"------------------------------------------------------------------",
"                                                                  ",
" Version Date   SE History:                                       ",
" ------- ----   -- --------                                       ",
"    1.00 070403 FB Initial version, by based on txt               ",
"    1.01 070411 FB -i install, -u update, -f force, -back         ",
"    1.02 070412 FB titlebar status                                ",
"    1.03 070414 FB -p packagelist (incomplete)                    ",
"    1.04 070423 FB remove vertmp.txt, rwfilesystem is unsafe      ",
"    1.05 070426 FB detect readonly, non-proxy okay                ",
"    1.06 070507 FB -undev                                         ",
"    1.07 070508 FB whereis eapm, -v5 debug output                 ",
"    1.08 070514 FB -b path to framework                           ",
"    1.09 070517 FB rwfilesystem safe, eapu=lock,stripsuffix,safe  ",
"    1.10 070523 FB allow old version to be blank                  ",
"    1.11 070608 FB verbose 1 just show version                    ",
"    1.12 070612 FB issafe stripsuffix quiet if name same          ",
"                                                                  ",
"------------------------------------------------------------------",
"\0"
};

#if 0
C:\env\packages\eadxt\dev>eapm latest snvsi
Finding latest version ...
Could not determine latest version because:
The underlying connection was closed: The remote name could not be resolved.

Try 'eapm help' for more information.
#endif

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

#include "spit.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#if defined(_MSC_VER)

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif

#include <windows.h>
#include <errno.h>
#else
#include <unistd.h>
#endif

const char TextVersion[]="1.12 (Samba) 2007.12.4";
#define TOOL_VERSION 112
#define TOOL_NAME "eapu"

int OPTback;
int OPTundev;
int OPTnumchanges;
int OPTpackages;
int OPTinstall;
int OPTupdate;
int OPTforce;
int *OPTxlate;
int OPTxlatereverse;
int OPTnewlinetype;
int OPTnocr;
int OPTjoin;
int OPTinfo;
int OPTsmart;
int OPTtolower;
int OPTunsmart;
int OPTopera;
int OPTgcc;  // add new line to end of file for gcc on unix
char OPTpath[512]="";
int unweb;  /* auto option */

int STATpackagecount=0;
int STATupdatedcount=0;
int STATunsafecount=0;

char whereisframework[512];

#define BUFSIZE 256

static int bufpos=0;
static char bufc[BUFSIZE+1];
static char buft[BUFSIZE+1];

#define ID(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d))

struct filetypes
{
    char *ext;
    int type;
    int creator;
} filetypes[]=
{
    "TXT",  ID('T','E','X','T'), ID('M','P','S',' '),
    "TEXT", ID('T','E','X','T'), ID('M','P','S',' '),
    "C",    ID('T','E','X','T'), ID('M','P','S',' '),
    "H",    ID('T','E','X','T'), ID('M','P','S',' '),
    "INC",  ID('T','E','X','T'), ID('M','P','S',' '),
    "ASM",  ID('T','E','X','T'), ID('M','P','S',' '),
    "VSM",  ID('T','E','X','T'), ID('M','P','S',' '),
    "DSM",  ID('T','E','X','T'), ID('M','P','S',' '),
    "DEF",  ID('T','E','X','T'), ID('M','P','S',' '),
    "I",    ID('T','E','X','T'), ID('M','P','S',' '),
    "S",    ID('T','E','X','T'), ID('M','P','S',' '),
    "RC",   ID('T','E','X','T'), ID('M','P','S',' '),
    "MAP",  ID('T','E','X','T'), ID('M','P','S',' '),
    "ERR",  ID('T','E','X','T'), ID('M','P','S',' '),
    "JAVA", ID('T','E','X','T'), ID('M','P','S',' '),
    "PY",   ID('T','E','X','T'), ID('M','P','S',' '),
    "CS",   ID('T','E','X','T'), ID('M','P','S',' '),
    "CPP",  ID('T','E','X','T'), ID('M','P','S',' '),
    "C++",  ID('T','E','X','T'), ID('M','P','S',' '),
    "CC",   ID('T','E','X','T'), ID('M','P','S',' '),
    "CXX",  ID('T','E','X','T'), ID('M','P','S',' '),
    "MAK",  ID('T','E','X','T'), ID('M','P','S',' '),
    "BAT",  ID('T','E','X','T'), ID('M','P','S',' '),
    "SCR",  ID('T','E','X','T'), ID('M','P','S',' '),
    "RSP",  ID('T','E','X','T'), ID('M','P','S',' '),
    "LNK",  ID('T','E','X','T'), ID('M','P','S',' '),
    "BIF",  ID('T','E','X','T'), ID('M','P','S',' '),
    "LOG",  ID('T','E','X','T'), ID('M','P','S',' '),
    "PS",   ID('T','E','X','T'), ID('M','P','S',' '),
    "ASC",  ID('T','E','X','T'), ID('M','P','S',' '),
    "HTM",  ID('T','E','X','T'), ID('M','P','S',' '),
    "HTML", ID('T','E','X','T'), ID('M','P','S',' '),
    "XML",  ID('T','E','X','T'), ID('M','P','S',' '),
    "DOF",  ID('T','E','X','T'), ID('M','P','S',' '),
    "HRC",  ID('T','E','X','T'), ID('M','P','S',' '),
    "TOG",  ID('T','E','X','T'), ID('M','P','S',' '),
    "ABS",  ID('T','E','X','T'), ID('M','P','S',' '),
    "LST",  ID('T','E','X','T'), ID('M','P','S',' '),
    "TCL",  ID('T','C','L','T'), ID('M','P','S',' '),
    "ION",  ID('T','E','X','T'), ID('M','P','S',' '),
    "SHA",  ID('T','E','X','T'), ID('M','P','S',' '),
#ifndef __unix__
    "A",    ID('T','E','X','T'), ID('M','P','S',' '),
#endif

    "SEA",  ID('A','P','P','L'), ID('M','P','S',' '),
    "ICON", ID('I','C','O','N'), ID('S','P','o','T'),
    "ICO",  ID('I','C','O','N'), ID('S','P','o','T'),
    "ANIM", ID('3','D','O','a'), ID('S','P','o','T'),
    "BMP",  ID('.','B','M','P'), ID('S','P','o','T'),
    "BLT",  ID('.','B','L','T'), ID('S','P','o','T'),
    "BOB",  ID('B','O','B',' '), ID('B','A','B','L'),
    "CEL",  ID('3','D','O','c'), ID('S','P','o','T'),
    "C65",  ID('.','C','6','5'), ID('S','P','o','T'),
    "CMP",  ID('.','C','M','P'), ID('S','P','o','T'),
    "CUT",  ID('.','C','U','T'), ID('B','A','B','L'),
    "EPS",  ID('E','P','S','F'), ID('8','B','I','M'),
    "EPI",  ID('E','P','S','F'), ID('8','B','I','M'),
    "EPSF", ID('E','P','S','F'), ID('8','B','I','M'),
    "EPSI", ID('E','P','S','F'), ID('8','B','I','M'),
    "FLI",  ID('F','L','I','C'), ID('B','A','B','L'),
    "FLC",  ID('F','L','I','C'), ID('B','A','B','L'),
    "GIF",  ID('G','I','F','f'), ID('8','B','I','M'),
    "IMG",  ID('3','D','O','i'), ID('3','D','O','e'),
    "IMAG", ID('3','D','O','i'), ID('3','D','O','e'),
    "JPG",  ID('J','P','E','G'), ID('8','B','I','M'),
    "JFIF", ID('J','P','E','G'), ID('8','B','I','M'),
    "LBM",  ID('I','L','B','M'), ID('S','P','o','T'),
    "IFF",  ID('I','L','B','M'), ID('S','P','o','T'),
    "BBM",  ID('I','L','B','M'), ID('S','P','o','T'),
    "ILBM", ID('I','L','B','M'), ID('S','P','o','T'),
    "MOOV", ID('M','o','o','V'), ID('B','A','B','L'),
    "MOV",  ID('M','o','o','V'), ID('B','A','B','L'),
    "MSP",  ID('.','M','S','P'), ID('B','A','B','L'),
    "MVI",  ID('.','M','V','I'), ID('S','P','o','T'),
    "NEO",  ID('.','N','E','O'), ID('B','A','B','L'),
    "PAL",  ID('8','B','C','T'), ID('8','B','I','M'),
    "PCD",  ID('P','I','C','T'), ID('p','p','x','i'),
    "PCX",  ID('.','P','C','X'), ID('S','P','o','T'),
    "PI1",  ID('D','E','G','A'), ID('B','A','B','L'),
    "PIC",  ID('.','S','I','M'), ID('S','P','o','T'),
    "PICT", ID('P','I','C','T'), ID('S','P','o','T'),
    "PIQT", ID('P','I','C','T'), ID('T','V','O','D'),
    "PNTG", ID('P','N','T','G'), ID('M','P','N','T'),
    "PPM",  ID('P','P','M',' '), ID('8','B','I','M'),
    "PBM",  ID('P','P','M',' '), ID('8','B','I','M'),
    "PGM",  ID('P','P','M',' '), ID('8','B','I','M'),
    "PNM",  ID('P','P','M',' '), ID('8','B','I','M'),
    "PSD",  ID('8','B','I','M'), ID('8','B','I','M'),
    "PXR",  ID('P','X','A','R'), ID('8','B','I','M'),
    "QDV",  ID('.','Q','D','V'), ID('B','A','B','L'),
    "RAST", ID('.','S','U','N'), ID('B','A','B','L'),
    "RGB",  ID('R','R','G','B'), ID('B','A','B','L'),
    "RAW",  ID('.','H','S','I'), ID('S','P','o','T'),
    "RLE",  ID('R','L','E','C'), ID('B','A','B','L'),
    "SANM", ID('3','D','O','s'), ID('3','D','O','e'),
    "SCAN", ID('S','C','A','N'), ID('B','A','B','L'),
    "SCT",  ID('.','.','C','T'), ID('8','B','I','M'),
    "SCR",  ID('.','S','C','R'), ID('S','P','o','T'),
    "SGI",  ID('.','S','G','I'), ID('B','A','B','L'),
    "TGA",  ID('T','P','I','C'), ID('S','P','o','T'),
    "TIF",  ID('T','I','F','F'), ID('8','B','I','M'),
    "TIFF", ID('T','I','F','F'), ID('8','B','I','M'),
    "TIM",  ID('.','T','I','M'), ID('S','P','o','T'),
    "VDAN", ID('V','D','A','N'), ID('V','D','3','2'),
    "VGA",  ID('.','V','G','A'), ID('S','P','o','T'),
    "VSH",  ID('.','V','S','H'), ID('S','P','o','T'),
    "YUV",  ID('A','B','E','K'), ID('B','A','B','L'),
    "3SP",  ID('.','3','S','P'), ID('S','P','o','T'),
    "3SH",  ID('.','3','S','H'), ID('S','P','o','T'),
    "PSH",  ID('.','P','S','H'), ID('S','P','o','T'),
    "FSH",  ID('.','F','S','H'), ID('S','P','o','T'),
    "TGV",  ID('.','t','g','v'), ID('S','P','o','T'),
    "AVI",  ID('.','a','v','i'), ID('S','P','o','T'),
    "PYC",  ID('.','p','y','c'), ID('S','P','o','T'),
 (char *)0, ID( 0 , 0 , 0 , 0 ), ID( 0 , 0 , 0 , 0 ),
};

/* Translation tables */

/* Convert DOS ASCII to Windows */
int Xdostowindows[256] =
{
    0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  /*   0: */
   16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  /*  16: */
   32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  /*  32: */
   48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  /*  48: */
   64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  /*  64: */
   80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  /*  80: */
   96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,  /*  96: */
  112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,  /* 112: */
  199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197,  /* 128: */
  201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 162, 163, 165,  -1, 131,  /* 144: */
  225, 237, 243, 250, 241, 209, 170,  -1, 191,  -1, 172, 189, 188, 161, 171, 187,  /* 160: */
   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  /* 176: */
   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  /* 192: */
   -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  /* 208: */
   -1, 223,  -1,  -1,  -1,  -1, 181,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  /* 224: */
   -1, 177, 178,  -1,  -1,  -1, 247,  -1, 176, 130, 183,  -1,  -1,  -1,  -1,  -1   /* 240: */
};

/* Convert to lowercase */

int Xtolower[256] =
{
    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
    0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
    0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
    0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
    0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
    0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
    0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
    0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
    0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
    0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
    0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
    0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
    0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
    0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
    0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
    0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,
    0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
    0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
    0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
    0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,
    0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
    0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,
    0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
    0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,
    0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
};



static int SearchRegEXT(const char *name,char *whereisbuf, int whereisbuflen=512)
{
    int len=0;

#if defined(_MSC_VER)
    int err;
    unsigned long valuelen;
    HKEY phkeyresult;
    char *subkey=(char *)alloca(whereisbuflen);
//    char subkey[512];
    HKEY key=HKEY_LOCAL_MACHINE;

    if (!strncmp(name,"HKEY_",strlen("HKEY_")))
    {
        struct
        {
            char *name;
            HKEY hkey;
        } hkeys[]=
        {
            {   "HKEY_CLASSES_ROOT",    HKEY_CLASSES_ROOT },
            {   "HKEY_CURRENT_USER",    HKEY_CURRENT_USER },
            {   "HKEY_LOCAL_MACHINE",   HKEY_LOCAL_MACHINE },
            {   "HKEY_USERS",           HKEY_USERS },
            {   "HKEY_CURRENT_CONFIG",  HKEY_CURRENT_CONFIG },
            {   NULL, 0 }
        };

        for (int i=0; hkeys[i].name; ++i)
        {
            if (!strncmp(name,hkeys[i].name,strlen(hkeys[i].name)))
            {
                key = hkeys[i].hkey;
                name += strlen(hkeys[i].name);
                if (*name=='/' || *name=='\\')
                    ++name;
            }
        }
    }

    /* Try to open the subkey */

    sprintf(subkey,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s",name);
    err = RegOpenKey(key,subkey,&phkeyresult);
    if (err)
    {
        sprintf(subkey,"SOFTWARE\\Microsoft\\%s",name);
        err = RegOpenKey(key,subkey,&phkeyresult);
    }
    if (err)
    {
        sprintf(subkey,"SOFTWARE\\Electronic Arts\\%s",name);
        err = RegOpenKey(key,subkey,&phkeyresult);
    }
    if (err)
    {
        sprintf(subkey,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s.exe",name);
        err = RegOpenKey(key,subkey,&phkeyresult);
    }
    if (err)
    {
        sprintf(subkey,"SOFTWARE\\Apple Computer, Inc.\\%s",name);
        err = RegOpenKey(key,subkey,&phkeyresult);
    }

    // allow user to fully specify registry subkey
    // ie SOFTWARE\Electronic Arts\Framework-0.6.2
    if (err)
    {
        sprintf(subkey,"%s",name);
        err = RegOpenKey(key,subkey,&phkeyresult);
    }
    // allow user to specify registry subkey with forward slashes (easier to pass)
    // ie SOFTWARE/Electronic Arts/Framework-0.6.2
    if (err)
    {
        sprintf(subkey,"%s",name);
        for (int i=0; subkey[i]; ++i)
            if (subkey[i]=='/') subkey[i]='\\';
        err = RegOpenKey(key,subkey,&phkeyresult);
    }

    if (!err)
    {
        /* subkey exists so read in value */

        err = 1;
        if (strstr(subkey,".exe"))
        {
            valuelen=whereisbuflen;
            memset(whereisbuf,0,whereisbuflen);

            err = RegQueryValueEx(phkeyresult,
                        NULL,
                        NULL,
                        NULL,
                        (unsigned char *)whereisbuf,
                        &valuelen);
        }

        if (err)
        {
            valuelen=whereisbuflen;
            memset(whereisbuf,0,whereisbuflen);

            // first try Path value
            err = RegQueryValueEx(phkeyresult,
                        TEXT("Path"),  // most apps use path - ie framework
                        NULL,
                        NULL,
                        (unsigned char *)whereisbuf,
                        &valuelen);
        }

        if (err)
        {
            valuelen=whereisbuflen;
            memset(whereisbuf,0,whereisbuflen);

            err = RegQueryValueEx(phkeyresult,
                        TEXT("InstallPath"), // xbox uses this one
                        NULL,
                        NULL,
                        (unsigned char *)whereisbuf,
                        &valuelen);
        }

        if (err)
        {
            valuelen=whereisbuflen;
            memset(whereisbuf,0,whereisbuflen);

            err = RegQueryValueEx(phkeyresult,
                        TEXT("Install Dir"), // platform sdk uses this one HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MicrosoftSDK\Directories
                        NULL,
                        NULL,
                        (unsigned char *)whereisbuf,
                        &valuelen);
        }

        if (err)
        {
            valuelen=whereisbuflen;
            memset(whereisbuf,0,whereisbuflen);

            err = RegQueryValueEx(phkeyresult,
                        TEXT("InstallDir"), // quicktime uses this
                        NULL,
                        NULL,
                        (unsigned char *)whereisbuf,
                        &valuelen);
        }

        if (err)
        {
            valuelen=whereisbuflen;
            memset(whereisbuf,0,whereisbuflen);

            err = RegQueryValueEx(phkeyresult,
                        NULL,
                        NULL,
                        NULL,
                        (unsigned char *)whereisbuf,
                        &valuelen);
        }


    }


    if (!err)
        len = strlen(whereisbuf);

#endif

    return(len);
}


static int GetPackageDirectory(const char *szPackage, char *whereisbuf)//, const char *szVersion)
{
    int len = SearchRegEXT("framework", whereisbuf, 512);
    if (len)
    {
        char slashbuf[512];
        strcpy(slashbuf,szPackage);
        for (int i=0; slashbuf[i]; ++i)
            if (slashbuf[i]=='/')
                slashbuf[i] = '\\';

        bool FindVersion=false;
        if (strchr(slashbuf,'\\'))  // version specified
        {
            sprintf(whereisbuf,"%s\\%s",whereisbuf,slashbuf);
            if (whereisbuf[strlen(whereisbuf)-1]=='\\')
                strcat(whereisbuf,"*");
        }
        else
        {
            sprintf(whereisbuf,"%s\\%s\\*",whereisbuf,slashbuf);
            FindVersion = true;
        }

        WIN32_FIND_DATA findfiledata;


        HANDLE hFind = FindFirstFileEx(
                            whereisbuf,
                            (FINDEX_INFO_LEVELS) FindExInfoStandard,
                            &findfiledata,
                            FindExSearchLimitToDirectories,
                            NULL, 0);

        if (hFind == INVALID_HANDLE_VALUE)
        {
            return 0;
        }

        char whereisbufLatest[512];
        whereisbufLatest[0] = '\0';
        bool Found=false;
        do
        {
            if ((findfiledata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                && (stricmp(findfiledata.cFileName,whereisbufLatest) > 0))
            {
                strcpy(whereisbufLatest, findfiledata.cFileName);
                Found = true;
            }
        }
        while(FindNextFile(hFind, &findfiledata));
        if (!Found)
            return 0;

        char *ext = strrchr(whereisbuf,'\\');
        if (ext)
        {
            strcpy(ext+1,whereisbufLatest); // replace * with what we found
        }

        len = strlen(whereisbuf);
    }

    return len;
}





static void EAPU_settitle(char *title)
{
#if defined(_MSC_VER)
    if (OPTverbose)
        SetConsoleTitle(title);
#endif
}

// example line
// <package name="rwfilesystem" version="1.01.00"/>


bool PackageGetAttrib(char *packagename, const char *bufc, const char *attrib)
{
    packagename[0] = '\0';
    const char *s = strstr(bufc,"<package");
    if (s)
    {
        s = strstr(bufc,attrib);
        if (s)
        {
            s += strlen(attrib)+1;
            while (*s!='\"' && *s)
            {
                *packagename++ = *s++;
            }
            *packagename++ = '\0';
            return true;
        }
    }
    return false;
}

bool PackageGetName(char *packagename, const char *bufc)
{
    return PackageGetAttrib(packagename,bufc,"name=");
}


bool PackageGetOldVersion(char *oldpackageversion, const char *bufc)
{
    return PackageGetAttrib(oldpackageversion,bufc,"version=");
}

bool PackageGetEapu(char *packageeapu, const char *bufc)
{
    return PackageGetAttrib(packageeapu,bufc,"eapu=");
}


bool PackageUpdateVersion(char *packageline, const char *, const char *packageversion)
{
    const char *s = strstr(bufc,"<package");
    if (s)
    {
        s = strstr(bufc,"version=");
        if (s)
        {
            s += strlen("version=")+1;
			int len=(int)(s-bufc);
            strncpy(packageline,bufc,len);
			packageline[len] = '\0';
            strcat(packageline,packageversion);
            const char *s2 = strchr(s,'\"');
            strcat(packageline,s2);
            return true;
        }
    }
    return false;
}

bool PackageFindLatestVersion(char *packageversion, const char *packagename)
{
    char packagespawn[BUFSIZE];
    sprintf(packagespawn,"%seapm latest %s>vertmp.txt",whereisframework,packagename);

    int sok = system(packagespawn);

    GSTREAM *g = gopen("vertmp.txt");
    int len = (int)glen(g);
    char *t = (char *)galloc(len+1);
    memset(t,0,len+1);
    gread(g,t,len);
    gclose(g);

    if (OPTverbose>=5)
        printf(" DEBUG: %s return %d\n%s\n",packagespawn,sok,t);

    int ok = remove("vertmp.txt");
    if (ok!=0 && errno!=ENOENT)
    {
        if (OPTverbose)
            printf("eapu - warning unable to remove temporary file vertmp.txt.  %s\n",errno==EACCES?"Access denied":"");
    }

    char *vt = strstr(t,"version ...");
    if (vt)
    {
        vt += strlen("version ...");
        while (*vt && *vt<' ')
        {
            ++vt;
        }
        if (!strncmp(vt,"Installing ",strlen("Installing ")))
            vt += strlen("Installing ");
        if (!strncmp(vt,"Package '",strlen("Package '")))
            vt += strlen("Package '");

        char *v = strstr(vt,"-");
		if (v)
		{
            if (!strncmp(packagename,vt,v-vt))
            {
                v += 1;

                while (*v>' ' && *v!='\'')
                {
                    *packageversion++ = *v++;
                }
                *packageversion = '\0';
                gfree(t);
                return true;
            }
		}
    }
    gfree(t);
    return false;
}

bool PackageInstallVersion(const char *packagename, const char *packageversion)
{
	bool ret=false;
    char packagespawn[BUFSIZE];
    sprintf(packagespawn,"%seapm install %s-%s>vertmp.txt",whereisframework,packagename,packageversion);

    int r = system(packagespawn);

    GSTREAM *g = gopen("vertmp.txt");
    int len = (int)glen(g);
    char *t = (char *)galloc(len+1);
    memset(t,0,len+1);
    gread(g,t,len);
    gclose(g);

    int ok = remove("vertmp.txt");
    if (ok!=0 && errno!=ENOENT)
        if (OPTverbose)
            printf("eapu - warning unable to remove temporary file vertmp.txt. %s\n",errno==EACCES?"Access denied":"");

    if (r==0)
    {
        char *vt = strstr(t,"Installing ");
        if (vt)
			ret = true;
    }
    gfree(t);
    return ret;
}

bool PackageIsSafe(const char *packagename, const char *oldpackageversion, char *newpackageversion, const char *packageeapu)
{
    bool safe=true;

    // unsafe versions
    if (strstr(oldpackageversion,"dev"))
    {
        if (!OPTundev)
            safe = false;
    }
    else
    {
        if ((strstr(newpackageversion,"proxy") && !strstr(newpackageversion,"non-proxy")))
           safe = false;
        else if (oldpackageversion[0] && (oldpackageversion[0]!=newpackageversion[0])) // same major?
           safe = false;
    }

    // unsafe packages
    if (strstr(packagename,"bison"))
        safe = false;
    if (strstr(packagename,"eastl"))
        safe = false;

    if (strstr(packageeapu,"unsafe") || strstr(packageeapu,"lock"))
        safe = false;
    else
        if (strstr(packageeapu,"safe"))
            safe = true;
    if (strstr(packageeapu,"stripsuffix"))
    {
        safe = true;
        char *p = strrchr(newpackageversion,'-');
        if (p)
            *p = '\0';
    }

    return safe;
}

static int numchanges=0;

void SPIT_flushc(GSTREAM *out)
{
    if (!strnicmp(bufc,"comments=",9))
        unweb = 1;

    if (unweb)
    {
        int i;
        int j=0;
        int c;
        static int lastc=0;

        i = 0;
        if (bufc[i]==lastc)
            ++i;

        while (i<bufpos)
        {
            switch (bufc[i])
            {
                case '%':
                    sscanf(bufc+i+1, "%02x", &c);
                    buft[j++] = (char) c;
                    i += 3-1;
                    break;

                case '+':
                    buft[j++] = (char) ' ';
                    break;

                case 10:
                case 13:
                    break;

                default:
                    lastc = bufc[i];
                    buft[j++] = (char) lastc;
                    break;
            }
            ++i;
        }
        memcpy(bufc,buft,j);
        bufpos = j;
    }

    bufc[bufpos] = (char) 0;
    {
        char packagename[BUFSIZE];

        if (PackageGetName(packagename, bufc))
        {
            ++STATpackagecount;

            char oldpackageversion[BUFSIZE];

            char titlebuf[SPITMAXLINE];

            if (OPTverbose>=1)
            {
                sprintf(titlebuf,"%s - EAPU latest",packagename);
                EAPU_settitle(titlebuf);
            }
            if (OPTverbose>=2 || (OPTverbose==1 && OPTupdate==0))
            {
                printf("%s",packagename);
                SPIT_flush();
            }

            if (PackageGetOldVersion(oldpackageversion, bufc))
            {
                if (OPTverbose>=2 || (OPTverbose==1 && OPTupdate==0))
                {
                    printf("-%s",oldpackageversion);
                    SPIT_flush();
                }

                char packageversion[BUFSIZE];

                if (PackageFindLatestVersion(packageversion, packagename))
                {
                    if (strcmp(oldpackageversion,packageversion))
                    {
                        char packageeapu[BUFSIZE];
                        PackageGetEapu(packageeapu, bufc);

                        bool issafe = true;
                        if (!OPTforce)
                        {
                            issafe = PackageIsSafe(packagename,oldpackageversion,packageversion,packageeapu);
                        }


                        if (strcmp(oldpackageversion,packageversion)) // issafe stripsuffix may make them the same version again
                        {

                            if (!issafe)
                            {
                                ++STATunsafecount;

                                if (OPTverbose>=2 && (!(OPTinstall==1 && OPTupdate==0)))
                                    printf(" unsafe to update to %s",packageversion);
                                strcpy(packageversion,oldpackageversion);
                            }
                            else
                            {
                                ++STATupdatedcount;

                                if (OPTupdate && (!OPTnumchanges || numchanges<OPTnumchanges))
                                {
                                    char templine[BUFSIZE];
                                    PackageUpdateVersion(templine,bufc,packageversion);
                                    strcpy(bufc,templine);
                                    bufpos = strlen(bufc);


                                    printf(" updated to %s",packageversion);
                                    ++numchanges;
                                    if (OPTnumchanges)
                                    {
                                        printf(" change #%d of %d",numchanges,OPTnumchanges);
                                    }

                                }
                                else if (!OPTinstall)
                                {
                                    if (OPTverbose>=2)
                                        printf(" latest is %s",packageversion);
                                    else if (OPTverbose==1 && OPTupdate!=0)
                                        printf("%s",packageversion);
                                    strcpy(packageversion,oldpackageversion);
                                }
                            }
                        }
                    }
                }
                else
                {
                    if (OPTverbose>=2 || (OPTverbose>=1 && OPTupdate))
                        printf(" error unable to determine latest version");
                }


                if (OPTinstall)
                {
                    if (OPTverbose>=1)
                    {
                        sprintf(titlebuf,"%s - EAPU install %s",packagename,packageversion);
                        EAPU_settitle(titlebuf);
                    }

                    if (PackageInstallVersion(packagename, packageversion))
                        printf(" installed");
                }
            }
            else
                printf(" not found");

            printf("\n");
        }
    }

    if (OPTwrite && out)
        gwrite(out,bufc,bufpos);
    bufpos = 0;
}

void SPIT_putc(int c,GSTREAM *out)
{
    bufc[bufpos++] = (char) c;
    if (bufpos>=BUFSIZE)
        SPIT_flushc(out);
}

void SPIT_putcr(GSTREAM *out,int type)
{
    if (OPTopera)
        SPIT_putc(32,out);
    switch(type)
    {
        case 0: /* PC style cr/lf */
            SPIT_putc(13,out);
            SPIT_putc(10,out);
            break;

        case 1: /* Mac style cr */
            SPIT_putc(13,out);
            break;

        default: /* Unix style lf */
            SPIT_putc(10,out);
            break;
    }
    SPIT_flushc(out);
}

/* Table-based character translation. */
int xlate(int cin, int *table, int reverse)
{
    int cout=0;

    if (reverse)
    {
        int     i;

        /* If translation is reversed then search the table (first */
        /* check for identity translation). */
        if (table[cin] == cin)
        {
            cout = cin;
        }
        else
        {
            for (i = 0; i < 256; ++i)
            {
                if (table[i] == cin)
                {
                    cout = i;
                    break;
                }
            }
        }
    }
    else
    {
        cout = table[cin];
    }

    /* If character wasn't found then warn user and return the */
    /* input character. */
    if (cout < 0)
    {
        if (OPTverbose>=4)
        {
            printf("Untranslatable character \'%c\' (0x%02x, %dd)\n", cin, cin, cin);
        }

        cout = cin;
    }

    return(cout);
}

int eapu(GSTREAM *in,GSTREAM *out, int type, int nocr, int join)
{
    bool done=false;
    int lastch=0;
    int lastnl=0;
    int ch=0;
    unsigned char buf[4];
    int numberoflines=0;

    while (!done)
    {
        lastch = ch;
        ch = EOF;
        if (gread(in,buf,1))
            ch = buf[0];

        switch(ch)
        {
            case EOF:
                done = true;
                break;

            case 13:
                if (nocr)   /* completely ignore CRs */
                {
                    ch = 0;
                }
                else
                {
                    int p;
                    int numread;

                    p = (int) gtell(in);
                    numread = gread(in,buf+1,3);

                    if (!(numread==3 && buf[1]==(char)0 && buf[2]==(char)13 && buf[3]==(char)10)) // if not cr00crlf
                        gseek(in,p);

                    if (lastch==10)     /* lfCR */
                    {
                        ch = 0;
                    }
                    else if (!(lastch==13 && buf[1]==(char)10))   /* !crCRlf */
                    {
                        ++numberoflines;
                        ++lastnl;
                        if (join && (numberoflines%join!=0))    // join nth line with ,
                            SPIT_putc(',',out);
                        else
                            SPIT_putcr(out,type);
                    }
                }
                break;

            case 10:
                if (lastch==13) /* crLF */
                {
                    ch = 0;
                }
                else
                {
                    ++numberoflines;
                    ++lastnl;
                    if (join && (numberoflines%join==0))    // join nth line with ,
                        SPIT_putc(',',out);
                    else
                        SPIT_putcr(out,type);
                }
                break;

            default:
                lastnl = 0;
                if (OPTxlate)
                    ch = xlate(ch, OPTxlate, OPTxlatereverse);
                if (OPTunsmart)
                {
                    if (ch==0x91 || ch==0x92)
                        ch = '\'';
                }
                SPIT_putc(ch,out);
            case 'z'&31:
                break;
        }
    }
    if (OPTgcc && lastnl<2) // gcc wants one blank line
        SPIT_putcr(out,type);

    SPIT_flushc(out);

    return(numberoflines);
}

/* copy file with no translation */

int eapucopy(GSTREAM *in,GSTREAM *out)
{
    int ch=0;
    int len=0;
    unsigned char buf[4];

    while (ch!=EOF)
    {
        ch = EOF;
        if (gread(in,buf,1))
            ch = buf[0];

        if (ch!=EOF)
        {
            SPIT_putc(ch,out);
            ++len;
        }
    }
    SPIT_flushc(out);
    return(len);
}

void SPIT_openstr(const char *fname)
{
    char statbuf[SPITMAXLINE];

    if (OPTverbose)
    {
        if (OPTverbose>=4)
            printf("%s: ",fname);
        else
        {
            if (OPTverbose>=3)
                printf("%s: ",SPIT_getname( statbuf,fname));
            else
                printf("%s ",SPIT_getname( statbuf,fname));
        }
    }
}

int findtype(const char *fname)
{
    int i;
    int type=0;
    char *ext;
    char buf[512];

    ext = strrchr(SPIT_getname(buf,fname),'.');
    if (ext)
    {
        ++ext;
        for (i=0; filetypes[i].ext; ++i)
        {
            if (!stricmp(ext,filetypes[i].ext))
            {
                type = i;
            }
        }
    }

    return(type);
}

/* Do translation if */
/*   recognised eapu file extension */
/*   or unrecognised extension, 1 file only, and dest==source */

int checkdotranslation(char *inname,char *outname,int SPITargnum,int smart)
{
    int i;
    int doit=1;

    if (smart)
    {
        doit = 0;
        i = findtype(inname);

        if (i)
        {
            if (filetypes[i].type == ID('T','E','X','T'))
                doit = 1;
        }
        else
        {
            char buf[512];
            if (!strrchr(SPIT_getname(buf,inname),'.'))
                if (smart==2)
                    doit = 1;

            if (!strcmp(inname, outname) && SPITargnum==1)
                doit = 1;
        }
    }

    return(doit);
}

/*
;
; ABSTRACT
;
; eapu - updates masterconfigs to the latest versions
;
; SUMMARY
;
; eapu -options [masterconfig.xml]
;    @file     response file, containing a list of options and files
;    =file     specify a output file ie eapu source=dest
;    -nologo   disable banner
;    -back     backup masterconfig to masterconfig.bak
;    -undev    change dev to latest
;    -install  install packages (aka -i)
;    -force    force updates of unsafe versions and packages (aka -f)
;    -n<n>     limit to first N changes
;    -b<path>  path to where framework eapm.exe is installed
;    -update   update to latest version of package (ake -u)
;    -v0       no console output
;    -v1       just show name-version
;    -v2       status line for each file (default)
;
; DESCRIPTION
;
; EAPU updates Nant 2 masterconfig.xml version numbers to the most recent.
; For each package in the eapu config, the latest version is looked up
; and updated.
;
; RETURNS
;
; no return code
;
; SEE ALSO
;
; xd -t, tabs, type, Spit
;
; SAMPLE OUTPUT
;
; >eapu *.h
;
; HUFF.H: Translating, 163 lines, done.
; FILLMAC.H: Translating, 97 lines, done.
; MACPS.H: Translating, 16 lines, done.
; FILL.H: Translating, 102 lines, done.
; FILLCUR.H: Translating, 18 lines, done.
; CEL2SHPI.H: Translating, 2 lines, done.
; FILLSMGR.H: Translating, 14 lines, done.
; SPIT.H: Translating, 169 lines, done.
; XI.H: Translating, 29 lines, done.
; IMG2SHPI.H: Translating, 17 lines, done.
; MACHINE.H: Translating, 470 lines, done.
; VSH2SHPI.H: Translating, 10 lines, done.
; SHP2CELI.H: Translating, 21 lines, done.
; EMM.H: Translating, 14 lines, done.
; AZM.H: Translating, 1043 lines, done.
; LUMPY.H: Translating, 70 lines, done.
;
; END ABSTRACT
;
*/

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

void SPIT_reset(void)
{
    OPTxlate = NULL;
    OPTxlatereverse = 0;
    OPTinfo = 1;
    OPTback = 0;
    OPTundev = 0;
    OPTnumchanges = 0;
    OPTinstall = 0;
    OPTforce = 0;
    OPTsmart = 2;
    OPTnocr = 0;
    OPTjoin = 0;
/*    OPTverbose = -1; */

#if defined(__WATCOMC__) || defined(_MSC_VER)
    OPTnewlinetype = 0;   /* crlf */
#elif defined(applec) || defined(powerc) || defined (__powerc)
    OPTnewlinetype = 1;   /* cr */
#else
    OPTnewlinetype = 2;   /* lf */
#endif
    OPTtolower = 0;
    OPTopera = 0;
    OPTgcc = 0;
    OPTbanner = 0;
    OPTunsmart = 0;
    OPTupdate = 0;
    unweb = 0;

}

void SPIT_usage(const char *prgname,const char *envname,const char *urlname, int utype)
{
    printf("Eapu v%s by FrANK Barchard, EAC\n",TextVersion);
    if (utype)
        printf("USAGE: %s -options [files]\n", prgname);

    switch (utype)
    {
        case 2:
            puts("    -i install                   -u update to latest");
            puts("    -f force unsafe updates      -p packages to update");
            puts("    -back backup masterconfig    -undev change dev to latest");
            puts("    -b<path>  path to framework");
            puts("    -w write file                -v verbose");
            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("");
          printf("VERSION: %s v%s, Spit v%.2f\n",SPIT_MACHINE,TextVersion,(float)SPIT_VERSION/100.0f);
            puts("SUMMARY: Eapu updates masterconfigs to the latest versions");
          printf("         SPIT environment variable is %s\n",envname);
            puts("");
            puts("    @file     response file, containing a list of options and files");
          printf("    =file     specify a output file ie %s source=dest\n", prgname);
            puts("    -nologo   disable banner");
            puts("    -back     backup masterconfig to masterconfig.bak");
            puts("    -undev    change dev to latest");
//            puts("    -p<names> packages to update seperated by comma");
            puts("    -install  install packages (aka -i)");
            puts("    -force    force updates of unsafe versions and packages (aka -f)");
//            puts("    -info     enable info/stats");
            puts("    -n<n>     limit to first N changes");
            puts("    -b<path>  path to where framework eapm.exe is installed");
            puts("    -update   update to latest version of package (ake -u)");
            puts("    -v0       no console output");
            puts("    -v1       just show name-version");
            puts("    -v2       status line for each file (default)");

        default:
            break;
    }
}

char *SPIT_opt(const char *optptr)
{
    int i;
    const char *d=NULL;
    char optbuf[SPITMAXLINE];

    for (i=0; (unsigned char)optptr[i]>(unsigned char)' ' && i<SPITMAXLINE; ++i)
        optbuf[i] = (char) tolower(optptr[i]);
    optbuf[i] = 0;

    if (!stricmp(optbuf,"pc") || !stricmp(optbuf,"ibm") || !stricmp(optbuf,"dos") || !stricmp(optbuf,"pc") || !stricmp(optbuf,"crlf"))
    {
        OPTnewlinetype = 0;
        d = (char *)optptr+i;
    }
    else if (!stricmp(optbuf,"mac") || !stricmp(optbuf,"mpw") || !stricmp(optbuf,"ppc") || !stricmp(optbuf,"cr"))
    {
        OPTnewlinetype = 1;
        d = (char *)optptr+i;
    }
    else if (!stricmp(optbuf,"sgi") || !stricmp(optbuf,"linux") || !stricmp(optbuf,"unix") || !stricmp(optbuf,"lf"))
    {
        OPTnewlinetype = 2;
        d = (char *)optptr+i;
    }
    else if (!stricmp(optbuf,"nocr"))
    {
        d = SPIT_getopt( &OPTnocr,optptr+4, "Kill CRs", 0, 1);
    }

    if (!d)
    {
        switch (*optptr|(char)' ')
        {
            case 'b':
                if (!strnicmp(optptr,"back",4))
                    d = SPIT_getopt( &OPTback,optptr+4, "back", 0, 1);
                else
                    d = SPIT_getfield( &OPTpath[0],optptr+1, 1,0);
                break;

            case 'i':
                if (!strnicmp(optptr,"info",4))
                    d = SPIT_getopt( &OPTinfo,optptr+4, "info", 0, 1);
                else if (!strnicmp(optptr,"install",7))
                    d = SPIT_getopt( &OPTinstall,optptr+7, "install", 0, 1);
                else
                    d = SPIT_getopt( &OPTinstall,optptr+1, "install", 0, 1);
                break;


            case 'j':
                if (!strnicmp(optptr,"join",4))
                    d = SPIT_getopt( &OPTjoin,optptr+4, "join lines", 0, 10000000);
                break;

            case 'f':
                if (!strnicmp(optptr,"force",5))
                    d = SPIT_getopt( &OPTforce,optptr+5, "force", 0, 1);
                else
                    d = SPIT_getopt( &OPTforce,optptr+1, "force", 0, 1);
                break;

            case 'g':
                if (!strnicmp(optptr,"gcc",3))
                    d = SPIT_getopt( &OPTgcc,optptr+3, "gcc nl at end of eapu", 0, 1);
                break;


            case 's':
                d = SPIT_getopt( &OPTsmart,optptr+1, "smart", 0, 2);
                break;

            case 't':
                if (!strnicmp(optptr, "tolower", 7))
                {
                    d = SPIT_getopt( &OPTtolower,optptr+7, "name to lower case", 0, 1);
                }
                else
                {
                    d = SPIT_getopt( &OPTnewlinetype,optptr+1, "cr type", 0, 3);
                }
                break;

            case 'l':
                d = SPIT_getopt( &OPTtolower,optptr+1, "name to lower case", 0, 1);
                break;

            case 'n':
                d = SPIT_getopt( &OPTnumchanges,optptr+1, "number of changes", 0, 1000);
                break;

            case 'o':
                if (!strnicmp(optptr,"opera",5))
                    d = SPIT_getopt( &OPTopera,optptr+5, "opera add space at eol", 0, 1);
                break;

            case 'p':
                d = SPIT_getopt( &OPTpackages,optptr+1, "packages", 0, 1);
                break;


            case 'u':
                if (!strnicmp(optptr, "update", 6))
                    d = SPIT_getopt( &OPTupdate,optptr+6, "update to latest version of package", 0, 1);
                else if  (!strnicmp(optptr,"undev",5))
                    d = SPIT_getopt( &OPTundev, optptr+5, "change dev to most recent", 0, 1);
                else if (!strnicmp(optptr, "unsmart", 7))
                    d = SPIT_getopt( &OPTunsmart,optptr+7, "convert smart quotes to single quotes", 0, 1);
                else
                    d = SPIT_getopt( &OPTupdate,optptr+1, "update to latest version of package", 0, 1);

                break;

            /* Translation options */
            case 'x':
                if ((optptr[1]|(char)' ') == 'l')
                {
                    /* Convert DOS ASCII to Windows */
                    OPTxlate = Xtolower;
                    OPTxlatereverse = 0;
                    d = (char *)optptr+2;
                }
                else if (((optptr[1]|(char)' ') == 'd') &&
                    ((optptr[2]|(char)' ') == 'w'))
                {
                    /* Convert DOS ASCII to Windows */
                    OPTxlate = Xdostowindows;
                    OPTxlatereverse = 0;
                    d = (char *)optptr+3;
                }
                else if (((optptr[1]|(char)' ') == 'w') &&
                         ((optptr[2]|(char)' ') == 'd'))
                {
                    /* Convert Windows ASCII to DOS */
                    OPTxlate = Xdostowindows;
                    OPTxlatereverse = 1;
                    d = (char *)optptr+3;
                }
                break;

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

int main(int argc,char **argv)
{
    int more;
    int i;
    int ok;
    int numberoflines;
    int numberofbytes;
    int totalnumberoflines;
    int totalnumberofbytes;
    char *transtype;
    GSTREAM *infile=0;
    GSTREAM *outfile=0;

    SPIT_init(SPIT_reset, SPIT_usage, SPIT_opt, SPIT_history);

    do
    {
        more = SPIT_parse(argc, argv, TOOL_NAME, TOOL_VERSION);

        switch (OPTnewlinetype)
        {
            default:;
            case 0: transtype = "PC";    break;
            case 1: transtype = "Mac";   break;
            case 2: transtype = "Unix";  break;
        }


        whereisframework[0] = 0;
        if (OPTpath[0])
            strcpy(whereisframework,OPTpath);
        else
        {
            ok = GetPackageDirectory("Framework", whereisframework);
            if (ok)
            {
                strcat(whereisframework,"\\bin\\");
            }
        }
        if (whereisframework[0] && OPTverbose>=3)
            printf("eapm is here %s\n",whereisframework);

        totalnumberoflines = 0;
        totalnumberofbytes = 0;
        for (i=0; i<SPITargnum; ++i)
        {
            if (OPTverbose>=3)
            {
                SPIT_openstr(SPITsargv[i]);
                SPIT_flush();
            }

            infile = gopen(SPITsargv[i]);
            if (!infile)
            {
                if (OPTverbose>=2)
                    printf("eapu - COULD NOT OPEN FILE FOR READ '%s'\n",SPITsargv[i]);
            }
            else
            {
                char outname[SPITMAXLINE];

                ok = 1;
                if (OPTwrite)
                {
                    if (OPTtolower)
                        strlwr(SPITdargv[i]);

                    SPIT_tempname(outname,SPITdargv[i],"tmp");
                    int ok = remove(outname);
                    if (ok!=0 && errno!=ENOENT)
                        if (errno==EACCES && OPTverbose)
                            printf("eapu - warning unable to remove backup temp file %s. %s\n",outname,errno==EACCES?"Access denied":"");

                    outfile = gwopen(outname);
                    if (!outfile)
                    {
                        if (OPTverbose>=2)
                            printf("eapu - COULD NOT OPEN FILE FOR WRITE '%s'\n",outname);
                        gclose(infile);
                        ok = 0;
                    }
                }
                else
                    outfile = 0;

                if (ok)
                {
                    numberoflines = 0;
                    numberofbytes = 0;
                    if (checkdotranslation(SPITsargv[i],SPITdargv[i],SPITargnum,OPTsmart))
                    {
                        if (OPTverbose>=3)
                        {
                            if (OPTinstall)
                                printf(" install");
                            if (OPTupdate)
                                printf(" update");
                            printf("\n");
                            SPIT_flush();
                        }

                        numberoflines = eapu(infile,outfile,OPTnewlinetype,OPTnocr,OPTjoin);
                    }
                    else
                    {
                        numberofbytes = eapucopy(infile,outfile);
                    }

                    totalnumberoflines += numberoflines;
                    totalnumberofbytes += numberofbytes;


                    gclose(infile);
                    if (OPTwrite && outfile)
                    {
                        gclose(outfile);
#if defined(applec) || defined(powerc) || defined (__powerc)
                        {
                            int type;

                            type = findtype(SPITsargv[i]);
                            fsetfileinfo(SPITdargv[i],filetypes[type].creator,filetypes[type].type);
                        }
#endif

                        if (OPTupdate)
                        {
                            if (OPTback)
                            {
                                char backname[SPITMAXLINE];

                                SPIT_tempname(backname,SPITdargv[i],"bak");
                                if (OPTverbose>=3)
                                {
                                    printf("backed up to %s\n",backname);
                                }

                                int ok = remove(backname);
                                if (ok!=0 && errno!=ENOENT)
                                    if (OPTverbose)
                                        printf("eapu - warning unable to remove backup temp file %s.  %s\n",backname,errno==EACCES?"Access denied":"");

                                rename(SPITdargv[i],backname);
                            }
                            else
                            {
                                int ok = remove(SPITdargv[i]);
                                if (ok!=0 && errno!=ENOENT)
                                    if (OPTverbose)
                                        printf("eapu - warning unable to old file %s. %s\n",SPITdargv[i],errno==EACCES?"Access denied":"");
                            }
                            rename(outname,SPITdargv[i]);
                        }
                        else
                        {
                                int ok = remove(outname);
                                if (ok!=0 && errno!=ENOENT)
                                    if (OPTverbose)
                                        printf("eapu - warning unable to remove temp file %s.  %s\n",outname,errno==EACCES?"Access denied":"");
                        }


#if defined(__unix__)
                        if (OPTnewlinetype == 2)  /* unix script? */
                        {
                            int type;
                            char *ext;
                            char buf[512];

                            /* if not extension, assume its a unix script or executable and make it executable */

                            ext = strrchr(SPIT_getname(buf,SPITsargv[i]),'.');
                            if (!ext || !strcmp(ext,".tcl") || !strcmp(ext,".py"))
                            {
                                if (OPTverbose>=3)
                                    printf(" script");
                                sprintf(buf,"chmod +x %s",SPITdargv[i]);
                                system(buf);
                            }
                        }
#endif
                    }

                    if (OPTverbose>=3)
                    {
                        printf(", ");
                        if (numberofbytes)
                           printf("%ld bytes, done.\n",numberofbytes);
                        else
                           printf("%d lines, done.\n",numberoflines);
                        SPIT_flush();
                    }
                    if (OPTverbose>=5)
                        printf("renamed %s to %s\n",outname,SPITdargv[i]);
                }
            }
        }
        if (OPTverbose && OPTinfo && STATpackagecount)
        {   printf("total %d packages, %d updated, %d unsafe to update\n",STATpackagecount,STATupdatedcount,STATunsafecount);
            SPIT_flush();
        }
    } while (more > 0);
    SPIT_restore();

    return(0);
}

