Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/src/shell/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 18 kB image not shown  

Quelle  jsoptparse.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "shell/jsoptparse.h"

#include <algorithm>
#include <stdarg.h>
#include <string_view>

#include "util/Unicode.h"

using namespace js;
using namespace js::cli;
using namespace js::cli::detail;

#define OPTION_CONVERT_IMPL(__cls)                                             \
  bool Option::is##__cls##Option() const { return kind == OptionKind##__cls; } \
  __cls##Option* Option::as##__cls##Option() {                                 \
    MOZ_ASSERT(is##__cls##Option());                                           \
    return static_cast<__cls##Option*>(this);                                  \
  }                                                                            \
  const __cls##Option* Option::as##__cls##Option() const {                     \
    return const_cast<Option*>(this)->as##__cls##Option();                     \
  }

ValuedOption* Option::asValued() {
  MOZ_ASSERT(isValued());
  return static_cast<ValuedOption*>(this);
}

const ValuedOption* Option::asValued() const {
  return const_cast<Option*>(this)->asValued();
}

OPTION_CONVERT_IMPL(Bool)
OPTION_CONVERT_IMPL(String)
OPTION_CONVERT_IMPL(Int)
OPTION_CONVERT_IMPL(MultiString)

void OptionParser::setArgTerminatesOptions(const char* name, bool enabled) {
  findArgument(name)->setTerminatesOptions(enabled);
}

void OptionParser::setIgnoresUnknownOptions(const char* name, bool enabled) {
  auto* opt = findOption(name);
  MOZ_ASSERT(opt);
  opt->setIgnoresUnknownOptions(enabled);
}

void OptionParser::setArgCapturesRest(const char* name) {
  MOZ_ASSERT(restArgument == -1,
             "only one argument may be set to capture the rest");
  restArgument = findArgumentIndex(name);
  MOZ_ASSERT(restArgument != -1,
             "unknown argument name passed to setArgCapturesRest");
}

OptionParser::Result OptionParser::error(const char* fmt, ...) {
  va_list args;
  va_start(args, fmt);
  fprintf(stderr, "Error: ");
  vfprintf(stderr, fmt, args);
  va_end(args);
  fputs("\n\n", stderr);
  return ParseError;
}

/* Quick and dirty paragraph printer. */
static void PrintParagraph(const char* text, unsigned startColno,
                           const unsigned limitColno, bool padFirstLine) {
  unsigned colno = startColno;
  unsigned indent = 0;
  const char* it = text;

  if (padFirstLine) {
    printf("%*s"int(startColno), "");
  }

  /* Skip any leading spaces. */
  while (*it != '\0' && unicode::IsSpace(*it)) {
    ++it;
  }

  while (*it != '\0') {
    MOZ_ASSERT(!unicode::IsSpace(*it) || *it == '\n');

    /* Delimit the current token. */
    const char* limit = it;
    while (!unicode::IsSpace(*limit) && *limit != '\0') {
      ++limit;
    }

    /*
     * If the current token is longer than the available number of columns,
     * then make a line break before printing the token.
     */

    size_t tokLen = limit - it;
    if (tokLen + colno >= limitColno) {
      printf("\n%*s%.*s"int(startColno + indent), ""int(tokLen), it);
      colno = startColno + tokLen;
    } else {
      printf("%.*s"int(tokLen), it);
      colno += tokLen;
    }

    switch (*limit) {
      case '\0':
        return;
      case ' ':
        putchar(' ');
        colno += 1;
        it = limit;
        while (*it == ' ') {
          ++it;
        }
        break;
      case '\n':
        /* |text| wants to force a newline here. */
        printf("\n%*s"int(startColno), "");
        colno = startColno;
        it = limit + 1;
        /* Could also have line-leading spaces. */
        indent = 0;
        while (*it == ' ') {
          putchar(' ');
          ++colno;
          ++indent;
          ++it;
        }
        break;
      default:
        MOZ_CRASH("unhandled token splitting character in text");
    }
  }
}

