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

const char *SPIT_history[] =
{
"------------------------------------------------------------------",
"                                                                  ",
"                         WHEREIS v1.37                            ",
"                                                                  ",
"                    by FrANK G. Barchard, EAC                     ",
"                                                                  ",
"                   Main program - Oct 8, 2006                     ",
"                                                                  ",
"------------------------------------------------------------------",
"                                                                  ",
" Version Date   SE History:                                       ",
" ------- ----   -- --------                                       ",
"    1.00 000910 FB based on url                                   ",
"    1.01 000915 FB try current directory first, and THRASH_DRIVER ",
"    1.02 000918 FB try registry                                   ",
"    1.03 000926 FB try lib/include paths                          ",
"    1.04 001004 FB return code 0 found, 1 not found               ",
"    1.05 001118 FB include path too                               ",
"    1.06 010519 FB ps2,gc paths                                   ",
"    1.07 010522 FB -v0 silent                                     ",
"    1.08 010602 FB unix version                                   ",
"    1.09 010711 FB -noclip to not put result in clipboard         ",
"    1.10 010808 FB try finding apps and looking in those dirs     ",
"    1.11 011120 FB window fonts                                   ",
"    1.12 020328 FB ps2 lib folder                                 ",
"    1.13 020726 FB quotes for spaces                              ",
"    1.14 020829 FB ttf/ttc extensions                             ",
"    1.15 021008 FB returncode without verbose                     ",
"    1.16 021104 FB search path first, eagl                        ",
"    1.17 021105 FB search real                                    ",
"    1.18 021107 FB search current folder first                    ",
"    1.19 030309 FB allow user to specify registry subkey          ",
"    1.20 030312 FB -d to return a directory                       ",
"    1.21 030406 FB shortname, reg keys, quote removal             ",
"    1.22 030428 FB -time                                          ",
"    1.23 030505 FB .net control                                   ",
"    1.24 030507 FB -unc to get Universal Name Convention of name  ",
"    1.25 030602 FB find packages and most recent version          ",
"    1.26 030604 FB name mangler in public api                     ",
"    1.27 030605 FB lib api/internal change and allow null         ",
"    1.28 030929 FB -clip fixed                                    ",
"    1.29 031005 FB -q-1 -shortname work together, sn.ini          ",
"    1.30 031026 FB -/ to make back slashes into forward slashes   ",
"    1.31 031027 FB whereis package sort order numerical           ",
"    1.32 040924 FB .pl perl files                                 ",
"    1.33 050509 FB -rel to make names relative to CWD             ",
"    1.34 050516 FB -\\                                            ",
"    1.35 050621 FB -short and -long                               ",
"    1.36 051003 FB fully quality 3 eac servers                    ",
"    1.37 060808 FB -c to use cygwin/mingw style folders (aka -/C) ",
"                                                                  ",
" Some sample registry items                                       ",
" SOFTWARE/Microsoft/Windows/CurrentVersion/App Paths/IEXPLORE.EXE ",
" SOFTWARE/Electronic Arts/Framework-0.6.2                         ",
" SOFTWARE/Microsoft/MicrosoftSDK/Directories                      ",
"                                                                  ",
"------------------------------------------------------------------",
"\0"
};


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

#if defined(_MSC_VER)
#pragma warning(push,1)
#include <windows.h>
#pragma warning(pop)
#endif

#include "spit.h"
#include "whereis.h"
#if defined(_MSC_VER)
#include "gclip.h"
#endif

const char TextVersion[]="1.37 (Samba) 2007.12.4";
#define TOOL_VERSION 137
#define TOOL_NAME "whereis"

/****************************************************************/
/*  Internal Functions                                          */
/****************************************************************/

#define MAXREGLEN 256
#define MSGLEN 1024

char OPTfilename[MAXREGLEN+4]="";
char OPTwidth[MAXREGLEN+4]="";
char OPTheight[MAXREGLEN+4]="";
char OPTbpp[MAXREGLEN+4]="";
int OPTclip;
int OPTdir;
int OPTquote;
int OPTshortname;
int OPTlongname;
int OPTuncname;
int OPTslash;
int OPTrelative;    // make paths relative

