add positionals to arg parser, avoid unnecessary parts in arg options

This commit is contained in:
John
2023-11-01 22:37:30 +01:00
parent b901232678
commit 3d9dd9b1c3
10 changed files with 169 additions and 126 deletions
+1 -1
View File
@@ -83,7 +83,7 @@ static vector<string>* g_integrationVars = nullptr; //!< the integration settin
* @param arg the option argument, or nullptr.
* @param state the parsing state.
*/
static int knx_parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
static int knx_parse_opt(int key, char *arg, const argParseOpt *parseOpt, void *userArg) {
result_t result;
unsigned int value;
switch (key) {
+7 -7
View File
@@ -222,8 +222,7 @@ void signalHandler(int sig) {
* @return the exit code.
*/
int main(int argc, char* argv[], char* envp[]) {
int arg_index = -1;
switch (parse_main_args(argc, argv, envp, &s_opt, &arg_index)) {
switch (parse_main_args(argc, argv, envp, &s_opt)) {
case 0: // OK
break;
case '?': // help printed
@@ -236,9 +235,9 @@ int main(int argc, char* argv[], char* envp[]) {
return EINVAL;
}
if (arg_index >= 0) {
if (s_opt.injectCount > 0) {
if (!s_opt.injectMessages && !(s_opt.checkConfig && s_opt.scanConfig)) {
fprintf(stderr, "invalid arguments starting with \"%s\"", argv[arg_index]);
fprintf(stderr, "invalid inject arguments");
return EINVAL;
}
}
@@ -302,10 +301,11 @@ int main(int argc, char* argv[], char* envp[]) {
if (s_opt.checkConfig) {
logNotice(lf_main, PACKAGE_STRING "." REVISION " performing configuration check...");
result_t result = s_scanHelper->loadConfigFiles(!s_opt.scanConfig || arg_index >= argc);
result_t result = s_scanHelper->loadConfigFiles(!s_opt.scanConfig || s_opt.injectCount <= 0);
result_t overallResult = s_scanHelper->executeInstructions(nullptr);
MasterSymbolString master;
SlaveSymbolString slave;
int arg_index = argc - s_opt.injectCount;
while (result == RESULT_OK && s_opt.scanConfig && arg_index < argc) {
// check scan config for each passed ident message
if (!s_scanHelper->parseMessage(argv[arg_index++], true, &master, &slave)) {
@@ -413,11 +413,11 @@ int main(int argc, char* argv[], char* envp[]) {
if (s_opt.injectMessages) {
int scanAdrCount = 0;
bool scanAddresses[256] = {};
while (arg_index < argc) {
for (int arg_index = argc - s_opt.injectCount; arg_index < argc; arg_index++) {
// add each passed message
MasterSymbolString master;
SlaveSymbolString slave;
if (!s_scanHelper->parseMessage(argv[arg_index++], false, &master, &slave)) {
if (!s_scanHelper->parseMessage(argv[arg_index], false, &master, &slave)) {
continue;
}
protocol->injectMessage(master, slave);
+4 -2
View File
@@ -33,6 +33,8 @@ namespace ebusd {
*/
/** the config path part behind the scheme (scheme without "://"). */
//#define CONFIG_PATH_SUFFIX "://ebus.github.io/cfg/de/"
#define CONFIG_PATH_SUFFIX "://cfg.ebusd.eu/"
/** A structure holding all program options. */
@@ -62,6 +64,7 @@ typedef struct options {
unsigned int pollInterval; //!< poll interval in seconds, 0 to disable [5]
bool injectMessages; //!< inject remaining arguments as already seen messages
bool stopAfterInject; //!< only inject messages once, then stop
int injectCount; //!< number of message arguments to inject, or 0
const char* caFile; //!< the CA file to use (uses defaults if neither caFile nor caPath are set), or "#" for insecure
const char* caPath; //!< the path with CA files to use (uses defaults if neither caFile nor caPath are set)
@@ -107,11 +110,10 @@ typedef struct options {
* @param argv the command line arguments.
* @param envp the environment variables to parse before the args, or nullptr.
* @param opt pointer to the parsed arguments (will be initialized to defaults first).
* @param argIndex optional pointer for storing the index to the first non-argument found in argv.
* @return 0 on success, '!' for an invalid argument value, ':' for a missing argument value,
* '?' when "-?" was given, or the result of the parse function if non-zero.
*/
int parse_main_args(int argc, char* argv[], char* envp[], options_t* opt, int* argIndex);
int parse_main_args(int argc, char* argv[], char* envp[], options_t* opt);
} // namespace ebusd
+17 -12
View File
@@ -56,6 +56,7 @@ static const options_t s_default_opt = {
.pollInterval = 5,
.injectMessages = false,
.stopAfterInject = false,
.injectCount = 0,
.caFile = nullptr,
.caPath = nullptr,
@@ -133,6 +134,7 @@ static string s_configPath = CONFIG_PATH;
#define O_DMPFIL (O_RAWSIZ-1)
#define O_DMPSIZ (O_DMPFIL-1)
#define O_DMPFLU (O_DMPSIZ-1)
#define O_INJPOS 0x100
/** the definition of the known program arguments. */
static const argDef argDefs[] = {
@@ -169,6 +171,7 @@ static const argDef argDefs[] = {
{"pollinterval", O_POLINT, "SEC", 0, "Poll for data every SEC seconds (0=disable) [5]"},
{"inject", 'i', "stop", af_optional, "Inject remaining arguments as already seen messages (e.g. "
"\"FF08070400/0AB5454850303003277201\"), optionally stop afterwards"},
{nullptr, O_INJPOS, "INJECT", af_optional|af_multiple, "Message(s) to inject (if --inject was given)"},
#ifdef HAVE_SSL
{"cafile", O_CAFILE, "FILE", 0, "Use CA FILE for checking certificates (uses defaults,"
" \"#\" for insecure)"},
@@ -229,8 +232,7 @@ static const argDef argDefs[] = {
* @param arg the option argument, or nullptr.
* @param parseOpt the parse options.
*/
static int parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
struct options *opt = (struct options*)parseOpt->userArg;
static int parse_opt(int key, char *arg, const argParseOpt *parseOpt, struct options *opt) {
result_t result = RESULT_OK;
unsigned int value;
@@ -590,7 +592,14 @@ static int parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
break;
default:
return ESRCH;
if (key >= O_INJPOS) { // INJECT
if (!opt->injectMessages || !arg || !arg[0]) {
return ESRCH;
}
opt->injectCount++;
} else {
return ESRCH;
}
}
// check for invalid arg combinations
@@ -610,18 +619,15 @@ static int parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
return 0;
}
int parse_main_args(int argc, char* argv[], char* envp[], options_t *opt, int *arg_index) {
int parse_main_args(int argc, char* argv[], char* envp[], options_t *opt) {
*opt = s_default_opt;
const argParseOpt parseOpt = {
argDefs,
parse_opt,
reinterpret_cast<parse_function_t>(parse_opt),
0,
"" PACKAGE_NAME,
"[INJECT...]",
"A daemon for communication with eBUS heating systems.",
"Report bugs to " PACKAGE_BUGREPORT " .",
datahandler_getargs(),
opt
datahandler_getargs()
};
char envname[32] = "--"; // needs to cover at least max length of any option name plus "--"
@@ -651,7 +657,7 @@ int parse_main_args(int argc, char* argv[], char* envp[], options_t *opt, int *a
int cnt = pos[1] ? 2 : 1;
if (pos[1] && strlen(*env) < sizeof(envname)-3
&& (strcmp(envopt, "scanconfig") == 0 || strcmp(envopt, "lograwdata") == 0)) {
// only really special case: OPTION_ARG_OPTIONAL with non-empty arg needs to use "=" syntax
// only really special case: af_optional with non-empty arg needs to use "=" syntax
cnt = 1;
strcat(envopt, pos);
}
@@ -666,8 +672,7 @@ int parse_main_args(int argc, char* argv[], char* envp[], options_t *opt, int *a
}
}
*arg_index = -1;
int ret = argParse(&parseOpt, argc, argv, arg_index);
int ret = argParse(&parseOpt, argc, argv, reinterpret_cast<void*>(opt));
if (ret != 0) {
return ret;
}
+1 -1
View File
@@ -140,7 +140,7 @@ void splitFields(const string& str, vector<string>* row);
* @param arg the option argument, or nullptr.
* @param state the parsing state.
*/
static int mqtt_parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
static int mqtt_parse_opt(int key, char *arg, const argParseOpt *parseOpt, void *userArg) {
result_t result = RESULT_OK;
unsigned int value;
switch (key) {
+87 -38
View File
@@ -28,50 +28,50 @@ namespace ebusd {
#define isAlpha(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
void calcCounts(const argDef *argDefs, int &count, int &shortCharsCount, int &shortOptsCount) {
void calcCounts(const argDef *argDefs, int *count, int *shortCharsCount, int *shortOptsCount) {
for (const argDef *arg = argDefs; arg && arg->help; arg++) {
if (!arg->name) {
continue;
}
count++;
(*count)++;
if (!isAlpha(arg->key)) {
continue;
}
shortCharsCount++;
shortOptsCount++;
(*shortCharsCount)++;
(*shortOptsCount)++;
if (arg->valueName) {
shortOptsCount++;
(*shortOptsCount)++;
if (arg->flags & af_optional) {
shortOptsCount++;
(*shortOptsCount)++;
}
}
}
}
void buildOpts(const argDef *argDefs, int &count, int &shortCharsCount, int &shortOptsCount,
void buildOpts(const argDef *argDefs, int *count, int *shortCharsCount, int *shortOptsCount,
struct option *longOpts, char *shortChars, int *shortIndexes, char *shortOpts, int argDefIdx) {
struct option *opt = longOpts+count;
struct option *opt = longOpts+(*count);
for (const argDef *arg = argDefs; arg && arg->help; arg++, argDefIdx++) {
if (!arg->name) {
continue;
}
opt->name = arg->name;
opt->has_arg = arg->valueName ? ((arg->flags & af_optional) ? optional_argument : required_argument) : no_argument;
opt->flag = nullptr;
opt->flag = NULL;
opt->val = argDefIdx;
if (isAlpha(arg->key)) {
shortChars[shortCharsCount] = static_cast<char>(arg->key);
shortIndexes[shortCharsCount++] = count;
shortOpts[shortOptsCount++] = static_cast<char>(arg->key);
shortChars[(*shortCharsCount)] = static_cast<char>(arg->key);
shortIndexes[(*shortCharsCount)++] = *count;
shortOpts[(*shortOptsCount)++] = static_cast<char>(arg->key);
if (arg->valueName) {
shortOpts[shortOptsCount++] = ':';
shortOpts[(*shortOptsCount)++] = ':';
if (arg->flags & af_optional) {
shortOpts[shortOptsCount++] = ':';
shortOpts[(*shortOptsCount)++] = ':';
}
}
}
opt++;
count++;
(*count)++;
}
}
@@ -87,17 +87,17 @@ static const argDef versionArgDefs[] = {
endArgDef
};
int argParse(const argParseOpt *parseOpt, int argc, char **argv, int *argIndex) {
int argParse(const argParseOpt *parseOpt, int argc, char **argv, void* userArg) {
int count = 0, shortCharsCount = 0, shortOptsCount = 0;
if (!(parseOpt->flags & af_noHelp)) {
calcCounts(helpArgDefs, count, shortCharsCount, shortOptsCount);
calcCounts(helpArgDefs, &count, &shortCharsCount, &shortOptsCount);
}
if (!(parseOpt->flags & af_noVersion)) {
calcCounts(versionArgDefs, count, shortCharsCount, shortOptsCount);
calcCounts(versionArgDefs, &count, &shortCharsCount, &shortOptsCount);
}
calcCounts(parseOpt->argDefs, count, shortCharsCount, shortOptsCount);
calcCounts(parseOpt->argDefs, &count, &shortCharsCount, &shortOptsCount);
for (const argParseChildOpt *child = parseOpt->childOpts; child && child->argDefs; child++) {
calcCounts(child->argDefs, count, shortCharsCount, shortOptsCount);
calcCounts(child->argDefs, &count, &shortCharsCount, &shortOptsCount);
}
struct option *longOpts = (struct option*)calloc(count+1, sizeof(struct option)); // room for EOF
char *shortChars = reinterpret_cast<char*>(calloc(shortCharsCount+1, sizeof(char))); // room for \0
@@ -109,18 +109,18 @@ int argParse(const argParseOpt *parseOpt, int argc, char **argv, int *argIndex)
shortOpts[shortOptsCount++] = '+'; // posix mode to stop at first non-option
shortOpts[shortOptsCount++] = ':'; // return ':' for missing option
if (!(parseOpt->flags & af_noHelp)) {
buildOpts(helpArgDefs, count, shortCharsCount, shortOptsCount, longOpts, shortChars,
buildOpts(helpArgDefs, &count, &shortCharsCount, &shortOptsCount, longOpts, shortChars,
shortIndexes, shortOpts, 0xff00);
}
if (!(parseOpt->flags & af_noVersion)) {
buildOpts(versionArgDefs, count, shortCharsCount, shortOptsCount, longOpts, shortChars,
buildOpts(versionArgDefs, &count, &shortCharsCount, &shortOptsCount, longOpts, shortChars,
shortIndexes, shortOpts, 0xff01);
}
buildOpts(parseOpt->argDefs, count, shortCharsCount, shortOptsCount, longOpts, shortChars,
buildOpts(parseOpt->argDefs, &count, &shortCharsCount, &shortOptsCount, longOpts, shortChars,
shortIndexes, shortOpts, 0);
int children = 0;
for (const argParseChildOpt *child = parseOpt->childOpts; child && child->argDefs; child++) {
buildOpts(child->argDefs, count, shortCharsCount, shortOptsCount, longOpts, shortChars,
buildOpts(child->argDefs, &count, &shortCharsCount, &shortOptsCount, longOpts, shortChars,
shortIndexes, shortOpts, 0x100*(++children));
}
optind = 1; // setting to 0 does not work
@@ -177,16 +177,49 @@ int argParse(const argParseOpt *parseOpt, int argc, char **argv, int *argIndex)
parser = parseOpt->parser;
}
const argDef *arg = argDefs + (val & 0xff);
c = parser(arg->key, optarg, parseOpt);
c = parser(arg->key, optarg, parseOpt, userArg);
if (c != 0) {
ret = c;
break;
}
}
if (ret == 0) {
// check for positionals
for (const argDef *arg = parseOpt->argDefs; arg && arg->help; arg++) {
if (arg->name || !arg->valueName) {
continue; // short/long arg or group
}
if (optind < argc) {
int key = arg->key;
do {
c = parseOpt->parser(key, argv[optind], parseOpt, userArg);
if (c != 0) {
ret = c;
break;
}
if (optind+1 >= argc || !(arg->flags & af_multiple)) {
break;
}
key++;
optind++;
} while (true);
if (ret != 0) {
break;
}
} else if (!(arg->flags & af_optional)) {
ret = ':'; // missing argument
fprintf(stderr, "missing argument\n");
break;
}
optind++;
}
if (ret == 0 && optind < argc) {
ret = '!'; // extra unexpected argument
fprintf(stderr, "extra argument %s\n", argv[optind]);
}
}
if (ret == '?') {
argHelp(parseOpt);
} else if (argIndex && optind < argc) {
*argIndex = optind;
argHelp(argv[0], parseOpt);
}
free(longOpts);
free(shortChars);
@@ -270,7 +303,7 @@ size_t calcIndent(const argDef *argDefs) {
void printArgs(const argDef *argDefs, size_t indent) {
for (const argDef *arg = argDefs; arg && arg->help; arg++) {
if (!arg->name) {
if (!arg->name && !arg->valueName) {
if (*arg->help) {
printf("\n %s\n", arg->help);
} else {
@@ -284,15 +317,21 @@ void printArgs(const argDef *argDefs, size_t indent) {
} else {
printf(" ");
}
printf(" --%s", arg->name);
size_t taken = 2 + 3 + 3 + strlen(arg->name);
size_t taken = 2 + 3 + 3;
if (arg->name) {
printf(" --%s", arg->name);
taken += strlen(arg->name);
} else {
printf(" ");
}
if (arg->valueName) {
taken += 1 + strlen(arg->valueName);
bool multi = arg->flags & af_multiple;
taken += (arg->name ? 1 : 0) + strlen(arg->valueName) + (multi ? 3 : 0);
if (arg->flags & af_optional) {
printf("[=%s]", arg->valueName);
printf("[%s%s%s]", arg->name ? "=" : "", arg->valueName, multi ? "..." : "");
taken += 2;
} else {
printf("=%s", arg->valueName);
printf("%s%s%s", arg->name ? "=" : "", arg->valueName, multi ? "..." : "");
}
}
if (taken > indent) {
@@ -305,7 +344,7 @@ void printArgs(const argDef *argDefs, size_t indent) {
}
}
void argHelp(const argParseOpt *parseOpt) {
void argHelp(const char* name, const argParseOpt *parseOpt) {
size_t indent = calcIndent(parseOpt->argDefs);
if (indent < MAX_INDENT) {
for (const argParseChildOpt *child = parseOpt->childOpts; child && child->argDefs; child++) {
@@ -323,9 +362,19 @@ void argHelp(const argParseOpt *parseOpt) {
} else if (indent < MIN_INDENT) {
indent = MIN_INDENT;
}
printf("Usage: %s [OPTION...] %s\n",
parseOpt->name,
parseOpt->positional ? parseOpt->positional : "");
printf("Usage: %s [OPTION...]", basename(name));
for (const argDef *arg = parseOpt->argDefs; arg && arg->help; arg++) {
if (arg->name || !arg->valueName) {
continue;
}
bool multi = arg->flags & af_multiple;
if (arg->flags & af_optional) {
printf(" [%s%s]", arg->valueName, multi ? "..." : "");
} else {
printf(" %s%s", arg->valueName, multi ? "..." : "");
}
}
printf("\n");
wrap(parseOpt->help, 0, 0);
printArgs(parseOpt->argDefs, indent);
for (const argParseChildOpt *child = parseOpt->childOpts; child && child->argDefs; child++) {
+14 -14
View File
@@ -26,15 +26,16 @@ namespace ebusd {
/** the available arg flags. */
enum ArgFlag {
af_optional = 1<<0, //!< optional argument value
af_noHelp = 1<<1, //!< do not include -?/--help option
af_noVersion = 1<<2, //!< do not include -V/--version option
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
};
/** Definition of a single argument. */
typedef struct argDef {
const char* name; //!< the (long) name of the argument, or nullptr for a group header
const char* name; //!< the (long) name of the argument, or nullptr for a group header or positional
int key; //!< the argument key, also used as short name if alphabetic or the question mark
const char* valueName; //!< the optional argument value name
const char* valueName; //!< the optional argument value name, or nullptr for group header or argument without value name
int flags; //!< flags for the argument, bit combination of @a ArgFlag
const char* help; //!< help text (mandatory)
} argDef;
@@ -43,12 +44,13 @@ struct argParseOpt;
/**
* Function to be called for each argument.
* @param key the argument key as defined.
* @param key the argument key as defined. for positional arguments with multiple flag this will be increased with each call.
* @param arg the argument value, or nullptr.
* @param parseOpt ppointer to the @a argParseOpt structure.
* @param parseOpt pointer to the @a argParseOpt structure.
* @param userArg pointer to user argument.
* @return 0 on success, non-zero otherwise.
*/
typedef int (*parse_function_t)(int key, char *arg, const struct argParseOpt *parseOpt);
typedef int (*parse_function_t)(int key, char *arg, const struct argParseOpt *parseOpt, void *userArg);
/** Options for child definitions. */
typedef struct argParseChildOpt {
@@ -61,12 +63,9 @@ typedef struct argParseOpt {
const argDef *argDefs; //!< pointer to the argument defintions (last one needs to have nullptr help as end sign)
parse_function_t parser; //!< parse function to use
int flags; //!< flags for the parser, bit combination of @a ArgFlag
const char* name; //!< name of the program parsed
const char* positional; //!< help text for optional positional argument
const char* help; //!< help text for the program (second line of help output)
const char* suffix; //!< optional help suffix text
const argParseChildOpt *childOpts; //!< optional child definitions
void* userArg; //!< optional user argument
} argParseOpt;
/**
@@ -74,17 +73,18 @@ typedef struct argParseOpt {
* @param parseOpt pointer to the @a argParseOpt structure.
* @param argc the argument count (including the full program name in index 0).
* @param argv the argument values (including the full program name in index 0).
* @param argIndex optional pointer for storing the index to the first non-argument found in argv.
* @param userArg pointer to user argument to pass to parser.
* @return 0 on success, '!' for an invalid argument value, ':' for a missing argument value,
* '?' when "-?" was given, or the result of the parse function if non-zero.
*/
int argParse(const argParseOpt *parseOpt, int argc, char **argv, int *argIndex);
int argParse(const argParseOpt *parseOpt, int argc, char **argv, void *userArg);
/**
* Print the help text.
* @param parseOpt ppointer to the @a argParseOpt structure.
* @param name the name of the program.
* @param parseOpt pointer to the @a argParseOpt structure.
*/
void argHelp(const argParseOpt *parseOpt);
void argHelp(const char* name, const argParseOpt *parseOpt);
/**
* Convenience macro to print an error message to stderr.
+12 -17
View File
@@ -47,7 +47,6 @@ struct options {
uint16_t timeout; //!< ebusd connect/send/receive timeout
bool errorResponse; //!< non-zero exit on error response
char* const *args; //!< arguments to pass to ebusd
unsigned int argCount; //!< number of arguments to pass to ebusd
};
@@ -58,7 +57,6 @@ static struct options opt = {
60, // timeout
false, // non-zero exit on error response
nullptr, // args
0 // argCount
};
@@ -71,6 +69,8 @@ static const argDef argDefs[] = {
", 0 for none [60]"},
{"error", 'e', nullptr, 0, "Exit non-zero if the connection was fine but the response indicates non-success"},
{nullptr, 0x100, "COMMAND", af_optional|af_multiple, "COMMAND (and arguments) to send to " PACKAGE "."},
{nullptr, 0, nullptr, 0, nullptr},
};
@@ -80,8 +80,7 @@ static const argDef argDefs[] = {
* @param arg the option argument, or nullptr.
* @param parseOpt the parse options.
*/
static int parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
struct options *opt = (struct options*)parseOpt->userArg;
static int parse_opt(int key, char *arg, const argParseOpt *parseOpt, struct options *opt) {
char* strEnd = nullptr;
unsigned int value;
switch (key) {
@@ -113,7 +112,11 @@ static int parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
opt->errorResponse = true;
break;
default:
return ESRCH;
if (key >= 0x100) {
opt->argCount++;
} else {
return ESRCH;
}
}
return 0;
}
@@ -344,18 +347,14 @@ bool connect(const char* host, uint16_t port, uint16_t timeout, char* const *arg
int main(int argc, char* argv[]) {
argParseOpt parseOpt = {
argDefs,
parse_opt,
reinterpret_cast<parse_function_t>(parse_opt),
af_noVersion,
"ebusctl",
"[COMMAND [CMDOPT...]]",
"Client for accessing " PACKAGE " via TCP.",
"If given, send COMMAND together with CMDOPT options to " PACKAGE ".\n"
"If given, send COMMAND together with arguments to " PACKAGE ".\n"
"Use 'help' as COMMAND for help on available " PACKAGE " commands.",
nullptr,
&opt
};
int arg_index = -1;
switch (argParse(&parseOpt, argc, argv, &arg_index)) {
switch (argParse(&parseOpt, argc, argv, &opt)) {
case 0: // OK
break;
case '?': // help printed
@@ -363,12 +362,8 @@ int main(int argc, char* argv[]) {
default:
return EINVAL;
}
if (arg_index >= 0) {
opt.args = argv + arg_index;
opt.argCount = argc - arg_index;
}
bool success = connect(opt.server, opt.port, opt.timeout, opt.args, opt.argCount);
bool success = connect(opt.server, opt.port, opt.timeout, argv + argc - opt.argCount, opt.argCount);
exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
}
+13 -23
View File
@@ -62,6 +62,7 @@ static struct options opt = {
static const ebusd::argDef argDefs[] = {
{"device", 'd', "DEV", 0, "Write to DEV (serial device) [/dev/ttyUSB60]"},
{"time", 't', "USEC", 0, "Delay each byte by USEC us [10000]"},
{nullptr, 0x100, "DUMPFILE", af_optional, "Dump file to read [/tmp/ebus_dump.bin]"},
{nullptr, 0, nullptr, 0, nullptr},
};
@@ -72,8 +73,7 @@ static const ebusd::argDef argDefs[] = {
* @param arg the option argument, or nullptr.
* @param parseOpt the parse options.
*/
static int parse_opt(int key, char *arg, const ebusd::argParseOpt *parseOpt) {
struct options *opt = (struct options*)parseOpt->userArg;
static int parse_opt(int key, char *arg, const ebusd::argParseOpt *parseOpt, struct options *opt) {
char* strEnd = nullptr;
switch (key) {
// Device settings:
@@ -91,6 +91,14 @@ static int parse_opt(int key, char *arg, const ebusd::argParseOpt *parseOpt) {
return EINVAL;
}
break;
case 0x100: // DUMPFILE
if (arg[0] == 0 || strcmp("/", arg) == 0) {
argParseError(parseOpt, "invalid dumpfile");
return EINVAL;
}
opt->dumpFile = arg;
break;
default:
return ESRCH;
}
@@ -107,13 +115,9 @@ static int parse_opt(int key, char *arg, const ebusd::argParseOpt *parseOpt) {
int main(int argc, char* argv[]) {
ebusd::argParseOpt parseOpt = {
argDefs,
parse_opt,
reinterpret_cast<parse_function_t>(parse_opt),
af_noVersion,
"ebusfeed",
"[DUMPFILE]",
"Feed data from an " PACKAGE " DUMPFILE to a serial device.",
"With no DUMPFILE, /tmp/ebus_dump.bin is used.\n"
"\n"
"Example for setting up two pseudo terminals with 'socat':\n"
" 1. 'socat -d -d pty,raw,echo=0 pty,raw,echo=0'\n"
" 2. create symbol links to appropriate devices, e.g.\n"
@@ -122,10 +126,8 @@ int main(int argc, char* argv[]) {
" 3. start " PACKAGE ": '" PACKAGE " -f -d /dev/ttyUSB20 --nodevicecheck'\n"
" 4. start ebusfeed: 'ebusfeed /path/to/ebus_dump.bin'",
nullptr,
&opt
};
int arg_index = -1;
switch (ebusd::argParse(&parseOpt, argc, argv, &arg_index)) {
switch (ebusd::argParse(&parseOpt, argc, argv, &opt)) {
case 0: // OK
break;
case '?': // help printed
@@ -133,20 +135,8 @@ int main(int argc, char* argv[]) {
default:
return EINVAL;
}
if (arg_index >= 0) {
if (argv[arg_index][0] == 0 || strcmp("/", argv[arg_index]) == 0) {
argParseError(parseOpt, "invalid dumpfile");
return EINVAL;
}
if (arg_index != argc -1) {
// more than one arg
argParseError(parseOpt, "multiple dumpfile");
return EINVAL;
}
opt.dumpFile = argv[arg_index];
}
Device* device = Device::create(opt.device, false, false, false);
Device* device = Device::create(opt.device, 0, false);
if (device == nullptr) {
cout << "unable to create device " << opt.device << endl;
return EINVAL;
+13 -11
View File
@@ -65,6 +65,7 @@ static const ebusd::argDef argDefs[] = {
{nullptr, 0, nullptr, 0, "Tool options:"},
{"verbose", 'v', nullptr, 0, "enable verbose output"},
{"slow", 's', nullptr, 0, "low speed mode for transfer (115kBd instead of 921kBd)"},
{nullptr, 0x100, "PORT", ebusd::af_optional, "port to connect to"},
{nullptr, 0, nullptr, 0, nullptr},
};
@@ -88,6 +89,7 @@ static bool setVariantForced = false;
static char* flashFile = nullptr;
static bool reset = false;
static bool lowSpeed = false;
static const char* portArg = nullptr;
bool parseByte(const char *arg, uint8_t minValue, uint8_t maxValue, uint8_t *result) {
char* strEnd = nullptr;
@@ -125,7 +127,7 @@ bool parseShort(const char *arg, uint16_t minValue, uint16_t maxValue, uint16_t
* @param arg the option argument, or nullptr.
* @param parseOpt the parse options.
*/
static int parse_opt(int key, char *arg, const ebusd::argParseOpt *parseOpt) {
static int parse_opt(int key, char *arg, const ebusd::argParseOpt *parseOpt, void *userArg) {
char *ip = nullptr, *part = nullptr;
int pos = 0, sum = 0;
struct stat st;
@@ -327,6 +329,9 @@ static int parse_opt(int key, char *arg, const ebusd::argParseOpt *parseOpt) {
case 's': // --slow
lowSpeed = true;
break;
case 0x100: // PORT
portArg = arg;
break;
default:
return ESRCH;
}
@@ -1161,10 +1166,8 @@ int run(int fd);
int main(int argc, char* argv[]) {
ebusd::argParseOpt parseOpt = {
argDefs,
parse_opt,
reinterpret_cast<ebusd::parse_function_t>(parse_opt),
ebusd::af_noVersion,
"ebuspicloader",
"[PORT]",
"A tool for loading firmware to the eBUS adapter PIC and configure adjustable settings.",
"PORT is either the serial port to use (e.g. "
#ifdef __CYGWIN__
@@ -1174,11 +1177,9 @@ int main(int argc, char* argv[]) {
#endif
") that also supports a trailing wildcard '*' for testing"
" multiple ports, or a network port as \"ip:port\" for use with e.g. socat or ebusd-esp in PIC pass-through mode.",
nullptr,
nullptr
};
int arg_index = -1;
switch (ebusd::argParse(&parseOpt, argc, argv, &arg_index)) {
switch (ebusd::argParse(&parseOpt, argc, argv, nullptr)) {
case 0: // OK
break;
case '?': // help printed
@@ -1187,20 +1188,21 @@ int main(int argc, char* argv[]) {
return EINVAL;
}
bool forceHelp = false;
if (setIp != setMask || (setMacFromIp && !setIp)) {
std::cerr << "incomplete IP arguments" << std::endl;
arg_index = argc; // force help output
forceHelp = true;
}
if (arg_index < 0 || argc-arg_index < 1) {
if (forceHelp || !portArg) {
if (flashFile) {
printFileChecksum();
exit(EXIT_SUCCESS);
} else {
ebusd::argHelp(&parseOpt);
ebusd::argHelp(argv[0], &parseOpt);
exit(EXIT_FAILURE);
}
}
std::string port = argv[arg_index];
std::string port = portArg;
std::string::size_type pos = port.find('*');
if (pos == std::string::npos || pos != port.length()-1) {
int fd;