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

const char *SPIT_history[] =
{
"------------------------------------------------------------------",
"                                                                  ",
"                            UnDup v1.10                           ",
"                                                                  ",
"                     by FrANK G. Barchard, EAC                    ",
"                                                                  ",
"                    Main program - Sep 24, 2003                   ",
"                                                                  ",
"------------------------------------------------------------------",
"                                                                  ",
" Version Date   SE History:                                       ",
" ------- ----   -- --------                                       ",
"    1.00 971104 FB count duplicate lines and output # line        ",
"    1.01 971120 KO Works. No stdout.                              ",
"    1.02 000526 FB -nocount and %5d to make more consistant       ",
"    1.03 000527 FB -pc/-mac/-unix and -history                    ",
"    1.04 000918 FB -filename                                      ",
"    1.05 010929 FB fix last line if no cr/lf on it                ",
"    1.06 011006 FB -count2 to count things with 2 or more         ",
"    1.07 011031 FB -noblank                                       ",
"    1.08 011124 FB -less<n>                                       ",
"    1.09 030923 FB -count use %d\t to import into excel directly  ",
"    1.10 030924 FB -i case independent for dictionary duplicates  ",
"                                                                  ",
"------------------------------------------------------------------",
"\0"
};

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

#include    "spit.h"

const char TextVersion[]="1.10 (Samba) 2007.12.4";
#define TOOL_VERSION 110
#define TOOL_NAME "undup"

static int OPTcount;
static int OPTless;
static int OPTnewlinetype;
static int OPTfilenamesort;
static int OPTblank;
static int OPTcaseindependent;

static char *DUPnextline(const char *s)
{
    while (*s)
    {
        if (*s==10)
        {
            ++s;
            if (*s==13)
                ++s;
            break;
        }
        if (*s==13)
        {
            ++s;
            if (*s==10)
                ++s;
            break;
        }
        ++s;
    }
    return((char *)s);
}

static char *DUPgetline(char *buf,const char *s)
{
    char *d=buf;
    while (*s)
    {
        if (*s==10)
        {
            ++s;
            if (*s==13)
                ++s;
            break;
        }
        if (*s==13)
        {
            ++s;
            if (*s==10)
                ++s;
            break;
        }
        *d++ = *s++;
    }
    *d = 0;
    return(buf);
}

static int DUPcmplines(char *s1,char *s2)
{
    char l1[SPITMAXLINE];
    char l2[SPITMAXLINE];

    DUPgetline(l1,s1);
    DUPgetline(l2,s2);

    if (OPTfilenamesort)
    {
        SPIT_getname(l1,l1);
        SPIT_getname(l2,l2);
        if (OPTverbose>5)
        {
            printf("comparing %s to %s\n",l1,l2);
        }
    }

    if (OPTcaseindependent)
        return stricmp(l1,l2);

    return strcmp(l1,l2);
}

static void undupfile(SPITMEM *infile, SPITMEM *outfile, int &linecount)
{
    char *s1;
    char *s2;
    char *d;
    int count=1;
    int more;
    int len;
    s1 = infile->ptr;
    s2 = DUPnextline(s1);
    d = outfile->ptr;

    outfile->len = 0;
    linecount = 0;

    while (*s1)
    {
        more = 0;
        if (DUPcmplines(s1,s2)==0)
        {
            ++count;
            more = 1;
        }
        else
        {
            char l1[SPITMAXLINE];

            if (OPTblank==0 && strlen(s1)==0)
            {
                len = 0;
            }
            else
            {
                if (OPTless)
                {
                    if (count<OPTless)
                    {
                        if (OPTverbose>=3)
                            len = sprintf(d,"%d\t%s",count,DUPgetline(l1,s1));
                        else
                            len = sprintf(d,"%s",DUPgetline(l1,s1));
                    }
                    else
                        len = 0;
                }
                else if (OPTcount)
                {
                    if (count>=OPTcount)
                    {
                        if (OPTverbose>=3)
                            len = sprintf(d,"%d\t%s",count,DUPgetline(l1,s1));
                        else
                            len = sprintf(d,"%s",DUPgetline(l1,s1));
                    }
                    else
                        len = 0;
                }
                else
                    len = sprintf(d,"%s",DUPgetline(l1,s1));
            }

            if (len)
            {
                switch (OPTnewlinetype)
                {
                    case 0: /* PC style cr/lf */
                        d[len++] = 13;
                        d[len++] = 10;
                        break;

                    case 1: /* Mac style cr */
                        d[len++] = 13;
                        break;

                    default: /* Unix style lf */
                        d[len++] = 10;
                        break;
                }
                ++linecount;

            }

            outfile->len += len;
            d += len;
            count = 1;
        }
        s1 = s2;
        s2 = DUPnextline(s1);
    }
}