static void CLPtext(const char *str)
{
#if defined(_MSC_VER)
    GCLIP *gclip = GCLIP_wopen();
    HGLOBAL hData;

    if (gclip)
    {
        hData = GlobalAlloc(GHND | GMEM_SHARE, strlen(str)+1);  /* note freed by clipboard itself */
        if (hData)
        {
            char *p = (char *) GlobalLock(hData);
            if (p)
            {
                strcpy(p, str);
                GCLIP_write(gclip, CF_TEXT, p, strlen(p)+1);
            }
        }
        GCLIP_wclose(gclip);
    }
#endif
}

/*
;
; ABSTRACT
;
; whereis - finds files in your paths
;
; SUMMARY
;
; whereis -options [files]
;     -v<n>      amount of verbosity. 0 none,1 less,2 normal,3 more
;     -time      show execution time
;     -clip      put result in clipboard (default). -clip0 to disable
;     -d         return directory
;     -d<n>      strip N directory levels from path
;     -q-1       quote names that have spaces
;     -q0        don't quote names (default)
;     -q         quote names
;     -noclip    dont put result in clipboard
;     -shortname reduce long names to 8.3 DOS short names (aka -short)
;     -longname  expand to long path names (aka -long)
;     -unc       expand to UNC file name
;     -rel       make paths relative to current directory
;     -/         convert \ to / in file name. Also -\
;     -c         convert /C/folder cygwin/mingw style

; DESCRIPTION
;
; Whereis finds files on your system.
; It will find any file type, but the intent is executables/dlls and headers.
; executables/dlls, headers and libraries for all
;
; Whereis searches through various methods, in the following order
;
;   current folder
;   PATH         pc executables search path
;
;   System Registry
;
;   LIB          visual c include path
;   INCLUDE      visual c library path
;   PS2_CPATH    ps2 c include path
;   /usr/local/sce/ee/lib ps2 library path
;   MWCIINCLUDE  metrowerks include path
;   MWLIBRARIES  metrowerks library path
;
;   GDF package server packages
;   most recent version in package subfolder
;
;   plugin folders of
;   P2
;   ACDsee
;   Photoshop
;
; Some recommended items to find
;
; framework     the framework is found via registry, if installed
; ps2dbg        prodg
; sn.ini        found by locating prodg
; gimex.dll     searches in same way as loadlibrary would
; stdio.h       determines include order
;
;
; RETURNS
;
; clipboard contains name of full path where the file was found
; no return code
;
; SEE ALSO
;
; huff, Spit
;
; SAMPLE OUTPUT
;
; >whereis dolphin.h
; C:\DolphinSDK1.0\include\dolphin.h
;
; END ABSTRACT
;
*/

char *optionhelp[]=
{
    "    -v<n>      amount of verbosity. 0 none,1 less,2 normal,3 more\n",
    "    -time      show execution time\n",
    "    -clip      put result in clipboard (default). -clip0 to disable\n",
    "    -d         return directory\n",
    "    -d<n>      strip N directory levels from path\n",
    "    -q-1       quote names that have spaces\n",
    "    -q0        don't quote names (default)\n",
    "    -q         quote names\n",
    "    -noclip    dont put result in clipboard\n",
    "    -shortname reduce long names to 8.3 DOS short names (aka -short)\n",
    "    -longname  expand to long path names (aka -long)\n",
    "    -unc       expand to UNC file name\n",
    "    -rel       make paths relative to current directory\n",
    "    -/         convert \\ to / in file name.  Also -\\\n",
    "    -c         convert /C/folder cygwin/mingw stylen\n",
    0,
};

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

