/*
             CREATOR: DAn williams
            FILENAME: cmnCmdOptions.c
             STARTED: Nov 27
           PLATFORMS: Linux
         DESCRIPTION: Gathering of code to parse command line options. "library"


 cmdLineOptionInit:
   Call this first to initialize variables;
   DO NOT call this to clear added options! (memory leak)

 addCmdLineOption:
   Call a few of these to define options for your command line
   Handler procedures that are called need to return the number of extra 
     options they used, for this implimentation 0 or 1 e.g. specifying a filename (-I foo.foo)
     would take 1 extra paramiter, setting a verbose flag (-V) would take none.
   return:
    0 = success
    1 = failed (out of memory)
    2 = failed (out of index space ( 32767 entries)) 

 parseOptions:
  Call this after all your addCmdLineOption calls to actually evaluate the command line
  If there are multiple declarations for the same option it uses the last one declared.
  Pass this the same paramiters that come in from main e.g. 
      parseOptions(argc, argv);
    where int main(int argc, char** argv);


 cleanupOptionStuff:
  Mine! leave it alone!

*/

#include <string.h>
#include "cmnCmdOptions.h"

/* 
   call this first to reset the variables
   DO NOT call this to clear added options! (memory leak)
*/
void cmdLineOptionInit(void) {
  CmdOptions = NULL; //no defined options
  LineCommands = 0; // no defined options
  cmdParseVerbose = 1; // put error to stdout
}


/* 
   Call a few of these to define options for your command line
   Handler procedures that are called need to return the number of extra 
     options they used, for this implimentation 0 or 1 e.g. specifying a filename (-I foo.foo)
     would take 1 extra paramiter, setting a verbose flag (-V) would take none.
   return:
    0 = success
    1 = failed (out of memory)
    2 = failed (out of index space ( 32767 entries)) 
*/
int addCmdLineOption(char** optionNames, int optionNameCount, int (*newHandler)(char*)){
    
  _cmdOption* tempPtr;

  // modify paramiter counter
  if (LineCommands+1 > LineCommands) {
    LineCommands++;
  } else {
    // return 2 if full
    return 2;
  }

  // allocate memory to expand array
  

  if ((tempPtr = (_cmdOption *)realloc(CmdOptions, sizeof(_cmdOption)*LineCommands)) == NULL) {
    return 1;     // if fail return 1
  } else {
    CmdOptions = tempPtr; 
  }
  
  // add entry
  CmdOptions[LineCommands-1].handler = newHandler;
  CmdOptions[LineCommands-1].CallNameCount = optionNameCount;
  CmdOptions[LineCommands-1].CallName = optionNames;

  return 0;

}



/*
  Call this after all your addCmdLineOption calls to actually evaluate the command line
  If there are multiple declarations for the same option it uses the last one declared.
  Pass this the same paramiters that come in from main e.g. 
      parseOptions(argc, argv);
    where int main(int argc, char** argv);
*/
void parseOptions(int argCount, char** argVars) {

  // pardon me lord, for I have copied and pasted code. (but I swear, I made it better!)
  
  int currOpt;
  int cmdIndex;
  int cmdSubIndex;
  int matched;

  /* 
   do some string comparisons to find out what we should do.
   On Intelish hardware, a good compiler should be able to get some extra
     speed from me having made the loops backwards.
   Handler procedures that are called need to return the number of extra 
     options they used, for this implimentation 0 or 1
  */

  currOpt = 1; // start at option 1
  matched = 0; // which is not initially matched to anything

  while (currOpt < argCount) {  // for all the options...

    for (cmdIndex = (LineCommands-1); cmdIndex >= 0; cmdIndex--) { // go through each command

      for (cmdSubIndex = (CmdOptions[cmdIndex].CallNameCount-1);cmdSubIndex >= 0; cmdSubIndex--) {// by each name

	if (strcmp(argVars[currOpt],CmdOptions[cmdIndex].CallName[cmdSubIndex]) == 0) {// and if its a match...
          if ((currOpt+1) <= argCount) {// if were not out of user input
	    currOpt += (*CmdOptions[cmdIndex].handler)(argVars[currOpt+1]); // run the handler with givn string
	  } else { 
	    currOpt += (*CmdOptions[cmdIndex].handler)(""); // run handler with MT string
	  }
          matched = 1; // found it!
          cmdSubIndex = (-1); // stop for!
          cmdIndex = (-1); // stop for!!
	} // close " if strings matched"
      } // end of for cmdSubIndex loup
    } // end of for cmdIndex loup
    if ((matched == 0)&(cmdParseVerbose == 1)) {
      printf("Ignoring unknown option %s\n", argVars[currOpt]);
    }
    matched = 0; //reset match flag.
    currOpt++; // next victim
  } // end of while loup

  //were done, wrap up
  cleanupOptionStuff();

}


void cleanupOptionStuff(void){
  
  // dealloc memory
  free(CmdOptions);
  
  // reset variables
  LineCommands = 0;
}


// Lex? Yacc?? what are those :-)









