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

#if 0
/*
const char *SPIT_history[] =
{
"------------------------------------------------------------------",
"                                                                  ",
"                  Timex - Time eXecution v1.29                    ",
"                                                                  ",
"                    by Frank G. Barchard, EAC                     ",
"                                                                  ",
"                   Main program - Mar 15, 2007                    ",
"                                                                  ",
"------------------------------------------------------------------",
"                                                                  ",
" Version Date   SE History:                                       ",
" ------- ------ -- --------                                       ",
"    1.00 951106 FB initial version for using response files on ss ",
"    1.01 960717 FB single default. added multi option             ",
"    1.02 970327 FB -cd, option parsing before cmd                 ",
"    1.03 970408 FB -cd off by default (slow)                      ",
"    1.04 970714 FB -out to produce 'tool in out' form lines       ",
"    1.05 990201 FB -r spit recurse is zrun option                 ",
"    1.06 990909 FB use dargv. zrun saveit *.exe=*                 ",
"    1.07 991004 FB extension rule '', not '.'                     ",
"    1.08 000117 ND -stderr= option - redirection stderr to file   ",
"    1.09 000126 ND -stdout                                        ",
"    1.10 001005 FB -v0 do stderr to default file                  ",
"    1.11 001126 FB cleanup stderr/stdout files                    ",
"    1.12 001128 FB -time                                          ",
"    1.13 010505 FB -tolower                                       ",
"    1.14 010517 FB timex tool                                     ",
"    1.15 010601 FB show in minutes                                ",
"    1.16 010926 FB show seconds if more than 1                    ",
"    1.17 010926 FB qutoes filename arguments and passes thru opts ",
"    1.18 020623 FB exception handler                              ",
"    1.19 020721 FB rewritten based on DB                          ",
"    1.20 020812 FB -comment option to spew comment per line       ",
"    1.21 030630 FB -s to display seconds only                     ",
"    1.22 030614 FB -l to log to a text file, PerformanceCounter   ",
"    1.23 040927 FB -stderr to send TIMEX output to stderr         ",
"    1.24 050902 FB -hours show just hours, -c show cmd            ",
"    1.25 050906 FB -v show performance frequency                  ",
"    1.26 050919 FB time with real time clock and performance time ",
"    1.27 051201 FB -a to do the command AT the specified level    ",
"    1.28 060313 FB -comment as second field for csv files         ",
"    1.29 070314 FB -min/-hour affect -log                         ",
"                                                                  ",
"------------------------------------------------------------------",
"\0"
};
*/
#endif

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

#if defined(_MSC_VER) && !defined(_XBOX)
#include <windows.h>
#endif

#if defined(_MSC_VER)
#pragma warning(disable: 4996)  // warning C4996: 'fscanf' was declared deprecated
#endif
#if defined(__ICL)
#pragma warning(disable: 1478)  // (icl) warning #1478: function "strcpy" was declared "deprecated"
#endif

#include <stdio.h>
#include <limits.h>
#include <time.h>
#if defined(_MSC_VER)
#include <string.h>
#include <process.h>
#endif

#if defined(__unix__) || defined(__APPLE__) || defined(__BEOS__)
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#define strlwr(__s)   { int __i; for (__i=0; (__s)[__i]; ++__i) (__s)[__i]=(char)tolower((__s)[__i]); }
#define strupr(__s)   { int __i; for (__i=0; (__s)[__i]; ++__i) (__s)[__i]=(char)toupper((__s)[__i]); }
#define stricmp strcasecmp
#define strnicmp strncasecmp
#endif

#define TESTNULLPTRCRASH 0

#define TextVersion "1.29 (Samba) 2007.12.4"

#define TIMEXMAXLINE 512
char OPTcomment[TIMEXMAXLINE];
char OPTlogfile[TIMEXMAXLINE];

#if defined(_MSC_VER)

double TIMEX_getclocktime(int)
{
    clock_t t = clock();
    return double(t*1000.0/CLOCKS_PER_SEC);
}

#else

// unix flavour
double TIMEX_getclocktime(int)
{
    struct timeval tv;
    struct timezone tz; // not used
    gettimeofday(&tv,&tz);
    return (double)tv.tv_sec*1000.0+(double)tv.tv_usec/1000.0;
}

#endif

// A high a precision timer, as well as long duration
// caveat - once in a blue moon, 64 bit counter will overflow and this will glitch

