#pragma once
#include "last_getopt_opts.h"
#include "last_getopt_easy_setup.h"
#include "last_getopt_parse_result.h"
#include <util/generic/function.h>
#include <util/string/split.h>
/// see some documentation in
/// https://wiki.yandex-team.ru/development/poisk/arcadia/util/lastgetopt/
/// https://wiki.yandex-team.ru/development/poisk/arcadia/library/getopt/
/// see examples in library/cpp/getopt/last_getopt_demo
//TODO: in most cases this include is unnecessary, but needed THandlerFunctor1<TpFunc, TpArg>::HandleOpt
#include "last_getopt_parser.h"
namespace NLastGetopt {
/// Handler to split option value by delimiter into a target container and allow ranges.
template <class Container>
struct TOptRangeSplitHandler: public IOptHandler {
public:
using TContainer = Container;
using TValue = typename TContainer::value_type;
explicit TOptRangeSplitHandler(TContainer* target, const char elementsDelim, const char rangesDelim)
: Target(target)
, ElementsDelim(elementsDelim)
, RangesDelim(rangesDelim)
{
}
void HandleOpt(const TOptsParser* parser) override {
const TStringBuf curval(parser->CurValOrDef());
if (curval.IsInited()) {
StringSplitter(curval).Split(ElementsDelim).Consume([&](const TStringBuf& val) {
TStringBuf mutableValue = val;
TValue first = NPrivate::OptFromString<TValue>(mutableValue.NextTok(RangesDelim), parser->CurOpt());
TValue last = mutableValue ? NPrivate::OptFromString<TValue>(mutableValue, parser->CurOpt()) : first;
if (last < first) {
throw TUsageException() << "failed to parse opt " << NPrivate::OptToString(parser->CurOpt()) << " value " << TString(val).Quote() << ": the second argument is less than the first one";
}
for (++last; first < last; ++first) {
Target->insert(Target->end(), first);
}
});
}
}
private:
TContainer* Target;
char ElementsDelim;
char RangesDelim;
};
template <class Container>
struct TOptSplitHandler: public IOptHandler {
public:
using TContainer = Container;
using TValue = typename TContainer::value_type;
explicit TOptSplitHandler(TContainer* target, const char delim)
: Target(target)
, Delim(delim)
{
}
void HandleOpt(const TOptsParser* parser) override {
const TStringBuf curval(parser->CurValOrDef());
if (curval.IsInited()) {
StringSplitter(curval).Split(Delim).Consume([&](const TStringBuf& val) {
Target->insert(Target->end(), NPrivate::OptFromString<TValue>(val, parser->CurOpt()));
});
}
}
private:
TContainer* Target;
char Delim;
};
template <class TpFunc>
struct TOptKVHandler: public IOptHandler {
public:
using TKey = typename TFunctionArgs<TpFunc>::template TGet<0>;
using TValue = typename TFunctionArgs<TpFunc>::template TGet<1>;
explicit TOptKVHandler(TpFunc func, const char kvdelim = '=')
: Func(func)
, KVDelim(kvdelim)
{
}
void HandleOpt(const TOptsParser* parser) override {
const TStringBuf curval(parser->CurValOrDef());
const TOpt* curOpt(parser->CurOpt());
if (curval.IsInited()) {
TStringBuf key, value;
if (!curval.TrySplit(KVDelim, key, value)) {
throw TUsageException() << "failed to parse opt " << NPrivate::OptToString(curOpt)
<< " value " << TString(curval).Quote() << ": expected key" << KVDelim << "value format";
}
Func(NPrivate::OptFromString<TKey>(key, curOpt), NPrivate::OptFromString<TValue>(value, curOpt));
}
}
private:
TpFunc Func;
char KVDelim;
};
namespace NPrivate {
template <typename TpFunc, typename TpArg>
void THandlerFunctor1<TpFunc, TpArg>::HandleOpt(const TOptsParser* parser) {
const TStringBuf curval = parser->CurValOrDef(!HasDef_);
const TpArg& arg = curval.IsInited() ? OptFromString<TpArg>(curval, parser->CurOpt()) : Def_;
try {
Func_(arg);
} catch (const TUsageException&) {
throw;
} catch (...) {
throw TUsageException() << "failed to handle opt " << OptToString(parser->CurOpt())
<< " value " << TString(curval).Quote() << ": " << CurrentExceptionMessage();
}
}
}
}