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