/*
   <p>Test harness for the CSV library.</p>

               Written by M.C.Gregorie.

               Version history
               
               1.0   18/12/02   Initial release

   <kbd>
   <b>environ - C programming support functions</b><br>
   Copyright (C) 2005  Martin C Gregorie
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the Lesser GNU General Public License.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the Lesser GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   </kbd>
  
   <p>Contact Martin Gregorie at <i>martin@gregorie.org</i></p>
*/

#define VERSION         "1.0"
#define COPYRIGHT       "(c) M.C.Gregorie, 2002"

#ifndef TRUE
#define TRUE       1
#endif

#ifndef FALSE
#define FALSE      0
#endif

#define FLAGCNT    2

#define HELP       0      /* -? help */
#define DEBUG      1      /* -d debug mode */

#define MAYBEMARK  '%'
#define BADMARK    '!'
#define OK         ' '
#define OPTLIST    "?d"

#define MAXCSV     4

#include <environ.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>

#include "csv.h"

int readargs(int argc, char *argv[], int flags[]);
void showhelp();
int runtest(char *script, int debug);
char *whichptr(CSV *p, CSV *pa[]);

/*
   This function scans the command line for options and does
   all the associated setup.
*/
int readargs(int argc, char *argv[], int flags[])
{
   int i; 
   int opt;

   /* initialise flags */

   for (i=0 ; i<FLAGCNT ; i++) flags[i] = FALSE;

   /* set up options from the command line */

   optmaybe = MAYBEMARK;
   optbad = BADMARK;
   optind = 1;
   
   while ((opt=getopt(argc,argv,OPTLIST)) != EOF)   
   {
      switch (opt) {
         case 0:         continue;
         case BADMARK:   return(opt);
         case '?':       flags[HELP] = TRUE;       
                         break;
         case 'd':       flags[DEBUG]++;
                         break;
         default :       error(argv[0],
                               "impossible happened parsing options",
                               "");
      }
   }
   return(OK);
}

/*
   Show the punter what the options are
*/
void showhelp()
{
   printf("\ntestcsv v%s %s\n\n",VERSION,COPYRIGHT);
   printf("Syntax  : testcsv [<opts>] script ...\n");
   printf("Function: CSV library test harness runs the test\n");
   printf("          scripts and displays test results.\n");
   printf("Options :\n");
   printf("     -d           debug mode\n");
   printf("if given\n");
}

/*
   The main program starts here
   ----------------------------
*/
int main(int argc, char *argv[])
{
   int   flags[FLAGCNT],
         argtype,
         reply;

   /*
      Parse and set up command options
   */
   setprog(argv[0]);
   if (readargs(argc,argv,flags) == BADMARK)
   {
      return(1);
   }

   /*
      If help was asked for, give it and quit
   */
   if (flags[HELP]) 
   {
      showhelp();
      return(0);
   }

   optind = 1;
   while ((argtype = getarg(argc, argv)) >= 0)
   {
      if (argtype > 0)
      {
         reply = runtest(optarg, flags[DEBUG]);
         if (reply)
            break;
      }
   }
   
   return(reply);
}

