diff --git a/src/ebusd/knxhandler.cpp b/src/ebusd/knxhandler.cpp index 2e73a8d1..912482e8 100644 --- a/src/ebusd/knxhandler.cpp +++ b/src/ebusd/knxhandler.cpp @@ -83,7 +83,7 @@ static vector* 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) { diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index 5995c8ee..c404edf2 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -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); diff --git a/src/ebusd/main.h b/src/ebusd/main.h index 03543e24..2935b1ce 100755 --- a/src/ebusd/main.h +++ b/src/ebusd/main.h @@ -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 diff --git a/src/ebusd/main_args.cpp b/src/ebusd/main_args.cpp index be8a0da1..61d39b0b 100755 --- a/src/ebusd/main_args.cpp +++ b/src/ebusd/main_args.cpp @@ -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_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(opt)); if (ret != 0) { return ret; } diff --git a/src/ebusd/mqtthandler.cpp b/src/ebusd/mqtthandler.cpp index 51aedd84..459c99d1 100755 --- a/src/ebusd/mqtthandler.cpp +++ b/src/ebusd/mqtthandler.cpp @@ -140,7 +140,7 @@ void splitFields(const string& str, vector* 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) { diff --git a/src/lib/utils/arg.cpp b/src/lib/utils/arg.cpp index 7653271f..fc8e4cdc 100755 --- a/src/lib/utils/arg.cpp +++ b/src/lib/utils/arg.cpp @@ -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(arg->key); - shortIndexes[shortCharsCount++] = count; - shortOpts[shortOptsCount++] = static_cast(arg->key); + shortChars[(*shortCharsCount)] = static_cast(arg->key); + shortIndexes[(*shortCharsCount)++] = *count; + shortOpts[(*shortOptsCount)++] = static_cast(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(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++) { diff --git a/src/lib/utils/arg.h b/src/lib/utils/arg.h index 5bc8963f..8ef28961 100755 --- a/src/lib/utils/arg.h +++ b/src/lib/utils/arg.h @@ -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. diff --git a/src/tools/ebusctl.cpp b/src/tools/ebusctl.cpp index 42d8ad22..95b240d3 100755 --- a/src/tools/ebusctl.cpp +++ b/src/tools/ebusctl.cpp @@ -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_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); } diff --git a/src/tools/ebusfeed.cpp b/src/tools/ebusfeed.cpp index f423611f..fbc89339 100755 --- a/src/tools/ebusfeed.cpp +++ b/src/tools/ebusfeed.cpp @@ -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_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; diff --git a/src/tools/ebuspicloader.cpp b/src/tools/ebuspicloader.cpp index 36dae377..ab59bb64 100644 --- a/src/tools/ebuspicloader.cpp +++ b/src/tools/ebuspicloader.cpp @@ -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(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;