CommandLineArguments.cxx 23.9 KB
Newer Older
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3 4 5 6
#include "kwsysPrivate.h"
#include KWSYS_HEADER(CommandLineArguments.hxx)

#include KWSYS_HEADER(Configure.hxx)
7
#include KWSYS_HEADER(String.hxx)
8

9 10 11
// Work-around CMake dependency scanning limitation.  This must
// duplicate the above list of headers.
#if 0
12 13 14
#  include "CommandLineArguments.hxx.in"
#  include "Configure.hxx.in"
#  include "String.hxx.in"
15 16
#endif

17
#include <iostream>
Brad King's avatar
Brad King committed
18 19
#include <map>
#include <set>
20
#include <sstream>
21
#include <vector>
22

23
#include <stdio.h>
Andy Cedilnik's avatar
Andy Cedilnik committed
24
#include <stdlib.h>
25
#include <string.h>
26

27
#ifdef _MSC_VER
28
#  pragma warning(disable : 4786)
29 30
#endif

31
#if defined(__sgi) && !defined(__GNUC__)
32
#  pragma set woff 1375 /* base class destructor not virtual */
33 34
#endif

35
#if 0
36 37
#  define CommandLineArguments_DEBUG(x)                                       \
    std::cout << __LINE__ << " CLA: " << x << std::endl
38
#else
39
#  define CommandLineArguments_DEBUG(x)
40 41
#endif

42
namespace KWSYS_NAMESPACE {
43

44 45 46 47 48 49 50 51 52 53
struct CommandLineArgumentsCallbackStructure
{
  const char* Argument;
  int ArgumentType;
  CommandLineArguments::CallbackType Callback;
  void* CallData;
  void* Variable;
  int VariableType;
  const char* Help;
};
54 55 56 57 58 59 60 61 62 63 64

class CommandLineArgumentsVectorOfStrings : public std::vector<kwsys::String>
{
};
class CommandLineArgumentsSetOfStrings : public std::set<kwsys::String>
{
};
class CommandLineArgumentsMapOfStrucs
  : public std::map<kwsys::String, CommandLineArgumentsCallbackStructure>
{
};
65 66 67 68 69

class CommandLineArgumentsInternal
{
public:
  CommandLineArgumentsInternal()
70
  {
71 72
    this->UnknownArgumentCallback = KWSYS_NULLPTR;
    this->ClientData = KWSYS_NULLPTR;
73
    this->LastArgument = 0;
74
  }
75 76 77

  typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
  typedef CommandLineArgumentsMapOfStrucs CallbacksMap;
78
  typedef kwsys::String String;
79 80 81
  typedef CommandLineArgumentsSetOfStrings SetOfStrings;

  VectorOfStrings Argv;
82
  String Argv0;
83 84 85
  CallbacksMap Callbacks;

  CommandLineArguments::ErrorCallbackType UnknownArgumentCallback;
86
  void* ClientData;
87 88

  VectorOfStrings::size_type LastArgument;
89 90