#if defined(_MSC_VER) && !defined(_WIN64)

static double i64tod(__int64 it)
{
    return (double) it;
}

double TIMEX_getperformancetime(int OPTverbose)
{
    double t=0;

    static double freqs=0.0;
    if (!freqs)
    {
        LARGE_INTEGER t1;
        BOOL ok = QueryPerformanceFrequency(&t1);
        if (ok)
        {
            freqs = 1000.0 / i64tod(t1.QuadPart);
            if (OPTverbose)
                printf("PerformanceFrequency is %I64d\n",t1.QuadPart);
        }
    }

    if (freqs)
    {
        LARGE_INTEGER t2;
        BOOL ok = QueryPerformanceCounter(&t2);
        if (ok)
        {
            t = i64tod(t2.QuadPart);
            return t * freqs;
        }
    }
    return 0;
}
#else
double TIMEX_getperformancetime(int OPTverbose)
{
    return TIMEX_getclocktime(OPTverbose);
}
#endif

/*
;
; ABSTRACT
;
; timex - launches and times commands
;
; SUMMARY
;
; timex -opts <commandline>
;     -v             verbose
;     -c             show command executed
;     -stderr        output to stderr instead of stdout
;     -hours         measure in hours
;     -minutes       measure in minutes (aka -min)
;     -seconds       measure in seconds (aka -s)
;     -comment<text> add a comment to end of text line
;     -log<file.txt> append to specified log file
;
; DESCRIPTION
;
; This utility executes times commands and tools.
; The duration and return code are output.
;
; RETURNS
;
; 0 success
; n return code from system() call
;
; SEE ALSO
;
; zrun, Spit
;
; EXAMPLE
;
; >timex bldhelp
; bldhelp
; Abstract v3.07 (La Opera) 010522 by FrANK Barchard, EAC
; Building Cross Reference <html\ref.txt>
; gx.c: Reading, Parsing, 184401->33 (1)
; gcmp.c: Reading, Parsing, 26550->37 (1)
; ...
; html\zhelp.htm
; html\zrename.htm
; html\zrun.htm
; 49 File(s) copied
; TIMEX 2658.72 ms
;
; END ABSTRACT
;
*/

void TIMEX_usage(void)
{
    printf( "TIMEX v" TextVersion " by Frank Barchard,EAC\n"
            "SUMMARY: TIMEX launches apps and times them\n"
            "USAGE: TIMEX -options [app] [parameters]\n"
            "    -v             verbose\n"
            "    -c             show command executed (default). -c0 to disable\n"
            "    -stderr        output to stderr instead of stdout\n"
            "    -hours         measure in hours\n"
            "    -minutes       measure in minutes (aka -min)\n"
            "    -seconds       measure in seconds (aka -s)\n"
            "    -comment<text> add a comment to end of text line\n"
            "    -log<file.txt> append to specified log file\n");
}

