/****************************************************************************\
 
                         Copyright (C) 1991						
                         Joe Kleinwaechter

      This file remains the property of Joe Kleinwaechter and may be
      used freely at no charge. It may not however be resold by anyone or
      included in a Class Library package without my written consent.
 
 
 File:         flag.cpp
 
 Description:  This handles command line arguments and values
        
 Created by:   Joe Kleinwaechter (j2k)
 Date:         14-Feb-1991

\****************************************************************************/

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

#include "arg.hpp"

//void main(int argc, char *argv[]);




/****************************************************************************\
 
 Name:             argString::argString(char *s)
 
 Description:      This is the constructor for the class argString
 
 Parameters:       s - this is the command line string to be passed
 
 Returns:          nothing
 
 Preconditions:    
 
 Altered Global:
 
 Altered Static:
 
 Remarks:          This class is to be only used by the class arg.
 
 Side effects:
 
\****************************************************************************/
argString::argString(char *s)
{

   value = 0;  // preset value and linked list pointer
   next = 0;

   if (*s == '-')  // parameter turned off or has value
      {
      state = ARG_CLEAR;
      s++;
      if (*s)          // this prevents going past eol
         {
         letter = *s;  // get the switch name
         s++;          // point to beginning of phrase
         }
      }
   else if (*s == '+') // parameter turned on or has value
      {
      state = ARG_SET;
      s++;
      if (*s)          // this prevents going past eol
         {
         letter = *s;  // get the switch name
         s++;          // point to beginning of phrase
         }
      }
   else                // non-switch parameter
      {
      state = ARG_NO_SWITCH;
      letter = 0;
      }

   // s now points to the string part of the switch (NULL if there isn't one)

   if (s)  // only make a new string if one exists
      value = strdup(s);

}

/****************************************************************************\
 
 Name:             argString::~argString()
 
 Description:      This is the destructor for the class argString
 
 Parameters:       none
 
 Returns:          nothing
 
 Preconditions:
 
 Altered Global:
 
 Altered Static:
 
 Remarks:         This class is only useable by the class arg.
 
 Side effects:
 
\****************************************************************************/
argString::~argString()
{
   letter = 0;
   if (value)
      free(value);
   next = 0;
}



/****************************************************************************\
 
 Name:             arg::arg(int ac, char *av[], int c)
 
 Description:      This is the constructor for the class arg.
 
 Parameters:       ac - the argc parameter passed to main()
                   av - the argv parameter passed to main()
                   c  - 1 if switches are case-sensitive, else 0
                        This has a default value of being non-case-sensitive
 
 Returns:          nothing
 
 Preconditions:    ac and av must be passed.
 
 Altered Global:
 
 Altered Static:
 
 Remarks:          
 
 Side effects:
 
\****************************************************************************/
arg::arg(int ac, char *av[], int c)
{
int firstTime = 1;
argString *link;

   caseSensitive = c;
   first = 0;

   for (ac--;ac;ac--)
      {
      if (firstTime)
         {
         first = new argString(av[ac]);
         link = first;
         firstTime = 0;
         }
      else
         {
         link->next = new argString(av[ac]);  // build the object
         link = link->next;                   // point to newly created object
         }
      }

}


/****************************************************************************\
 
 Name:             arg::~arg()
 
 Description:      This is the destructor for the calss arg.
 
 Parameters:     
 
 Returns:        
 
 Preconditions:
 
 Altered Global:
 
 Altered Static:
 
 Remarks:        
 
 Side effects:
 
\****************************************************************************/
arg::~arg()
{
argString *p;
argString *n;

   p = first;

   while (p)
      {
      n = p->next;
      delete p;
      p = n;
      }
   first = 0;
}



/****************************************************************************\
 
 Name:             argState arg::isSet(char l, char *s)
 
 Description:      See if a certain flag has been set,cleared or not specified.
 
 Parameters:       l - the character flag name. Use 0 for unnamed switches.
                   s - a pointer to a string where the value of the parameter
                       should be placed. The user must allocate enough space
                       for this string.
 
 Returns:         ARG_NOT_SPECIFIED - this switch was not specified by the user
                  ARG_CLEAR - this switch had a leading minus sign (-).
                  ARG_SET,  - this switch had a leading plus sign (+).
                  ARG_NO_SWITCH - this parameter is unlabeled

 
 Preconditions:
 
 Altered Global:
 
 Altered Static:
 
 Remarks:        
 
 Side effects:
 
\****************************************************************************/
argState arg::isSet(char l, char *s)
{
argString *p;

   p = locate(l);
   if (!p) // no match in the list
      {
      *s = 0;
      return ARG_NOT_SPECIFIED;
      }

   strcpy(s,p->value);
   return p->state;

}

/****************************************************************************\
 
 Name:             argString * arg::locate(char l)
 
 Description:      Find the argString that has letter = l
 
 Parameters:       l - the switch to look for
 
 Returns:          A pointer to the argString that matches. 0 - if none
 
 Preconditions:    
 
 Altered Global:
 
 Altered Static:
 
 Remarks:         This is not accessible to the user.
 
 Side effects:
 
\****************************************************************************/
argString * arg::locate(char l)
{
argString *p;

   p = first;

   if (!caseSensitive)
      l = toupper(l);

   while (p)
      {

      if ( (caseSensitive?p->letter:toupper(p->letter)) == l)
         return p;
      else
         p = p->next;
      }
}


/****************************************************************************\
 
 Name:             void arg::display()
 
 Description:      Display the list of arguments and their conditions to the
                   screen.
 
 Parameters:       none
 
 Returns:          nothing
 
 Preconditions:
 
 Altered Global:
 
 Altered Static:
 
 Remarks:         This is meant for debugging purposes.
 
 Side effects:
 
\****************************************************************************/
void arg::display()
{
argString *p;

   p = first;

   while (p)
      {
      switch(p->state)
         {
         case ARG_NOT_SPECIFIED:
            printf("l=%c  state=ARG_NOT_SPECIFIED   value=%s\n",p->letter, p->value);
            break;
         case ARG_CLEAR:
            printf("l=%c  state=ARG_CLEAR           value=%s\n",p->letter, p->value);
            break;
         case ARG_SET:
            printf("l=%c  state=ARG_SET             value=%s\n",p->letter, p->value);
            break;
         case ARG_NO_SWITCH:
            printf("l=%c  state=ARG_NO_SWITCH       value=%s\n",p->letter, p->value);
            break;
         };

      p = p->next;
      }
   printf("\n");

}


