get rid of argp dependency
This commit is contained in:
@@ -74,18 +74,6 @@ check_function_exists(ppoll HAVE_PPOLL)
|
||||
check_include_file(linux/serial.h HAVE_LINUX_SERIAL -DHAVE_LINUX_SERIAL=1)
|
||||
check_include_file(dev/usb/uftdiio.h HAVE_FREEBSD_UFTDI -DHAVE_FREEBSD_UFTDI=1)
|
||||
|
||||
check_function_exists(argp_parse HAVE_ARGP_H)
|
||||
if(NOT HAVE_ARGP_H)
|
||||
if(NOT ARGP_HINTS)
|
||||
set(ARGP_HINTS ~/argp-standalone/src)
|
||||
endif(NOT ARGP_HINTS)
|
||||
find_library(LIB_ARGP NAMES argp argp-standalone HINTS ARGP_HINTS)
|
||||
if (NOT LIB_ARGP)
|
||||
message(FATAL_ERROR "argp library not available")
|
||||
endif(NOT LIB_ARGP)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} ${LIB_ARGP}")
|
||||
endif(NOT HAVE_ARGP_H)
|
||||
|
||||
option(coverage "enable code coverage tracking." OFF)
|
||||
if(NOT coverage STREQUAL OFF)
|
||||
add_definitions(-g -O0 --coverage -Wall)
|
||||
|
||||
@@ -61,7 +61,7 @@ Building ebusd from the source requires the following packages and/or features:
|
||||
* g++ with C++11 support (>=4.8.1)
|
||||
* make
|
||||
* kernel with pselect or ppoll support
|
||||
* glibc with argp support or argp-standalone
|
||||
* glibc with getopt_long support
|
||||
* libmosquitto-dev for MQTT support
|
||||
* libssl-dev for SSL support
|
||||
|
||||
|
||||
@@ -40,9 +40,6 @@
|
||||
/* Defined if syslog.h is available. */
|
||||
#cmakedefine HAVE_SYSLOG_H
|
||||
|
||||
/* Defined if argp.h is available. */
|
||||
#cmakedefine HAVE_ARGP_H
|
||||
|
||||
/* The name of package. */
|
||||
#cmakedefine PACKAGE "${PACKAGE_NAME}"
|
||||
|
||||
|
||||
@@ -48,14 +48,6 @@ if test "x$with_contrib" != "xno"; then
|
||||
fi
|
||||
AC_ARG_WITH(ebusfeed, AS_HELP_STRING([--with-ebusfeed], [enable inclusion of ebusfeed tool]), [with_ebusfeed=yes], [])
|
||||
AM_CONDITIONAL([WITH_EBUSFEED], [test "x$with_ebusfeed" == "xyes"])
|
||||
AC_ARG_WITH(argp-lib, AS_HELP_STRING([--with-argp-lib=PATH], [path to argp libraries]), [LDFLAGS+="-L$with_argp_lib"])
|
||||
AC_ARG_WITH(argp-include, AS_HELP_STRING([--with-argp-include=PATH], [path to argp includes]), [CXXFLAGS+="-I$with_argp_include"])
|
||||
AC_CHECK_FUNC([argp_parse], [have_argp=yes], AC_CHECK_LIB([argp], [argp_parse], [have_argp=yes; LIBS="-largp $LIBS"], [have_argp=no]))
|
||||
if test "x$have_argp" = "xyes"; then
|
||||
AC_CHECK_HEADER([argp.h], AC_DEFINE([HAVE_ARGP_H], [1], [Defined if argp.h is available.]), AC_MSG_ERROR([argp.h not found]))
|
||||
else
|
||||
AC_MSG_ERROR([argp library not found, specify argp-standalone location in --with-argp-lib= and --with-argp-include= options.])
|
||||
fi
|
||||
AC_ARG_WITH(mqtt, AS_HELP_STRING([--without-mqtt], [disable support for MQTT handling]), [], [with_mqtt=yes])
|
||||
if test "x$with_mqtt" != "xno"; then
|
||||
AC_CHECK_LIB([mosquitto], [mosquitto_lib_init],
|
||||
|
||||
@@ -8,7 +8,7 @@ url="https://github.com/john30/ebusd"
|
||||
# Upstream only supports these archs.
|
||||
arch="x86 x86_64 aarch64 armhf armv7"
|
||||
license="GPL-3.0-only"
|
||||
makedepends="argp-standalone cmake mosquitto-dev openssl-dev"
|
||||
makedepends="cmake mosquitto-dev openssl-dev"
|
||||
source="$pkgname-$pkgver.tar.gz::https://github.com/john30/${pkgname}/archive/refs/tags/${pkgver}.tar.gz"
|
||||
|
||||
build() {
|
||||
|
||||
@@ -33,7 +33,7 @@ include_directories(../lib/ebus)
|
||||
include_directories(../lib/utils)
|
||||
|
||||
add_executable(ebusd ${ebusd_SOURCES})
|
||||
target_link_libraries(ebusd utils ebus pthread rt ${LIB_ARGP} ${ebusd_LIBS})
|
||||
target_link_libraries(ebusd utils ebus pthread rt ${ebusd_LIBS})
|
||||
|
||||
install(TARGETS ebusd EXPORT ebusd DESTINATION usr/bin)
|
||||
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
/** the final @a argp_child structure. */
|
||||
static const struct argp_child g_last_argp_child = {nullptr, 0, nullptr, 0};
|
||||
/** the final @a argParseChildOpt structure. */
|
||||
static const argParseChildOpt g_last_arg_child = {nullptr, nullptr};
|
||||
|
||||
/** the list of @a argp_child structures. */
|
||||
static struct argp_child g_argp_children[
|
||||
/** the list of @a argParseChildOpt structures. */
|
||||
static argParseChildOpt g_arg_children[
|
||||
1
|
||||
#ifdef HAVE_MQTT
|
||||
+1
|
||||
@@ -44,17 +44,17 @@ static struct argp_child g_argp_children[
|
||||
#endif
|
||||
];
|
||||
|
||||
const struct argp_child* datahandler_getargs() {
|
||||
const argParseChildOpt* datahandler_getargs() {
|
||||
size_t count = 0;
|
||||
#ifdef HAVE_MQTT
|
||||
g_argp_children[count++] = *mqtthandler_getargs();
|
||||
g_arg_children[count++] = *mqtthandler_getargs();
|
||||
#endif
|
||||
#ifdef HAVE_KNX
|
||||
g_argp_children[count++] = *knxhandler_getargs();
|
||||
g_arg_children[count++] = *knxhandler_getargs();
|
||||
#endif
|
||||
if (count > 0) {
|
||||
g_argp_children[count] = g_last_argp_child;
|
||||
return g_argp_children;
|
||||
g_arg_children[count] = g_last_arg_child;
|
||||
return g_arg_children;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
#ifndef EBUSD_DATAHANDLER_H_
|
||||
#define EBUSD_DATAHANDLER_H_
|
||||
|
||||
#include <argp.h>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include "ebusd/bushandler.h"
|
||||
#include "lib/ebus/message.h"
|
||||
#include "lib/utils/arg.h"
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
@@ -49,10 +49,10 @@ enum scanStatus_t {
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for getting the argp definition for all known @a DataHandler instances.
|
||||
* @return a pointer to the argp_child structure, or nullptr.
|
||||
* Helper function for getting the arg definition for all known @a DataHandler instances.
|
||||
* @return a pointer to the child argument options, or nullptr.
|
||||
*/
|
||||
const struct argp_child* datahandler_getargs();
|
||||
const argParseChildOpt* datahandler_getargs();
|
||||
|
||||
/**
|
||||
* Registration function that is called once during initialization.
|
||||
|
||||
+14
-17
@@ -52,9 +52,9 @@ using std::dec;
|
||||
#define O_VAR (O_INT-1)
|
||||
|
||||
/** the definition of the KNX arguments. */
|
||||
static const struct argp_option g_knx_argp_options[] = {
|
||||
static const argDef g_knx_argDefs[] = {
|
||||
{nullptr, 0, nullptr, 0, "KNX options:", 1 },
|
||||
{"knxurl", O_URL, "URL", OPTION_ARG_OPTIONAL, "URL to open (i.e. \"[multicast][@interface]\" for KNXnet/IP"
|
||||
{"knxurl", O_URL, "URL", af_optional, "URL to open (i.e. \"[multicast][@interface]\" for KNXnet/IP"
|
||||
#ifdef HAVE_KNXD
|
||||
" or \"ip:host[:port]\" / \"local:/socketpath\" for knxd"
|
||||
#endif
|
||||
@@ -79,11 +79,11 @@ static vector<string>* g_integrationVars = nullptr; //!< the integration settin
|
||||
|
||||
/**
|
||||
* The KNX argument parsing function.
|
||||
* @param key the key from @a g_knx_argp_options.
|
||||
* @param key the key from @a g_knx_arg_options.
|
||||
* @param arg the option argument, or nullptr.
|
||||
* @param state the parsing state.
|
||||
*/
|
||||
static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
static int knx_parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
|
||||
result_t result;
|
||||
unsigned int value;
|
||||
switch (key) {
|
||||
@@ -94,12 +94,12 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_AGR: // --knxrage=5
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid knxrage value");
|
||||
argParseError(parseOpt, "invalid knxrage value");
|
||||
return EINVAL;
|
||||
}
|
||||
value = parseInt(arg, 10, 0, 99999999, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid knxrage");
|
||||
argParseError(parseOpt, "invalid knxrage");
|
||||
return EINVAL;
|
||||
}
|
||||
g_maxReadAge = value;
|
||||
@@ -107,12 +107,12 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_AGW: // --knxwage=5
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid knxwage value");
|
||||
argParseError(parseOpt, "invalid knxwage value");
|
||||
return EINVAL;
|
||||
}
|
||||
value = parseInt(arg, 10, 0, 99999999, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid knxwage");
|
||||
argParseError(parseOpt, "invalid knxwage");
|
||||
return EINVAL;
|
||||
}
|
||||
g_maxWriteAge = value;
|
||||
@@ -120,7 +120,7 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_INT: // --knxint=/etc/ebusd/knx.cfg
|
||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid knxint file");
|
||||
argParseError(parseOpt, "invalid knxint file");
|
||||
return EINVAL;
|
||||
}
|
||||
g_integrationFile = arg;
|
||||
@@ -129,7 +129,7 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_VAR: // --knxvar=NAME=VALUE[,NAME=VALUE]*
|
||||
{
|
||||
if (arg == nullptr || arg[0] == 0 || !strchr(arg, '=')) {
|
||||
argp_error(state, "invalid knxvar");
|
||||
argParseError(parseOpt, "invalid knxvar");
|
||||
return EINVAL;
|
||||
}
|
||||
if (!g_integrationVars) {
|
||||
@@ -143,18 +143,15 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
}
|
||||
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
return ESRCH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct argp g_knx_argp = { g_knx_argp_options, knx_parse_opt, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr };
|
||||
static const struct argp_child g_knx_argp_child = {&g_knx_argp, 0, "", 1};
|
||||
static const argParseChildOpt g_knx_arg_child = { g_knx_argDefs, knx_parse_opt };
|
||||
|
||||
|
||||
const struct argp_child* knxhandler_getargs() {
|
||||
return &g_knx_argp_child;
|
||||
const argParseChildOpt* knxhandler_getargs() {
|
||||
return &g_knx_arg_child;
|
||||
}
|
||||
|
||||
bool knxhandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages,
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "lib/ebus/message.h"
|
||||
#include "lib/ebus/stringhelper.h"
|
||||
#include "lib/knx/knx.h"
|
||||
#include "lib/utils/arg.h"
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
@@ -41,10 +42,10 @@ using std::string;
|
||||
using std::vector;
|
||||
|
||||
/**
|
||||
* Helper function for getting the argp definition for KNX.
|
||||
* @return a pointer to the argp_child structure.
|
||||
* Helper function for getting the arg definition for KNX.
|
||||
* @return a pointer to the child argument options, or nullptr.
|
||||
*/
|
||||
const struct argp_child* knxhandler_getargs();
|
||||
const argParseChildOpt* knxhandler_getargs();
|
||||
|
||||
/**
|
||||
* Registration function that is called once during initialization.
|
||||
|
||||
+81
-76
@@ -23,7 +23,6 @@
|
||||
#include "ebusd/main.h"
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <argp.h>
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
@@ -32,17 +31,11 @@
|
||||
#include <vector>
|
||||
#include "ebusd/mainloop.h"
|
||||
#include "ebusd/network.h"
|
||||
#include "lib/utils/arg.h"
|
||||
#include "lib/utils/log.h"
|
||||
#include "lib/utils/httpclient.h"
|
||||
#include "ebusd/scan.h"
|
||||
|
||||
|
||||
/** the version string of the program. */
|
||||
const char *argp_program_version = "" PACKAGE_STRING "." REVISION "";
|
||||
|
||||
/** the report bugs to address of the program. */
|
||||
const char *argp_program_bug_address = "" PACKAGE_BUGREPORT "";
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
using std::dec;
|
||||
@@ -146,10 +139,6 @@ static string s_configPath = CONFIG_PATH;
|
||||
/** whether scanConfig or configPath were set by arguments. */
|
||||
static bool s_scanConfigOrPathSet = false;
|
||||
|
||||
/** the documentation of the program. */
|
||||
static const char argpdoc[] =
|
||||
"A daemon for communication with eBUS heating systems.";
|
||||
|
||||
#define O_INISND -2
|
||||
#define O_DEVLAT (O_INISND-1)
|
||||
#define O_SCNRET (O_DEVLAT-1)
|
||||
@@ -187,7 +176,7 @@ static const char argpdoc[] =
|
||||
#define O_DMPFLU (O_DMPSIZ-1)
|
||||
|
||||
/** the definition of the known program arguments. */
|
||||
static const struct argp_option argpoptions[] = {
|
||||
static const argDef argDefs[] = {
|
||||
{nullptr, 0, nullptr, 0, "Device options:", 1 },
|
||||
{"device", 'd', "DEV", 0, "Use DEV as eBUS device ("
|
||||
"prefix \"ens:\" for enhanced high speed device or "
|
||||
@@ -203,7 +192,7 @@ static const struct argp_option argpoptions[] = {
|
||||
{nullptr, 0, nullptr, 0, "Message configuration options:", 2 },
|
||||
{"configpath", 'c', "PATH", 0, "Read CSV config files from PATH (local folder or HTTPS URL) ["
|
||||
CONFIG_PATH "]", 0 },
|
||||
{"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan ADDR: "
|
||||
{"scanconfig", 's', "ADDR", af_optional, "Pick CSV config files matching initial scan ADDR: "
|
||||
"empty for broadcast ident message (default when configpath is not given), "
|
||||
"\"none\" for no initial scan message, "
|
||||
"\"full\" for full scan, "
|
||||
@@ -215,11 +204,11 @@ static const struct argp_option argpoptions[] = {
|
||||
{"configlang", O_CFGLNG, "LANG", 0,
|
||||
"Prefer LANG in multilingual configuration files [system default language]", 0 },
|
||||
{"checkconfig", O_CHKCFG, nullptr, 0, "Check config files, then stop", 0 },
|
||||
{"dumpconfig", O_DMPCFG, "FORMAT", OPTION_ARG_OPTIONAL,
|
||||
{"dumpconfig", O_DMPCFG, "FORMAT", af_optional,
|
||||
"Check and dump config files in FORMAT (\"json\" or \"csv\"), then stop", 0 },
|
||||
{"dumpconfigto", O_DMPCTO, "FILE", 0, "Dump config files to FILE", 0 },
|
||||
{"pollinterval", O_POLINT, "SEC", 0, "Poll for data every SEC seconds (0=disable) [5]", 0 },
|
||||
{"inject", 'i', "stop", OPTION_ARG_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", 0 },
|
||||
#ifdef HAVE_SSL
|
||||
{"cafile", O_CAFILE, "FILE", 0, "Use CA FILE for checking certificates (uses defaults,"
|
||||
@@ -261,7 +250,7 @@ static const struct argp_option argpoptions[] = {
|
||||
" [notice]", 0 },
|
||||
|
||||
{nullptr, 0, nullptr, 0, "Raw logging options:", 6 },
|
||||
{"lograwdata", O_RAW, "bytes", OPTION_ARG_OPTIONAL,
|
||||
{"lograwdata", O_RAW, "bytes", af_optional,
|
||||
"Log messages or all received/sent bytes on the bus", 0 },
|
||||
{"lograwdatafile", O_RAWFIL, "FILE", 0, "Write raw log to FILE [" PACKAGE_LOGFILE "]", 0 },
|
||||
{"lograwdatasize", O_RAWSIZ, "SIZE", 0, "Make raw log file no larger than SIZE kB [100]", 0 },
|
||||
@@ -277,12 +266,12 @@ static const struct argp_option argpoptions[] = {
|
||||
|
||||
/**
|
||||
* The program argument parsing function.
|
||||
* @param key the key from @a argpoptions.
|
||||
* @param key the key from @a argDefs.
|
||||
* @param arg the option argument, or nullptr.
|
||||
* @param state the parsing state.
|
||||
* @param parseOpt the parse options.
|
||||
*/
|
||||
error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
struct options *opt = (struct options*)state->input;
|
||||
static int parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
|
||||
struct options *opt = (struct options*)parseOpt->userArg;
|
||||
result_t result = RESULT_OK;
|
||||
unsigned int value;
|
||||
|
||||
@@ -290,7 +279,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
// Device options:
|
||||
case 'd': // --device=/dev/ttyUSB0
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid device");
|
||||
argParseError(parseOpt, "invalid device");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->device = arg;
|
||||
@@ -307,7 +296,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_DEVLAT: // --latency=10
|
||||
value = parseInt(arg, 10, 0, 200000, &result); // backwards compatible (micros)
|
||||
if (result != RESULT_OK || (value <= 1000 && value > 200)) { // backwards compatible (micros)
|
||||
argp_error(state, "invalid latency");
|
||||
argParseError(parseOpt, "invalid latency");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->extraLatency = value > 1000 ? value/1000 : value; // backwards compatible (micros)
|
||||
@@ -316,7 +305,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
// Message configuration options:
|
||||
case 'c': // --configpath=https://cfg.ebusd.eu/
|
||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid configpath");
|
||||
argParseError(parseOpt, "invalid configpath");
|
||||
return EINVAL;
|
||||
}
|
||||
s_configPath = arg;
|
||||
@@ -336,7 +325,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
} else {
|
||||
auto address = (symbol_t)parseInt(arg, 16, 0x00, 0xff, &result);
|
||||
if (result != RESULT_OK || !isValidAddress(address)) {
|
||||
argp_error(state, "invalid initial scan address");
|
||||
argParseError(parseOpt, "invalid initial scan address");
|
||||
return EINVAL;
|
||||
}
|
||||
if (isMaster(address)) {
|
||||
@@ -353,7 +342,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_SCNRET: // --scanretries=10
|
||||
value = parseInt(arg, 10, 0, 100, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid scanretries");
|
||||
argParseError(parseOpt, "invalid scanretries");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->scanRetries = value;
|
||||
@@ -371,14 +360,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
} else if (strcmp("json", arg) == 0) {
|
||||
opt->dumpConfig = OF_DEFINITION | OF_NAMES | OF_UNITS | OF_COMMENTS | OF_VALUENAME | OF_ALL_ATTRS | OF_JSON;
|
||||
} else {
|
||||
argp_error(state, "invalid dumpconfig");
|
||||
argParseError(parseOpt, "invalid dumpconfig");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->checkConfig = true;
|
||||
break;
|
||||
case O_DMPCTO: // --dumpconfigto=FILE
|
||||
if (!arg || arg[0] == 0) {
|
||||
argp_error(state, "invalid dumpconfigto");
|
||||
argParseError(parseOpt, "invalid dumpconfigto");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->dumpConfigTo = arg;
|
||||
@@ -386,7 +375,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_POLINT: // --pollinterval=5
|
||||
value = parseInt(arg, 10, 0, 3600, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid pollinterval");
|
||||
argParseError(parseOpt, "invalid pollinterval");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->pollInterval = value;
|
||||
@@ -407,7 +396,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
{
|
||||
auto address = (symbol_t)parseInt(arg, 16, 0, 0xff, &result);
|
||||
if (result != RESULT_OK || !isMaster(address)) {
|
||||
argp_error(state, "invalid address");
|
||||
argParseError(parseOpt, "invalid address");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->address = address;
|
||||
@@ -419,7 +408,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_ACQTIM: // --acquiretimeout=10
|
||||
value = parseInt(arg, 10, 1, 100000, &result); // backwards compatible (micros)
|
||||
if (result != RESULT_OK || (value <= 1000 && value > 100)) { // backwards compatible (micros)
|
||||
argp_error(state, "invalid acquiretimeout");
|
||||
argParseError(parseOpt, "invalid acquiretimeout");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->acquireTimeout = value > 1000 ? value/1000 : value; // backwards compatible (micros)
|
||||
@@ -427,7 +416,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_ACQRET: // --acquireretries=3
|
||||
value = parseInt(arg, 10, 0, 10, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid acquireretries");
|
||||
argParseError(parseOpt, "invalid acquireretries");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->acquireRetries = value;
|
||||
@@ -435,7 +424,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_SNDRET: // --sendretries=2
|
||||
value = parseInt(arg, 10, 0, 10, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid sendretries");
|
||||
argParseError(parseOpt, "invalid sendretries");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->sendRetries = value;
|
||||
@@ -443,7 +432,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_RCVTIM: // --receivetimeout=25
|
||||
value = parseInt(arg, 10, 1, 100000, &result); // backwards compatible (micros)
|
||||
if (result != RESULT_OK || (value <= 1000 && value > 100)) { // backwards compatible (micros)
|
||||
argp_error(state, "invalid receivetimeout");
|
||||
argParseError(parseOpt, "invalid receivetimeout");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->receiveTimeout = value > 1000 ? value/1000 : value; // backwards compatible (micros)
|
||||
@@ -451,7 +440,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_MASCNT: // --numbermasters=0
|
||||
value = parseInt(arg, 10, 0, 25, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid numbermasters");
|
||||
argParseError(parseOpt, "invalid numbermasters");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->masterCount = value;
|
||||
@@ -463,14 +452,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
// Daemon options:
|
||||
case O_ACLDEF: // --accesslevel=*
|
||||
if (arg == nullptr) {
|
||||
argp_error(state, "invalid accesslevel");
|
||||
argParseError(parseOpt, "invalid accesslevel");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->accessLevel = arg;
|
||||
break;
|
||||
case O_ACLFIL: // --aclfile=/etc/ebusd/acl
|
||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid aclfile");
|
||||
argParseError(parseOpt, "invalid aclfile");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->aclFile = arg;
|
||||
@@ -486,7 +475,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
break;
|
||||
case O_PIDFIL: // --pidfile=/var/run/ebusd.pid
|
||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid pidfile");
|
||||
argParseError(parseOpt, "invalid pidfile");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->pidFile = arg;
|
||||
@@ -494,7 +483,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case 'p': // --port=8888
|
||||
value = parseInt(arg, 10, 1, 65535, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid port");
|
||||
argParseError(parseOpt, "invalid port");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->port = (uint16_t)value;
|
||||
@@ -505,21 +494,21 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_HTTPPT: // --httpport=0
|
||||
value = parseInt(arg, 10, 1, 65535, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid httpport");
|
||||
argParseError(parseOpt, "invalid httpport");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->httpPort = (uint16_t)value;
|
||||
break;
|
||||
case O_HTMLPA: // --htmlpath=/var/ebusd/html
|
||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid htmlpath");
|
||||
argParseError(parseOpt, "invalid htmlpath");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->htmlPath = arg;
|
||||
break;
|
||||
case O_UPDCHK: // --updatecheck=on
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid updatecheck");
|
||||
argParseError(parseOpt, "invalid updatecheck");
|
||||
return EINVAL;
|
||||
}
|
||||
if (strcmp("on", arg) == 0) {
|
||||
@@ -527,7 +516,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
} else if (strcmp("off", arg) == 0) {
|
||||
opt->updateCheck = false;
|
||||
} else {
|
||||
argp_error(state, "invalid updatecheck");
|
||||
argParseError(parseOpt, "invalid updatecheck");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
@@ -535,7 +524,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
// Log options:
|
||||
case 'l': // --logfile=/var/log/ebusd.log
|
||||
if (arg == nullptr || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid logfile");
|
||||
argParseError(parseOpt, "invalid logfile");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->logFile = arg;
|
||||
@@ -546,23 +535,23 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
if (pos == nullptr) {
|
||||
pos = strchr(arg, ' ');
|
||||
if (pos == nullptr) {
|
||||
argp_error(state, "invalid log");
|
||||
argParseError(parseOpt, "invalid log");
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
*pos = 0;
|
||||
int facilities = parseLogFacilities(arg);
|
||||
if (facilities == -1) {
|
||||
argp_error(state, "invalid log: areas");
|
||||
argParseError(parseOpt, "invalid log: areas");
|
||||
return EINVAL;
|
||||
}
|
||||
LogLevel level = parseLogLevel(pos + 1);
|
||||
if (level == ll_COUNT) {
|
||||
argp_error(state, "invalid log: level");
|
||||
argParseError(parseOpt, "invalid log: level");
|
||||
return EINVAL;
|
||||
}
|
||||
if (opt->logAreas != -1 || opt->logLevel != ll_COUNT) {
|
||||
argp_error(state, "invalid log (combined with logareas or loglevel)");
|
||||
argParseError(parseOpt, "invalid log (combined with logareas or loglevel)");
|
||||
return EINVAL;
|
||||
}
|
||||
setFacilitiesLogLevel(facilities, level);
|
||||
@@ -573,11 +562,11 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
{
|
||||
int facilities = parseLogFacilities(arg);
|
||||
if (facilities == -1) {
|
||||
argp_error(state, "invalid logareas");
|
||||
argParseError(parseOpt, "invalid logareas");
|
||||
return EINVAL;
|
||||
}
|
||||
if (opt->multiLog) {
|
||||
argp_error(state, "invalid logareas (combined with log)");
|
||||
argParseError(parseOpt, "invalid logareas (combined with log)");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->logAreas = facilities;
|
||||
@@ -587,11 +576,11 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
{
|
||||
LogLevel logLevel = parseLogLevel(arg);
|
||||
if (logLevel == ll_COUNT) {
|
||||
argp_error(state, "invalid loglevel");
|
||||
argParseError(parseOpt, "invalid loglevel");
|
||||
return EINVAL;
|
||||
}
|
||||
if (opt->multiLog) {
|
||||
argp_error(state, "invalid loglevel (combined with log)");
|
||||
argParseError(parseOpt, "invalid loglevel (combined with log)");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->logLevel = logLevel;
|
||||
@@ -604,7 +593,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
break;
|
||||
case O_RAWFIL: // --lograwdatafile=/var/log/ebusd.log
|
||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid lograwdatafile");
|
||||
argParseError(parseOpt, "invalid lograwdatafile");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->logRawFile = arg;
|
||||
@@ -612,7 +601,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_RAWSIZ: // --lograwdatasize=100
|
||||
value = parseInt(arg, 10, 1, 1000000, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid lograwdatasize");
|
||||
argParseError(parseOpt, "invalid lograwdatasize");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->logRawSize = value;
|
||||
@@ -625,7 +614,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
break;
|
||||
case O_DMPFIL: // --dumpfile=/tmp/ebusd_dump.bin
|
||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid dumpfile");
|
||||
argParseError(parseOpt, "invalid dumpfile");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->dumpFile = arg;
|
||||
@@ -633,7 +622,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_DMPSIZ: // --dumpsize=100
|
||||
value = parseInt(arg, 10, 1, 1000000, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid dumpsize");
|
||||
argParseError(parseOpt, "invalid dumpsize");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->dumpSize = value;
|
||||
@@ -642,33 +631,27 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
opt->dumpFlush = true;
|
||||
break;
|
||||
|
||||
case ARGP_KEY_ARG:
|
||||
if (opt->injectMessages || (opt->checkConfig && opt->scanConfig)) {
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
argp_error(state, "invalid arguments starting with \"%s\"", arg);
|
||||
return EINVAL;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
|
||||
// check for invalid arg combinations
|
||||
if (opt->readOnly && (opt->answer || opt->generateSyn || opt->initialSend
|
||||
|| (opt->scanConfig && opt->initialScan != ESC))) {
|
||||
argp_error(state, "cannot combine readonly with answer/generatesyn/initsend/scanconfig");
|
||||
argParseError(parseOpt, "cannot combine readonly with answer/generatesyn/initsend/scanconfig");
|
||||
return EINVAL;
|
||||
}
|
||||
if (opt->scanConfig && opt->pollInterval == 0) {
|
||||
argp_error(state, "scanconfig without polling may lead to invalid files included for certain products!");
|
||||
argParseError(parseOpt, "scanconfig without polling may lead to invalid files included for certain products!");
|
||||
return EINVAL;
|
||||
}
|
||||
if (opt->injectMessages && (opt->checkConfig || opt->dumpConfig)) {
|
||||
argp_error(state, "cannot combine inject with checkconfig/dumpconfig");
|
||||
argParseError(parseOpt, "cannot combine inject with checkconfig/dumpconfig");
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void shutdown(bool error = false);
|
||||
|
||||
void daemonize() {
|
||||
@@ -823,8 +806,17 @@ void signalHandler(int sig) {
|
||||
* @return the exit code.
|
||||
*/
|
||||
int main(int argc, char* argv[], char* envp[]) {
|
||||
struct argp aargp = { argpoptions, parse_opt, nullptr, argpdoc, datahandler_getargs(), nullptr, nullptr };
|
||||
setenv("ARGP_HELP_FMT", "no-dup-args-note", 0);
|
||||
const argParseOpt parseOpt = {
|
||||
argDefs,
|
||||
parse_opt,
|
||||
0,
|
||||
"" PACKAGE_NAME,
|
||||
"[INJECT...]",
|
||||
"A daemon for communication with eBUS heating systems.",
|
||||
"Report bugs to " PACKAGE_BUGREPORT " .",
|
||||
datahandler_getargs(),
|
||||
&s_opt
|
||||
};
|
||||
|
||||
char envname[32] = "--"; // needs to cover at least max length of any option name plus "--"
|
||||
char* envopt = envname+2;
|
||||
@@ -849,7 +841,7 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
// ignore those defined in Dockerfile, EBUSD_OPTS, those with final args, and interactive ones
|
||||
continue;
|
||||
}
|
||||
char* envargv[] = {envname, pos+1};
|
||||
char* envargv[] = {argv[0], envname, pos+1};
|
||||
int cnt = pos[1] ? 2 : 1;
|
||||
if (pos[1] && strlen(*env) < sizeof(envname)-3
|
||||
&& (strcmp(envopt, "scanconfig") == 0 || strcmp(envopt, "lograwdata") == 0)) {
|
||||
@@ -858,8 +850,7 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
strcat(envopt, pos);
|
||||
}
|
||||
int idx = -1;
|
||||
s_opt.injectMessages = true; // for skipping unknown values via ARGP_ERR_UNKNOWN
|
||||
error_t err = argp_parse(&aargp, cnt, envargv, ARGP_PARSE_ARGV0|ARGP_SILENT|ARGP_IN_ORDER, &idx, &s_opt);
|
||||
int err = argParse(&parseOpt, 1+cnt, envargv, &idx);
|
||||
if (err != 0 && idx == -1) { // ignore args for non-arg boolean options
|
||||
if (err == ESRCH) { // special value to abort immediately
|
||||
logWrite(lf_main, ll_error, "invalid argument in env: %s", *env); // force logging on exit
|
||||
@@ -867,13 +858,27 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
}
|
||||
logWrite(lf_main, ll_error, "invalid/unknown argument in env (ignored): %s", *env); // force logging
|
||||
}
|
||||
s_opt.injectMessages = false; // restore (was not parsed from cmdline args yet)
|
||||
}
|
||||
|
||||
int arg_index = -1;
|
||||
if (argp_parse(&aargp, argc, argv, ARGP_IN_ORDER, &arg_index, &s_opt) != 0) {
|
||||
logWrite(lf_main, ll_error, "invalid arguments"); // force logging on exit
|
||||
return EINVAL;
|
||||
switch (argParse(&parseOpt, argc, argv, &arg_index)) {
|
||||
case 0: // OK
|
||||
break;
|
||||
case '?': // help printed
|
||||
return 0;
|
||||
case 'V':
|
||||
printf("" PACKAGE_STRING "." REVISION "\n");
|
||||
return 0;
|
||||
default:
|
||||
logWrite(lf_main, ll_error, "invalid arguments"); // force logging on exit
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (arg_index >= 0) {
|
||||
if (!s_opt.injectMessages && !(s_opt.checkConfig && s_opt.scanConfig)) {
|
||||
fprintf(stderr, "invalid arguments starting with \"%s\"", argv[arg_index]);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_opt.logAreas != -1 || s_opt.logLevel != ll_COUNT) {
|
||||
|
||||
+28
-28
@@ -56,7 +56,7 @@ using std::dec;
|
||||
#define O_VERB (O_INSE+1)
|
||||
|
||||
/** the definition of the MQTT arguments. */
|
||||
static const struct argp_option g_mqtt_argp_options[] = {
|
||||
static const argDef g_mqtt_argDefs[] = {
|
||||
{nullptr, 0, nullptr, 0, "MQTT options:", 1 },
|
||||
{"mqtthost", O_HOST, "HOST", 0, "Connect to MQTT broker on HOST [localhost]", 0 },
|
||||
{"mqttport", O_PORT, "PORT", 0, "Connect to MQTT broker on PORT (usually 1883), 0 to disable [0]", 0 },
|
||||
@@ -72,7 +72,7 @@ static const struct argp_option g_mqtt_argp_options[] = {
|
||||
{"mqttqos", O_PQOS, "QOS", 0, "Set the QoS value for all topics (0-2) [0]", 0 },
|
||||
{"mqttint", O_INTF, "FILE", 0, "Read MQTT integration settings from FILE (no default)", 0 },
|
||||
{"mqttvar", O_IVAR, "NAME=VALUE[,...]", 0, "Add variable(s) to the read MQTT integration settings", 0 },
|
||||
{"mqttjson", O_JSON, "short", OPTION_ARG_OPTIONAL,
|
||||
{"mqttjson", O_JSON, "short", af_optional,
|
||||
"Publish in JSON format instead of strings, optionally in short (value directly below field key)", 0 },
|
||||
{"mqttverbose", O_VERB, nullptr, 0, "Publish all available attributes", 0 },
|
||||
#if (LIBMOSQUITTO_VERSION_NUMBER >= 1003001)
|
||||
@@ -144,17 +144,17 @@ void splitFields(const string& str, vector<string>* row);
|
||||
|
||||
/**
|
||||
* The MQTT argument parsing function.
|
||||
* @param key the key from @a g_mqtt_argp_options.
|
||||
* @param key the key from @a g_mqtt_argDefs.
|
||||
* @param arg the option argument, or nullptr.
|
||||
* @param state the parsing state.
|
||||
*/
|
||||
static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
static int mqtt_parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
|
||||
result_t result = RESULT_OK;
|
||||
unsigned int value;
|
||||
switch (key) {
|
||||
case O_HOST: // --mqtthost=localhost
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid mqtthost");
|
||||
argParseError(parseOpt, "invalid mqtthost");
|
||||
return EINVAL;
|
||||
}
|
||||
g_host = arg;
|
||||
@@ -163,7 +163,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_PORT: // --mqttport=1883
|
||||
value = parseInt(arg, 10, 1, 65535, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid mqttport");
|
||||
argParseError(parseOpt, "invalid mqttport");
|
||||
return EINVAL;
|
||||
}
|
||||
g_port = (uint16_t)value;
|
||||
@@ -171,7 +171,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_CLID: // --mqttclientid=clientid
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid mqttclientid");
|
||||
argParseError(parseOpt, "invalid mqttclientid");
|
||||
return EINVAL;
|
||||
}
|
||||
g_clientId = arg;
|
||||
@@ -179,7 +179,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_USER: // --mqttuser=username
|
||||
if (arg == nullptr) {
|
||||
argp_error(state, "invalid mqttuser");
|
||||
argParseError(parseOpt, "invalid mqttuser");
|
||||
return EINVAL;
|
||||
}
|
||||
g_username = arg;
|
||||
@@ -187,7 +187,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_PASS: // --mqttpass=password
|
||||
if (arg == nullptr) {
|
||||
argp_error(state, "invalid mqttpass");
|
||||
argParseError(parseOpt, "invalid mqttpass");
|
||||
return EINVAL;
|
||||
}
|
||||
g_password = replaceSecret(arg);
|
||||
@@ -196,21 +196,21 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_TOPI: // --mqtttopic=ebusd
|
||||
{
|
||||
if (arg == nullptr || arg[0] == 0 || arg[0] == '/' || strchr(arg, '+') || arg[strlen(arg)-1] == '/') {
|
||||
argp_error(state, "invalid mqtttopic");
|
||||
argParseError(parseOpt, "invalid mqtttopic");
|
||||
return EINVAL;
|
||||
}
|
||||
char *pos = strchr(arg, '#');
|
||||
if (pos && (pos == arg || pos[1])) { // allow # only at very last position (to indicate not using any default)
|
||||
argp_error(state, "invalid mqtttopic");
|
||||
argParseError(parseOpt, "invalid mqtttopic");
|
||||
return EINVAL;
|
||||
}
|
||||
if (g_topic) {
|
||||
argp_error(state, "duplicate mqtttopic");
|
||||
argParseError(parseOpt, "duplicate mqtttopic");
|
||||
return EINVAL;
|
||||
}
|
||||
StringReplacer replacer;
|
||||
if (!replacer.parse(arg, true)) {
|
||||
argp_error(state, "malformed mqtttopic");
|
||||
argParseError(parseOpt, "malformed mqtttopic");
|
||||
return ESRCH; // abort in any case due to the above potentially being destructive
|
||||
}
|
||||
g_topic = arg;
|
||||
@@ -219,7 +219,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_GTOP: // --mqttglobal=global/
|
||||
if (arg == nullptr || strchr(arg, '+') || strchr(arg, '#')) {
|
||||
argp_error(state, "invalid mqttglobal");
|
||||
argParseError(parseOpt, "invalid mqttglobal");
|
||||
return EINVAL;
|
||||
}
|
||||
g_globalTopic = arg;
|
||||
@@ -232,7 +232,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_PQOS: // --mqttqos=0
|
||||
value = parseInt(arg, 10, 0, 2, &result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid mqttqos value");
|
||||
argParseError(parseOpt, "invalid mqttqos value");
|
||||
return EINVAL;
|
||||
}
|
||||
g_qos = static_cast<signed>(value);
|
||||
@@ -240,7 +240,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_INTF: // --mqttint=/etc/ebusd/mqttint.cfg
|
||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid mqttint file");
|
||||
argParseError(parseOpt, "invalid mqttint file");
|
||||
return EINVAL;
|
||||
}
|
||||
g_integrationFile = arg;
|
||||
@@ -248,7 +248,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_IVAR: // --mqttvar=NAME=VALUE[,NAME=VALUE]*
|
||||
if (arg == nullptr || arg[0] == 0 || !strchr(arg, '=')) {
|
||||
argp_error(state, "invalid mqttvar");
|
||||
argParseError(parseOpt, "invalid mqttvar");
|
||||
return EINVAL;
|
||||
}
|
||||
if (!g_integrationVars) {
|
||||
@@ -277,7 +277,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
#if (LIBMOSQUITTO_VERSION_NUMBER >= 1004001)
|
||||
case O_VERS: // --mqttversion=3.1.1
|
||||
if (arg == nullptr || arg[0] == 0 || (strcmp(arg, "3.1") != 0 && strcmp(arg, "3.1.1") != 0)) {
|
||||
argp_error(state, "invalid mqttversion");
|
||||
argParseError(parseOpt, "invalid mqttversion");
|
||||
return EINVAL;
|
||||
}
|
||||
g_version = strcmp(arg, "3.1.1") == 0 ? MQTT_PROTOCOL_V311 : MQTT_PROTOCOL_V31;
|
||||
@@ -295,7 +295,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
#if (LIBMOSQUITTO_MAJOR >= 1)
|
||||
case O_CAFI: // --mqttca=file or --mqttca=dir/
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid mqttca");
|
||||
argParseError(parseOpt, "invalid mqttca");
|
||||
return EINVAL;
|
||||
}
|
||||
if (arg[strlen(arg)-1] == '/') {
|
||||
@@ -309,7 +309,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_CERT: // --mqttcert=CERTFILE
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid mqttcert");
|
||||
argParseError(parseOpt, "invalid mqttcert");
|
||||
return EINVAL;
|
||||
}
|
||||
g_certfile = arg;
|
||||
@@ -317,7 +317,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_KEYF: // --mqttkey=KEYFILE
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid mqttkey");
|
||||
argParseError(parseOpt, "invalid mqttkey");
|
||||
return EINVAL;
|
||||
}
|
||||
g_keyfile = arg;
|
||||
@@ -325,7 +325,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
case O_KEPA: // --mqttkeypass=PASSWORD
|
||||
if (arg == nullptr) {
|
||||
argp_error(state, "invalid mqttkeypass");
|
||||
argParseError(parseOpt, "invalid mqttkeypass");
|
||||
return EINVAL;
|
||||
}
|
||||
g_keypass = replaceSecret(arg);
|
||||
@@ -336,18 +336,18 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
#endif
|
||||
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct argp g_mqtt_argp = { g_mqtt_argp_options, mqtt_parse_opt, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr };
|
||||
static const struct argp_child g_mqtt_argp_child = {&g_mqtt_argp, 0, "", 1};
|
||||
static const argParseChildOpt g_mqtt_arg_child = {
|
||||
g_mqtt_argDefs, mqtt_parse_opt
|
||||
};
|
||||
|
||||
|
||||
const struct argp_child* mqtthandler_getargs() {
|
||||
return &g_mqtt_argp_child;
|
||||
const argParseChildOpt* mqtthandler_getargs() {
|
||||
return &g_mqtt_arg_child;
|
||||
}
|
||||
|
||||
bool check(int code, const char* method) {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "ebusd/bushandler.h"
|
||||
#include "lib/ebus/message.h"
|
||||
#include "lib/ebus/stringhelper.h"
|
||||
#include "lib/utils/arg.h"
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
@@ -42,10 +43,10 @@ using std::string;
|
||||
using std::vector;
|
||||
|
||||
/**
|
||||
* Helper function for getting the argp definition for MQTT.
|
||||
* @return a pointer to the argp_child structure.
|
||||
* Helper function for getting the arg definition for MQTT.
|
||||
* @return a pointer to the child argument options, or nullptr.
|
||||
*/
|
||||
const struct argp_child* mqtthandler_getargs();
|
||||
const argParseChildOpt* mqtthandler_getargs();
|
||||
|
||||
/**
|
||||
* Registration function that is called once during initialization.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
add_definitions(-Wconversion)
|
||||
|
||||
set(libutils_a_SOURCES
|
||||
arg.h arg.cpp
|
||||
log.h log.cpp
|
||||
tcpsocket.h tcpsocket.cpp
|
||||
thread.h thread.cpp
|
||||
|
||||
Executable
+346
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* ebusd - daemon for communication with eBUS heating systems.
|
||||
* Copyright (C) 2023 John Baier <ebusd@ebusd.eu>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "lib/utils/arg.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <memory.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
#define isAlpha(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
|
||||
|
||||
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++;
|
||||
if (!isAlpha(arg->key)) {
|
||||
continue;
|
||||
}
|
||||
shortCharsCount++;
|
||||
shortOptsCount++;
|
||||
if (arg->valueName) {
|
||||
shortOptsCount++;
|
||||
if (arg->flags & af_optional) {
|
||||
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;
|
||||
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->val = argDefIdx;
|
||||
if (isAlpha(arg->key)) {
|
||||
shortChars[shortCharsCount] = (char)arg->key;
|
||||
shortIndexes[shortCharsCount++] = count;
|
||||
shortOpts[shortOptsCount++] = (char)arg->key;
|
||||
if (arg->valueName) {
|
||||
shortOpts[shortOptsCount++] = ':';
|
||||
if (arg->flags & af_optional) {
|
||||
shortOpts[shortOptsCount++] = ':';
|
||||
}
|
||||
}
|
||||
}
|
||||
opt++;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
static const argDef endArgDef = {nullptr, 0, nullptr, 0, nullptr, 0 };
|
||||
static const argDef helpArgDef = {"help", '?', nullptr, 0, "Give this help list", 0 };
|
||||
static const argDef helpArgDefs[] = {
|
||||
helpArgDef,
|
||||
endArgDef
|
||||
};
|
||||
static const argDef versionArgDef = {"version", 'V', nullptr, 0, "Print program version", 0 };
|
||||
static const argDef versionArgDefs[] = {
|
||||
versionArgDef,
|
||||
endArgDef
|
||||
};
|
||||
|
||||
int argParse(const argParseOpt *parseOpt, int argc, char **argv, int *argIndex) {
|
||||
int count = 0, shortCharsCount = 0, shortOptsCount = 0;
|
||||
if (!(parseOpt->flags & af_noHelp)) {
|
||||
calcCounts(helpArgDefs, count, shortCharsCount, shortOptsCount);
|
||||
}
|
||||
if (!(parseOpt->flags & af_noVersion)) {
|
||||
calcCounts(versionArgDefs, 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);
|
||||
}
|
||||
struct option *longOpts = (struct option*)calloc(count+1, sizeof(struct option)); // room for EOF
|
||||
char *shortChars = (char*)calloc(shortCharsCount+1, sizeof(char)); // room for \0
|
||||
int *shortIndexes = (int*)calloc(shortCharsCount, sizeof(int));
|
||||
char *shortOpts = (char*)calloc(2+shortOptsCount+1, sizeof(char)); // room for +, :, and \0
|
||||
count = 0;
|
||||
shortCharsCount = 0;
|
||||
shortOptsCount = 0;
|
||||
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, shortIndexes, shortOpts, 0xff00);
|
||||
}
|
||||
if (!(parseOpt->flags & af_noVersion)) {
|
||||
buildOpts(versionArgDefs, count, shortCharsCount, shortOptsCount, longOpts, shortChars, shortIndexes, shortOpts, 0xff01);
|
||||
}
|
||||
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, shortIndexes, shortOpts, 0x100*(++children));
|
||||
}
|
||||
optind = 1; // setting to 0 does not work
|
||||
int c = 0, longIdx = -1, ret = 0;
|
||||
while ((c = getopt_long(argc, argv, shortOpts, longOpts, &longIdx)) != -1) {
|
||||
if (c == '?') {
|
||||
// unknown option or help
|
||||
if (optopt != '?') {
|
||||
ret = '!';
|
||||
fprintf(stderr, "invalid argument %s\n", argv[optind - 1]);
|
||||
} else {
|
||||
ret = c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c == ':') {
|
||||
// missing option
|
||||
fprintf(stderr, "missing argument to %s\n", argv[optind - 1]);
|
||||
ret = c;
|
||||
break;
|
||||
}
|
||||
if (isAlpha(c)) {
|
||||
// short name
|
||||
int idx = (int)(strchr(shortChars, c) - shortChars);
|
||||
if (idx >= 0 && idx < shortCharsCount) {
|
||||
longIdx = shortIndexes[idx];
|
||||
} else {
|
||||
longIdx = -1;
|
||||
}
|
||||
} else if (c >= 0 && longIdx < 0) {
|
||||
longIdx = c;
|
||||
}
|
||||
if (longIdx < 0 || longIdx >= count) {
|
||||
ret = '!'; // error
|
||||
break;
|
||||
}
|
||||
int val = longOpts[longIdx].val;
|
||||
if (val == 0xff00) { // help
|
||||
ret = '?';
|
||||
break;
|
||||
}
|
||||
if (val == 0xff01) { // version
|
||||
ret = 'V';
|
||||
break;
|
||||
}
|
||||
const argDef *argDefs;
|
||||
parse_function_t parser;
|
||||
if (val & 0xff00) {
|
||||
const argParseChildOpt *child = parseOpt->childOpts + ((val>>8)-1);
|
||||
argDefs = child->argDefs;
|
||||
parser = child->parser;
|
||||
} else {
|
||||
argDefs = parseOpt->argDefs;
|
||||
parser = parseOpt->parser;
|
||||
}
|
||||
const argDef *arg = argDefs + (val & 0xff);
|
||||
c = parser(arg->key, optarg, parseOpt);
|
||||
if (c != 0) {
|
||||
ret = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret == '?') {
|
||||
argHelp(parseOpt);
|
||||
} else if (argIndex && optind < argc) {
|
||||
*argIndex = optind;
|
||||
}
|
||||
free(longOpts);
|
||||
free(shortChars);
|
||||
free(shortOpts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define MIN_INDENT 18
|
||||
#define MAX_INDENT 29
|
||||
#define MAX_BREAK 79
|
||||
|
||||
void wrap(const char* str, size_t pos, size_t indent) {
|
||||
const char* end = strchr(str, 0);
|
||||
const char* eol = strchr(str, '\n');
|
||||
char buf[MAX_BREAK + 1];
|
||||
bool first = true;
|
||||
while (*str && str < end) {
|
||||
if (!first) {
|
||||
if (indent) {
|
||||
printf("%*c", (int)indent, ' ');
|
||||
}
|
||||
pos = indent;
|
||||
}
|
||||
// start from max position backwards to find a break char
|
||||
size_t cnt = MAX_BREAK - pos;
|
||||
if (eol && eol < str) {
|
||||
eol = strchr(str, '\n');
|
||||
}
|
||||
if (eol && eol < str + cnt) {
|
||||
// EOL is before latest possible break
|
||||
cnt = eol - str;
|
||||
} else if (end < str + cnt) {
|
||||
cnt = end - str;
|
||||
}
|
||||
for (; cnt > 0; cnt--) {
|
||||
char ch = str[cnt];
|
||||
if (ch == ' ' || ch == '\n' || ch == 0) {
|
||||
// break found
|
||||
buf[0] = 0;
|
||||
strncat(buf, str, cnt);
|
||||
printf("%s\n", buf);
|
||||
str += cnt;
|
||||
if (*str) {
|
||||
str++;
|
||||
}
|
||||
break; // restart
|
||||
}
|
||||
}
|
||||
if (cnt == 0 && *str) {
|
||||
// final
|
||||
printf("%s\n", str);
|
||||
break;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t calcIndent(const argDef *argDefs) {
|
||||
size_t indent = 0;
|
||||
for (const argDef *arg = argDefs; arg && arg->help; arg++) {
|
||||
if (!arg->name) {
|
||||
continue;
|
||||
}
|
||||
// e.g. " -d, --device=DEV Use DEV..."
|
||||
size_t length = 2 + 3 + 3 + strlen(arg->name) + 2;
|
||||
if (arg->valueName) {
|
||||
length += 1 + strlen(arg->valueName);
|
||||
if (arg->flags & af_optional) {
|
||||
length += 2;
|
||||
}
|
||||
}
|
||||
if (length > indent) {
|
||||
indent = length;
|
||||
if (indent > MAX_INDENT) {
|
||||
return indent;
|
||||
}
|
||||
}
|
||||
}
|
||||
return indent;
|
||||
}
|
||||
|
||||
void printArgs(const argDef *argDefs, size_t indent) {
|
||||
for (const argDef *arg = argDefs; arg && arg->help; arg++) {
|
||||
if (!arg->name) {
|
||||
if (*arg->help) {
|
||||
printf("\n %s\n", arg->help);
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
printf(" ");
|
||||
if (isAlpha(arg->key) || arg->key == '?') {
|
||||
printf("-%c,", arg->key);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
printf(" --%s", arg->name);
|
||||
size_t taken = 2 + 3 + 3 + strlen(arg->name);
|
||||
if (arg->valueName) {
|
||||
taken += 1 + strlen(arg->valueName);
|
||||
if (arg->flags & af_optional) {
|
||||
printf("[=%s]", arg->valueName);
|
||||
taken += 2;
|
||||
} else {
|
||||
printf("=%s", arg->valueName);
|
||||
}
|
||||
}
|
||||
if (taken > indent) {
|
||||
printf(" ");
|
||||
wrap(arg->help, taken+1, indent);
|
||||
} else {
|
||||
printf("%*c", (int)(indent - taken), ' ');
|
||||
wrap(arg->help, indent, indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void argHelp(const argParseOpt *parseOpt) {
|
||||
size_t indent = calcIndent(parseOpt->argDefs);
|
||||
if (indent < MAX_INDENT) {
|
||||
for (const argParseChildOpt *child = parseOpt->childOpts; child && child->argDefs; child++) {
|
||||
size_t childIndent = calcIndent(child->argDefs);
|
||||
if (childIndent > indent) {
|
||||
indent = childIndent;
|
||||
if (indent > MAX_INDENT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (indent > MAX_INDENT) {
|
||||
indent = MAX_INDENT;
|
||||
} else if (indent < MIN_INDENT) {
|
||||
indent = MIN_INDENT;
|
||||
}
|
||||
printf("Usage: %s [OPTION...] %s\n",
|
||||
parseOpt->name,
|
||||
parseOpt->positional ? parseOpt->positional : ""
|
||||
);
|
||||
wrap(parseOpt->help, 0, 0);
|
||||
printArgs(parseOpt->argDefs, indent);
|
||||
for (const argParseChildOpt *child = parseOpt->childOpts; child && child->argDefs; child++) {
|
||||
printArgs(child->argDefs, indent);
|
||||
}
|
||||
if (!(parseOpt->flags & (af_noHelp|af_noVersion))) {
|
||||
printf("\n");
|
||||
if (!(parseOpt->flags & af_noHelp)) {
|
||||
printArgs(helpArgDefs, indent);
|
||||
}
|
||||
if (!(parseOpt->flags & af_noVersion)) {
|
||||
printArgs(versionArgDefs, indent);
|
||||
}
|
||||
}
|
||||
if (parseOpt->suffix) {
|
||||
printf("\n");
|
||||
wrap(parseOpt->suffix, 0, 0);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
Executable
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* ebusd - daemon for communication with eBUS heating systems.
|
||||
* Copyright (C) 2023 John Baier <ebusd@ebusd.eu>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIB_UTILS_ARGS_H_
|
||||
#define LIB_UTILS_ARGS_H_
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
/** \file lib/utils/args.h */
|
||||
|
||||
/** 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
|
||||
};
|
||||
|
||||
/** Definition of a single argument. */
|
||||
typedef struct argDef {
|
||||
const char* name; //!< the (long) name of the argument, or nullptr for a group header
|
||||
int key; //!< the argument key, also used as short name if alphabetic or the question mark
|
||||
const char* valueName; //!< the optional argument value name
|
||||
int flags; //!< flags for the argument, bit combination of @a ArgFlag
|
||||
const char* help; //!< help text (mandatory)
|
||||
int unused; //!< currently unused (kept for compatibility to argp)
|
||||
} argDef;
|
||||
|
||||
struct argParseOpt;
|
||||
|
||||
/**
|
||||
* Function to be called for each argument.
|
||||
* @param key the argument key as defined.
|
||||
* @param arg the argument value, or nullptr.
|
||||
* @param parseOpt ppointer to the @a argParseOpt structure.
|
||||
* @return 0 on success, non-zero otherwise.
|
||||
*/
|
||||
typedef int (*parse_function_t)(int key, char *arg, const struct argParseOpt *parseOpt);
|
||||
|
||||
/** Options for child definitions. */
|
||||
typedef struct argParseChildOpt {
|
||||
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
|
||||
} argParseChildOpt;
|
||||
|
||||
/** Options to pass to @a argParse(). */
|
||||
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;
|
||||
|
||||
/**
|
||||
* Parse the arguments given in @a argv.
|
||||
* @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.
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Print the help text.
|
||||
* @param parseOpt ppointer to the @a argParseOpt structure.
|
||||
*/
|
||||
void argHelp(const argParseOpt *parseOpt);
|
||||
|
||||
/**
|
||||
* Convenience macro to print an error message to stderr.
|
||||
*/
|
||||
#define argParseError(argParseOpt, message) fprintf(stderr, "%s\n", message);
|
||||
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // LIB_UTILS_ARGS_H_
|
||||
@@ -1,3 +1,5 @@
|
||||
add_definitions(-Wno-unused-parameter)
|
||||
|
||||
set(ebusctl_SOURCES ebusctl.cpp)
|
||||
set(ebuspicloader_SOURCES ebuspicloader.cpp intelhex/intelhexclass.cpp)
|
||||
|
||||
@@ -7,13 +9,13 @@ include_directories(intelhex)
|
||||
|
||||
add_executable(ebusctl ${ebusctl_SOURCES})
|
||||
add_executable(ebuspicloader ${ebuspicloader_SOURCES})
|
||||
target_link_libraries(ebusctl utils ebus ${LIB_ARGP} ${ebusctl_LIBS})
|
||||
target_link_libraries(ebuspicloader utils ${LIB_ARGP} ${ebuspicloader_LIBS})
|
||||
target_link_libraries(ebusctl utils ebus ${ebusctl_LIBS})
|
||||
target_link_libraries(ebuspicloader utils ${ebuspicloader_LIBS})
|
||||
|
||||
if(WITH_EBUSFEED)
|
||||
set(ebusfeed_SOURCES ebusfeed.cpp)
|
||||
add_executable(ebusfeed ${ebusfeed_SOURCES})
|
||||
target_link_libraries(ebusfeed ebus ${LIB_ARGP} ${ebusfeed_LIBS})
|
||||
target_link_libraries(ebusfeed utils ebus ${ebusfeed_LIBS})
|
||||
endif(WITH_EBUSFEED)
|
||||
|
||||
install(TARGETS ebusctl ebuspicloader EXPORT ebusd DESTINATION usr/bin)
|
||||
|
||||
+35
-34
@@ -20,7 +20,6 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <argp.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_PPOLL
|
||||
# include <poll.h>
|
||||
@@ -30,6 +29,7 @@
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "lib/utils/arg.h"
|
||||
#include "lib/utils/tcpsocket.h"
|
||||
|
||||
namespace ebusd {
|
||||
@@ -62,24 +62,8 @@ static struct options opt = {
|
||||
0 // argCount
|
||||
};
|
||||
|
||||
/** the version string of the program. */
|
||||
const char *argp_program_version = "ebusctl of """ PACKAGE_STRING "";
|
||||
|
||||
/** the report bugs to address of the program. */
|
||||
const char *argp_program_bug_address = "" PACKAGE_BUGREPORT "";
|
||||
|
||||
/** the documentation of the program. */
|
||||
static const char argpdoc[] =
|
||||
"Client for acessing " PACKAGE " via TCP.\n"
|
||||
"\v"
|
||||
"If given, send COMMAND together with CMDOPT options to " PACKAGE ".\n"
|
||||
"Use 'help' as COMMAND for help on available " PACKAGE " commands.";
|
||||
|
||||
/** the description of the accepted arguments. */
|
||||
static char argpargsdoc[] = "\nCOMMAND [CMDOPT...]";
|
||||
|
||||
/** the definition of the known program arguments. */
|
||||
static const struct argp_option argpoptions[] = {
|
||||
static const argDef argDefs[] = {
|
||||
{nullptr, 0, nullptr, 0, "Options:", 1 },
|
||||
{"server", 's', "HOST", 0, "Connect to " PACKAGE " on HOST (name or IP) [localhost]", 0 },
|
||||
{"port", 'p', "PORT", 0, "Connect to " PACKAGE " on PORT [8888]", 0 },
|
||||
@@ -92,19 +76,19 @@ static const struct argp_option argpoptions[] = {
|
||||
|
||||
/**
|
||||
* The program argument parsing function.
|
||||
* @param key the key from @a argpoptions.
|
||||
* @param key the key from @a argDefs.
|
||||
* @param arg the option argument, or nullptr.
|
||||
* @param state the parsing state.
|
||||
* @param parseOpt the parse options.
|
||||
*/
|
||||
error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
struct options *opt = (struct options*)state->input;
|
||||
static int parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
|
||||
struct options *opt = (struct options*)parseOpt->userArg;
|
||||
char* strEnd = nullptr;
|
||||
unsigned int value;
|
||||
switch (key) {
|
||||
// Device settings:
|
||||
case 's': // --server=localhost
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid server");
|
||||
argParseError(parseOpt, "invalid server");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->server = arg;
|
||||
@@ -112,7 +96,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case 'p': // --port=8888
|
||||
value = strtoul(arg, &strEnd, 10);
|
||||
if (strEnd == nullptr || strEnd == arg || *strEnd != 0 || value < 1 || value > 65535) {
|
||||
argp_error(state, "invalid port");
|
||||
argParseError(parseOpt, "invalid port");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->port = (uint16_t)value;
|
||||
@@ -120,7 +104,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case 't': // --timeout=10
|
||||
value = strtoul(arg, &strEnd, 10);
|
||||
if (strEnd == nullptr || strEnd == arg || *strEnd != 0 || value > 3600) {
|
||||
argp_error(state, "invalid timeout");
|
||||
argParseError(parseOpt, "invalid timeout");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->timeout = (uint16_t)value;
|
||||
@@ -128,12 +112,8 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case 'e': // --error
|
||||
opt->errorResponse = true;
|
||||
break;
|
||||
case ARGP_KEY_ARGS:
|
||||
opt->args = state->argv + state->next;
|
||||
opt->argCount = state->argc - state->next;
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
return ESRCH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -362,11 +342,32 @@ bool connect(const char* host, uint16_t port, uint16_t timeout, char* const *arg
|
||||
* @return the exit code.
|
||||
*/
|
||||
int main(int argc, char* argv[]) {
|
||||
struct argp argp = { argpoptions, parse_opt, argpargsdoc, argpdoc, nullptr, nullptr, nullptr };
|
||||
setenv("ARGP_HELP_FMT", "no-dup-args-note", 0);
|
||||
if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, nullptr, &opt) != 0) {
|
||||
return EINVAL;
|
||||
argParseOpt parseOpt = {
|
||||
argDefs,
|
||||
parse_opt,
|
||||
af_noVersion,
|
||||
"ebusctl",
|
||||
"[COMMAND [CMDOPT...]]",
|
||||
"Client for accessing " PACKAGE " via TCP.",
|
||||
"If given, send COMMAND together with CMDOPT options 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)) {
|
||||
case 0: // OK
|
||||
break;
|
||||
case '?': // help printed
|
||||
return 0;
|
||||
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);
|
||||
|
||||
exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
|
||||
+47
-47
@@ -20,7 +20,6 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <argp.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
@@ -29,6 +28,7 @@
|
||||
#include <iomanip>
|
||||
#include "lib/ebus/device.h"
|
||||
#include "lib/ebus/result.h"
|
||||
#include "lib/utils/arg.h"
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
@@ -58,31 +58,8 @@ static struct options opt = {
|
||||
"/tmp/ebus_dump.bin", // dumpFile
|
||||
};
|
||||
|
||||
/** the version string of the program. */
|
||||
const char *argp_program_version = "ebusfeed of """ PACKAGE_STRING "";
|
||||
|
||||
/** the report bugs to address of the program. */
|
||||
const char *argp_program_bug_address = "" PACKAGE_BUGREPORT "";
|
||||
|
||||
/** the documentation of the program. */
|
||||
static const char argpdoc[] =
|
||||
"Feed data from an " PACKAGE " DUMPFILE to a serial device.\n"
|
||||
"\v"
|
||||
"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"
|
||||
" 'ln -s /dev/pts/2 /dev/ttyUSB60'\n"
|
||||
" 'ln -s /dev/pts/3 /dev/ttyUSB20'\n"
|
||||
" 3. start " PACKAGE ": '" PACKAGE " -f -d /dev/ttyUSB20 --nodevicecheck'\n"
|
||||
" 4. start ebusfeed: 'ebusfeed /path/to/ebus_dump.bin'\n";
|
||||
|
||||
/** the description of the accepted arguments. */
|
||||
static char argpargsdoc[] = "[DUMPFILE]";
|
||||
|
||||
/** the definition of the known program arguments. */
|
||||
static const struct argp_option argpoptions[] = {
|
||||
static const ebusd::argDef argDefs[] = {
|
||||
{"device", 'd', "DEV", 0, "Write to DEV (serial device) [/dev/ttyUSB60]", 0 },
|
||||
{"time", 't', "USEC", 0, "Delay each byte by USEC us [10000]", 0 },
|
||||
|
||||
@@ -91,18 +68,18 @@ static const struct argp_option argpoptions[] = {
|
||||
|
||||
/**
|
||||
* The program argument parsing function.
|
||||
* @param key the key from @a argpoptions.
|
||||
* @param key the key from @a argDefs.
|
||||
* @param arg the option argument, or nullptr.
|
||||
* @param state the parsing state.
|
||||
* @param parseOpt the parse options.
|
||||
*/
|
||||
error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
struct options *opt = (struct options*)state->input;
|
||||
static int parse_opt(int key, char *arg, const ebusd::argParseOpt *parseOpt) {
|
||||
struct options *opt = (struct options*)parseOpt->userArg;
|
||||
char* strEnd = nullptr;
|
||||
switch (key) {
|
||||
// Device settings:
|
||||
case 'd': // --device=/dev/ttyUSB60
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid device");
|
||||
argParseError(parseOpt, "invalid device");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->device = arg;
|
||||
@@ -110,23 +87,12 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case 't': // --time=10000
|
||||
opt->time = (unsigned int)strtoul(arg, &strEnd, 10);
|
||||
if (strEnd == nullptr || strEnd == arg || *strEnd != 0 || opt->time < 1000 || opt->time > 100000000) {
|
||||
argp_error(state, "invalid time");
|
||||
argParseError(parseOpt, "invalid time");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
if (state->arg_num == 0) {
|
||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid dumpfile");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->dumpFile = arg;
|
||||
} else {
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
return ESRCH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -139,11 +105,45 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
* @return the exit code.
|
||||
*/
|
||||
int main(int argc, char* argv[]) {
|
||||
struct argp argp = { argpoptions, parse_opt, argpargsdoc, argpdoc, nullptr, nullptr, nullptr };
|
||||
setenv("ARGP_HELP_FMT", "no-dup-args-note", 0);
|
||||
if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, nullptr, &opt) != 0) {
|
||||
return EINVAL;
|
||||
ebusd::argParseOpt parseOpt = {
|
||||
argDefs,
|
||||
parse_opt,
|
||||
"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"
|
||||
" 'ln -s /dev/pts/2 /dev/ttyUSB60'\n"
|
||||
" 'ln -s /dev/pts/3 /dev/ttyUSB20'\n"
|
||||
" 3. start " PACKAGE ": '" PACKAGE " -f -d /dev/ttyUSB20 --nodevicecheck'\n"
|
||||
" 4. start ebusfeed: 'ebusfeed /path/to/ebus_dump.bin'",
|
||||
&opt
|
||||
};
|
||||
int arg_index = -1;
|
||||
switch (ebusd::argParse(&parseOpt, argc, argv, &arg_index)) {
|
||||
case 0: // OK
|
||||
break;
|
||||
case '?': // help printed
|
||||
return 0;
|
||||
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);
|
||||
if (device == nullptr) {
|
||||
cout << "unable to create device " << opt.device << endl;
|
||||
|
||||
+62
-54
@@ -29,7 +29,6 @@
|
||||
#include <time.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <argp.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
@@ -37,29 +36,13 @@
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include "intelhex/intelhexclass.h"
|
||||
#include "lib/utils/arg.h"
|
||||
#include "lib/utils/tcpsocket.h"
|
||||
|
||||
using ebusd::socketConnect;
|
||||
|
||||
/** the version string of the program. */
|
||||
const char *argp_program_version = "eBUS adapter PIC firmware loader";
|
||||
|
||||
/** the documentation of the program. */
|
||||
static const char argpdoc[] =
|
||||
"A tool for loading firmware to the eBUS adapter PIC and configure adjustable settings."
|
||||
"\vPORT is either the serial port to use (e.g. "
|
||||
#ifdef __CYGWIN__
|
||||
"/dev/ttyS0 for COM1 on Windows"
|
||||
#else
|
||||
"/dev/ttyUSB0"
|
||||
#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.";
|
||||
|
||||
static const char argpargsdoc[] = "PORT";
|
||||
|
||||
/** the definition of the known program arguments. */
|
||||
static const struct argp_option argpoptions[] = {
|
||||
static const ebusd::argDef argDefs[] = {
|
||||
{nullptr, 0, nullptr, 0, "IP options:", 1 },
|
||||
{"dhcp", 'd', nullptr, 0, "set dynamic IP address via DHCP (default)", 0 },
|
||||
{"ip", 'i', "IP", 0, "set fix IP address (e.g. 192.168.0.10)", 0 },
|
||||
@@ -82,7 +65,7 @@ static const struct argp_option argpoptions[] = {
|
||||
{nullptr, 0, nullptr, 0, "Tool options:", 9 },
|
||||
{"verbose", 'v', nullptr, 0, "enable verbose output", 0 },
|
||||
{"slow", 's', nullptr, 0, "low speed mode for transfer (115kBd instead of 921kBd)", 0 },
|
||||
{nullptr, 0, nullptr, 0, nullptr, 0 },
|
||||
{nullptr, 0, nullptr, 0, nullptr, 0 },
|
||||
};
|
||||
|
||||
static bool verbose = false;
|
||||
@@ -136,7 +119,13 @@ bool parseShort(const char *arg, uint16_t minValue, uint16_t maxValue, uint16_t
|
||||
return true;
|
||||
}
|
||||
|
||||
error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
/**
|
||||
* The program argument parsing function.
|
||||
* @param key the key from @a 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) {
|
||||
char *ip = nullptr, *part = nullptr;
|
||||
int pos = 0, sum = 0;
|
||||
struct stat st;
|
||||
@@ -147,22 +136,22 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
break;
|
||||
case 'd': // --dhcp
|
||||
if (setIp || setMask || setGateway) {
|
||||
argp_error(state, "either DHCP or IP address is needed");
|
||||
argParseError(parseOpt, "either DHCP or IP address is needed");
|
||||
return EINVAL;
|
||||
}
|
||||
setDhcp = true;
|
||||
break;
|
||||
case 'i': // --ip=192.168.0.10
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid IP address");
|
||||
argParseError(parseOpt, "invalid IP address");
|
||||
return EINVAL;
|
||||
}
|
||||
if (setDhcp) {
|
||||
argp_error(state, "either DHCP or IP address is needed");
|
||||
argParseError(parseOpt, "either DHCP or IP address is needed");
|
||||
return EINVAL;
|
||||
}
|
||||
if (setIp) {
|
||||
argp_error(state, "IP address was specified twice");
|
||||
argParseError(parseOpt, "IP address was specified twice");
|
||||
return EINVAL;
|
||||
}
|
||||
ip = strdup(arg);
|
||||
@@ -177,41 +166,41 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
}
|
||||
free(ip);
|
||||
if (pos != 4 || part || sum == 0) {
|
||||
argp_error(state, "invalid IP address");
|
||||
argParseError(parseOpt, "invalid IP address");
|
||||
return EINVAL;
|
||||
}
|
||||
setIp = true;
|
||||
break;
|
||||
case 'm': // --mask=24
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid IP mask");
|
||||
argParseError(parseOpt, "invalid IP mask");
|
||||
return EINVAL;
|
||||
}
|
||||
if (setDhcp) {
|
||||
argp_error(state, "either DHCP or IP address is needed");
|
||||
argParseError(parseOpt, "either DHCP or IP address is needed");
|
||||
return EINVAL;
|
||||
}
|
||||
if (setMask) {
|
||||
argp_error(state, "mask was specified twice");
|
||||
argParseError(parseOpt, "mask was specified twice");
|
||||
return EINVAL;
|
||||
}
|
||||
if (!parseByte(arg, 1, 0x1e, &setMaskLen)) {
|
||||
argp_error(state, "invalid IP mask");
|
||||
argParseError(parseOpt, "invalid IP mask");
|
||||
return EINVAL;
|
||||
}
|
||||
setMask = true;
|
||||
break;
|
||||
case 'g': // --gateway=192.168.0.11
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid gateway");
|
||||
argParseError(parseOpt, "invalid gateway");
|
||||
return EINVAL;
|
||||
}
|
||||
if (setDhcp) {
|
||||
argp_error(state, "either DHCP or IP address is needed");
|
||||
argParseError(parseOpt, "either DHCP or IP address is needed");
|
||||
return EINVAL;
|
||||
}
|
||||
if (!setIp || !setMask) {
|
||||
argp_error(state, "IP and mask need to be specified before gateway");
|
||||
argParseError(parseOpt, "IP and mask need to be specified before gateway");
|
||||
return EINVAL;
|
||||
}
|
||||
ip = strdup(arg);
|
||||
@@ -228,7 +217,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
uint8_t maskRemain = setMaskLen-pos*8;
|
||||
uint8_t mask = maskRemain >= 8 ? 255 : maskRemain == 0 ? 0 : (255^((1 << (8 - maskRemain)) - 1));
|
||||
if ((address & mask) != (setIpAddress[pos] & mask)) {
|
||||
argp_error(state, "invalid gateway (different network)");
|
||||
argParseError(parseOpt, "invalid gateway (different network)");
|
||||
free(ip);
|
||||
return EINVAL;
|
||||
}
|
||||
@@ -237,15 +226,15 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
}
|
||||
free(ip);
|
||||
if (pos != 4 || part || sum == 0 || setGatewayBits == 0) {
|
||||
argp_error(state, "invalid gateway");
|
||||
argParseError(parseOpt, "invalid gateway");
|
||||
return EINVAL;
|
||||
}
|
||||
if (setGatewayBits == hostBits) {
|
||||
argp_error(state, "invalid gateway (same as address)");
|
||||
argParseError(parseOpt, "invalid gateway (same as address)");
|
||||
return EINVAL;
|
||||
}
|
||||
if (!setGatewayBits || setGatewayBits == ((1 << (32 - setMaskLen)) - 1)) {
|
||||
argp_error(state, "invalid gateway (net or broadcast address)");
|
||||
argParseError(parseOpt, "invalid gateway (net or broadcast address)");
|
||||
return EINVAL;
|
||||
}
|
||||
if (setGatewayBits == 1) { // default
|
||||
@@ -260,7 +249,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
}
|
||||
if (!(setGatewayBits >> 5)) {
|
||||
if (!(setGatewayBits & 0x1f)) {
|
||||
argp_error(state, "invalid gateway (net address)");
|
||||
argParseError(parseOpt, "invalid gateway (net address)");
|
||||
return EINVAL;
|
||||
}
|
||||
// fine: host part above max gateway adjustable bits is the same and remainder non-zero
|
||||
@@ -274,7 +263,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
setGateway = true;
|
||||
break;
|
||||
}
|
||||
argp_error(state, "invalid gateway (out of possible range of first/last 31 hosts in subnet)");
|
||||
argParseError(parseOpt, "invalid gateway (out of possible range of first/last 31 hosts in subnet)");
|
||||
return EINVAL;
|
||||
case 'M': // --macip
|
||||
setMacFromIp = true;
|
||||
@@ -286,11 +275,11 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
break;
|
||||
case 'a': // --arbdel=1000
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid arbitration delay");
|
||||
argParseError(parseOpt, "invalid arbitration delay");
|
||||
return EINVAL;
|
||||
}
|
||||
if (!parseShort(arg, 0, 620, &setArbitrationDelayMicros)) {
|
||||
argp_error(state, "invalid arbitration delay");
|
||||
argParseError(parseOpt, "invalid arbitration delay");
|
||||
return EINVAL;
|
||||
}
|
||||
setArbitrationDelay = true;
|
||||
@@ -305,7 +294,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
break;
|
||||
case -3: // --variant=U|W|E|F|N|u|w|e|f|n
|
||||
if (arg == nullptr || arg[0] == 0) {
|
||||
argp_error(state, "invalid variant");
|
||||
argParseError(parseOpt, "invalid variant");
|
||||
return EINVAL;
|
||||
}
|
||||
if (arg[0] == 'u' || arg[0] == 'U') {
|
||||
@@ -319,7 +308,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
} else if (arg[0] == 'n' || arg[0] == 'N') {
|
||||
setVariantValue = 0;
|
||||
} else {
|
||||
argp_error(state, "invalid variant");
|
||||
argParseError(parseOpt, "invalid variant");
|
||||
return EINVAL;
|
||||
}
|
||||
setVariantForced = arg[0]<'a';
|
||||
@@ -327,7 +316,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
break;
|
||||
case 'f': // --flash=firmware.hex
|
||||
if (arg == nullptr || arg[0] == 0 || stat(arg, &st) != 0 || !S_ISREG(st.st_mode)) {
|
||||
argp_error(state, "invalid flash file");
|
||||
argParseError(parseOpt, "invalid flash file");
|
||||
return EINVAL;
|
||||
}
|
||||
flashFile = arg;
|
||||
@@ -339,7 +328,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
lowSpeed = true;
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
return ESRCH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1094,7 +1083,7 @@ int readSettings(int fd, uint8_t* currentData = nullptr) {
|
||||
} else {
|
||||
std::cout << "off" << std::endl;
|
||||
}
|
||||
std::cout << "Variant: "; // since firmware 20221206
|
||||
std::cout << "Variant: "; // since firmware 20221206
|
||||
switch (configData[5]&0x03) {
|
||||
case 3:
|
||||
std::cout << "USB/RPI (high-speed)";
|
||||
@@ -1156,7 +1145,7 @@ bool writeSettings(int fd, uint8_t* currentData = nullptr) {
|
||||
if (setVariant) {
|
||||
configData[5] = (configData[5]&0x38) | (setVariantForced?0:0x04) | (setVariantValue&0x03);
|
||||
if (setVariantValue==0) {
|
||||
configData[1] = (configData[1]&~0x1f); // set mask=0 to disable Ethernet
|
||||
configData[1] = (configData[1]&~0x1f); // set mask=0 to disable Ethernet
|
||||
}
|
||||
}
|
||||
if (writeConfig(fd, 0x0000, 8, configData) != 0) {
|
||||
@@ -1170,13 +1159,32 @@ bool writeSettings(int fd, uint8_t* currentData = nullptr) {
|
||||
int run(int fd);
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
struct argp aargp = { argpoptions, parse_opt, argpargsdoc, argpdoc, nullptr, nullptr, nullptr };
|
||||
ebusd::argParseOpt parseOpt = {
|
||||
argDefs,
|
||||
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__
|
||||
"/dev/ttyS0 for COM1 on Windows"
|
||||
#else
|
||||
"/dev/ttyUSB0"
|
||||
#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;
|
||||
setenv("ARGP_HELP_FMT", "no-dup-args-note", 0);
|
||||
|
||||
if (argp_parse(&aargp, argc, argv, ARGP_IN_ORDER, &arg_index, nullptr) != 0) {
|
||||
std::cerr << "invalid arguments" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
switch (ebusd::argParse(&parseOpt, argc, argv, &arg_index)) {
|
||||
case 0: // OK
|
||||
break;
|
||||
case '?': // help printed
|
||||
return 0;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (setIp != setMask || (setMacFromIp && !setIp)) {
|
||||
@@ -1188,7 +1196,7 @@ int main(int argc, char* argv[]) {
|
||||
printFileChecksum();
|
||||
exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
argp_help(&aargp, stderr, ARGP_HELP_STD_ERR, const_cast<char*>("ebuspicloader"));
|
||||
ebusd::argHelp(&parseOpt);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user