int main(int argc, char *argv[])
{
    int first;
    int OPTverbose=0;
    int OPThours=0;
    int OPTminutes=0;
    int OPTseconds=0;
    int OPTshowcommand=1;
    FILE *OPTstdout=stdout;
    int errors=0;
    char commandline[2048];

    commandline[0] = 0;

    for (first=1; first<argc; ++first)
    {
        if (!strnicmp(argv[first],"-comment",8))
        {
            strcpy(OPTcomment,argv[first]+8);
        }
        else if (!stricmp(argv[first],"-v"))
        {
            OPTverbose = 1;
        }
        else if (!stricmp(argv[first],"-c"))
        {
            OPTshowcommand = 1;
        }
        else if (!stricmp(argv[first],"-c0"))
        {
            OPTshowcommand = 0;
        }
        else if (!stricmp(argv[first],"-stderr"))
        {
            OPTstdout = stderr;
        }
        else if (!stricmp(argv[first],"-seconds"))
        {
            OPTseconds = 1;
        }
        else if (!stricmp(argv[first],"-s"))
        {
            OPTseconds = 1;
        }
        else if (!stricmp(argv[first],"-minutes"))
        {
            OPTminutes = 1;
        }
        else if (!stricmp(argv[first],"-min"))
        {
            OPTminutes = 1;
        }
        else if (!stricmp(argv[first],"-hours"))
        {
            OPThours = 1;
        }
        else if (!strnicmp(argv[first],"-log",4))
        {
            strcpy(OPTlogfile,argv[first]+4);
        }
        else if (argv[first][0]=='?' || argv[first][0]=='-' || !stricmp(argv[first],"/?"))
        {
            TIMEX_usage();
            exit(10);
        }
        else
            break;
    }


    if (first>=argc)
    {
        TIMEX_usage();
        exit(10);
    }

    {
        /* get all file names */
        for (int i=first; i<argc; ++i)
        {
            char nextarg[1024];

            // add space, if not the first argument
            if (i>first)
                strcat(commandline," ");

            // quote args with spaces in them.  we really should quote quotes too
            if (strchr(argv[i],' '))
                sprintf(nextarg,"\"%s\"",argv[i]);
            else
                strcpy(nextarg,argv[i]);

            strcat(commandline,nextarg);
        }
        if (OPTverbose)
            printf("%s\n",commandline);

        TIMEX_getclocktime(OPTverbose);
        TIMEX_getperformancetime(OPTverbose);
        double totalclocktime = TIMEX_getclocktime(OPTverbose);
        double totalperformancetime = TIMEX_getperformancetime(OPTverbose);

        errors = system(commandline);

        totalperformancetime = TIMEX_getperformancetime(OPTverbose)-totalperformancetime;
        totalclocktime = TIMEX_getclocktime(OPTverbose)-totalclocktime;

        if (OPTverbose)
        {
            fprintf(OPTstdout,"TIMEX clock time %10.4f seconds vs %10.4f performance time\n",totalclocktime/1000.0,totalperformancetime/1000.0);
        }

        double totaltime = totalclocktime;

        if (OPTseconds)
        {
            if (OPTverbose) fprintf(OPTstdout,"TIMEX %10.4f seconds",totaltime/1000.0);
            else            fprintf(OPTstdout,"TIMEX %6.2f seconds",totaltime/1000.0);
        }
        else if (OPTminutes)
        {
            if (OPTverbose) fprintf(OPTstdout,"TIMEX %10.4f minutes",totaltime/60000.0);
            else            fprintf(OPTstdout,"TIMEX %6.2f minutes",totaltime/60000.0);
        }
        else if (OPThours)
        {
            if (OPTverbose) fprintf(OPTstdout,"TIMEX %10.4f hours",totaltime/3600000.0);
            else            fprintf(OPTstdout,"TIMEX %6.2f hours",totaltime/3600000.0);
        }
        else
        {
            if (totaltime>=3600000.0)
                fprintf(OPTstdout,"TIMEX %.2f ms (%.2f seconds) (%.2f minutes) (%.2f hours)",totaltime,totaltime/1000.0,totaltime/60000.0,totaltime/3600000.0);
            else if (totaltime>=60000.0)
                fprintf(OPTstdout,"TIMEX %.2f ms (%.2f seconds) (%.2f minutes)",totaltime,totaltime/1000.0,totaltime/60000.0);
            else if (totaltime>=1000.0)
                fprintf(OPTstdout,"TIMEX %.2f ms (%.2f seconds)",totaltime,totaltime/1000.0);
            else
                fprintf(OPTstdout,"TIMEX %.2f ms",totaltime);
        }
        if (OPTcomment[0])
            fprintf(OPTstdout,", %s",OPTcomment);

        if (OPTshowcommand)
            fprintf(OPTstdout,", %s", commandline);

        if ((OPTverbose>=2 || errors) && !OPTseconds)
            fprintf(OPTstdout,", returncode %d",errors);

        fprintf(OPTstdout,"\n");


        if (OPTlogfile[0])
        {
            char logstr[512];

            if (OPTminutes)
            {
                sprintf(logstr,"TIMEX %12.6f minutes",totaltime/60000.0);
            }
            else if (OPThours)
            {
                sprintf(logstr,"TIMEX %12.6f hours",totaltime/3600000.0);
            }
            else // if (OPTseconds)
            {
                sprintf(logstr,"TIMEX %12.6f seconds",totaltime/1000.0);
            }

            char commentstr[512];
            if (OPTcomment[0])
            {
                sprintf(commentstr,", %s",OPTcomment);
                strcat(logstr,commentstr);
            }
            strcat(logstr,"\n");

            FILE *g = fopen(OPTlogfile,"a");
            if (!g)
                printf("ERROR TIMEX could not open logfile %s\n",OPTlogfile);
            else
            {
                fwrite(logstr,strlen(logstr),1,g);
                fclose(g);
            }
        }

    }

    return errors;
}