void SPIT_reset(void)
{
    OPTbanner = 0;
    OPTminargs = 0;
    OPTwrite = 0;
    OPTclip = 1;
    OPTdir = 0;
    OPTquote = 0;
    OPTshortname = 0;
    OPTlongname = 0;
    OPTuncname = 0;
    OPTslash = 0;
    OPTtime = 0;
    OPTrelative = 0; // option to make paths relative off
    return;
}

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

    printf("WHEREIS 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("    -v verbose");
            puts("    -d return directory");
            puts("     @ response file         -noclip disable clipboard result");
          printf("type '%s -h' for more help\n", prgname);
          printf("type '%s -help' for web page (%s)\n", prgname, urlname);
            break;

        case 3:
          printf("VERSION: %s v%s, Spit v%.2f\n",SPIT_MACHINE,TextVersion,(float)SPIT_VERSION/100.0f);
            puts("SUMMARY: Finds files on your system");
          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 (*optptr|(char)' ')
    {
        case '/':
            if (!strnicmp(optptr,"/c",2))
            {
                d = SPIT_getopt( &OPTslash,optptr+2, "slash convert to mingw style", 0, 1);
                if (OPTslash==1) OPTslash = 3;
            }
            else
                d = SPIT_getopt( &OPTslash,optptr+1, "slash convert back to forward", 0, 1);
            break;

        case '\\'|' ':
            d = SPIT_getopt( &OPTslash,optptr+1, "slash convert back to backward", 0, 1);
            if (OPTslash==1) OPTslash = 2;
            break;

        case 'c':
            if (!strnicmp(optptr,"clip",4))
            {
                d = SPIT_getopt( &OPTclip,optptr+4, "clipboard", 0, 1);
            }
            else
            {
                d = SPIT_getopt( &OPTslash,optptr+1, "slash convert to mingw style", 0, 1);
                if (OPTslash==1) OPTslash = 3;
            }

            break;

        case 'd':
            d = SPIT_getopt( &OPTdir,optptr+1, "directory level", 0, 32);
            break;

        case 'l':
            if (!strnicmp(optptr,"longname",8))
            {
                d = SPIT_getopt( &OPTlongname,optptr+8, "long filenames", 0, 1);
            }
            else if  (!strnicmp(optptr,"long",4))
            {
                d = SPIT_getopt( &OPTlongname,optptr+4, "long filenames", 0, 1);
            }
            break;

        case 'n':
            if (!strnicmp(optptr,"noclip",6))
            {
                OPTclip = !OPTclip;
                d = SPIT_getopt( &OPTclip,optptr+6, "disable clipboard", 0, 1);
                OPTclip = !OPTclip;
            }
            break;

        case 'q':
            d = SPIT_getopt( &OPTquote,optptr+1, "quote names", -1, 1);
            break;

        case 'r':
            if (!strnicmp(optptr, "rel", 3))
                d = SPIT_getopt( &OPTrelative,optptr+3, "relative", 0, 1);
            break;

        case 's':
            if (!strnicmp(optptr,"shortname",9))
            {
                d = SPIT_getopt( &OPTshortname,optptr+9, "short filenames", 0, 1);
            }
            else if (!strnicmp(optptr,"short",5))
            {
                d = SPIT_getopt( &OPTshortname,optptr+5, "short filenames", 0, 1);
            }
            break;

        case 't':
            if (!strnicmp(optptr,"time",4))
            {
                d = SPIT_getopt( &OPTtime,optptr+4, "enable timing diagnostics", 0, 1);
            }
            break;

        case 'u':
            if (!strnicmp(optptr,"unc",3))
            {
                d = SPIT_getopt( &OPTuncname,optptr+3, "unc filenames", 0, 1);
            }
            break;

        default:
            break;
    }
    return(d);
}


int main(int argc, char* argv[])
{
    int more;
    int i;
    int rc=0; // return code is number of files not found (0=success)

    double totaltime = SPIT_gettime();
    SPIT_init(SPIT_reset, SPIT_usage, SPIT_opt, SPIT_history);
    do
    {
        more = SPIT_parse(argc, argv, TOOL_NAME, TOOL_VERSION);

        if (!SPIThelpgiven)
        {
            char *whereis=NULL;
            if (SPITargnum)
            {
                for (i=0; i<SPITargnum; ++i)
                {
                    whereis = WhereIs_Find(SPITdargv[i]);
                    whereis = WhereIs_Format(whereis, OPTquote,  OPTdir, OPTshortname, OPTlongname, OPTuncname, OPTslash, OPTrelative);

                    if (whereis)
                    {
                        if (OPTverbose)
                            printf("%s\n",whereis);
                    }
                    else
                         ++rc;
                }
            }
            else
            {
                whereis = WhereIs_Find(NULL);
                whereis = WhereIs_Format(whereis, OPTquote,  OPTdir, OPTshortname, OPTlongname, OPTuncname, OPTslash, OPTrelative);

                if (whereis)
                {
                    if (OPTverbose)
                        printf("%s\n",whereis);
                }
                else
                    ++rc;
            }
            if (OPTclip && whereis)
                CLPtext(whereis);
        }
    } while (more>0);

    SPIT_restore();

    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(rc);
}
