Skip to content

Commit

Permalink
Fix #16: repeated options should override by default
Browse files Browse the repository at this point in the history
+ New constructor to also accept config. flags
+ Test updates (also the engine, with an important fix -> 0.17)
  • Loading branch information
xparq committed Nov 2, 2023
1 parent a887eec commit b357093
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 31 deletions.
31 changes: 21 additions & 10 deletions Args.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Tiny "functional" cmdline processor (-> github.com/xparq/Args)
// v1.7
// v1.8

#include <string>
#include <vector>
Expand All @@ -10,21 +10,31 @@

class Args
{
public:
enum { Defaults,
RepeatAppends = 1, // for opts. expecting >1 params; default: override (replace) (GH #16)
//!! These two are implicitly forced by the current implementation (can't be disabled):
KeepInvalid = 2, // default: invalid opts. (i.e. those with incorrect # of params) are deleted (GH #44)
NonGreedy = 4 }; // undefined options don't try to take params; default: they do (GH #43)
unsigned flags = Defaults;

enum Error { None, ParameterMissing, Unimplemented = -1 }
error = None;

protected:
typedef std::map<std::string, int> Rules;

int argc;
char** argv;
Rules param_count; // entries: { "option_name", number_of_args }
// negative count means "at least n", until the next opt or EOS
// NOTE: nonexistent items will return 0 (map zero-inits primitive types)
public:
enum Error { None, ParameterMissing, Unimplemented = -1 }
error = None;

Rules param_count; // entries: { "option", nr_of_params_for_option }
// negative n means greedy: "at least n", until the next opt or EOS
// NOTE: nonexistent entries will return 0 (std::map zero-inits primitive types)
//!! const char* split_sep = ",;"; // split("option") will use this by default
public:
Args(int argc_, char** argv_, const Rules& rules = {})
: argc(argc_), argv(argv_), param_count(rules) { proc_next("", 0); }
Args(int argc_, char** argv_, unsigned flags, const Rules& rules = {})
: argc(argc_), argv(argv_), flags(flags), param_count(rules) { proc_next("", 0); }
Args(const Args&) = default;
Args& operator=(const Args&) = default;

Expand Down Expand Up @@ -91,6 +101,7 @@ class Args
//! Simply ignoring this case would just work as before.
} else if (eqpos != std::string::npos) { //! This also allows `--unknown-opt=value` (no matter the rules)!
new_opt = new_opt.substr(0, eqpos); // chop off the `=...`
if (!(flags & RepeatAppends)) named_params[new_opt].clear(); // Reset in case it's not actually new?...
if (a.size() > 2 + eqpos + 1) { // value after the `=`?
//std::cerr << "val: " << a.substr(2, eqpos) << "\n";
named_params[new_opt].emplace_back(a.substr(2 + eqpos+1)); //! don't crash on `--opt=`
Expand All @@ -99,9 +110,9 @@ class Args
// the value can just be ignored, and if != 0, then we've just
// started taking params anyway, the only thing left is to
// make sure to continue that if expecting more:
auto tmp = param_count[new_opt];
auto pc = param_count[new_opt];
//std::cerr << tmp << " params expected for [" << new_opt << "]\n";
return proc_next(new_opt, tmp < -1 ? tmp+1 : tmp-1);
return proc_next(new_opt, pc < -1 ? pc+1 : pc-1);
}
}
} else if (a[1] != a[0]) { // a real short opt, or short opt. aggregate
Expand Down
10 changes: 10 additions & 0 deletions test/ .cfg
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ export BUILD_DEPS_COMMON=../*.hpp
#EXPECT_FILE_NAME=expected.results
# Default: EXPECT

#!! Well, some POSIX emu envs (mainly: Git bash) will use incompatible path
#!! conversions for $PATH (/c/...), vs. $TEST_DIR (C:/...), so no use trying
#!! this... :-/ Good luck even figuring out the correct separator (: or ;)...
#!! BusyBox-w32 worked fine with this:
#!!export PATH="$TEST_DIR:$PATH"

# This would disable auto-prefixing cmd filenames for RUN with ./ to allow
# PATH lookup, which may be better done per test case, than here globally!
#export RUN_WITH_PATH_LOOKUP=1

export INCLUDE="$TEST_DIR/..;$INCLUDE"
export C_INCLUDE_PATH="$TEST_DIR/..;$C_INCLUDE_PATH"
export CPLUS_INCLUDE_PATH="$TEST_DIR/..;$CPLUS_INCLUDE_PATH"
1 change: 1 addition & 0 deletions test/_engine/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.17
17 changes: 9 additions & 8 deletions test/_engine/functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,16 @@ RUN(){
shift
args=$@

# Kludge to prepend ./ if no dir in cmd:
normalized_dirpath=`dirname "$cmd"`
cmd=$normalized_dirpath/$cmd
#DEBUG Cmdline to run: "$cmd" $args

savedir=`pwd`
cd "$TEST_CASE_DIR"
"$cmd" $args >> "$TMP_DIR/${CASE}.out" 2>> "$TMP_DIR/${CASE}.err"
echo $? >> "$TMP_DIR/${CASE}.retval"
cd "$TEST_CASE_DIR"
if [ -z "$RUN_WITH_PATH_LOOKUP" ]; then
# Prepend ./ if no dir in cmd (see also #53):
explicit_dirpath=`dirname "$cmd"`
cmd=$explicit_dirpath/`basename "$cmd"`
fi
#DEBUG Cmdline to run: "$cmd" $args
"$cmd" $args >> "$TMP_DIR/${CASE}.out" 2>> "$TMP_DIR/${CASE}.err"
echo $? >> "$TMP_DIR/${CASE}.retval"
cd "$savedir"
}

Expand Down
2 changes: 1 addition & 1 deletion test/_engine/init_once.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export TEST_DIR=${TEST_DIR:-`pwd`}
#DEBUG "Test dir is: \"$TEST_DIR\""
if [ ! -e "$TEST_DIR" ]; then FATAL "TEST_DIR \"$TEST_DIR\" doesn't seem to exist!" 102; fi

export TMP_DIR="$TEST_DIR/tmp"
export TMP_DIR="$TEST_DIR/.tmp"
#!! Fall back to $TMP, $TEMP, /tmp etc...
if [ ! -d "$TMP_DIR" ]; then
mkdir -p "$TMP_DIR"
Expand Down
23 changes: 21 additions & 2 deletions test/args-test.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
#include "Args.hpp"
/*
This file can be #included from test cases, to keep its behavior,
but alter the config!
E.g.:
#define FLAGS Args::RepeatAppends,
#include "args-test.cpp"
*/

//---------------------------------------------------------------------------
// Parameter macros currently supported (name: format):

#ifdef FLAGS // unsigned
# define FLAGS_COMMA_IF_DEFINED FLAGS,
#else
# define FLAGS_COMMA_IF_DEFINED
#endif
//---------------------------------------------------------------------------

#include "Args.hpp"
#include <iostream>
using namespace std;

Expand All @@ -13,7 +32,7 @@ auto listvals(auto const& vect)

int main(int argc, char* argv[])
{
Args args(argc, argv, {
Args args(argc, argv, FLAGS_COMMA_IF_DEFINED {
{"one", 1}, // take 1 param.
{"i", -1}, // short; any nr. of params up to the next arg or EOS
{"many", -1}, // long; any nr. of params up to the next arg or EOS
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#include "Args.hpp"
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
Args args(argc, argv);

if (args["long"])
{ cout << "- 'long' was set\n"; }
}
#include "Args.hpp"
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
Args args(argc, argv);

if (args["long"])
{ cout << "- 'long' was set\n"; }
}
19 changes: 19 additions & 0 deletions test/issue 16 (override on repeat by default).case/case
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
RUN ../args-test --take-two=1 2 junk --take-two=a b

EXPECT "-------- NAMED:
take-two = a, b
-------- POSITIONAL:
junk
"

#--------------------------------------------------
# And try appending (Args::RepeatAppends), too...
#--------------------------------------------------
alt="$CASE"
RUN "$alt" --take-two=1 2 junk --take-two=a b

EXPECT "-------- NAMED:
take-two = 1, 2, a, b
-------- POSITIONAL:
junk
"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#define FLAGS Args::RepeatAppends
#include "args-test.cpp"

0 comments on commit b357093

Please sign in to comment.