<commit_before>/*=========================================================================

  Program:   KWSys - Kitware System Library
  Module:    CommandLineArguments.cxx

  Copyright (c) Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "kwsysPrivate.h"
#include KWSYS_HEADER(CommandLineArguments.hxx)

#include KWSYS_HEADER(Configure.hxx)

#include KWSYS_HEADER(stl/vector)
#include KWSYS_HEADER(stl/map)
#include KWSYS_HEADER(stl/set)
#include KWSYS_HEADER(ios/sstream)
#include KWSYS_HEADER(ios/iostream)

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

#ifdef _MSC_VER
# pragma warning (disable: 4786)
#endif

namespace KWSYS_NAMESPACE
{

//----------------------------------------------------------------------------
//============================================================================
class CommandLineArgumentsString : public kwsys_stl::string 
{
public:
  typedef kwsys_stl::string StdString;
  CommandLineArgumentsString(): StdString() {}
  CommandLineArgumentsString(const value_type* s): StdString(s) {}
  CommandLineArgumentsString(const value_type* s, size_type n): StdString(s, n) {}
  CommandLineArgumentsString(const StdString& s, size_type pos=0, size_type n=npos):
    StdString(s, pos, n) {}
};

struct CommandLineArgumentsCallbackStructure
{
  const char* Argument;
  int ArgumentType;
  CommandLineArguments::CallbackType Callback;
  void* CallData;
  void* Variable;
  int VariableType;
  const char* Help;
};
 
class CommandLineArgumentsVectorOfStrings : 
  public kwsys_stl::vector<CommandLineArgumentsString> {};
class CommandLineArgumentsSetOfStrings :
  public kwsys_stl::set<CommandLineArgumentsString> {};
class CommandLineArgumentsMapOfStrucs : 
  public kwsys_stl::map<CommandLineArgumentsString,
    CommandLineArgumentsCallbackStructure> {};

class CommandLineArgumentsInternal
{
public:
  CommandLineArgumentsInternal()
    {
    this->UnknownArgumentCallback = 0;
    this->ClientData = 0;
    this->LastArgument = 0;
    }

  typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
  typedef CommandLineArgumentsMapOfStrucs CallbacksMap;
  typedef CommandLineArgumentsString String;
  typedef CommandLineArgumentsSetOfStrings SetOfStrings;

  VectorOfStrings Argv;
  String Argv0;
  CallbacksMap Callbacks;

  CommandLineArguments::ErrorCallbackType UnknownArgumentCallback;
  void*             ClientData;

  VectorOfStrings::size_type LastArgument;
};
//============================================================================
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
CommandLineArguments::CommandLineArguments()
{
  this->Internals = new CommandLineArguments::Internal;
  this->Help = "";
  this->LineLength = 80;
}

//----------------------------------------------------------------------------
CommandLineArguments::~CommandLineArguments()
{
  delete this->Internals;
}

//----------------------------------------------------------------------------
void CommandLineArguments::Initialize(int argc, const char* const argv[])
{
  int cc;

  this->Initialize();
  this->Internals->Argv0 = argv[0];
  for ( cc = 1; cc < argc; cc ++ )
    {
    this->ProcessArgument(argv[cc]);
    }
}

//----------------------------------------------------------------------------
void CommandLineArguments::Initialize(int argc, char* argv[])
{
  this->Initialize(argc, static_cast<const char* const*>(argv));
}

//----------------------------------------------------------------------------
void CommandLineArguments::Initialize()
{
  this->Internals->Argv.clear();
  this->Internals->LastArgument = 0;
}

//----------------------------------------------------------------------------
void CommandLineArguments::ProcessArgument(const char* arg)
{
  this->Internals->Argv.push_back(arg);
}

//----------------------------------------------------------------------------
int CommandLineArguments::Parse()
{
  CommandLineArguments::Internal::VectorOfStrings::size_type cc;
  CommandLineArguments::Internal::VectorOfStrings matches;
  for ( cc = 0; cc < this->Internals->Argv.size(); cc ++ )
    {
    this->Internals->LastArgument = cc;
    matches.clear();
    CommandLineArguments::Internal::String& arg = this->Internals->Argv[cc];
    CommandLineArguments::Internal::CallbacksMap::iterator it;

    // Does the argument match to any we know about?
    for ( it = this->Internals->Callbacks.begin();
      it != this->Internals->Callbacks.end();
      it ++ )
      {
      const CommandLineArguments::Internal::String& parg = it->first;
      CommandLineArgumentsCallbackStructure *cs = &it->second;
      if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT ||
        cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT) 
        {
        if ( arg == parg )
          {
          matches.push_back(parg);
          }
        }
      else if ( arg.find( parg ) == 0 )
        {
        matches.push_back(parg);
        }
      }
    if ( matches.size() > 0 )
      {
      // Ok, we found one or more arguments that match what user specified.
      // Let's find the longest one.
      CommandLineArguments::Internal::VectorOfStrings::size_type kk;
      CommandLineArguments::Internal::VectorOfStrings::size_type maxidx = 0;
      CommandLineArguments::Internal::String::size_type maxlen = 0;
      for ( kk = 0; kk < matches.size(); kk ++ )
        {
        if ( matches[kk].size() > maxlen )
          {
          maxlen = matches[kk].size();
          maxidx = kk;
          }
        }
      // So, the longest one is probably the right one. Now see if it has any
      // additional value
      const char* value = 0;
      CommandLineArgumentsCallbackStructure *cs 
        = &this->Internals->Callbacks[matches[maxidx]];
      const CommandLineArguments::Internal::String& sarg = matches[maxidx];
      if ( cs->ArgumentType == NO_ARGUMENT )
        {
        // No value
        }
      else if ( cs->ArgumentType == SPACE_ARGUMENT )
        {
        if ( cc == this->Internals->Argv.size()-1 )
          {
          this->Internals->LastArgument --;
          return 0;
          }
        // Value is the next argument
        value = this->Internals->Argv[cc+1].c_str();
        cc ++;
        }
      else if ( cs->ArgumentType == EQUAL_ARGUMENT )
        {
        if ( arg.size() == sarg.size() || *(arg.c_str() + sarg.size()) != '=' )
          {
          this->Internals->LastArgument --;
          return 0;
          }
        // Value is everythng followed the '=' sign
        value = arg.c_str() + sarg.size()+1;
        }
      else if ( cs->ArgumentType == CONCAT_ARGUMENT )
        {
        // Value is whatever follows the argument
        value = arg.c_str() + sarg.size();
        }

      // Call the callback
      if ( cs->Callback )
        {
        if ( !cs->Callback(sarg.c_str(), value, cs->CallData) )
          {
          this->Internals->LastArgument --;
          return 0;
          }
        }
      if ( cs->Variable )
        {
        kwsys_stl::string var = "1";
        if ( value )
          {
          var = value;
          }
        if ( cs->VariableType == CommandLineArguments::INT_TYPE )
          {
          int* variable = static_cast<int*>(cs->Variable);
          char* res = 0;
          *variable = strtol(var.c_str(), &res, 10);
          //if ( res && *res )
          //  {
          //  Can handle non-int
          //  }
          }
        else if ( cs->VariableType == CommandLineArguments::DOUBLE_TYPE )
          {
          double* variable = static_cast<double*>(cs->Variable);
          char* res = 0;
          *variable = strtod(var.c_str(), &res);
          //if ( res && *res )
          //  {
          //  Can handle non-int
          //  }
          }
        else if ( cs->VariableType == CommandLineArguments::STRING_TYPE )
          {
          char** variable = static_cast<char**>(cs->Variable);
          if ( *variable )
            {
            delete [] *variable;
            *variable = 0;
            }
          *variable = new char[ strlen(var.c_str()) + 1 ];
          strcpy(*variable, var.c_str());
          }
        else if ( cs->VariableType == CommandLineArguments::STL_STRING_TYPE )
          {
          kwsys_stl::string* variable = static_cast<kwsys_stl::string*>(cs->Variable);
          *variable = var;
          }
        else if ( cs->VariableType == CommandLineArguments::BOOL_TYPE )
          {
          bool* variable = static_cast<bool*>(cs->Variable);
          if ( var == "1" || var == "ON" || var == "TRUE" || var == "true" || var == "on" ||
            var == "True" || var == "yes" || var == "Yes" || var == "YES" )
            {
            *variable = true;
            }
          else
            {
            *variable = false;
            }
          }
        else
          {
          kwsys_ios::cerr << "Got unknown argument type: \"" << cs->VariableType << "\"" << kwsys_ios::endl;
          this->Internals->LastArgument --;
          return 0;
          }
        }
      }
    else
      {
      // Handle unknown arguments
      if ( this->Internals->UnknownArgumentCallback )
        {
        if ( !this->Internals->UnknownArgumentCallback(arg.c_str(), 
            this->Internals->ClientData) )
          {
          this->Internals->LastArgument --;
          return 0;
          }
        return 1;
        }
      else
        {
        kwsys_ios::cerr << "Got unknown argument: \"" << arg.c_str() << "\"" << kwsys_ios::endl;
        this->Internals->LastArgument --;
        return 0;
        }
      }
    }
  return 1;
}

//----------------------------------------------------------------------------
void CommandLineArguments::GetRemainingArguments(int* argc, char*** argv)
{
  CommandLineArguments::Internal::VectorOfStrings::size_type size 
    = this->Internals->Argv.size() - this->Internals->LastArgument + 1;
  CommandLineArguments::Internal::VectorOfStrings::size_type cc;

  // Copy Argv0 as the first argument
  char** args = new char*[ size ];
  args[0] = new char[ this->Internals->Argv0.size() + 1 ];
  strcpy(args[0], this->Internals->Argv0.c_str());
  int cnt = 1;

  // Copy everything after the LastArgument, since that was not parsed.
  for ( cc = this->Internals->LastArgument+1; 
    cc < this->Internals->Argv.size(); cc ++ )
    {
    args[cnt] = new char[ this->Internals->Argv[cc].size() + 1];
    strcpy(args[cnt], this->Internals->Argv[cc].c_str());
    cnt ++;
    }
  *argc = cnt;
  *argv = args;
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddCallback(const char* argument, ArgumentTypeEnum type, 
  CallbackType callback, void* call_data, const char* help)
{
  CommandLineArgumentsCallbackStructure s;
  s.Argument     = argument;
  s.ArgumentType = type;
  s.Callback     = callback;
  s.CallData     = call_data;
  s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE;
  s.Variable     = 0;
  s.Help         = help;

  this->Internals->Callbacks[argument] = s;
  this->GenerateHelp();
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  VariableTypeEnum vtype, void* variable, const char* help)
{
  CommandLineArgumentsCallbackStructure s;
  s.Argument     = argument;
  s.ArgumentType = type;
  s.Callback     = 0;
  s.CallData     = 0;
  s.VariableType = vtype;
  s.Variable     = variable;
  s.Help         = help;

  this->Internals->Callbacks[argument] = s;
  this->GenerateHelp();
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  int* variable, const char* help)
{
  this->AddArgument(argument, type, CommandLineArguments::INT_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  double* variable, const char* help)
{
  this->AddArgument(argument, type, CommandLineArguments::DOUBLE_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  char** variable, const char* help)
{
  this->AddArgument(argument, type, CommandLineArguments::STRING_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  kwsys_stl::string* variable, const char* help)
{
  this->AddArgument(argument, type, CommandLineArguments::STL_STRING_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  bool* variable, const char* help)
{
  this->AddArgument(argument, type, CommandLineArguments::BOOL_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddBooleanArgument(const char* argument, bool*
  variable, const char* help)
{
  this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
    CommandLineArguments::BOOL_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddBooleanArgument(const char* argument, int*
  variable, const char* help)
{
  this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
    CommandLineArguments::INT_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::SetClientData(void* client_data)
{
  this->Internals->ClientData = client_data;
}

//----------------------------------------------------------------------------
void CommandLineArguments::SetUnknownArgumentCallback(
  CommandLineArguments::ErrorCallbackType callback)
{
  this->Internals->UnknownArgumentCallback = callback;
}

//----------------------------------------------------------------------------
const char* CommandLineArguments::GetHelp(const char* arg)
{
  CommandLineArguments::Internal::CallbacksMap::iterator it 
    = this->Internals->Callbacks.find(arg);
  if ( it == this->Internals->Callbacks.end() )
    {
    return 0;
    }

  // Since several arguments may point to the same argument, find the one this
  // one point to if this one is pointing to another argument.
  CommandLineArgumentsCallbackStructure *cs = &(it->second);
  while ( 1 )
    {
    CommandLineArguments::Internal::CallbacksMap::iterator hit 
      = this->Internals->Callbacks.find(cs->Help);
    if ( hit == this->Internals->Callbacks.end() )
      {
      return cs->Help;
      }
    cs = &(hit->second);
    }
  // Should never happened
  return 0;
}

//----------------------------------------------------------------------------
void CommandLineArguments::SetLineLength(unsigned int ll)
{
  if ( ll < 9 || ll > 1000 )<commit_msg>COMP: Remove warning<commit_after>/*=========================================================================

  Program:   KWSys - Kitware System Library
  Module:    CommandLineArguments.cxx

  Copyright (c) Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "kwsysPrivate.h"
#include KWSYS_HEADER(CommandLineArguments.hxx)

#include KWSYS_HEADER(Configure.hxx)

#include KWSYS_HEADER(stl/vector)
#include KWSYS_HEADER(stl/map)
#include KWSYS_HEADER(stl/set)
#include KWSYS_HEADER(ios/sstream)
#include KWSYS_HEADER(ios/iostream)

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

#ifdef _MSC_VER
# pragma warning (disable: 4786)
#endif

namespace KWSYS_NAMESPACE
{

//----------------------------------------------------------------------------
//============================================================================
class CommandLineArgumentsString : public kwsys_stl::string 
{
public:
  typedef kwsys_stl::string StdString;
  CommandLineArgumentsString(): StdString() {}
  CommandLineArgumentsString(const value_type* s): StdString(s) {}
  CommandLineArgumentsString(const value_type* s, size_type n): StdString(s, n) {}
  CommandLineArgumentsString(const StdString& s, size_type pos=0, size_type n=npos):
    StdString(s, pos, n) {}
};

struct CommandLineArgumentsCallbackStructure
{
  const char* Argument;
  int ArgumentType;
  CommandLineArguments::CallbackType Callback;
  void* CallData;
  void* Variable;
  int VariableType;
  const char* Help;
};
 
class CommandLineArgumentsVectorOfStrings : 
  public kwsys_stl::vector<CommandLineArgumentsString> {};
class CommandLineArgumentsSetOfStrings :
  public kwsys_stl::set<CommandLineArgumentsString> {};
class CommandLineArgumentsMapOfStrucs : 
  public kwsys_stl::map<CommandLineArgumentsString,
    CommandLineArgumentsCallbackStructure> {};

class CommandLineArgumentsInternal
{
public:
  CommandLineArgumentsInternal()
    {
    this->UnknownArgumentCallback = 0;
    this->ClientData = 0;
    this->LastArgument = 0;
    }

  typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
  typedef CommandLineArgumentsMapOfStrucs CallbacksMap;
  typedef CommandLineArgumentsString String;
  typedef CommandLineArgumentsSetOfStrings SetOfStrings;

  VectorOfStrings Argv;
  String Argv0;
  CallbacksMap Callbacks;

  CommandLineArguments::ErrorCallbackType UnknownArgumentCallback;
  void*             ClientData;

  VectorOfStrings::size_type LastArgument;
};
//============================================================================
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
CommandLineArguments::CommandLineArguments()
{
  this->Internals = new CommandLineArguments::Internal;
  this->Help = "";
  this->LineLength = 80;
}

//----------------------------------------------------------------------------
CommandLineArguments::~CommandLineArguments()
{
  delete this->Internals;
}

//----------------------------------------------------------------------------
void CommandLineArguments::Initialize(int argc, const char* const argv[])
{
  int cc;

  this->Initialize();
  this->Internals->Argv0 = argv[0];
  for ( cc = 1; cc < argc; cc ++ )
    {
    this->ProcessArgument(argv[cc]);
    }
}

//----------------------------------------------------------------------------
void CommandLineArguments::Initialize(int argc, char* argv[])
{
  this->Initialize(argc, static_cast<const char* const*>(argv));
}

//----------------------------------------------------------------------------
void CommandLineArguments::Initialize()
{
  this->Internals->Argv.clear();
  this->Internals->LastArgument = 0;
}

//----------------------------------------------------------------------------
void CommandLineArguments::ProcessArgument(const char* arg)
{
  this->Internals->Argv.push_back(arg);
}

//----------------------------------------------------------------------------
int CommandLineArguments::Parse()
{
  CommandLineArguments::Internal::VectorOfStrings::size_type cc;
  CommandLineArguments::Internal::VectorOfStrings matches;
  for ( cc = 0; cc < this->Internals->Argv.size(); cc ++ )
    {
    this->Internals->LastArgument = cc;
    matches.clear();
    CommandLineArguments::Internal::String& arg = this->Internals->Argv[cc];
    CommandLineArguments::Internal::CallbacksMap::iterator it;

    // Does the argument match to any we know about?
    for ( it = this->Internals->Callbacks.begin();
      it != this->Internals->Callbacks.end();
      it ++ )
      {
      const CommandLineArguments::Internal::String& parg = it->first;
      CommandLineArgumentsCallbackStructure *cs = &it->second;
      if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT ||
        cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT) 
        {
        if ( arg == parg )
          {
          matches.push_back(parg);
          }
        }
      else if ( arg.find( parg ) == 0 )
        {
        matches.push_back(parg);
        }
      }
    if ( matches.size() > 0 )
      {
      // Ok, we found one or more arguments that match what user specified.
      // Let's find the longest one.
      CommandLineArguments::Internal::VectorOfStrings::size_type kk;
      CommandLineArguments::Internal::VectorOfStrings::size_type maxidx = 0;
      CommandLineArguments::Internal::String::size_type maxlen = 0;
      for ( kk = 0; kk < matches.size(); kk ++ )
        {
        if ( matches[kk].size() > maxlen )
          {
          maxlen = matches[kk].size();
          maxidx = kk;
          }
        }
      // So, the longest one is probably the right one. Now see if it has any
      // additional value
      const char* value = 0;
      CommandLineArgumentsCallbackStructure *cs 
        = &this->Internals->Callbacks[matches[maxidx]];
      const CommandLineArguments::Internal::String& sarg = matches[maxidx];
      if ( cs->ArgumentType == NO_ARGUMENT )
        {
        // No value
        }
      else if ( cs->ArgumentType == SPACE_ARGUMENT )
        {
        if ( cc == this->Internals->Argv.size()-1 )
          {
          this->Internals->LastArgument --;
          return 0;
          }
        // Value is the next argument
        value = this->Internals->Argv[cc+1].c_str();
        cc ++;
        }
      else if ( cs->ArgumentType == EQUAL_ARGUMENT )
        {
        if ( arg.size() == sarg.size() || *(arg.c_str() + sarg.size()) != '=' )
          {
          this->Internals->LastArgument --;
          return 0;
          }
        // Value is everythng followed the '=' sign
        value = arg.c_str() + sarg.size()+1;
        }
      else if ( cs->ArgumentType == CONCAT_ARGUMENT )
        {
        // Value is whatever follows the argument
        value = arg.c_str() + sarg.size();
        }

      // Call the callback
      if ( cs->Callback )
        {
        if ( !cs->Callback(sarg.c_str(), value, cs->CallData) )
          {
          this->Internals->LastArgument --;
          return 0;
          }
        }
      if ( cs->Variable )
        {
        kwsys_stl::string var = "1";
        if ( value )
          {
          var = value;
          }
        if ( cs->VariableType == CommandLineArguments::INT_TYPE )
          {
          int* variable = static_cast<int*>(cs->Variable);
          char* res = 0;
          *variable = strtol(var.c_str(), &res, 10);
          //if ( res && *res )
          //  {
          //  Can handle non-int
          //  }
          }
        else if ( cs->VariableType == CommandLineArguments::DOUBLE_TYPE )
          {
          double* variable = static_cast<double*>(cs->Variable);
          char* res = 0;
          *variable = strtod(var.c_str(), &res);
          //if ( res && *res )
          //  {
          //  Can handle non-int
          //  }
          }
        else if ( cs->VariableType == CommandLineArguments::STRING_TYPE )
          {
          char** variable = static_cast<char**>(cs->Variable);
          if ( *variable )
            {
            delete [] *variable;
            *variable = 0;
            }
          *variable = new char[ strlen(var.c_str()) + 1 ];
          strcpy(*variable, var.c_str());
          }
        else if ( cs->VariableType == CommandLineArguments::STL_STRING_TYPE )
          {
          kwsys_stl::string* variable = static_cast<kwsys_stl::string*>(cs->Variable);
          *variable = var;
          }
        else if ( cs->VariableType == CommandLineArguments::BOOL_TYPE )
          {
          bool* variable = static_cast<bool*>(cs->Variable);
          if ( var == "1" || var == "ON" || var == "TRUE" || var == "true" || var == "on" ||
            var == "True" || var == "yes" || var == "Yes" || var == "YES" )
            {
            *variable = true;
            }
          else
            {
            *variable = false;
            }
          }
        else
          {
          kwsys_ios::cerr << "Got unknown argument type: \"" << cs->VariableType << "\"" << kwsys_ios::endl;
          this->Internals->LastArgument --;
          return 0;
          }
        }
      }
    else
      {
      // Handle unknown arguments
      if ( this->Internals->UnknownArgumentCallback )
        {
        if ( !this->Internals->UnknownArgumentCallback(arg.c_str(), 
            this->Internals->ClientData) )
          {
          this->Internals->LastArgument --;
          return 0;
          }
        return 1;
        }
      else
        {
        kwsys_ios::cerr << "Got unknown argument: \"" << arg.c_str() << "\"" << kwsys_ios::endl;
        this->Internals->LastArgument --;
        return 0;
        }
      }
    }
  return 1;
}

//----------------------------------------------------------------------------
void CommandLineArguments::GetRemainingArguments(int* argc, char*** argv)
{
  CommandLineArguments::Internal::VectorOfStrings::size_type size 
    = this->Internals->Argv.size() - this->Internals->LastArgument + 1;
  CommandLineArguments::Internal::VectorOfStrings::size_type cc;

  // Copy Argv0 as the first argument
  char** args = new char*[ size ];
  args[0] = new char[ this->Internals->Argv0.size() + 1 ];
  strcpy(args[0], this->Internals->Argv0.c_str());
  int cnt = 1;

  // Copy everything after the LastArgument, since that was not parsed.
  for ( cc = this->Internals->LastArgument+1; 
    cc < this->Internals->Argv.size(); cc ++ )
    {
    args[cnt] = new char[ this->Internals->Argv[cc].size() + 1];
    strcpy(args[cnt], this->Internals->Argv[cc].c_str());
    cnt ++;
    }
  *argc = cnt;
  *argv = args;
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddCallback(const char* argument, ArgumentTypeEnum type, 
  CallbackType callback, void* call_data, const char* help)
{
  CommandLineArgumentsCallbackStructure s;
  s.Argument     = argument;
  s.ArgumentType = type;
  s.Callback     = callback;
  s.CallData     = call_data;
  s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE;
  s.Variable     = 0;
  s.Help         = help;

  this->Internals->Callbacks[argument] = s;
  this->GenerateHelp();
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  VariableTypeEnum vtype, void* variable, const char* help)
{
  CommandLineArgumentsCallbackStructure s;
  s.Argument     = argument;
  s.ArgumentType = type;
  s.Callback     = 0;
  s.CallData     = 0;
  s.VariableType = vtype;
  s.Variable     = variable;
  s.Help         = help;

  this->Internals->Callbacks[argument] = s;
  this->GenerateHelp();
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  int* variable, const char* help)
{
  this->AddArgument(argument, type, CommandLineArguments::INT_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  double* variable, const char* help)
{
  this->AddArgument(argument, type, CommandLineArguments::DOUBLE_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  char** variable, const char* help)
{
  this->AddArgument(argument, type, CommandLineArguments::STRING_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  kwsys_stl::string* variable, const char* help)
{
  this->AddArgument(argument, type, CommandLineArguments::STL_STRING_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  bool* variable, const char* help)
{
  this->AddArgument(argument, type, CommandLineArguments::BOOL_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddBooleanArgument(const char* argument, bool*
  variable, const char* help)
{
  this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
    CommandLineArguments::BOOL_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::AddBooleanArgument(const char* argument, int*
  variable, const char* help)
{
  this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
    CommandLineArguments::INT_TYPE, variable, help);
}

//----------------------------------------------------------------------------
void CommandLineArguments::SetClientData(void* client_data)
{
  this->Internals->ClientData = client_data;
}

//----------------------------------------------------------------------------
void CommandLineArguments::SetUnknownArgumentCallback(
  CommandLineArguments::ErrorCallbackType callback)
{
  this->Internals->UnknownArgumentCallback = callback;
}

//----------------------------------------------------------------------------
const char* CommandLineArguments::GetHelp(const char* arg)
{
  CommandLineArguments::Internal::CallbacksMap::iterator it 
    = this->Internals->Callbacks.find(arg);
  if ( it == this->Internals->Callbacks.end() )
    {
    return 0;
    }

  // Since several arguments may point to the same argument, find the one this
  // one point to if this one is pointing to another argument.
  CommandLineArgumentsCallbackStructure *cs = &(it->second);
  while ( 1 )
    {
    CommandLineArguments::Internal::CallbacksMap::iterator hit 
      = this->Internals->Callbacks.find(cs->Help);
    if ( hit == this->Internals->Callbacks.end() )
      {
      break;
      }
    cs = &(hit->second);
    }
  return cs->Help;
}

//----------------------------------------------------------------------------
void CommandLineArguments::SetLineLength(unsigned int ll)
{
  if ( ll < 9 || ll > 1000 )
{'fraction_non_alphanumeric': 0.2435794154609609, 'fraction_numerical': 0.003963522701640189, 'mean_word_length': 1.9388257575757575, 'pattern_counts': {'":': 0, '<': 67, '<?xml version=': 0, '>': 271, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2848605', 'n_tokens_mistral': 8276, 'n_tokens_neox': 8102, 'n_words': 1744}