  VectorOfStrings UnusedArguments;
91 92 93 94 95 96 97
};

CommandLineArguments::CommandLineArguments()
{
  this->Internals = new CommandLineArguments::Internal;
  this->Help = "";
  this->LineLength = 80;
98
  this->StoreUnusedArgumentsFlag = false;
99 100 101 102 103 104 105
}

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

106
void CommandLineArguments::Initialize(int argc, const char* const argv[])
107 108 109 110
{
  int cc;

  this->Initialize();
111
  this->Internals->Argv0 = argv[0];
112
  for (cc = 1; cc < argc; cc++) {
113
    this->ProcessArgument(argv[cc]);
114
  }
115 116
}

Ken Martin's avatar
Ken Martin committed
117 118
void CommandLineArguments::Initialize(int argc, char* argv[])
{
119
  this->Initialize(argc, static_cast<const char* const*>(argv));
Ken Martin's avatar
Ken Martin committed
120 121
}

122 123 124 125 126 127 128 129 130 131 132
void CommandLineArguments::Initialize()
{
  this->Internals->Argv.clear();
  this->Internals->LastArgument = 0;
}

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

133
bool CommandLineArguments::GetMatchedArguments(
134
  std::vector<std::string>* matches, const std::string& arg)
135
{
136 137 138 139
  matches->clear();
  CommandLineArguments::Internal::CallbacksMap::iterator it;

  // Does the argument match to any we know about?
140 141
  for (it = this->Internals->Callbacks.begin();
       it != this->Internals->Callbacks.end(); it++) {
142
    const CommandLineArguments::Internal::String& parg = it->first;
143
    CommandLineArgumentsCallbackStructure* cs = &it->second;
144
    if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT ||
145 146
        cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT) {
      if (arg == parg) {
147
        matches->push_back(parg);
148
      }
149
    } else if (arg.find(parg) == 0) {
150 151
      matches->push_back(parg);
    }
152
  }
153
  return !matches->empty();
154 155 156 157
}

int CommandLineArguments::Parse()
{
Brad King's avatar
Brad King committed
158 159
  std::vector<std::string>::size_type cc;
  std::vector<std::string> matches;
160
  if (this->StoreUnusedArgumentsFlag) {
161
    this->Internals->UnusedArguments.clear();
162 163
  }
  for (cc = 0; cc < this->Internals->Argv.size(); cc++) {
Brad King's avatar
Brad King committed
164
    const std::string& arg = this->Internals->Argv[cc];
165 166
    CommandLineArguments_DEBUG("Process argument: " << arg);
    this->Internals->LastArgument = cc;
167
    if (this->GetMatchedArguments(&matches, arg)) {
168 169 170 171 172
      // 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;
173 174
      for (kk = 0; kk < matches.size(); kk++) {
        if (matches[kk].size() > maxlen) {
175 176 177
          maxlen = matches[kk].size();
          maxidx = kk;
        }
178
      }
179 180
      // So, the longest one is probably the right one. Now see if it has any
      // additional value
181 182
      CommandLineArgumentsCallbackStructure* cs =
        &this->Internals->Callbacks[matches[maxidx]];
Brad King's avatar
Brad King committed
183
      const std::string& sarg = matches[maxidx];
184
      if (cs->Argument != sarg) {
185
        abort();
186 187 188 189
      }
      switch (cs->ArgumentType) {
        case NO_ARGUMENT:
          // No value
190
          if (!this->PopulateVariable(cs, KWSYS_NULLPTR)) {
191
            return 0;
192
          }
193 194 195 196 197
          break;
        case SPACE_ARGUMENT:
          if (cc == this->Internals->Argv.size() - 1) {
            this->Internals->LastArgument--;
            return 0;
198
          }
199 200 201 202 203 204 205
          CommandLineArguments_DEBUG("This is a space argument: "
                                     << arg << " value: "
                                     << this->Internals->Argv[cc + 1]);
          // Value is the next argument
          if (!this->PopulateVariable(cs,
                                      this->Internals->Argv[cc + 1].c_str())) {
            return 0;
206
          }
207 208 209 210 211 212
          cc++;
          break;
        case EQUAL_ARGUMENT:
          if (arg.size() == sarg.size() || arg.at(sarg.size()) != '=') {
            this->Internals->LastArgument--;
            return 0;
213
          }
214 215 216
          // Value is everythng followed the '=' sign
          if (!this->PopulateVariable(cs, arg.c_str() + sarg.size() + 1)) {
            return 0;
217
          }
218 219 220 221 222
          break;
        case CONCAT_ARGUMENT:
          // Value is whatever follows the argument
          if (!this->PopulateVariable(cs, arg.c_str() + sarg.size())) {
            return 0;
223
          }
224 225 226 227 228 229 230 231 232 233 234 235
          break;
        case MULTI_ARGUMENT:
          // Suck in all the rest of the arguments
          CommandLineArguments_DEBUG("This is a multi argument: " << arg);
          for (cc++; cc < this->Internals->Argv.size(); ++cc) {
            const std::string& marg = this->Internals->Argv[cc];
            CommandLineArguments_DEBUG(
              " check multi argument value: " << marg);
            if (this->GetMatchedArguments(&matches, marg)) {
              CommandLineArguments_DEBUG("End of multi argument "
                                         << arg << " with value: " << marg);
              break;
236
            }
237 238 239 240
            CommandLineArguments_DEBUG(
              " populate multi argument value: " << marg);
            if (!this->PopulateVariable(cs, marg.c_str())) {
              return 0;
241 242
            }
          }
243 244 245 246
          if (cc != this->Internals->Argv.size()) {
            CommandLineArguments_DEBUG("Again End of multi argument " << arg);
            cc--;
            continue;
247
          }
248 249 250 251 252 253
          break;
        default:
          std::cerr << "Got unknown argument type: \"" << cs->ArgumentType
                    << "\"" << std::endl;
          this->Internals->LastArgument--;
          return 0;
254
      }
255
    } else {
256
      // Handle unknown arguments
257 258 259 260
      if (this->Internals->UnknownArgumentCallback) {
        if (!this->Internals->UnknownArgumentCallback(
              arg.c_str(), this->Internals->ClientData)) {
          this->Internals->LastArgument--;
261 262
          return 0;
        }
263 264
        return 1;
      } else if (this->StoreUnusedArgumentsFlag) {
265
        CommandLineArguments_DEBUG("Store unused argument " << arg);
266
        this->Internals->UnusedArguments.push_back(arg);
267
      } else {
268
        std::cerr << "Got unknown argument: \"" << arg << "\"" << std::endl;
269
        this->Internals->LastArgument--;
270 271 272
        return 0;
      }
    }
273
  }
274 275 276 277 278
  return 1;
}

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

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

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

