1 Star 1 Fork 0

RonxBulld / yaco

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

Build Status

Quick start

This is a LLVM-style lightweight C++ option parser library, supporting the standard GNU style syntax for options.

Options can be given as:

--long
--long=argument
--long argument
-a
-ab
-abc argument
-c5

where c takes an argument, but a and b do not.

Additionally, anything after -- will be parsed as a positional argument.

Basics

#include <yaco.hpp>

Create a yaco::Parser instance or not.

yaco::Parser parser("MyProgram");

Then declare options anywhere.

yaco::Opt<bool> debug("d",
                      yaco::cat("Analysis"),
                      yaco::init(false),
                      yaco::desc("Enable debug"),
                      yaco::inject(parser)
                      );

First, you must specify the option storage value type.

yaco::Opt<bool> debug;

Options are declared with a long and an optional short option.

yaco::Opt<bool> debug("d");

If not specified, it will be treated as a position-related option.

You can using a lot of modifier to modify the attributes of option. These modifiers are currently provided:


yaco::cat

yaco::init

yaco::desc

yaco::inject


If you want to add option to the specified parser, you should use the yaco::inject modifier.

You can specify a default value through the yaco::init modifier, but you may encounter some conversion problems.

Yes, any type can be given as long as it can be parsed, with operator>>. But there are more types that cannot be parsed, such as vector<string>.

So, you should DIY the serializer. For example, to handle the vector<string>:

namespace yaco
{
  template<template<typename...> class C, typename U>
  struct val2str <C<U>>
  {
    static std::string make(std::vector<U> vec)
    {
      std::string buf;
      for (auto iter = vec.begin(), end = vec.end(); iter != end; ++iter)
      {
        buf.append(val2str<U>::make(*iter)).append(1, CXXOPTS_VECTOR_DELIMITER);
      }
      if (!buf.empty())
      {
        buf.pop_back();
      }
      return buf;
    }
  };
}

You will encounter some compilation problems when you decide to use a custom structure. This is usually because you didn't tell the compiler how to serialize and deserialize.

Here is a structure:

struct uti {
  std::string a = "";
  int i = 0;
};

and option:

yaco::Opt<struct uti> utisw("u");

Now, we declare the special value parser:

namespace cxxopts {
namespace values {
template <>
ErrOr<void>
parse_value<uti>(const std::string& text, uti& value) {
  value.a = text;
  value.i = (int) text.length();
  return true;
}
}
}

The parser will call it during the parsing process.

To parse the command line do:

int result = parser.enparse(argc, argv);

To retrieve an option use opt.IsSpecified() to check if it appeared, and use the option self to get its value. If "opt" doesn't exist, or isn't of the right type, then an exception will be thrown.

Exceptions

Exceptional situations throw C++ exceptions. There are two types of exceptions: errors defining the options, and errors when parsing a list of arguments. All exceptions derive from cxxopts::OptionException. Errors defining options derive from cxxopts::OptionSpecException and errors parsing arguments derive from cxxopts::OptionParseException.

All exceptions define a what() function to get a printable string explaining the error.

Help groups

Options can be placed into groups for the purposes of displaying help messages. To place options in a group, pass the group as a string to add_options. Then, when displaying the help, pass the groups that you would like displayed as a vector to the help function.

Positional Arguments

Positional arguments can be optionally parsed into one or more options. To set up positional arguments, use

yaco::Opt<std::string> head(yaco::value_desc("head file"),
                            yaco::Positional
                            );

Enumeration

Compared to cxxopts, yaco support enumerations:

enum OptLevel { Debug, O1, O2, O3 };
yaco::Opt<OptLevel> OptimizationLevel(
    "opt",
    yaco::desc("Choose optimization level."),
    yaco::values(
        coEnumValN(Debug, "g", "No optimizations, enable debugging"),
        coEnumVal(O1, "Trivial optimizations"),
        coEnumVal(O2, "Default optimizations"),
        coEnumVal(O3, "Expensive optimizations")
        ),
    yaco::inject(parser)
    );

When using the command line, specify it in a way similar to --opt O3. And use

  std::cout << "optimization level: ";
  switch (OptimizationLevel) {
  case OptLevel::Debug: std::cout << "debug" << std::endl; break;
  case OptLevel::O1:    std::cout << "O1"    << std::endl; break;
  case OptLevel::O2:    std::cout << "O2"    << std::endl; break;
  case OptLevel::O3:    std::cout << "O3"    << std::endl; break;
  }

to check the enumeration value.

Boolean values

Boolean options have a default implicit value of "true", which can be overridden. The effect is that writing -o by itself will set option o to true. However, they can also be written with various strings using =value. There is no way to disambiguate positional arguments from the value following a boolean, so we have chosen that they will be positional arguments, and therefore, -o false does not work.

std::vector<T> values