static const char* OptionFlagsToFormatInfo(char shortflag, bool isValued,
                                           size_t* length) {
  static const charconst fmt[4] = {" -%c --%s "" --%s "" -%c --%s=%s ",
                                     " --%s=%s "};

  /* How mny chars w/o longflag? */
  size_t lengths[4] = {strlen(fmt[0]) - 3, strlen(fmt[1]) - 3,
                       strlen(fmt[2]) - 5, strlen(fmt[3]) - 5};
  int index = isValued ? 2 : 0;
  if (!shortflag) {
    index++;
  }

  *length = lengths[index];
  return fmt[index];
}

OptionParser::Result OptionParser::printHelp(const char* progname) {
  constexpr std::string_view prognameMeta = "{progname}";

  const char* prefixEnd = strstr(usage, prognameMeta.data());
  if (prefixEnd) {
    printf("%.*s%s%s\n"int(prefixEnd - usage), usage, progname,
           prefixEnd + prognameMeta.length());
  } else {
    puts(usage);
  }

  if (descr) {
    putchar('\n');
    PrintParagraph(descr, 2, descrWidth, true);
    putchar('\n');
  }

  if (version) {
    printf("\nVersion: %s\n\n", version);
  }

  if (!arguments.empty()) {
    printf("Arguments:\n");

    static const char fmt[] = " %s ";
    size_t fmtChars = sizeof(fmt) - 2;
    size_t lhsLen = 0;
    for (Option* arg : arguments) {
      lhsLen = std::max(lhsLen, strlen(arg->longflag) + fmtChars);
    }

    for (Option* arg : arguments) {
      size_t chars = printf(fmt, arg->longflag);
      for (; chars < lhsLen; ++chars) {
        putchar(' ');
      }
      PrintParagraph(arg->help, lhsLen, helpWidth, false);
      putchar('\n');
    }
    putchar('\n');
  }

  if (!options.empty()) {
    printf("Options:\n");

    /* Calculate sizes for column alignment. */
    size_t lhsLen = 0;
    for (Option* opt : options) {
      size_t longflagLen = strlen(opt->longflag);

      size_t fmtLen;
      OptionFlagsToFormatInfo(opt->shortflag, opt->isValued(), &fmtLen);

      size_t len = fmtLen + longflagLen;
      if (opt->isValued()) {
        len += strlen(opt->asValued()->metavar);
      }
      lhsLen = std::max(lhsLen, len);
    }

    /* Print option help text. */
    for (Option* opt : options) {
      size_t fmtLen;
      const char* fmt =
          OptionFlagsToFormatInfo(opt->shortflag, opt->isValued(), &fmtLen);
      size_t chars;
      if (opt->isValued()) {
        if (opt->shortflag) {
          chars = printf(fmt, opt->shortflag, opt->longflag,
                         opt->asValued()->metavar);
        } else {
          chars = printf(fmt, opt->longflag, opt->asValued()->metavar);
        }
      } else {
        if (opt->shortflag) {
          chars = printf(fmt, opt->shortflag, opt->longflag);
        } else {
          chars = printf(fmt, opt->longflag);
        }
      }
      for (; chars < lhsLen; ++chars) {
        putchar(' ');
      }
      PrintParagraph(opt->help, lhsLen, helpWidth, false);
      putchar('\n');
    }
  }

  return EarlyExit;
}

OptionParser::Result OptionParser::printVersion() {
  MOZ_ASSERT(version);
  printf("%s\n", version);
  return EarlyExit;
}

OptionParser::Result OptionParser::extractValue(size_t argc, char** argv,
                                                size_t* i, char** value) {
  MOZ_ASSERT(*i < argc);
  char* eq = strchr(argv[*i], '=');
  if (eq) {
    *value = eq + 1;
    if (*value[0] == '\0') {
      return error("A value is required for option %.*s", (int)(eq - argv[*i]),
                   argv[*i]);
    }
    return Okay;
  }

  if (argc == *i + 1) {
    return error("Expected a value for option %s", argv[*i]);
  }

  *i += 1;
  *value = argv[*i];
  return Okay;
}