int runtest(char *script, int debug)
{
   FILE   *f;
   char   line[MAXLINE];
   int    lineno;
   int    linelth;
   int    i;

   char   *fn;
   int    n;
   char   *p1;
   char   *p2;
   int    m;
   double r;
   int    x;
   char   *s;

   CSV    *csv[MAXCSV];
   char   *es;
   int    e;
   int    errcnt;

   lineno = 0;
   errcnt = 0;
   for (i = 0; i < MAXCSV; i++)
      csv[i] = NULL;
      
   f = fopen(script, "r");
   if (f)
   {
      printf("Processing script %s\n", script);
   }
   else
   {
      printf("Can't open %s\n\n", script);
      return errno;
   }

   csvsetdebug(debug);

   while (fgets(line, MAXLINE, f))
   {
      /*
         Count lines read.
         Remove trailing newlines and spaces.
         Print the line.
      */
      lineno++;
      linelth = strlen(line);
      if (line[linelth-1] == '\n')
      {
      	line[linelth-1] = '\0';
      }

      for (i = strlen(line) -1; i >=0 ;i--)
      {
         if (isspace(line[i]))
            line[i] = '\0';
         else
            break;
      }
            
      printf("%3d: %s\n", lineno, line);

      /*
         Ignore empty lines and those starting with #
      */
      if (line[0] == '#' || strlen(line) == 0)
         continue;

      /*
         If the line has a trailing comment, remove it
      */
      s = strchr(line, '#');
      if (s)
      {
         *s = '\0';
         if (debug > 2)
         {
            printf("Line truncated to '%s'\n", line);
         }
      }

      /*
         Parse the command
      */
      p1 = "";
      p2 = "";
      n = 0;
      m = 0;
      r = 0.0;
      fn = strtok(line, " \t");
      if (!fn)
      {
         printf("     Error:  No function in this line\n");
         errcnt++;
         continue;
      }
      
      s = strtok(NULL, " \t");
      if (!s)
      {
         printf("     Error:  No CSV file reference in this line\n");
         errcnt++;
         continue;
      }
      else
      {
         n = atoi(s);
         if (n < 1 || n > MAXCSV)
         {
            printf("     Error: CSV file reference must be 1-%d\n", MAXCSV);
            errcnt++;
            continue;
         }

         n = n -1;
      }

      if ((p1 = strtok(NULL, " \t")))
      {
         m = atoi(p1);
         r = atof(p1);
         if (!(p2 = strtok(NULL, " \t")))
         {
            p2 = "";
         }
      }
      else
      {
      	p1 = "";
      }

      if (debug > 1)
      {
         printf("     Debug:   fn=%s n=%d p1='%s' p2='%s'\n", fn, n, p1, p2);
         printf("                         m=%d r=%f\n", m, r);
      }

      /*
         Identify the function to be run and do so, reporting results
      */
      if (strcmp("csvopen", fn) == 0)
      {
      	 if (strcmp(p1, ".") == 0)
            csv[n] = csvopen(NULL, p2);
      	 else
            csv[n] = csvopen(p1, p2);

         printf("     Result: %s\n", whichptr(csv[n], csv));
      }
      else
      if (strcmp("csvclose", fn) == 0)
      {
         csv[n] = csvclose(csv[n]);
         printf("     Result: %s\n", whichptr(csv[n], csv));
      }
      else
      if (strcmp("csvsetsep", fn) == 0)
      {
      	 if (strcmp(p1, "\\n") == 0)
      	   x = '\n';
      	 else
      	 if (strcmp(p1, "\\r") == 0)
      	   x = '\r';
      	 else
      	   x = p1[0];
      	   
         x = csvsetsep(csv[n], x);
         printf("     Result: %d\n", x);
      }
      else
      if (strcmp("csvsetquote", fn) == 0)
      {
      	 x = -1;
      	 if (strcmp("NORMAL", p1) == 0)
      	    x = NORMAL;
      	 else if (strcmp("ALWAYS", p1) == 0)
      	    x = ALWAYS;
      	 else if (strcmp("NEVER", p1) == 0)
      	    x = NEVER;
      	 else if (strcmp("MINIMAL", p1) == 0)
      	    x = MINIMAL;
         else
            x = m;
            
         x = csvsetquote(csv[n], x);
         printf("     Result: %d\n", x);
      }
      else
      if (strcmp("csvsetnl", fn) == 0)
      {
      	 x = -1;
      	 if (strcmp("CRLF", p1) == 0)
      	    x = CRLF;
      	 else if (strcmp("CR", p1) == 0)
      	    x = CR;
      	 else if (strcmp("LF", p1) == 0)
      	    x = LF;
         else
            x = m;
            
         x = csvsetnl(csv[n], x);
         printf("     Result: %d\n", x);
      }
      else
      if (strcmp("csvgetline", fn) == 0)
      {
         s = csvgetline(csv[n]);
         if (s)
            printf("     Result: %d = [%s]\n", strlen(s), s);
         else
            printf("     Result: (nil)\n");
      }
      else
      if (strcmp("csvgetfield", fn) == 0)
      {
         s = csvgetfield(csv[n], m);
         if (s)
            printf("     Result: %d = [%s]\n", strlen(s), s);
         else
            printf("     Result: (nil)\n");
      }
      else
      if (strcmp("csvgetn", fn) == 0)
      {
         x = csvgetn(csv[n]);
         printf("     Result: %d\n", x);
      }
      else
      if (strcmp("csvputline", fn) == 0)
      {
         x = csvputline(csv[n]);
         printf("     Result: %d\n", x);
      }
      else
      if (strcmp("csvputstr", fn) == 0)
      {
         x = csvputstr(csv[n], p1);
         printf("     Result: %d\n", x);
      }
      else
      if (strcmp("csvputint", fn) == 0)
      {
         x = csvputint(csv[n], m);
         printf("     Result: %d\n", x);
      }
      else
      if (strcmp("csvputreal", fn) == 0)
      {
         x = csvputreal(csv[n], r);
         printf("     Result: %d\n", x);
      }
      else
      if (strcmp("csvstrin", fn) == 0)
      {
         x = csvstrin(csv[n], p1);
         printf("     Result: %d\n", x);
      }
      else
      if (strcmp("csvstrout", fn) == 0)
      {
         s = csvstrout(csv[n]);
         if (s)
            printf("     Result: %d = [%s]\n", strlen(s), s);
         else
            printf("     Result: (nil)\n");
      }
      else
      if (strcmp("csvstrprep", fn) == 0)
      {
         x = csvstrprep(csv[n]);
         printf("     Result: %d\n", x);
      }
      else
      {
         printf("     Error: unknown function name\n");
         errcnt++;
         continue;
      }

      /*
         See if the function threw an error and report it
      */
      e = csvgeterr();
      if (e)
      {
         es = csvgeterrtext();
         printf("     Error:  %d,%s\n", e, es);
         errcnt++;
      }
   }

   /*
      Run complete
   */
   printf("Script ended: %d errors\n\n", errcnt);
   fclose(f);
   return 0;
}

char *whichptr(CSV *p, CSV *pa[])
{
   int i;
   static char buff[20];

   strcpy(buff, "Unknown CSV");
   if (p)
   {
      for (i = 0; i < MAXCSV; i++)
         if (p == pa[i])
            sprintf(buff, "csv[%d]", i+1);
   }
   else
      strcpy(buff, "(nil)");

   return buff;
}