Parsing of list of values in form of an std::vector<T> is also supported, as long as T can be parsed. To separate single values in a list the definition CXXOPTS_VECTOR_DELIMITER is used, which is ',' by default. Ensure that you use no whitespaces between values because those would be interpreted as the next command line option. Example for a command line option that can be parsed as a std::vector<double>:

--my_list=1,-2.1,3,4.5

Options specified multiple times

The same option can be specified several times, with different arguments, which will all be recorded in order of appearance. An example:

--use train --use bus --use ferry

this is supported through the use of a vector of value for the option:

yaco::Opt<std::vector<std::string>> used("use",
                                         yaco::desc("multiple used")
                                         );

Example

Putting all together:

#include "yaco.h"

struct uti {
  std::string a = "";
  int i = 0;
};

/// Type converter
namespace cxxopts {
namespace values {

template <>
ErrOr<void>
parse_value<uti>(const std::string& text, uti& value) {
  value.a = text;
  value.i = (int) text.length();
  return true;
}

}
}

yaco::Opt<bool> debug("d",
                      yaco::cat("Analysis"),
                      yaco::init(false),
                      yaco::desc("Enable debug")
                      );
yaco::Opt<bool> coverage("c,cover",
                         yaco::cat("Analysis")
                         );
yaco::Opt<bool> help("h,help",
                     yaco::desc("display help messages.\n"
                                "=== Here is more detail ==="),
                     yaco::cat("Auxiliary")
                     );
yaco::Opt<int> job("j,job",
                   yaco::desc("jobs"),
                   yaco::value_desc("N")
                   );
yaco::Opt<struct uti> utisw("u"
                            );
yaco::Opt<std::string> output("o",
                              yaco::init("a.out"),
                              yaco::value_desc("filename")
                              );
// These are two position-related parameters.
yaco::Opt<std::string> head(yaco::value_desc("head file"), yaco::Positional);
yaco::Opt<std::vector<std::string>> inputs("inputs",
                                           yaco::value_desc("input files"),
                                           yaco::Positional
                                           );
enum OptLevel { Debug, O1, O2, O3 };
yaco::Opt<OptLevel> OptimizationLevel(
    "opt",
    yaco::desc("Choose optimization level."),
    yaco::values(
        coEnumValN(Debug, "g", "No optimizations, enable debugging"),
        coEnumVal(O1, "Trivial optimizations"),
        coEnumVal(O2, "Default optimizations"),
        coEnumVal(O3, "Expensive optimizations")
        )
    );
yaco::Opt<std::vector<std::string>> used("use",
                                         yaco::desc("multiple used")
                                         );

int main(int argc, char **argv)
{
  yaco::enparse(argc, argv);

  if (job.IsSpecified())
  {
    int n = job;
    std::cout << "Parallel jobs: " << n << std::endl;
  }

  if (debug)
  {
    std::cout << "debug on" << std::endl;
  }
  else
  {
    std::cout << "debug off" << std::endl;
  }

  std::cout << "optimization level: ";
  switch (OptimizationLevel) {
  case OptLevel::Debug: std::cout << "debug" << std::endl; break;
  case OptLevel::O1:    std::cout << "O1"    << std::endl; break;
  case OptLevel::O2:    std::cout << "O2"    << std::endl; break;
  case OptLevel::O3:    std::cout << "O3"    << std::endl; break;
  }

  if (coverage)
  {
    std::cout << "coverage on" << std::endl;
  }
  else
  {
    std::cout << "coverage off" << std::endl;
  }

  if (utisw.IsSpecified())
  {
    std::cout << "util args: " << utisw.a
              << " len=" << utisw.i
              << std::endl;
  }

  if (head.IsSpecified())
  {
    std::cout << "head: " << head << std::endl;
  }
  if (inputs.IsSpecified())
  {
    std::cout << "inputs: ";
    for (auto &input : inputs)
    {
      std::cout << input << " ";
    }
    std::cout << std::endl;
  }

  if (used.IsSpecified())
  {
    std::cout << "used: ";
    for (auto &u : used)
    {
      std::cout << u << " ";
    }
    std::cout << std::endl;
  }

  if (help.IsSpecified())
  {
    std::cout << yaco::help() << std::endl;
    exit(0);
  }

  return 0;
}

Linking

This is a header only library.

Requirements

The only build requirement is a C++ compiler that supports C++11 features such as:

  • regex (When using gcc4.8, the regex library is not used.)
  • constexpr
  • default constructors

GCC >= 4.8.5 or clang >= 3.1 with libc++ are known to work.

The following compilers are known not to work:

  • MSVC 2013

Thanks

Thanks to the ubisec company for my work, they allowed me more time to write this library.

Thanks to jarro2783, his cxxopts project provided yaco's original parser, which is currently the core parser of yaco.

Copyright (c) 2014 Jarryd Beck Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

Yaco - Yet Another C++ commandline Option library. 展开 收起
C++ 等 3 种语言
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
C++
1
https://gitee.com/RonxBulld/yaco.git
git@gitee.com:RonxBulld/yaco.git
RonxBulld
yaco
yaco
master

搜索帮助