OptionParser::Result OptionParser::handleOption(Option* opt, size_t argc,
                                                char** argv, size_t* i,
                                                bool* optionsAllowed) {
  if (opt->getTerminatesOptions()) {
    *optionsAllowed = false;
  }

  switch (opt->kind) {
    case OptionKindBool: {
      if (opt == &helpOption) {
        return printHelp(argv[0]);
      }
      if (opt == &versionOption) {
        return printVersion();
      }
      opt->asBoolOption()->value = true;
      return Okay;
    }
    /*
     * Valued options are allowed to specify their values either via
     * successive arguments or a single --longflag=value argument.
     */

    case OptionKindString: {
      char* value = nullptr;
      if (Result r = extractValue(argc, argv, i, &value)) {
        return r;
      }
      opt->asStringOption()->value = value;
      return Okay;
    }
    case OptionKindInt: {
      char* value = nullptr;
      if (Result r = extractValue(argc, argv, i, &value)) {
        return r;
      }
      opt->asIntOption()->value = atoi(value);
      return Okay;
    }
    case OptionKindMultiString: {
      char* value = nullptr;
      if (Result r = extractValue(argc, argv, i, &value)) {
        return r;
      }
      StringArg arg(value, *i);
      return opt->asMultiStringOption()->strings.append(arg) ? Okay : Fail;
    }
    default:
      MOZ_CRASH("unhandled option kind");
  }
}

OptionParser::Result OptionParser::handleArg(size_t argc, char** argv,
                                             size_t* i, bool* optionsAllowed) {
  if (nextArgument >= arguments.length()) {
    return error("Too many arguments provided");
  }

  Option* arg = arguments[nextArgument];

  if (arg->getTerminatesOptions()) {
    *optionsAllowed = false;
  }

  switch (arg->kind) {
    case OptionKindString:
      arg->asStringOption()->value = argv[*i];
      nextArgument += 1;
      return Okay;
    case OptionKindMultiString: {
      // Don't advance the next argument -- there can only be one (final)
      // variadic argument.
      StringArg value(argv[*i], *i);
      return arg->asMultiStringOption()->strings.append(value) ? Okay : Fail;
    }
    default:
      MOZ_CRASH("unhandled argument kind");
  }
}

OptionParser::Result OptionParser::parseArgs(int inputArgc, char** argv) {
  MOZ_ASSERT(inputArgc >= 0);
  size_t argc = inputArgc;

  // Permit a "no more options" capability, like |--| offers in many shell
  // interfaces.
  bool optionsAllowed = true;

  // Whether unknown options should report a warning instead of an error. This
  // is enabled by setIgnoresUnknownOptions and used for --fuzzing-safe.
  bool ignoreUnknownOptions = false;

  for (size_t i = 1; i < argc; ++i) {
    char* arg = argv[i];
    Result r;
    /* Note: solo dash option is actually a 'stdin' argument. */
    if (arg[0] == '-' && arg[1] != '\0' && optionsAllowed) {
      /* Option. */
      Option* opt;
      if (arg[1] == '-') {
        if (arg[2] == '\0') {
          /* End of options */
          optionsAllowed = false;
          nextArgument = restArgument;
          continue;
        } else {
          /* Long option. */
          opt = findOption(arg + 2);
          if (!opt) {
            if (ignoreUnknownOptions) {
              fprintf(stderr, "Warning: Ignoring unknown shell flag: %s\n",
                      arg);
              continue;
            }
            return error("Invalid long option: %s", arg);
          }
        }
      } else {
        /* Short option */
        if (arg[2] != '\0') {
          return error("Short option followed by junk: %s", arg);
        }
        opt = findOption(arg[1]);
        if (!opt) {
          return error("Invalid short option: %s", arg);
        }
      }

      if (opt->getIgnoresUnknownOptions()) {
        ignoreUnknownOptions = true;
      }

      r = handleOption(opt, argc, argv, &i, &optionsAllowed);
    } else {
      /* Argument. */
      r = handleArg(argc, argv, &i, &optionsAllowed);
    }

    if (r != Okay) {
      return r;
    }
  }
  return Okay;
}

