add argFind and use it for more generic special args handling from env, improve help text
This commit is contained in:
+15
-10
@@ -130,6 +130,8 @@ static string s_configPath = CONFIG_PATH;
|
||||
#define O_DMPFLU (O_DMPSIZ-1)
|
||||
#define O_INJPOS 0x100
|
||||
|
||||
#define ARG_NO_ENV (af_max << 1)
|
||||
|
||||
/** the definition of the known program arguments. */
|
||||
static const argDef argDefs[] = {
|
||||
{nullptr, 0, nullptr, 0, "Device options:"},
|
||||
@@ -156,17 +158,17 @@ static const argDef argDefs[] = {
|
||||
"\"full\" for full scan, "
|
||||
"a single hex address to scan, or "
|
||||
"\"off\" for not picking CSV files by scan result (default when configpath is given).\n"
|
||||
"If combined with --checkconfig, you can add scan message data as "
|
||||
"If combined with --checkconfig and --inject, you can add scan message data as "
|
||||
"arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\"."},
|
||||
{"scanretries", O_SCNRET, "COUNT", 0, "Retry scanning devices COUNT times [5]"},
|
||||
{"configlang", O_CFGLNG, "LANG", 0,
|
||||
"Prefer LANG in multilingual configuration files [system default language, DE as fallback]"},
|
||||
{"checkconfig", O_CHKCFG, nullptr, 0, "Check config files, then stop"},
|
||||
{"dumpconfig", O_DMPCFG, "FORMAT", af_optional,
|
||||
{"checkconfig", O_CHKCFG, nullptr, ARG_NO_ENV, "Check config files, then stop"},
|
||||
{"dumpconfig", O_DMPCFG, "FORMAT", af_optional|ARG_NO_ENV,
|
||||
"Check and dump config files in FORMAT (\"json\" or \"csv\"), then stop"},
|
||||
{"dumpconfigto", O_DMPCTO, "FILE", 0, "Dump config files to FILE"},
|
||||
{"pollinterval", O_POLINT, "SEC", 0, "Poll for data every SEC seconds (0=disable) [5]"},
|
||||
{"inject", 'i', "stop", af_optional, "Inject remaining arguments as commands or already seen messages "
|
||||
{"inject", 'i', "stop", af_optional|ARG_NO_ENV, "Inject remaining arguments as commands or already seen messages "
|
||||
"(e.g. \"FF08070400/0AB5454850303003277201\"), optionally stop afterwards"},
|
||||
{nullptr, O_INJPOS, "INJECT", af_optional|af_multiple, "Commands and/or messages to inject "
|
||||
"(if --inject was given)"},
|
||||
@@ -642,18 +644,21 @@ int parse_main_args(int argc, char* argv[], char* envp[], options_t *opt) {
|
||||
}
|
||||
envopt[len] = 0;
|
||||
if (strcmp(envopt, "version") == 0 || strcmp(envopt, "image") == 0 || strcmp(envopt, "arch") == 0
|
||||
|| strcmp(envopt, "opts") == 0 || strcmp(envopt, "inject") == 0
|
||||
|| strcmp(envopt, "checkconfig") == 0 || strncmp(envopt, "dumpconfig", 10) == 0
|
||||
|| strcmp(envopt, "opts") == 0
|
||||
) {
|
||||
// ignore those defined in Dockerfile, EBUSD_OPTS, those with final args, and interactive ones
|
||||
// ignore those defined in Dockerfile, EBUSD_OPTS
|
||||
continue;
|
||||
}
|
||||
const argDef* found = argFind(&parseOpt, envopt);
|
||||
if (found && found->flags & ARG_NO_ENV) {
|
||||
// ignore those with final args and interactive ones
|
||||
continue;
|
||||
}
|
||||
char* envargv[] = {argv[0], envname, pos+1};
|
||||
int cnt = pos[1] ? 2 : 1;
|
||||
if (pos[1] && strlen(*env) < sizeof(envname)-3
|
||||
&& (strcmp(envopt, "scanconfig") == 0 || strcmp(envopt, "lograwdata") == 0
|
||||
|| strcmp(envopt, "mqttjson") == 0 || strcmp(envopt, "knxurl") == 0
|
||||
)) {
|
||||
&& found && found->flags & af_optional
|
||||
) {
|
||||
// only really special case: af_optional with non-empty arg needs to use "=" syntax
|
||||
cnt = 1;
|
||||
strcat(envopt, pos);
|
||||
|
||||
@@ -398,4 +398,30 @@ void argHelp(const char* name, const argParseOpt *parseOpt) {
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
const argDef* argFindIn(const argDef *argDefs, const char* name) {
|
||||
for (const argDef *arg = argDefs; arg && arg->help; arg++) {
|
||||
if (arg->name && strcmp(name, arg->name) == 0) { // long option
|
||||
return arg;
|
||||
}
|
||||
if (name[2] == 0 && arg->key >= '?' && name[0] == arg->key) { // short option
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const argDef* argFind(const argParseOpt *parseOpt, const char* name) {
|
||||
const argDef* found = argFindIn(parseOpt->argDefs, name);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
for (const argParseChildOpt *child = parseOpt->childOpts; child && child->argDefs; child++) {
|
||||
found = argFindIn(child->argDefs, name);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
|
||||
@@ -29,6 +29,7 @@ enum ArgFlag {
|
||||
af_multiple = 1<<1, //!< may appear multiple times (only allowed for last positional)
|
||||
af_noHelp = 1<<2, //!< do not include -?/--help option
|
||||
af_noVersion = 1<<3, //!< do not include -V/--version option
|
||||
af_max = 1<<3, //!< maximum defined flag value
|
||||
};
|
||||
|
||||
/** Definition of a single argument. */
|
||||
@@ -87,6 +88,14 @@ int argParse(const argParseOpt *parseOpt, int argc, char **argv, void *userArg);
|
||||
*/
|
||||
void argHelp(const char* name, const argParseOpt *parseOpt);
|
||||
|
||||
/**
|
||||
* Find the argument with the given name.
|
||||
* @param parseOpt pointer to the @a argParseOpt structure.
|
||||
* @param name the name of the argument, either short or long.
|
||||
* @return a pointer to the found @a argDef, or nullptr.
|
||||
*/
|
||||
const argDef* argFind(const argParseOpt *parseOpt, const char* name);
|
||||
|
||||
/**
|
||||
* Convenience macro to print an error message to stderr.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user