300 301
void CommandLineArguments::GetUnusedArguments(int* argc, char*** argv)
{
302 303
  CommandLineArguments::Internal::VectorOfStrings::size_type size =
    this->Internals->UnusedArguments.size() + 1;
304 305 306
  CommandLineArguments::Internal::VectorOfStrings::size_type cc;

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

  // Copy everything after the LastArgument, since that was not parsed.
313 314 315
  for (cc = 0; cc < this->Internals->UnusedArguments.size(); cc++) {
    kwsys::String& str = this->Internals->UnusedArguments[cc];
    args[cnt] = new char[str.size() + 1];
316
    strcpy(args[cnt], str.c_str());
317 318
    cnt++;
  }
319 320 321 322
  *argc = cnt;
  *argv = args;
}

323 324 325
void CommandLineArguments::DeleteRemainingArguments(int argc, char*** argv)
{
  int cc;
326 327 328 329
  for (cc = 0; cc < argc; ++cc) {
    delete[](*argv)[cc];
  }
  delete[] * argv;
330 331
}

332 333 334 335
void CommandLineArguments::AddCallback(const char* argument,
                                       ArgumentTypeEnum type,
                                       CallbackType callback, void* call_data,
                                       const char* help)
336
{
337
  CommandLineArgumentsCallbackStructure s;
338
  s.Argument = argument;
339
  s.ArgumentType = type;
340 341
  s.Callback = callback;
  s.CallData = call_data;
342
  s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE;
343
  s.Variable = KWSYS_NULLPTR;
344
  s.Help = help;
345 346 347 348 349

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

350 351 352 353
void CommandLineArguments::AddArgument(const char* argument,
                                       ArgumentTypeEnum type,
                                       VariableTypeEnum vtype, void* variable,
                                       const char* help)
354
{
355
  CommandLineArgumentsCallbackStructure s;
356
  s.Argument = argument;
357
  s.ArgumentType = type;
358 359
  s.Callback = KWSYS_NULLPTR;
  s.CallData = KWSYS_NULLPTR;
360
  s.VariableType = vtype;
361 362
  s.Variable = variable;
  s.Help = help;
363 364 365 366 367

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

368 369 370 371 372 373 374
#define CommandLineArgumentsAddArgumentMacro(type, ctype)                     \
  void CommandLineArguments::AddArgument(const char* argument,                \
                                         ArgumentTypeEnum type,               \
                                         ctype* variable, const char* help)   \
  {                                                                           \
    this->AddArgument(argument, type, CommandLineArguments::type##_TYPE,      \
                      variable, help);                                        \
375 376
  }

377
/* clang-format off */
378
CommandLineArgumentsAddArgumentMacro(BOOL, bool)
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
CommandLineArgumentsAddArgumentMacro(INT, int)
CommandLineArgumentsAddArgumentMacro(DOUBLE, double)
CommandLineArgumentsAddArgumentMacro(STRING, char*)
CommandLineArgumentsAddArgumentMacro(STL_STRING, std::string)

CommandLineArgumentsAddArgumentMacro(VECTOR_BOOL, std::vector<bool>)
CommandLineArgumentsAddArgumentMacro(VECTOR_INT, std::vector<int>)
CommandLineArgumentsAddArgumentMacro(VECTOR_DOUBLE, std::vector<double>)
CommandLineArgumentsAddArgumentMacro(VECTOR_STRING, std::vector<char*>)
CommandLineArgumentsAddArgumentMacro(VECTOR_STL_STRING,
                                     std::vector<std::string>)
#ifdef HELP_CLANG_FORMAT
;
#endif
/* clang-format on */
394 395 396 397 398 399 400

#define CommandLineArgumentsAddBooleanArgumentMacro(type, ctype)              \
  void CommandLineArguments::AddBooleanArgument(                              \
    const char* argument, ctype* variable, const char* help)                  \
  {                                                                           \
    this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,            \
                      CommandLineArguments::type##_TYPE, variable, help);     \
401 402
  }

403 404 405 406 407 408 409 410 411 412 413 414
/* clang-format off */
CommandLineArgumentsAddBooleanArgumentMacro(BOOL, bool)
CommandLineArgumentsAddBooleanArgumentMacro(INT, int)
CommandLineArgumentsAddBooleanArgumentMacro(DOUBLE, double)
CommandLineArgumentsAddBooleanArgumentMacro(STRING, char*)
CommandLineArgumentsAddBooleanArgumentMacro(STL_STRING, std::string)
#ifdef HELP_CLANG_FORMAT
;
#endif
/* clang-format on */

void CommandLineArguments::SetClientData(void* client_data)
415 416 417 418 419 420 421 422 423 424 425 426
{
  this->Internals->ClientData = client_data;
}

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

const char* CommandLineArguments::GetHelp(const char* arg)
{
427 428 429
  CommandLineArguments::Internal::CallbacksMap::iterator it =
    this->Internals->Callbacks.find(arg);
  if (it == this->Internals->Callbacks.end()) {
430
    return KWSYS_NULLPTR;
431
  }
432 433 434

  // Since several arguments may point to the same argument, find the one this
  // one point to if this one is pointing to another argument.
435 436 437 438 439
  CommandLineArgumentsCallbackStructure* cs = &(it->second);
  for (;;) {
    CommandLineArguments::Internal::CallbacksMap::iterator hit =
      this->Internals->Callbacks.find(cs->Help);
    if (hit == this->Internals->Callbacks.end()) {
Andy Cedilnik's avatar
Andy Cedilnik committed
440
      break;
441
    }
442 443
    cs = &(hit->second);
  }
Andy Cedilnik's avatar
Andy Cedilnik committed
444
  return cs->Help;
445 446
}

447 448
void CommandLineArguments::SetLineLength(unsigned int ll)
{
449
  if (ll < 9 || ll > 1000) {
450
    return;
451
  }
452 453 454 455
  this->LineLength = ll;
  this->GenerateHelp();
}

Andy Cedilnik's avatar
Andy Cedilnik committed
456 457 458 459 460
const char* CommandLineArguments::GetArgv0()
{
  return this->Internals->Argv0.c_str();
}

461 462
unsigned int CommandLineArguments::GetLastArgument()
{
Andy Cedilnik's avatar
Andy Cedilnik committed
463
  return static_cast<unsigned int>(this->Internals->LastArgument + 1);
464 465
}

466 467
void CommandLineArguments::GenerateHelp()
{
468
  std::ostringstream str;
469

470 471 472
  // Collapse all arguments into the map of vectors of all arguments that do
  // the same thing.
  CommandLineArguments::Internal::CallbacksMap::iterator it;
Brad King's avatar
Brad King committed
473
  typedef std::map<CommandLineArguments::Internal::String,
474 475
                   CommandLineArguments::Internal::SetOfStrings>
    MapArgs;
476 477
  MapArgs mp;
  MapArgs::iterator mpit, smpit;
478 479 480
  for (it = this->Internals->Callbacks.begin();
       it != this->Internals->Callbacks.end(); it++) {
    CommandLineArgumentsCallbackStructure* cs = &(it->second);
481
    mpit = mp.find(cs->Help);
482
    if (mpit != mp.end()) {
483 484
      mpit->second.insert(it->first);
      mp[it->first].insert(it->first);
485
    } else {
486 487
      mp[it->first].insert(it->first);
    }
488 489 490 491
  }
  for (it = this->Internals->Callbacks.begin();
       it != this->Internals->Callbacks.end(); it++) {
    CommandLineArgumentsCallbackStructure* cs = &(it->second);
492
    mpit = mp.find(cs->Help);
493
    if (mpit != mp.end()) {
494 495 496
      mpit->second.insert(it->first);
      smpit = mp.find(it->first);
      CommandLineArguments::Internal::SetOfStrings::iterator sit;
497
      for (sit = smpit->second.begin(); sit != smpit->second.end(); sit++) {
498 499
        mpit->second.insert(*sit);
      }
500 501
      mp.erase(smpit);
    } else {
502 503
      mp[it->first].insert(it->first);
    }
504 505
  }

506 507
  // Find the length of the longest string
  CommandLineArguments::Internal::String::size_type maxlen = 0;
508
  for (mpit = mp.begin(); mpit != mp.end(); mpit++) {
509
    CommandLineArguments::Internal::SetOfStrings::iterator sit;
510
    for (sit = mpit->second.begin(); sit != mpit->second.end(); sit++) {
511
      CommandLineArguments::Internal::String::size_type clen = sit->size();
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
      switch (this->Internals->Callbacks[*sit].ArgumentType) {
        case CommandLineArguments::NO_ARGUMENT:
          clen += 0;
          break;
        case CommandLineArguments::CONCAT_ARGUMENT:
          clen += 3;
          break;
        case CommandLineArguments::SPACE_ARGUMENT:
          clen += 4;
          break;
        case CommandLineArguments::EQUAL_ARGUMENT:
          clen += 4;
          break;
      }
      if (clen > maxlen) {
527 528 529
        maxlen = clen;
      }
    }
530
  }
531

532
  CommandLineArguments::Internal::String::size_type maxstrlen = maxlen;
533
  maxlen += 4; // For the space before and after the option
534 535

  // Print help for each option
536
  for (mpit = mp.begin(); mpit != mp.end(); mpit++) {
537
    CommandLineArguments::Internal::SetOfStrings::iterator sit;
538
    for (sit = mpit->second.begin(); sit != mpit->second.end(); sit++) {
539
      str << std::endl;
540
      std::string argument = *sit;
541 542 543 544
      switch (this->Internals->Callbacks[*sit].ArgumentType) {
        case CommandLineArguments::NO_ARGUMENT:
          break;
        case CommandLineArguments::CONCAT_ARGUMENT:
545
          argument += "opt";
546 547
          break;
        case CommandLineArguments::SPACE_ARGUMENT:
548
          argument += " opt";
549 550
          break;
        case CommandLineArguments::EQUAL_ARGUMENT:
551
          argument += "=opt";
552 553
          break;
        case CommandLineArguments::MULTI_ARGUMENT:
554
          argument += " opt opt ...";
555 556
          break;
      }
557
      str << "  " << argument.substr(0, maxstrlen) << "  ";
558
    }
559
    const char* ptr = this->Internals->Callbacks[mpit->first].Help;
560
    size_t len = strlen(ptr);
561
    int cnt = 0;
562
    while (len > 0) {
563 564 565
      // If argument with help is longer than line length, split it on previous
      // space (or tab) and continue on the next line
      CommandLineArguments::Internal::String::size_type cc;
566 567 568 569
      for (cc = 0; ptr[cc]; cc++) {
        if (*ptr == ' ' || *ptr == '\t') {
          ptr++;
          len--;
570
        }
571 572 573
      }
      if (cnt > 0) {
        for (cc = 0; cc < maxlen; cc++) {
574 575
          str << " ";
        }
576
      }
577
      CommandLineArguments::Internal::String::size_type skip = len;
578
      if (skip > this->LineLength - maxlen) {
579
        skip = this->LineLength - maxlen;
580 581
        for (cc = skip - 1; cc > 0; cc--) {
          if (ptr[cc] == ' ' || ptr[cc] == '\t') {
582 583
            break;
          }
584 585
        }
        if (cc != 0) {
586 587
          skip = cc;
        }
588
      }
589 590
      str.write(ptr, static_cast<std::streamsize>(skip));
      str << std::endl;
591 592
      ptr += skip;
      len -= skip;
593
      cnt++;
594
    }
595
  }
596 597 598 599 600 601 602 603 604 605
  /*
  // This can help debugging help string
  str << endl;
  unsigned int cc;
  for ( cc = 0; cc < this->LineLength; cc ++ )
    {
    str << cc % 10;
    }
  str << endl;
  */
606 607 608
  this->Help = str.str();
}

609 610
void CommandLineArguments::PopulateVariable(bool* variable,
                                            const std::string& value)
611
{
612 613 614
  if (value == "1" || value == "ON" || value == "on" || value == "On" ||
      value == "TRUE" || value == "true" || value == "True" ||
      value == "yes" || value == "Yes" || value == "YES") {
615
    *variable = true;
616
  } else {
617
    *variable = false;
618
  }
619 620
}

621 622
void CommandLineArguments::PopulateVariable(int* variable,
                                            const std::string& value)
623
{
624
  char* res = KWSYS_NULLPTR;
Francois Bertel's avatar
Francois Bertel committed
625
  *variable = static_cast<int>(strtol(value.c_str(), &res, 10));
626
  // if ( res && *res )
627 628 629 630 631
  //  {
  //  Can handle non-int
  //  }
}

632 633
void CommandLineArguments::PopulateVariable(double* variable,
                                            const std::string& value)
634
{
635
  char* res = KWSYS_NULLPTR;
636
  *variable = strtod(value.c_str(), &res);
637
  // if ( res && *res )
638 639 640 641 642
  //  {
  //  Can handle non-double
  //  }
}

643 644
void CommandLineArguments::PopulateVariable(char** variable,
                                            const std::string& value)
645
{
646
  delete[] * variable;
647
  *variable = new char[value.size() + 1];
648 649 650
  strcpy(*variable, value.c_str());
}

651 652
void CommandLineArguments::PopulateVariable(std::string* variable,
                                            const std::string& value)
653 654 655 656
{
  *variable = value;
}

657 658
void CommandLineArguments::PopulateVariable(std::vector<bool>* variable,
                                            const std::string& value)
659 660
{
  bool val = false;
661 662 663
  if (value == "1" || value == "ON" || value == "on" || value == "On" ||
      value == "TRUE" || value == "true" || value == "True" ||
      value == "yes" || value == "Yes" || value == "YES") {
664
    val = true;
665
  }
666 667 668
  variable->push_back(val);
}

669 670
void CommandLineArguments::PopulateVariable(std::vector<int>* variable,
                                            const std::string& value)
671
{
672
  char* res = KWSYS_NULLPTR;
Francois Bertel's avatar
Francois Bertel committed
673
  variable->push_back(static_cast<int>(strtol(value.c_str(), &res, 10)));
674
  // if ( res && *res )
675 676 677 678 679
  //  {
  //  Can handle non-int
  //  }
}

680 681
void CommandLineArguments::PopulateVariable(std::vector<double>* variable,
                                            const std::string& value)
682
{
683
  char* res = KWSYS_NULLPTR;
684
  variable->push_back(strtod(value.c_str(), &res));
685
  // if ( res && *res )
686 687 688 689 690
  //  {
  //  Can handle non-int
  //  }
}

691 692
void CommandLineArguments::PopulateVariable(std::vector<char*>* variable,
                                            const std::string& value)
693
{
694
  char* var = new char[value.size() + 1];
695 696 697 698
  strcpy(var, value.c_str());
  variable->push_back(var);
}

699 700
void CommandLineArguments::PopulateVariable(std::vector<std::string>* variable,
                                            const std::string& value)
701 702 703 704
{
  variable->push_back(value);
}

705 706
bool CommandLineArguments::PopulateVariable(
  CommandLineArgumentsCallbackStructure* cs, const char* value)
707 708
{
  // Call the callback
709 710 711
  if (cs->Callback) {
    if (!cs->Callback(cs->Argument, value, cs->CallData)) {
      this->Internals->LastArgument--;
712 713
      return 0;
    }
714 715 716 717
  }
  CommandLineArguments_DEBUG("Set argument: " << cs->Argument << " to "
                                              << value);
  if (cs->Variable) {
Brad King's avatar
Brad King committed
718
    std::string var = "1";
719
    if (value) {
720 721
      var = value;
    }
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
    switch (cs->VariableType) {
      case CommandLineArguments::INT_TYPE:
        this->PopulateVariable(static_cast<int*>(cs->Variable), var);
        break;
      case CommandLineArguments::DOUBLE_TYPE:
        this->PopulateVariable(static_cast<double*>(cs->Variable), var);
        break;
      case CommandLineArguments::STRING_TYPE:
        this->PopulateVariable(static_cast<char**>(cs->Variable), var);
        break;
      case CommandLineArguments::STL_STRING_TYPE:
        this->PopulateVariable(static_cast<std::string*>(cs->Variable), var);
        break;
      case CommandLineArguments::BOOL_TYPE:
        this->PopulateVariable(static_cast<bool*>(cs->Variable), var);
        break;
      case CommandLineArguments::VECTOR_BOOL_TYPE:
        this->PopulateVariable(static_cast<std::vector<bool>*>(cs->Variable),
                               var);
        break;
      case CommandLineArguments::VECTOR_INT_TYPE:
        this->PopulateVariable(static_cast<std::vector<int>*>(cs->Variable),
                               var);
        break;
      case CommandLineArguments::VECTOR_DOUBLE_TYPE:
        this->PopulateVariable(static_cast<std::vector<double>*>(cs->Variable),
                               var);
        break;
      case CommandLineArguments::VECTOR_STRING_TYPE:
        this->PopulateVariable(static_cast<std::vector<char*>*>(cs->Variable),
                               var);
        break;
      case CommandLineArguments::VECTOR_STL_STRING_TYPE:
        this->PopulateVariable(
          static_cast<std::vector<std::string>*>(cs->Variable), var);
        break;
      default:
        std::cerr << "Got unknown variable type: \"" << cs->VariableType
                  << "\"" << std::endl;
        this->Internals->LastArgument--;
        return 0;
    }
  }
765 766 767
  return 1;
}

768
} // namespace KWSYS_NAMESPACE