void OptionParser::setHelpOption(char shortflag, const char* longflag,
                                 const char* help) {
  helpOption.setFlagInfo(shortflag, longflag, help);
}

bool OptionParser::getHelpOption() const { return helpOption.value; }

bool OptionParser::getBoolOption(char shortflag) const {
  return tryFindOption(shortflag)->asBoolOption()->value;
}

int OptionParser::getIntOption(char shortflag) const {
  return tryFindOption(shortflag)->asIntOption()->value;
}

const char* OptionParser::getStringOption(char shortflag) const {
  return tryFindOption(shortflag)->asStringOption()->value;
}

MultiStringRange OptionParser::getMultiStringOption(char shortflag) const {
  const MultiStringOption* mso =
      tryFindOption(shortflag)->asMultiStringOption();
  return MultiStringRange(mso->strings.begin(), mso->strings.end());
}

bool OptionParser::getBoolOption(const char* longflag) const {
  return tryFindOption(longflag)->asBoolOption()->value;
}

int OptionParser::getIntOption(const char* longflag) const {
  return tryFindOption(longflag)->asIntOption()->value;
}

const char* OptionParser::getStringOption(const char* longflag) const {
  return tryFindOption(longflag)->asStringOption()->value;
}

MultiStringRange OptionParser::getMultiStringOption(
    const char* longflag) const {
  const MultiStringOption* mso = tryFindOption(longflag)->asMultiStringOption();
  return MultiStringRange(mso->strings.begin(), mso->strings.end());
}

OptionParser::~OptionParser() {
  for (Option* opt : options) {
    js_delete<Option>(opt);
  }
  for (Option* arg : arguments) {
    js_delete<Option>(arg);
  }
}

Option* OptionParser::findOption(char shortflag) {
  for (Option* opt : options) {
    if (opt->shortflag == shortflag) {
      return opt;
    }
  }

  if (versionOption.shortflag == shortflag) {
    return &versionOption;
  }

  return helpOption.shortflag == shortflag ? &helpOption : nullptr;
}

const Option* OptionParser::findOption(char shortflag) const {
  return const_cast<OptionParser*>(this)->findOption(shortflag);
}

const Option* OptionParser::tryFindOption(char shortflag) const {
  const Option* maybeOption = findOption(shortflag);
  if (!maybeOption) {
    fprintf(stderr, "Failed to find short option %c\n", shortflag);
    MOZ_CRASH();
  }
  return maybeOption;
}

Option* OptionParser::findOption(const char* longflag) {
  for (Option* opt : options) {
    const char* target = opt->longflag;
    if (opt->isValued()) {
      size_t targetLen = strlen(target);
      /* Permit a trailing equals sign on the longflag argument. */
      for (size_t i = 0; i < targetLen; ++i) {
        if (longflag[i] == '\0' || longflag[i] != target[i]) {
          goto no_match;
        }
      }
      if (longflag[targetLen] == '\0' || longflag[targetLen] == '=') {
        return opt;
      }
    } else {
      if (strcmp(target, longflag) == 0) {
        return opt;
      }
    }
  no_match:;
  }

  if (strcmp(versionOption.longflag, longflag) == 0) {
    return &versionOption;
  }

  return strcmp(helpOption.longflag, longflag) ? nullptr : &helpOption;
}

const Option* OptionParser::findOption(const char* longflag) const {
  return const_cast<OptionParser*>(this)->findOption(longflag);
}

