/*  getopt.cpp
    A simple command line parser.

    22.07.2002 tk, made some changes to support non-option
               arguments. All recognized options are now removed
               from the argv array.
    28.08.2001 tk, initial implementation, totally unrelated to
               the GNU getopt or similar. (just reinvented the
               wheel, i suppose :)

    Copyright (c)2002 by Thomas Kindler, thomas.kindler@gmx.de

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of
    the License, or (at your option) any later version. Read the
    full License at http://www.gnu.org/copyleft for more details.
*/

// include files -----
//
#include <string.h>
#include <stdio.h>
#include "getopt.h"

/**
 * Parse argv[] for command line options.
 *
 * While scanning for options, the array is permuted so
 * that the option-arguments are moved to the front, while
 * all non-option-arguments are moved to the end of the
 * array. The return value gives the index of the first
 * non-option argument found.
 *  
 * \param   argc, argv   argument count and array of
 *          arguments as given to the main() function.  
 * \param   options      pointer to options array, the
 *          last  entry must have a NULL-option pointer.
 * \return  index of first non-option argument, 
 *          or 0 if an invalid option was found.
 */
int getopt(int argc, char *argv[], CmdOpt *options)
{
  int  optc = argc;
  
  for (int i=1; i<optc; i++) {
    CmdOpt *opt = NULL;
    
    if (!stricmp(argv[i], "--")) {
      // stop option parsing.
      //
      break;
    } 
    
    if (!strnicmp(argv[i], "-", 1) || 
        !strnicmp(argv[i], "/", 1)  ) 
    {
      // search for short-option match
      //
      for (CmdOpt *o = options; o->option; o++)
        if (!stricmp(&argv[i][1], o->option))  opt = o;

      if (!opt) {
        printf("ERROR   : unknown option \"%s\".\n", argv[i]);
        return 0;
      }
    }
            
    if (opt) {
      if (opt->format) {
        // scan for format string..
        //
        if (i+1 >= argc) {
          printf("ERROR   : missing parameter for \"%s\".\n", argv[i]);
          return 0;
        }

        if (!sscanf(argv[i+1], opt->format, opt->param)) {
          printf("ERROR   : invalid parameter \"%s\" for \"%s\".\n",
                  argv[i+1], argv[i]);
          return 0;
        }
        // ..and continue with next argument
        //
        i++;  
      } else {
        // empty format string - set boolean value only.
        //
        if (opt->param)
          *((bool*)opt->param) = true;
      }
    } else {
      // a non-option argument was found. Move 
      // it to the end of the argv[] array.
      //
      char *arg = argv[i];
      for (int j=i; j<argc-1; j++)
        argv[j] = argv[j+1];
      argv[argc-1] = arg;
     
      // scan this argument again.
      //
      optc--; i--;
    }
  } 
  return optc;
}


/**
 * Print option help strings to stdout. 
 * The help texts are generated from the options array.
 *
 * \param options  pointer to array of CmdOpt options.
 */
void getopt_help(const char *cmdname, CmdOpt *options)
{
  printf("Options : ");

  while (options->option) {
    printf("/%-5s %s\n          ", options->option, options->help);
    options++;
  }
}

