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

const char *SPIT_history[] =
{
"------------------------------------------------------------------",
"                                                                  ",
"                          Hash_eg v1.00                           ",
"                                                                  ",
"                    by FrANK G. Barchard, EAC                     ",
"                                                                  ",
"                   Main program - Sep 23, 2003                    ",
"                                                                  ",
"------------------------------------------------------------------",
"                                                                  ",
" Version Date   SE History:                                       ",
" ------- ----   -- --------                                       ",
" 1.00    030923 FB hash example                                   ",
"                                                                  ",
"------------------------------------------------------------------",
"                                                                  ",
" http://burtleburtle.net/bob/hash/doobs.html                      ",
"                                                                  ",
"------------------------------------------------------------------",
"\0"
};


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

#include "spit.h"
#include "range.h"
#include "ranger.h"

const char TextVersion[]="1.00 (Samba) 2007.12.4";
#define TOOL_VERSION 100
#define TOOL_NAME "hash_eg"

int OPTmethod;
char OPTcomment[SPITMAXLINE];
int OPTfrank;


// DJB2 hash
// http://www.cs.yorku.ca/~oz/hash.html
// NOTE require int to be 32 bits

unsigned int Hash(const char *string,unsigned int hash=5381)
{
    const unsigned char *s = (const unsigned char *) string;
    int c;

    while (c = *s++)
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash;
}


// http://www.isthe.com/chongo/src/fnv/hash_32.c

/*
 * fnv_32_str - perform a 32 bit Fowler/Noll/Vo hash on a string
 *
 * input:
 *  str - string to hash
 *  hash    - previous hash value or 0 if first call
 *
 * returns:
 *  32 bit hash as a static hash type
 *
 * NOTE: To use the 32 bit FNV-0 historic hash, use FNV0_32_INIT as the hash
 *   argument on the first call to either fnv_32_buf() or fnv_32_str().
 *
 * NOTE: To use the recommended 32 bit FNV-1 hash, use FNV1_32_INIT as the hash
 *   argument on the first call to either fnv_32_buf() or fnv_32_str().
 */

typedef unsigned int Fnv32_t;

 /*
 * 32 bit magic FNV-0 and FNV-1 prime
 */
#define FNV_32_PRIME ((Fnv32_t)0x01000193)
#define FNV1_32_INIT ((Fnv32_t)0x811c9dc5)

unsigned int HashFNV1(const char *string,unsigned int hash=FNV1_32_INIT)
{
    const unsigned char *s = (const unsigned char *)string; /* unsigned string */

    /*
     * FNV-1 hash each octet in the buffer
     */
    while (*s)
    {
        /* multiply by the 32 bit FNV magic prime mod 2^64 */
        hash *= FNV_32_PRIME;

        /* xor the bottom with the current octet */
        hash ^= (Fnv32_t)*s++;
    }

    /* return our new hash value */
    return hash;
}


// ipp hash
// intel ipp libs support this simple hash function

unsigned int HashIPP(const char *string,unsigned int hash=5381)
{
    const unsigned char *s = (const unsigned char *) string;
    int c;

    while (c = *s++)
        hash = (hash << 1) ^ c;

    return hash;
}







static unsigned int crc_table[256] = {
  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
  0x2d02ef8dL
};

unsigned int HashCrc32(const char *string,unsigned int hash=0xfbea)
{
    hash = hash ^ 0xffffffffL;

    while (*string)
    {
        hash = crc_table[((unsigned int)hash ^ ((unsigned char)*string++)) & 0xff] ^ (hash >> 8);
    }
    return hash ^ 0xffffffffL;
}



/*
;
; ABSTRACT
;
; hash_eg - an example spit application that tests command line parsing
;
; SUMMARY
;
; hash_eg -options [files]
;     @file          response file, containing a list of options and files
;     =file          specify a output file ie source=dest
;     -b0            disable banner
;     -v0            no console output
;     -v1            less output
;     -v2            normal output (default)
;     -v             more output
;     -w0            dont output file
;     -r             recurse subdirectories to find files
;     -r%ENV%        traverse environment variable ENV to find files
;     -time          show execution time
;     -m<v>          method 0=djb2, 1=fnv1, 2-crc32, 3=ipp
;     -comment       just a comment option
;
; DESCRIPTION
;
; Hash_eg is does spit wildcards & command line parsing, displaying
; the list of files and options, but doing no operations on them.
; The tool is intended to be used as the starting point for new spit
; tools
;
; RETURNS
;
; no return code
;
; SEE ALSO
;
; huff, Spit
;
; SAMPLE OUTPUT
;
; >hash_eg spit*.?
;
;   Hash_eg v1.00 (text) 930101 by FrANK Barchard, EAC
;   spiti.c: Reading, Analysing, Writing
;   spit.h: Reading, Analysing, Writing
;
; END ABSTRACT
;
*/

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