const Option* OptionParser::tryFindOption(const char* longflag) const {
  const Option* maybeOption = findOption(longflag);
  if (!maybeOption) {
    fprintf(stderr, "Failed to find long option %s\n", longflag);
    MOZ_CRASH();
  }
  return maybeOption;
}

/* Argument accessors */

int OptionParser::findArgumentIndex(const char* name) const {
  for (Option* const* it = arguments.begin(); it != arguments.end(); ++it) {
    const char* target = (*it)->longflag;
    if (strcmp(target, name) == 0) {
      return it - arguments.begin();
    }
  }
  return -1;
}

Option* OptionParser::findArgument(const char* name) {
  int index = findArgumentIndex(name);
  return (index == -1) ? nullptr : arguments[index];
}

const Option* OptionParser::findArgument(const char* name) const {
  int index = findArgumentIndex(name);
  return (index == -1) ? nullptr : arguments[index];
}

const char* OptionParser::getStringArg(const char* name) const {
  return findArgument(name)->asStringOption()->value;
}

MultiStringRange OptionParser::getMultiStringArg(const char* name) const {
  const MultiStringOption* mso = findArgument(name)->asMultiStringOption();
  return MultiStringRange(mso->strings.begin(), mso->strings.end());
}

/* Option builders */

// Use vanilla malloc for allocations. See OptionAllocPolicy.
JS_DECLARE_NEW_METHODS(opt_new, malloc, static MOZ_ALWAYS_INLINE)

bool OptionParser::addIntOption(char shortflag, const char* longflag,
                                const char* metavar, const char* help,
                                int defaultValue) {
  if (!options.reserve(options.length() + 1)) {
    return false;
  }
  IntOption* io =
      opt_new<IntOption>(shortflag, longflag, help, metavar, defaultValue);
  if (!io) {
    return false;
  }
  options.infallibleAppend(io);
  return true;
}

bool OptionParser::addBoolOption(char shortflag, const char* longflag,
                                 const char* help) {
  if (!options.reserve(options.length() + 1)) {
    return false;
  }
  BoolOption* bo = opt_new<BoolOption>(shortflag, longflag, help);
  if (!bo) {
    return false;
  }
  options.infallibleAppend(bo);
  return true;
}

bool OptionParser::addStringOption(char shortflag, const char* longflag,
                                   const char* metavar, const char* help) {
  if (!options.reserve(options.length() + 1)) {
    return false;
  }
  StringOption* so = opt_new<StringOption>(shortflag, longflag, help, metavar);
  if (!so) {
    return false;
  }
  options.infallibleAppend(so);
  return true;
}

bool OptionParser::addMultiStringOption(char shortflag, const char* longflag,
                                        const char* metavar, const char* help) {
  if (!options.reserve(options.length() + 1)) {
    return false;
  }
  MultiStringOption* mso =
      opt_new<MultiStringOption>(shortflag, longflag, help, metavar);
  if (!mso) {
    return false;
  }
  options.infallibleAppend(mso);
  return true;
}

/* Argument builders */

bool OptionParser::addOptionalStringArg(const char* name, const char* help) {
  if (!arguments.reserve(arguments.length() + 1)) {
    return false;
  }
  StringOption* so = opt_new<StringOption>(1, name, help, (const char*)nullptr);
  if (!so) {
    return false;
  }
  arguments.infallibleAppend(so);
  return true;
}

bool OptionParser::addOptionalMultiStringArg(const char* name,
                                             const char* help) {
  MOZ_ASSERT_IF(!arguments.empty(), !arguments.back()->isVariadic());
  if (!arguments.reserve(arguments.length() + 1)) {
    return false;
  }
  MultiStringOption* mso =
      opt_new<MultiStringOption>(1, name, help, (const char*)nullptr);
  if (!mso) {
    return false;
  }
  arguments.infallibleAppend(mso);
  return true;
}

Messung V0.5
C=92 H=92 G=91

¤ Dauer der Verarbeitung: 0.8 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.