/*****************************************************************************
  FILENAME: args.cpp

*****************************************************************************/

#include "args.hpp"

#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

static const char* _optChars="/-";
static const char* _optSepChars=":=";

#ifdef VCPP // = Visual C++ compiler
// this one turns off warning about potentially unsafe standard C runtime calls
#pragma warning(disable: 4996) 
#endif

cArgvManager::cArgvManager(int argc, tArgArray argv, const char* PrgName)
 {
  mAutoCmdLine=NULL;
  mAutoArgv=NULL;
  membersInit(argc, argv, PrgName);
 }

cArgvManager::cArgvManager(const char* CmdLine, const char* PrgName)
 {
  int CmdLineLength=::strlen(CmdLine);
  if((mAutoCmdLine=new char[CmdLineLength+1])==NULL)
   {
    mAutoArgv=NULL;
    mAutoArgc=1;
   }
  else
   {
    ::strcpy(mAutoCmdLine, CmdLine);
    for(mAutoArgc=1; ::strtok(mAutoArgc==1 ? mAutoCmdLine : NULL, " \t")!=NULL; mAutoArgc++);
    if((mAutoArgv=new char*[mAutoArgc+1])!=NULL)
     {
      int i;
      mAutoArgv[0]=(char*)PrgName;
      ::strcpy(mAutoCmdLine, CmdLine);
      for(i=1; i<mAutoArgc+1;i++)
       mAutoArgv[i]=::strtok(i==1 ? mAutoCmdLine : NULL, " \t");
     }
   }
  membersInit(mAutoArgc, mAutoArgv, NULL);
 }

cArgvManager::~cArgvManager()
 {
  if(mPrgName != NULL)
	 delete[] mPrgName;
  if(mPrgShortName != NULL)
	 delete[] mPrgShortName;
  if(mPrgPath != NULL)
	 delete[] mPrgPath;
  if(mAutoArgv != NULL)
   delete[] mAutoArgv;
  if(mAutoCmdLine != NULL)
   delete[] mAutoCmdLine;
 }

int cArgvManager::membersInit(int argc, const char* const argv[], const char* FullPrgName)
 {
  const char dirSep='\\';
  int i, pathLg, nameLg, shortNameLg;
  mArgv = argv;
  mArgs = argc-1;
  if(FullPrgName==NULL)
   mFullPrgName=mArgv[0];
  else
   mFullPrgName=FullPrgName;
  for(pathLg=::strlen(mFullPrgName)-1;
		 pathLg >= 0 && mFullPrgName[pathLg]!= dirSep; pathLg--);
  pathLg++;
  for(shortNameLg=::strlen(mFullPrgName)-1;
		 shortNameLg >= 0 && mFullPrgName[shortNameLg]!= '.'; shortNameLg--);
  nameLg = ::strlen(mFullPrgName) - pathLg;
  if(shortNameLg>pathLg)
   shortNameLg-=pathLg;
  else
   shortNameLg=nameLg;
  mPrgPath = new char[(pathLg+2)/2*2+1];
  if(mPrgPath != NULL)
	{
	 for(i=0; i<pathLg; i++)
	  mPrgPath[i] = mFullPrgName[i];
	 mPrgPath[i] = '\0';
	}
  mPrgName = new char[(nameLg+2)/2*2+1];
  if(mPrgName != NULL)
	{
	 for(i=0; i<nameLg; i++)
	  mPrgName[i] = mFullPrgName[i+pathLg];
	 mPrgName[i] = '\0';
	}
  mPrgShortName = new char[(shortNameLg+2)/2*2+1];
  if(mPrgShortName != NULL)
	{
	 for(i=0; i<shortNameLg; i++)
	  mPrgShortName[i] = mPrgName[i];
	 mPrgShortName[i] = '\0';
	}
  if( mArgs<0             ||
	  mArgv == NULL         ||
	  mPrgPath == NULL      ||
	  mPrgShortName == NULL ||
	  mPrgName == NULL )
	 return(-1);
  return(0);
 }

const char* cArgvManager::arg(int nb) const
 {
  if(nb<0 || nb>=mArgs)
	return(NULL);
  return(mArgv[nb+1]);
 }

long int cArgvManager::lArg(int idx) const
 {
  long int buf=0l;
  if(idx<0 || idx>=mArgs)
	 return(buf);
  if(::strstr(mArgv[idx+1], "0x")==mArgv[idx+1] || ::strstr(mArgv[idx+1], "0X")==mArgv[idx+1])
   ::sscanf(mArgv[idx+1]+2, "%lx", &buf);
  else
   ::sscanf(mArgv[idx+1], "%ld", &buf);
  return(buf);
 }

double cArgvManager::dArg(int idx) const
 {
  double buf=0.0;
  if(idx<0 || idx>=mArgs)
	 return(buf);
  ::sscanf(mArgv[idx+1], "%lf", &buf);
  return(buf);
 }

int cArgvManager::option(char optc, int bCaseSensitive)
 {
  int index;
  char c;

  if(!bCaseSensitive)
   optc=::toupper(optc);
  for(index=mArgs-1; index>=0; index--)
   if(::strchr(_optChars, mArgv[index+1][0])!=NULL)
    {
     c=mArgv[index+1][1];
     if(!bCaseSensitive)
      c=::toupper(c);
     if(c==optc)
      return(index);
    }
  return(index);
 }

const char* cArgvManager::optValue(int index) const
 {
  int i;
  if(::strchr(_optChars, mArgv[index+1][0])!=NULL && 
     mArgv[index+1][1]!='\0')
   {
    i=2;
    if(mArgv[index+1][i]=='\0')
     return(NULL);
    if(::strchr(_optSepChars, mArgv[index+1][i])!=NULL)
     i++;
    return(mArgv[index+1]+i);
   }
  return(NULL);
 }

long int cArgvManager::optlValue(int idx) const
 {
  long int buf=0l;
  const char* pCh=optValue(idx);
  if(pCh==NULL)
	 return(buf);
  if(::strstr(pCh, "0x")==pCh || ::strstr(mArgv[idx+1], "0X")==pCh)
   ::sscanf(pCh+2, "%lx", &buf);
  else
   ::sscanf(pCh, "%ld", &buf);
  return(buf);
 }

double cArgvManager::optdValue(int idx) const
 {
  double buf=0.0;
  const char* pCh=optValue(idx);
  if(pCh==NULL)
	 return(buf);
  ::sscanf(pCh, "%lf", &buf);
  return(buf);
 }

int cArgvManager::nextNonOption(int index)
 {
  if(++index>=0 && index<mArgs)
   {
    for(; index<mArgs; index++)
     if(::strchr(_optChars, mArgv[index+1][0])==NULL)
      return(index);
   }
  return(-1);
 }