/*
;
; ABSTRACT
;
; undup - count duplicate lines and remove extras
;
; SUMMARY
;
; undup -options [files]
;     -nologo   disable banner
;     -v        print the count
;     -i        case independent
;     -w0       don't output file
;     -w1       output to file (default)
;     -count<n> find counts >= specifed value
;     -nocount  dont print a count
;     -less<n>  find counts < specifed value
;     -count    get line count
;     -nocount  no line count
;     @file     response file, containing a list of options and files
;     =file     specify a output file ie undup source=dest
;
; DESCRIPTION
;
; Undup counts the number of duplicate lines in a text file and
; outputs a count, space and the line, without duplicates
;
; RETURNS
;
; no return code
;
; SEE ALSO
;
; txt, gsr, Spit
;
; SAMPLE OUTPUT
;
; >undup sorted.txt=unduped.txt
;
; END ABSTRACT
;
*/


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

void SPIT_reset(void)
{
    OPTcount = 0;
    OPTless = 0;
#if defined(__WATCOMC__) || defined(_MSC_VER)
    OPTnewlinetype = 0;   /* crlf */
#elif defined(applec) || defined(powerc) || defined (__powerc)
    OPTnewlinetype = 1;   /* cr */
#else
    OPTnewlinetype = 2;   /* lf */
#endif
    OPTfilenamesort = 1;
    OPTcaseindependent = 0;
    OPTblank = 1;
    return;
}

char *optionhelp[]=
{
    "    @file          response file, containing a list of options and files\n",
    "    =file          specify a output file ie source=dest\n"
    "                   %%d in <dest> uses frame index.  %%s uses framename\n",
    "    -b0            disable banner\n",
    "    -v0            no console output\n"
    "    -v1            less output\n"
    "    -v2            normal output (default)\n"
    "    -v             more output\n",
    "    -i             case independent\n",
    "    -w0            dont output file\n",
    "    -r             recurse subdirectories to find files\n",
    "    -r%ENV%        traverse environment variable ENV to find files\n",
    "    -count<n>      find counts >= specifed value and print the count\n"
    "    -nocount       dont print a count\n"
    "    -less<n>       find counts < specifed value and print the count\n",
    "    -blank         count blank lines (default)\n",
    "    -noblank       dont count blank lines\n",
    0,
};

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

    printf("undup 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("    -count                       -nocount");
            puts("    -blank                       -noblank");
            puts("    -v verbose                   -w write file");
            puts("    -i case independent");
            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: SpitIE calculates something about a file");
          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;
    int i;
    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;
    }

    if (!d)
    {
        switch (*optptr|(char)' ')
        {
            case 'b':
                if (!strnicmp(optptr,"blank",5))
                {
                    d = SPIT_getopt( &OPTblank,optptr+5, "count blank lines", 0, 1);
                }
                break;


            case 'c':
                if (!strnicmp(optptr,"count",5))
                {
                    d = SPIT_getopt( &OPTcount,optptr+5, "count", 0, 1024);
                }
                break;

            case 'l':
                if (!strnicmp(optptr,"less",4))
                {
                    d = SPIT_getopt( &OPTless,optptr+4, "count less than specified count", 0, 1024);
                }
                break;

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

            case 'n':
                if (!strnicmp(optptr,"nocount",7))
                {
                    OPTcount ^= 1;
                    d = SPIT_getopt( &OPTcount,optptr+7, "no count", 0, 1);
                    OPTcount ^= 1;
                }
                else if (!strnicmp(optptr,"noblank",7))
                {
                    OPTblank ^= 1;
                    d = SPIT_getopt( &OPTblank,optptr+7, "no blank", 0, 1);
                    OPTblank ^= 1;
                }

                break;

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

int main(int argc, char* argv[])
{
    int more;
    int i;
    int isopt;
    SPITMEM infile;
    SPITMEM outfile;
    int linecount=0;
    int returnvalue=0;
    char statbuf[SPITMAXLINE];

    SPIT_init(SPIT_reset, SPIT_usage, SPIT_opt, SPIT_history);

    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)
                {
                    if (SPIT_loadfilev(&infile, SPITsargv[i], OPTverbose))
                    {
                        if (SPIT_alloc(&outfile, infile.len*2+50000L))
                        {
                            if (OPTverbose>=2)
                            {   printf("UnDuping, ");
                                SPIT_flush();
                            }

                            undupfile(&infile, &outfile, linecount);

                            if (OPTwrite)
                                SPIT_savefile(&outfile, SPITdargv[i]);

                            /* print some stats */

                            if (OPTverbose>=2)
                            {
                                SPIT_percentstr(statbuf, infile.len, outfile.len);
                                printf("%ld->%ld (%s)\n", infile.len, outfile.len, statbuf);
                                SPIT_flush();
                            }

                            SPIT_free(&outfile);

                        }
                        else
                        {
                            if (OPTverbose>=1)
                                printf("ERROR could not allocate dup buffer\n");
                        }
                        SPIT_free(&infile);
                    }

                }
            }
        }
    } while (more>0);

    SPIT_restore();

    returnvalue = 0;
    if (OPTcount)
        returnvalue = linecount;
    return(returnvalue);
}
