js/src/shell/jsoptparse.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "shell/jsoptparse.h"
michael@0 8
michael@0 9 #include <ctype.h>
michael@0 10 #include <stdarg.h>
michael@0 11
michael@0 12 #include "jsutil.h"
michael@0 13
michael@0 14 using namespace js;
michael@0 15 using namespace js::cli;
michael@0 16 using namespace js::cli::detail;
michael@0 17
michael@0 18 const char OptionParser::prognameMeta[] = "{progname}";
michael@0 19
michael@0 20 #define OPTION_CONVERT_IMPL(__cls) \
michael@0 21 bool \
michael@0 22 Option::is##__cls##Option() const \
michael@0 23 { \
michael@0 24 return kind == OptionKind##__cls; \
michael@0 25 } \
michael@0 26 __cls##Option * \
michael@0 27 Option::as##__cls##Option() \
michael@0 28 { \
michael@0 29 JS_ASSERT(is##__cls##Option()); \
michael@0 30 return static_cast<__cls##Option *>(this); \
michael@0 31 } \
michael@0 32 const __cls##Option * \
michael@0 33 Option::as##__cls##Option() const \
michael@0 34 { \
michael@0 35 return const_cast<Option *>(this)->as##__cls##Option(); \
michael@0 36 }
michael@0 37
michael@0 38 ValuedOption *
michael@0 39 Option::asValued()
michael@0 40 {
michael@0 41 JS_ASSERT(isValued());
michael@0 42 return static_cast<ValuedOption *>(this);
michael@0 43 }
michael@0 44
michael@0 45 const ValuedOption *
michael@0 46 Option::asValued() const
michael@0 47 {
michael@0 48 return const_cast<Option *>(this)->asValued();
michael@0 49 }
michael@0 50
michael@0 51 OPTION_CONVERT_IMPL(Bool)
michael@0 52 OPTION_CONVERT_IMPL(String)
michael@0 53 OPTION_CONVERT_IMPL(Int)
michael@0 54 OPTION_CONVERT_IMPL(MultiString)
michael@0 55
michael@0 56 void
michael@0 57 OptionParser::setArgTerminatesOptions(const char *name, bool enabled)
michael@0 58 {
michael@0 59 findArgument(name)->setTerminatesOptions(enabled);
michael@0 60 }
michael@0 61
michael@0 62 void
michael@0 63 OptionParser::setArgCapturesRest(const char *name)
michael@0 64 {
michael@0 65 MOZ_ASSERT(restArgument == -1, "only one argument may be set to capture the rest");
michael@0 66 restArgument = findArgumentIndex(name);
michael@0 67 MOZ_ASSERT(restArgument != -1, "unknown argument name passed to setArgCapturesRest");
michael@0 68 }
michael@0 69
michael@0 70 OptionParser::Result
michael@0 71 OptionParser::error(const char *fmt, ...)
michael@0 72 {
michael@0 73 va_list args;
michael@0 74 va_start(args, fmt);
michael@0 75 fprintf(stderr, "Error: ");
michael@0 76 vfprintf(stderr, fmt, args);
michael@0 77 va_end(args);
michael@0 78 fputs("\n\n", stderr);
michael@0 79 return ParseError;
michael@0 80 }
michael@0 81
michael@0 82 /* Quick and dirty paragraph printer. */
michael@0 83 static void
michael@0 84 PrintParagraph(const char *text, unsigned startColno, const unsigned limitColno, bool padFirstLine)
michael@0 85 {
michael@0 86 unsigned colno = startColno;
michael@0 87 const char *it = text;
michael@0 88
michael@0 89 if (padFirstLine)
michael@0 90 printf("%*s", startColno, "");
michael@0 91
michael@0 92 while (*it != '\0') {
michael@0 93 JS_ASSERT(!isspace(*it));
michael@0 94
michael@0 95 /* Delimit the current token. */
michael@0 96 const char *limit = it;
michael@0 97 while (!isspace(*limit) && *limit != '\0')
michael@0 98 ++limit;
michael@0 99
michael@0 100 /*
michael@0 101 * If the current token is longer than the available number of columns,
michael@0 102 * then make a line break before printing the token.
michael@0 103 */
michael@0 104 JS_ASSERT(limit - it > 0);
michael@0 105 size_t tokLen = limit - it;
michael@0 106 JS_ASSERT(tokLen);
michael@0 107 if (tokLen + colno >= limitColno) {
michael@0 108 printf("\n%*s%.*s", startColno, "", int(tokLen), it);
michael@0 109 colno = startColno + tokLen;
michael@0 110 } else {
michael@0 111 printf("%.*s", int(tokLen), it);
michael@0 112 colno += tokLen;
michael@0 113 }
michael@0 114
michael@0 115 switch (*limit) {
michael@0 116 case '\0':
michael@0 117 return;
michael@0 118 case ' ':
michael@0 119 putchar(' ');
michael@0 120 colno += 1;
michael@0 121 it = limit;
michael@0 122 while (*it == ' ')
michael@0 123 ++it;
michael@0 124 break;
michael@0 125 case '\n':
michael@0 126 /* |text| wants to force a newline here. */
michael@0 127 printf("\n%*s", startColno, "");
michael@0 128 colno = startColno;
michael@0 129 it = limit + 1;
michael@0 130 /* Could also have line-leading spaces. */
michael@0 131 while (*it == ' ') {
michael@0 132 putchar(' ');
michael@0 133 ++colno;
michael@0 134 ++it;
michael@0 135 }
michael@0 136 break;
michael@0 137 default:
michael@0 138 MOZ_ASSUME_UNREACHABLE("unhandled token splitting character in text");
michael@0 139 }
michael@0 140 }
michael@0 141 }
michael@0 142
michael@0 143 static const char *
michael@0 144 OptionFlagsToFormatInfo(char shortflag, bool isValued, size_t *length)
michael@0 145 {
michael@0 146 static const char * const fmt[4] = { " -%c --%s ",
michael@0 147 " --%s ",
michael@0 148 " -%c --%s=%s ",
michael@0 149 " --%s=%s " };
michael@0 150
michael@0 151 /* How mny chars w/o longflag? */
michael@0 152 size_t lengths[4] = { strlen(fmt[0]) - 3,
michael@0 153 strlen(fmt[1]) - 3,
michael@0 154 strlen(fmt[2]) - 5,
michael@0 155 strlen(fmt[3]) - 5 };
michael@0 156 int index = isValued ? 2 : 0;
michael@0 157 if (!shortflag)
michael@0 158 index++;
michael@0 159
michael@0 160 *length = lengths[index];
michael@0 161 return fmt[index];
michael@0 162 }
michael@0 163
michael@0 164 OptionParser::Result
michael@0 165 OptionParser::printHelp(const char *progname)
michael@0 166 {
michael@0 167 const char *prefixEnd = strstr(usage, prognameMeta);
michael@0 168 if (prefixEnd) {
michael@0 169 printf("%.*s%s%s\n", int(prefixEnd - usage), usage, progname,
michael@0 170 prefixEnd + sizeof(prognameMeta) - 1);
michael@0 171 } else {
michael@0 172 puts(usage);
michael@0 173 }
michael@0 174
michael@0 175 if (descr) {
michael@0 176 putchar('\n');
michael@0 177 PrintParagraph(descr, 2, descrWidth, true);
michael@0 178 putchar('\n');
michael@0 179 }
michael@0 180
michael@0 181 if (ver)
michael@0 182 printf("\nVersion: %s\n\n", ver);
michael@0 183
michael@0 184 if (!arguments.empty()) {
michael@0 185 printf("Arguments:\n");
michael@0 186
michael@0 187 static const char fmt[] = " %s ";
michael@0 188 size_t fmtChars = sizeof(fmt) - 2;
michael@0 189 size_t lhsLen = 0;
michael@0 190 for (Option **it = arguments.begin(), **end = arguments.end(); it != end; ++it)
michael@0 191 lhsLen = Max(lhsLen, strlen((*it)->longflag) + fmtChars);
michael@0 192
michael@0 193 for (Option **it = arguments.begin(), **end = arguments.end(); it != end; ++it) {
michael@0 194 Option *arg = *it;
michael@0 195 size_t chars = printf(fmt, arg->longflag);
michael@0 196 for (; chars < lhsLen; ++chars)
michael@0 197 putchar(' ');
michael@0 198 PrintParagraph(arg->help, lhsLen, helpWidth, false);
michael@0 199 putchar('\n');
michael@0 200 }
michael@0 201 putchar('\n');
michael@0 202 }
michael@0 203
michael@0 204 if (!options.empty()) {
michael@0 205 printf("Options:\n");
michael@0 206
michael@0 207 /* Calculate sizes for column alignment. */
michael@0 208 size_t lhsLen = 0;
michael@0 209 for (Option **it = options.begin(), **end = options.end(); it != end; ++it) {
michael@0 210 Option *opt = *it;
michael@0 211 size_t longflagLen = strlen(opt->longflag);
michael@0 212
michael@0 213 size_t fmtLen;
michael@0 214 OptionFlagsToFormatInfo(opt->shortflag, opt->isValued(), &fmtLen);
michael@0 215
michael@0 216 size_t len = fmtLen + longflagLen;
michael@0 217 if (opt->isValued())
michael@0 218 len += strlen(opt->asValued()->metavar);
michael@0 219 lhsLen = Max(lhsLen, len);
michael@0 220 }
michael@0 221
michael@0 222 /* Print option help text. */
michael@0 223 for (Option **it = options.begin(), **end = options.end(); it != end; ++it) {
michael@0 224 Option *opt = *it;
michael@0 225 size_t fmtLen;
michael@0 226 const char *fmt = OptionFlagsToFormatInfo(opt->shortflag, opt->isValued(), &fmtLen);
michael@0 227 size_t chars;
michael@0 228 if (opt->isValued()) {
michael@0 229 if (opt->shortflag)
michael@0 230 chars = printf(fmt, opt->shortflag, opt->longflag, opt->asValued()->metavar);
michael@0 231 else
michael@0 232 chars = printf(fmt, opt->longflag, opt->asValued()->metavar);
michael@0 233 } else {
michael@0 234 if (opt->shortflag)
michael@0 235 chars = printf(fmt, opt->shortflag, opt->longflag);
michael@0 236 else
michael@0 237 chars = printf(fmt, opt->longflag);
michael@0 238 }
michael@0 239 for (; chars < lhsLen; ++chars)
michael@0 240 putchar(' ');
michael@0 241 PrintParagraph(opt->help, lhsLen, helpWidth, false);
michael@0 242 putchar('\n');
michael@0 243 }
michael@0 244 }
michael@0 245
michael@0 246 return ParseHelp;
michael@0 247 }
michael@0 248
michael@0 249 OptionParser::Result
michael@0 250 OptionParser::extractValue(size_t argc, char **argv, size_t *i, char **value)
michael@0 251 {
michael@0 252 JS_ASSERT(*i < argc);
michael@0 253 char *eq = strchr(argv[*i], '=');
michael@0 254 if (eq) {
michael@0 255 *value = eq + 1;
michael@0 256 if (*value[0] == '\0')
michael@0 257 return error("A value is required for option %.*s", eq - argv[*i], argv[*i]);
michael@0 258 return Okay;
michael@0 259 }
michael@0 260
michael@0 261 if (argc == *i + 1)
michael@0 262 return error("Expected a value for option %s", argv[*i]);
michael@0 263
michael@0 264 *i += 1;
michael@0 265 *value = argv[*i];
michael@0 266 return Okay;
michael@0 267 }
michael@0 268
michael@0 269 OptionParser::Result
michael@0 270 OptionParser::handleOption(Option *opt, size_t argc, char **argv, size_t *i, bool *optionsAllowed)
michael@0 271 {
michael@0 272 if (opt->getTerminatesOptions())
michael@0 273 *optionsAllowed = false;
michael@0 274
michael@0 275 switch (opt->kind) {
michael@0 276 case OptionKindBool:
michael@0 277 {
michael@0 278 if (opt == &helpOption)
michael@0 279 return printHelp(argv[0]);
michael@0 280 opt->asBoolOption()->value = true;
michael@0 281 return Okay;
michael@0 282 }
michael@0 283 /*
michael@0 284 * Valued options are allowed to specify their values either via
michael@0 285 * successive arguments or a single --longflag=value argument.
michael@0 286 */
michael@0 287 case OptionKindString:
michael@0 288 {
michael@0 289 char *value = nullptr;
michael@0 290 if (Result r = extractValue(argc, argv, i, &value))
michael@0 291 return r;
michael@0 292 opt->asStringOption()->value = value;
michael@0 293 return Okay;
michael@0 294 }
michael@0 295 case OptionKindInt:
michael@0 296 {
michael@0 297 char *value = nullptr;
michael@0 298 if (Result r = extractValue(argc, argv, i, &value))
michael@0 299 return r;
michael@0 300 opt->asIntOption()->value = atoi(value);
michael@0 301 return Okay;
michael@0 302 }
michael@0 303 case OptionKindMultiString:
michael@0 304 {
michael@0 305 char *value = nullptr;
michael@0 306 if (Result r = extractValue(argc, argv, i, &value))
michael@0 307 return r;
michael@0 308 StringArg arg(value, *i);
michael@0 309 return opt->asMultiStringOption()->strings.append(arg) ? Okay : Fail;
michael@0 310 }
michael@0 311 default:
michael@0 312 MOZ_ASSUME_UNREACHABLE("unhandled option kind");
michael@0 313 }
michael@0 314 }
michael@0 315
michael@0 316 OptionParser::Result
michael@0 317 OptionParser::handleArg(size_t argc, char **argv, size_t *i, bool *optionsAllowed)
michael@0 318 {
michael@0 319 if (nextArgument >= arguments.length())
michael@0 320 return error("Too many arguments provided");
michael@0 321
michael@0 322 Option *arg = arguments[nextArgument];
michael@0 323
michael@0 324 if (arg->getTerminatesOptions())
michael@0 325 *optionsAllowed = false;
michael@0 326
michael@0 327 switch (arg->kind) {
michael@0 328 case OptionKindString:
michael@0 329 arg->asStringOption()->value = argv[*i];
michael@0 330 nextArgument += 1;
michael@0 331 return Okay;
michael@0 332 case OptionKindMultiString:
michael@0 333 {
michael@0 334 /* Don't advance the next argument -- there can only be one (final) variadic argument. */
michael@0 335 StringArg value(argv[*i], *i);
michael@0 336 return arg->asMultiStringOption()->strings.append(value) ? Okay : Fail;
michael@0 337 }
michael@0 338 default:
michael@0 339 MOZ_ASSUME_UNREACHABLE("unhandled argument kind");
michael@0 340 }
michael@0 341 }
michael@0 342
michael@0 343 OptionParser::Result
michael@0 344 OptionParser::parseArgs(int inputArgc, char **argv)
michael@0 345 {
michael@0 346 JS_ASSERT(inputArgc >= 0);
michael@0 347 size_t argc = inputArgc;
michael@0 348 /* Permit a "no more options" capability, like |--| offers in many shell interfaces. */
michael@0 349 bool optionsAllowed = true;
michael@0 350
michael@0 351 for (size_t i = 1; i < argc; ++i) {
michael@0 352 char *arg = argv[i];
michael@0 353 Result r;
michael@0 354 /* Note: solo dash option is actually a 'stdin' argument. */
michael@0 355 if (arg[0] == '-' && arg[1] != '\0' && optionsAllowed) {
michael@0 356 /* Option. */
michael@0 357 Option *opt;
michael@0 358 if (arg[1] == '-') {
michael@0 359 if (arg[2] == '\0') {
michael@0 360 /* End of options */
michael@0 361 optionsAllowed = false;
michael@0 362 nextArgument = restArgument;
michael@0 363 continue;
michael@0 364 } else {
michael@0 365 /* Long option. */
michael@0 366 opt = findOption(arg + 2);
michael@0 367 if (!opt)
michael@0 368 return error("Invalid long option: %s", arg);
michael@0 369 }
michael@0 370 } else {
michael@0 371 /* Short option */
michael@0 372 if (arg[2] != '\0')
michael@0 373 return error("Short option followed by junk: %s", arg);
michael@0 374 opt = findOption(arg[1]);
michael@0 375 if (!opt)
michael@0 376 return error("Invalid short option: %s", arg);
michael@0 377 }
michael@0 378
michael@0 379 r = handleOption(opt, argc, argv, &i, &optionsAllowed);
michael@0 380 } else {
michael@0 381 /* Argument. */
michael@0 382 r = handleArg(argc, argv, &i, &optionsAllowed);
michael@0 383 }
michael@0 384
michael@0 385 if (r != Okay)
michael@0 386 return r;
michael@0 387 }
michael@0 388 return Okay;
michael@0 389 }
michael@0 390
michael@0 391 void
michael@0 392 OptionParser::setHelpOption(char shortflag, const char *longflag, const char *help)
michael@0 393 {
michael@0 394 helpOption.setFlagInfo(shortflag, longflag, help);
michael@0 395 }
michael@0 396
michael@0 397 bool
michael@0 398 OptionParser::getHelpOption() const
michael@0 399 {
michael@0 400 return helpOption.value;
michael@0 401 }
michael@0 402
michael@0 403 bool
michael@0 404 OptionParser::getBoolOption(char shortflag) const
michael@0 405 {
michael@0 406 return findOption(shortflag)->asBoolOption()->value;
michael@0 407 }
michael@0 408
michael@0 409 int
michael@0 410 OptionParser::getIntOption(char shortflag) const
michael@0 411 {
michael@0 412 return findOption(shortflag)->asIntOption()->value;
michael@0 413 }
michael@0 414
michael@0 415 const char *
michael@0 416 OptionParser::getStringOption(char shortflag) const
michael@0 417 {
michael@0 418 return findOption(shortflag)->asStringOption()->value;
michael@0 419 }
michael@0 420
michael@0 421 MultiStringRange
michael@0 422 OptionParser::getMultiStringOption(char shortflag) const
michael@0 423 {
michael@0 424 const MultiStringOption *mso = findOption(shortflag)->asMultiStringOption();
michael@0 425 return MultiStringRange(mso->strings.begin(), mso->strings.end());
michael@0 426 }
michael@0 427
michael@0 428 bool
michael@0 429 OptionParser::getBoolOption(const char *longflag) const
michael@0 430 {
michael@0 431 return findOption(longflag)->asBoolOption()->value;
michael@0 432 }
michael@0 433
michael@0 434 int
michael@0 435 OptionParser::getIntOption(const char *longflag) const
michael@0 436 {
michael@0 437 return findOption(longflag)->asIntOption()->value;
michael@0 438 }
michael@0 439
michael@0 440 const char *
michael@0 441 OptionParser::getStringOption(const char *longflag) const
michael@0 442 {
michael@0 443 return findOption(longflag)->asStringOption()->value;
michael@0 444 }
michael@0 445
michael@0 446 MultiStringRange
michael@0 447 OptionParser::getMultiStringOption(const char *longflag) const
michael@0 448 {
michael@0 449 const MultiStringOption *mso = findOption(longflag)->asMultiStringOption();
michael@0 450 return MultiStringRange(mso->strings.begin(), mso->strings.end());
michael@0 451 }
michael@0 452
michael@0 453 OptionParser::~OptionParser()
michael@0 454 {
michael@0 455 for (Option **it = options.begin(), **end = options.end(); it != end; ++it)
michael@0 456 js_delete<Option>(*it);
michael@0 457 for (Option **it = arguments.begin(), **end = arguments.end(); it != end; ++it)
michael@0 458 js_delete<Option>(*it);
michael@0 459 }
michael@0 460
michael@0 461 Option *
michael@0 462 OptionParser::findOption(char shortflag)
michael@0 463 {
michael@0 464 for (Option **it = options.begin(), **end = options.end(); it != end; ++it) {
michael@0 465 if ((*it)->shortflag == shortflag)
michael@0 466 return *it;
michael@0 467 }
michael@0 468
michael@0 469 return helpOption.shortflag == shortflag ? &helpOption : nullptr;
michael@0 470 }
michael@0 471
michael@0 472 const Option *
michael@0 473 OptionParser::findOption(char shortflag) const
michael@0 474 {
michael@0 475 return const_cast<OptionParser *>(this)->findOption(shortflag);
michael@0 476 }
michael@0 477
michael@0 478 Option *
michael@0 479 OptionParser::findOption(const char *longflag)
michael@0 480 {
michael@0 481 for (Option **it = options.begin(), **end = options.end(); it != end; ++it) {
michael@0 482 const char *target = (*it)->longflag;
michael@0 483 if ((*it)->isValued()) {
michael@0 484 size_t targetLen = strlen(target);
michael@0 485 /* Permit a trailing equals sign on the longflag argument. */
michael@0 486 for (size_t i = 0; i < targetLen; ++i) {
michael@0 487 if (longflag[i] == '\0' || longflag[i] != target[i])
michael@0 488 goto no_match;
michael@0 489 }
michael@0 490 if (longflag[targetLen] == '\0' || longflag[targetLen] == '=')
michael@0 491 return *it;
michael@0 492 } else {
michael@0 493 if (strcmp(target, longflag) == 0)
michael@0 494 return *it;
michael@0 495 }
michael@0 496 no_match:;
michael@0 497 }
michael@0 498
michael@0 499 return strcmp(helpOption.longflag, longflag) ? nullptr : &helpOption;
michael@0 500 }
michael@0 501
michael@0 502 const Option *
michael@0 503 OptionParser::findOption(const char *longflag) const
michael@0 504 {
michael@0 505 return const_cast<OptionParser *>(this)->findOption(longflag);
michael@0 506 }
michael@0 507
michael@0 508 /* Argument accessors */
michael@0 509
michael@0 510 int
michael@0 511 OptionParser::findArgumentIndex(const char *name) const
michael@0 512 {
michael@0 513 for (Option * const *it = arguments.begin(); it != arguments.end(); ++it) {
michael@0 514 const char *target = (*it)->longflag;
michael@0 515 if (strcmp(target, name) == 0)
michael@0 516 return it - arguments.begin();
michael@0 517 }
michael@0 518 return -1;
michael@0 519 }
michael@0 520
michael@0 521 Option *
michael@0 522 OptionParser::findArgument(const char *name)
michael@0 523 {
michael@0 524 int index = findArgumentIndex(name);
michael@0 525 return (index == -1) ? nullptr : arguments[index];
michael@0 526 }
michael@0 527
michael@0 528 const Option *
michael@0 529 OptionParser::findArgument(const char *name) const
michael@0 530 {
michael@0 531 int index = findArgumentIndex(name);
michael@0 532 return (index == -1) ? nullptr : arguments[index];
michael@0 533 }
michael@0 534
michael@0 535 const char *
michael@0 536 OptionParser::getStringArg(const char *name) const
michael@0 537 {
michael@0 538 return findArgument(name)->asStringOption()->value;
michael@0 539 }
michael@0 540
michael@0 541 MultiStringRange
michael@0 542 OptionParser::getMultiStringArg(const char *name) const
michael@0 543 {
michael@0 544 const MultiStringOption *mso = findArgument(name)->asMultiStringOption();
michael@0 545 return MultiStringRange(mso->strings.begin(), mso->strings.end());
michael@0 546 }
michael@0 547
michael@0 548 /* Option builders */
michael@0 549
michael@0 550 bool
michael@0 551 OptionParser::addIntOption(char shortflag, const char *longflag, const char *metavar,
michael@0 552 const char *help, int defaultValue)
michael@0 553 {
michael@0 554 if (!options.reserve(options.length() + 1))
michael@0 555 return false;
michael@0 556 IntOption *io = js_new<IntOption>(shortflag, longflag, help, metavar, defaultValue);
michael@0 557 if (!io)
michael@0 558 return false;
michael@0 559 options.infallibleAppend(io);
michael@0 560 return true;
michael@0 561 }
michael@0 562
michael@0 563 bool
michael@0 564 OptionParser::addBoolOption(char shortflag, const char *longflag, const char *help)
michael@0 565 {
michael@0 566 if (!options.reserve(options.length() + 1))
michael@0 567 return false;
michael@0 568 BoolOption *bo = js_new<BoolOption>(shortflag, longflag, help);
michael@0 569 if (!bo)
michael@0 570 return false;
michael@0 571 options.infallibleAppend(bo);
michael@0 572 return true;
michael@0 573 }
michael@0 574
michael@0 575 bool
michael@0 576 OptionParser::addStringOption(char shortflag, const char *longflag, const char *metavar,
michael@0 577 const char *help)
michael@0 578 {
michael@0 579 if (!options.reserve(options.length() + 1))
michael@0 580 return false;
michael@0 581 StringOption *so = js_new<StringOption>(shortflag, longflag, help, metavar);
michael@0 582 if (!so)
michael@0 583 return false;
michael@0 584 options.infallibleAppend(so);
michael@0 585 return true;
michael@0 586 }
michael@0 587
michael@0 588 bool
michael@0 589 OptionParser::addMultiStringOption(char shortflag, const char *longflag, const char *metavar,
michael@0 590 const char *help)
michael@0 591 {
michael@0 592 if (!options.reserve(options.length() + 1))
michael@0 593 return false;
michael@0 594 MultiStringOption *mso = js_new<MultiStringOption>(shortflag, longflag, help, metavar);
michael@0 595 if (!mso)
michael@0 596 return false;
michael@0 597 options.infallibleAppend(mso);
michael@0 598 return true;
michael@0 599 }
michael@0 600
michael@0 601 /* Argument builders */
michael@0 602
michael@0 603 bool
michael@0 604 OptionParser::addOptionalStringArg(const char *name, const char *help)
michael@0 605 {
michael@0 606 if (!arguments.reserve(arguments.length() + 1))
michael@0 607 return false;
michael@0 608 StringOption *so = js_new<StringOption>(1, name, help, (const char *) nullptr);
michael@0 609 if (!so)
michael@0 610 return false;
michael@0 611 arguments.infallibleAppend(so);
michael@0 612 return true;
michael@0 613 }
michael@0 614
michael@0 615 bool
michael@0 616 OptionParser::addOptionalMultiStringArg(const char *name, const char *help)
michael@0 617 {
michael@0 618 JS_ASSERT_IF(!arguments.empty(), !arguments.back()->isVariadic());
michael@0 619 if (!arguments.reserve(arguments.length() + 1))
michael@0 620 return false;
michael@0 621 MultiStringOption *mso = js_new<MultiStringOption>(1, name, help, (const char *) nullptr);
michael@0 622 if (!mso)
michael@0 623 return false;
michael@0 624 arguments.infallibleAppend(mso);
michael@0 625 return true;
michael@0 626 }

mercurial