void SPIT_reset(void)
{
    OPTmethod = 0;
    OPTcomment[0] = 0;
    OPTfrank = 0;
    OPTstartsortat = 1;
    OPTkeepopts = 1;
    OPTtime = 0;
    OPTbanner = 0;

    return;
}

char *optionhelp[]=
{
    "    @file          response file, containing a list of options and files\n",
    "    =file          specify a output file ie source=dest\n",
    "    -b0            disable banner\n",
    "    -v0            no console output\n"
    "    -v1            less output\n"
    "    -v2            normal output (default)\n"
    "    -v             more output\n",
    "    -w0            dont output file\n",
    "    -r             recurse subdirectories to find files\n"
    "    -r%ENV%        traverse environment variable ENV to find files\n",
    "    -time          show execution time\n",
    "    -m<v>          method 0=djb2, 1=fnv1, 2=crc2, 3=ipp\n",
//    "    -frank         simple switch option\n",
    "    -comment       just a comment option\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("Hash_eg v%s by FrANK G. Barchard\n",TextVersion);

    if (utype)
        printf("USAGE: %s -options [files]\n", prgname);

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

        case 2:
            puts("    -m method                -frank franks option");
            puts("    -comment option           -time time execution");
            puts("    -v verbose                   -w write file");
            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: An example spit application that tests command line parsing");
          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)
{
    char *d=NULL;
    switch (tolower(*optptr))
    {
        case 'c':
            if (!strnicmp(optptr,"comment",7))
                d = SPIT_getfield( OPTcomment,optptr+7,1,1);
            break;

        case 'm':
            d = SPIT_getopt( &OPTmethod,optptr+1, "method", 0, 4);
            break;

        default:
            break;
    }
    return(d);
}

/* Useful SPIT functions ie's.  See SPIT.h for prototypes of all functions.
   struct SPITMEM infile;
   if (SPIT_loadfilev(&infile, SPITsargv[i]))
   SPIT_savefile(&outfile, SPITdargv[i]);
   if (SPIT_alloc(&outfile, infile.len+50000L))
   SPIT_free(&outfile);
   if (OPTverbose>=3) printf("print something");  SPIT_flush();
*/

extern "C" int galloccount;

int main(int argc, char* argv[])
{
    int more;
    int i;
    int isopt;
    RANGER *r=0;
    EXPR *expr=0;
    double totaltime;

    SPIT_init(SPIT_reset, SPIT_usage, SPIT_opt, SPIT_history);

    expr = EXPR_open();

    totaltime = SPIT_gettime();

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

        if (!SPIThelpgiven)
        {
            for (i=0; i<SPITargnum; ++i)
            {
                isopt = 0;
                if (SPITsargv[i][0]=='-' || SPITsargv[i][0]=='+' || (SPITsargv[i][0]==OPTdot && SPITsargv[i][1]!='.' && SPITsargv[i][1]!='/' && SPITsargv[i][1]!='\\'))
                {
                    isopt = Zop(SPITsargv[i]+1)?1:0;
                }
                else if (SPITsargv[i][0]=='=')
                {
                    isopt = Zop(SPITsargv[i])?1:0;
                }

                if (!isopt)
                {
                    int hash;
                    switch (OPTmethod)
                    {
                        default:
                        case 0:  hash = Hash(SPITdargv[i]); break;
                        case 1:  hash = HashFNV1(SPITdargv[i]); break;
                        case 2:  hash = HashCrc32(SPITdargv[i]); break;
                        case 3:  hash = HashIPP(SPITdargv[i]); break;
                    }
                    if (OPTverbose>=3)
                    {
                        printf("0x%08x %s\n",hash,SPITdargv[i]);
                    }
                    else if (OPTverbose>=2)
                    {
                        printf("0x%08x\n",hash);
                    }
                }
            }
        }
    } while (more>0);

    EXPR_close(expr);

    SPIT_restore();

    if (galloccount)
        printf("galloccount = %i\n", galloccount);

    totaltime = SPIT_gettime()-totaltime;

    if (OPTtime)
    {
        if (totaltime>=60000.0)
            printf("TIME " TOOL_NAME " totaltime %.2f ms (%.2f seconds) (%.2f minutes)\n",totaltime,totaltime/1000.0,totaltime/60000.0);
        else if (totaltime>=1000.0)
            printf("TIME " TOOL_NAME " totaltime %.2f ms (%.2f seconds)\n",totaltime,totaltime/1000.0);
        else
            printf("TIME " TOOL_NAME " totaltime %.2f ms\n",totaltime);
    }

    return(0);
}

