Add --driverdir=<dir> and --driver=<file> for loading drivers from text files.

pull/1167/head
Fredrik Öhrström 2024-02-11 00:12:31 +01:00
rodzic 440ea263b1
commit 04ed4d7628
15 zmienionych plików z 1969 dodań i 677 usunięć

Wyświetl plik

@ -157,6 +157,7 @@ PROG_OBJS:=\
$(BUILD)/bus.o \ $(BUILD)/bus.o \
$(BUILD)/cmdline.o \ $(BUILD)/cmdline.o \
$(BUILD)/config.o \ $(BUILD)/config.o \
$(BUILD)/drivers.o \
$(BUILD)/dvparser.o \ $(BUILD)/dvparser.o \
$(BUILD)/formula.o \ $(BUILD)/formula.o \
$(BUILD)/mbus_rawtty.o \ $(BUILD)/mbus_rawtty.o \

Wyświetl plik

@ -414,6 +414,8 @@ As {options} you can use:
--calculate_flow_f=flow_temperature_c --calculate_flow_f=flow_temperature_c
--debug for a lot of information --debug for a lot of information
--donotprobe=<tty> do not auto-probe this tty. Use multiple times for several ttys or specify "all" for all ttys. --donotprobe=<tty> do not auto-probe this tty. Use multiple times for several ttys or specify "all" for all ttys.
--driver=<file> load a driver
--driverdir=<dir> load all drivers in dir
--exitafter=<time> exit program after time, eg 20h, 10m 5s --exitafter=<time> exit program after time, eg 20h, 10m 5s
--format=<hr/json/fields> for human readable, json or semicolon separated fields --format=<hr/json/fields> for human readable, json or semicolon separated fields
--help list all options --help list all options

Wyświetl plik

@ -50,3 +50,18 @@ then
else else
echo "conf dir: $ROOT/etc/wmbusmeters.d unchanged" echo "conf dir: $ROOT/etc/wmbusmeters.d unchanged"
fi fi
####################################################################
##
## Create /etc/wmbusmeters.drivers.d
##
if [ ! -d "$ROOT"/etc/wmbusmeters.drivers.d ]
then
# Create the drivers directory
mkdir -p "$ROOT"/etc/wmbusmeters.drivers.d
chmod -R 755 "$ROOT"/etc/wmbusmeters.drivers.d
echo "conf dir: created $ROOT/etc/wmbusmeters.drivers.d"
else
echo "conf dir: $ROOT/etc/wmbusmeters.drivers.d unchanged"
fi

Wyświetl plik

@ -16,6 +16,7 @@
*/ */
#include"cmdline.h" #include"cmdline.h"
#include"drivers.h"
#include"meters.h" #include"meters.h"
#include"util.h" #include"util.h"
@ -62,17 +63,9 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv)
static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int argc, char **argv) static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int argc, char **argv)
{ {
int i = 1; int i = 1;
// First find all logging flags, --silent --verbose --normal --debug
while (argv[i] && argv[i][0] == '-') while (argv[i] && argv[i][0] == '-')
{ {
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
c->need_help = true;
return shared_ptr<Configuration>(c);
}
if (!strncmp(argv[i], "--device=", 9) || // Deprecated
!strncmp(argv[i], "--overridedevice=", 17))
{
error("You can only use --overridedevice=xyz with --useconfig=xyz\n");
}
if (!strcmp(argv[i], "--silent")) { if (!strcmp(argv[i], "--silent")) {
c->silent = true; c->silent = true;
i++; i++;
@ -93,6 +86,48 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
i++; i++;
continue; continue;
} }
if (!strcmp(argv[i], "--debug")) {
c->debug = true;
verboseEnabled(true);
debugEnabled(true);
i++;
continue;
}
if (!strcmp(argv[i], "--trace")) {
c->debug = true;
c->trace = true;
verboseEnabled(true);
debugEnabled(true);
traceEnabled(true);
i++;
continue;
}
i++;
}
// Now do the rest of the arguments.
i = 1;
while (argv[i] && argv[i][0] == '-')
{
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
c->need_help = true;
return shared_ptr<Configuration>(c);
}
if (!strcmp(argv[i], "--silent") ||
!strcmp(argv[i], "--verbose") ||
!strcmp(argv[i], "--normal") ||
!strcmp(argv[i], "--debug") ||
!strcmp(argv[i], "--trace"))
{
// Handled already.
i++;
continue;
}
if (!strncmp(argv[i], "--device=", 9) || // Deprecated
!strncmp(argv[i], "--overridedevice=", 17))
{
error("You can only use --overridedevice=xyz with --useconfig=xyz\n");
}
if (!strcmp(argv[i], "--version")) { if (!strcmp(argv[i], "--version")) {
c->version = true; c->version = true;
return shared_ptr<Configuration>(c); return shared_ptr<Configuration>(c);
@ -164,23 +199,6 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
i++; i++;
continue; continue;
} }
if (!strcmp(argv[i], "--debug")) {
c->debug = true;
verboseEnabled(true);
debugEnabled(true);
i++;
continue;
}
if (!strcmp(argv[i], "--trace")) {
c->debug = true;
c->trace = true;
verboseEnabled(true);
debugEnabled(true);
traceEnabled(true);
i++;
continue;
}
if (!strncmp(argv[i], "--logtimestamps=", 16)) if (!strncmp(argv[i], "--logtimestamps=", 16))
{ {
string ts = string(argv[i]+16); string ts = string(argv[i]+16);
@ -588,6 +606,31 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
i++; i++;
continue; continue;
} }
if (!strncmp(argv[i], "--driversdir=", 13))
{
size_t len = strlen(argv[i]) - 13;
c->drivers_dir = string(argv[i]+13, len);
if (!checkIfDirExists(c->drivers_dir.c_str()))
{
error("You must supply a valid directory to --driversdir=<dir>\n");
}
i++;
loadDriversFromDir(c->drivers_dir);
continue;
}
if (!strncmp(argv[i], "--driver=", 9))
{
size_t len = strlen(argv[i]) - 9;
string driver = string(argv[i]+9, len);
if (!checkFileExists(driver.c_str()))
{
error("You must supply a valid file to --driver=<file>\n");
}
i++;
loadDriver(driver);
continue;
}
error("Unknown option \"%s\"\n", argv[i]); error("Unknown option \"%s\"\n", argv[i]);
} }

Wyświetl plik

@ -16,6 +16,7 @@
*/ */
#include"config.h" #include"config.h"
#include"drivers.h"
#include"meters.h" #include"meters.h"
#include"units.h" #include"units.h"
@ -679,12 +680,14 @@ shared_ptr<Configuration> loadConfiguration(string root, ConfigOverrides overrid
string conf_dir = root; string conf_dir = root;
string conf_file = root+"/etc/wmbusmeters.conf"; string conf_file = root+"/etc/wmbusmeters.conf";
string conf_meter_dir = root+"/etc/wmbusmeters.d"; string conf_meter_dir = root+"/etc/wmbusmeters.d";
string conf_drivers_dir = root+"/etc/wmbusmeters.drivers.d";
if (!checkFileExists(conf_file.c_str())) if (!checkFileExists(conf_file.c_str()))
{ {
conf_dir = root+"/etc"; conf_dir = root+"/etc";
conf_file = root+"/wmbusmeters.conf"; conf_file = root+"/wmbusmeters.conf";
conf_meter_dir = root+"/wmbusmeters.d"; conf_meter_dir = root+"/wmbusmeters.d";
conf_drivers_dir = root+"/wmbusmeters.drivers.d";
} }
debug("(config) loading %s\n", conf_file.c_str()); debug("(config) loading %s\n", conf_file.c_str());
@ -805,6 +808,8 @@ shared_ptr<Configuration> loadConfiguration(string root, ConfigOverrides overrid
handleLogfile(c, overrides.logfile_override); handleLogfile(c, overrides.logfile_override);
} }
loadDriversFromDir(conf_drivers_dir);
return shared_ptr<Configuration>(c); return shared_ptr<Configuration>(c);
} }

Wyświetl plik

@ -68,6 +68,7 @@ struct Configuration
ConfigOverrides overrides; ConfigOverrides overrides;
bool useconfig {}; bool useconfig {};
std::string config_root; std::string config_root;
std::string drivers_dir;
bool need_help {}; bool need_help {};
bool silent {}; bool silent {};
bool verbose {}; bool verbose {};

Wyświetl plik

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2023 Fredrik Öhrström (gpl-3.0-or-later) Copyright (C) 2023-2024 Fredrik Öhrström (gpl-3.0-or-later)
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -67,7 +67,7 @@ bool DriverDynamic::load(DriverInfo *di, const string &file)
string default_fields = check_default_fields(xmqGetString(doc, NULL, "/driver/default_fields"), file); string default_fields = check_default_fields(xmqGetString(doc, NULL, "/driver/default_fields"), file);
di->setDefaultFields(default_fields); di->setDefaultFields(default_fields);
verbose("(driver) loading driver %s\n", name.c_str()); verbose("(driver) loading driver %s from file %s\n", name.c_str(), file.c_str());
di->setDynamic(file, doc); di->setDynamic(file, doc);
@ -90,7 +90,7 @@ DriverDynamic::DriverDynamic(MeterInfo &mi, DriverInfo &di) :
{ {
XMQDoc *doc = di.getDynamicDriver(); XMQDoc *doc = di.getDynamicDriver();
verbose("(driver) constructing driver %s from file %s\n", verbose("(driver) constructing driver %s from already loaded file %s\n",
di.name().str().c_str(), di.name().str().c_str(),
fileName().c_str()); fileName().c_str());

41
src/drivers.c 100644
Wyświetl plik

@ -0,0 +1,41 @@
/*
Copyright (C) 2024 Fredrik Öhrström (gpl-3.0-or-later)
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<vector>
#include<string>
#include"util.h"
#include"drivers.h"
#include"meters.h"
using namespace std;
void loadDriversFromDir(std::string dir)
{
if (!checkIfDirExists(dir.c_str())) return;
vector<string> drivers;
listFiles(dir, &drivers);
verbose("(drivers) scanning dir %s\n", dir.c_str());
for (string &file : drivers)
{
string filename = dir+"/"+file;
string s = loadDriver(filename);
}
}

25
src/drivers.h 100644
Wyświetl plik

@ -0,0 +1,25 @@
/*
Copyright (C) 2024 Fredrik Öhrström (gpl-3.0-or-later)
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 DRIVERS_H_
#define DRIVERS_H_
#include<string>
void loadDriversFromDir(std::string dir);
#endif

Wyświetl plik

@ -18,6 +18,7 @@
#include"bus.h" #include"bus.h"
#include"cmdline.h" #include"cmdline.h"
#include"config.h" #include"config.h"
#include"drivers.h"
#include"meters.h" #include"meters.h"
#include"printer.h" #include"printer.h"
#include"rtlsdr.h" #include"rtlsdr.h"
@ -311,11 +312,17 @@ void list_meters(Configuration *config)
{ {
string mname = di->name().str(); string mname = di->name().str();
const char *info = toString(di->type()); const char *info = toString(di->type());
const char *where = "";
const string f = di->getDynamicFileName();
if (f != "")
{
where = f.c_str();
}
if (config->list_meters_search == "" || \ if (config->list_meters_search == "" || \
stringFoundCaseIgnored(info, config->list_meters_search) || \ stringFoundCaseIgnored(info, config->list_meters_search) || \
stringFoundCaseIgnored(mname.c_str(), config->list_meters_search)) \ stringFoundCaseIgnored(mname.c_str(), config->list_meters_search)) \
printf("%-14s %s\n", mname.c_str(), info); printf("%-14s %s %s\n", mname.c_str(), info, where);
} }
} }

Wyświetl plik

@ -77,6 +77,21 @@ vector<DriverInfo*> &allDrivers()
return *registered_drivers_list_; return *registered_drivers_list_;
} }
void removeDriver(const string &name)
{
for (auto i = registered_drivers_list_->begin(); i != registered_drivers_list_->end(); i++)
{
if ((*i)->name().str() == name)
{
registered_drivers_list_->erase(i);
break;
}
}
registered_drivers_->erase(name);
assert(registered_drivers_->count(name) == 0);
}
void addRegisteredDriver(DriverInfo di) void addRegisteredDriver(DriverInfo di)
{ {
verifyDriverLookupCreated(); verifyDriverLookupCreated();
@ -192,13 +207,22 @@ string loadDriver(const string &file)
{ {
error("Failed to load driver from file: %s\n", file.c_str()); error("Failed to load driver from file: %s\n", file.c_str());
} }
// Check that the driver name has not been registered before!
if (lookupDriver(di.name().str()) != NULL) // Check if the driver name has been registered before....
DriverInfo *old = lookupDriver(di.name().str());
if (old != NULL)
{ {
debug("Ignoring loaded driver %s %s since it is already registered!\n", if (old->getDynamicFileName() != "")
di.name().str().c_str(), {
file.c_str()); error("Newly loaded driver file %s tries to register the same name %s as driver file %s has already taken!\n",
return di.name().str(); file.c_str(), di.name().str().c_str(), old->getDynamicFileName().c_str());
}
else
{
verbose("(drivers) newly loaded driver %s overrides builtin driver\n",
file.c_str(), di.name().str().c_str());
removeDriver(di.name().str());
}
} }
// Check that no other driver also triggers on the same detection values. // Check that no other driver also triggers on the same detection values.
@ -209,8 +233,30 @@ string loadDriver(const string &file)
bool foo = p->detect(d.mfct, d.type, d.version); bool foo = p->detect(d.mfct, d.type, d.version);
if (foo) if (foo)
{ {
error("Newly loaded driver %s tries to register the same auto detect combo as driver %s alread has taken!\n", string mfct = manufacturerFlag(d.mfct);
di.name().str().c_str(), p->name().str().c_str()); if (p->getDynamicFileName() != "")
{
// It is not ok to override an previously file loaded driver!
error("Newly loaded driver %s tries to register the same "
"auto detect combo as driver %s alread has taken! mvt=%s,%02x,%02x\n",
di.name().str().c_str(),
p->name().str().c_str(),
mfct.c_str(),
d.version,
d.type);
}
else
{
// It is ok to override a built in driver!
verbose("(driver) newly loaded driver %s forces removal of builtin "
"driver %s since it auto-detects the same combo! mvt=%s,%02x,%02x\n",
di.name().str().c_str(),
p->name().str().c_str(),
mfct.c_str(),
d.version,
d.type);
removeDriver(p->name().str());
}
} }
} }
} }

Wyświetl plik

@ -236,6 +236,8 @@ DriverInfo pickMeterDriver(Telegram *t);
// Return true for mbus and S2/C2/T2 drivers. // Return true for mbus and S2/C2/T2 drivers.
bool driverNeedsPolling(DriverName& dn); bool driverNeedsPolling(DriverName& dn);
string loadDriver(const string &file);
vector<DriverInfo*>& allDrivers(); vector<DriverInfo*>& allDrivers();
//////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////

2175
src/xmq.c

Plik diff jest za duży Load Diff

195
src/xmq.h
Wyświetl plik

@ -86,6 +86,7 @@ typedef struct XMQParseCallbacks XMQParseCallbacks;
@XMQ_CONTENT_XML: xml detected @XMQ_CONTENT_XML: xml detected
@XMQ_CONTENT_HTML: html detected @XMQ_CONTENT_HTML: html detected
@XMQ_CONTENT_JSON: json detected @XMQ_CONTENT_JSON: json detected
@XMQ_CONTENT_TEXT: valid utf8 text input/output is selected
Specify the file/buffer content type. Specify the file/buffer content type.
*/ */
@ -97,7 +98,8 @@ typedef enum
XMQ_CONTENT_HTMQ = 3, XMQ_CONTENT_HTMQ = 3,
XMQ_CONTENT_XML = 4, XMQ_CONTENT_XML = 4,
XMQ_CONTENT_HTML = 5, XMQ_CONTENT_HTML = 5,
XMQ_CONTENT_JSON = 6 XMQ_CONTENT_JSON = 6,
XMQ_CONTENT_TEXT = 7
} XMQContentType; } XMQContentType;
/** /**
@ -143,76 +145,37 @@ typedef enum
} XMQTrimType; } XMQTrimType;
/** /**
XMQColorType: The normal coloring options for xmq. XMQSyntax:
@COLORTYPE_xmq_c: Comments @SYNTAX_C: Comments
@COLORTYPE_xmq_q: Standalone quote. @SYNTAX_Q: Standalone quote.
@COLORTYPE_xmq_e: Entity @SYNTAX_E: Entity
@COLORTYPE_xmq_ens: Element Namespace @SYNTAX_ENS: Element Namespace
@COLORTYPE_xmq_en: Element Name @SYNTAX_EN: Element Name
@COLORTYPE_xmq_ek: Element Key @SYNTAX_EK: Element Key
@COLORTYPE_xmq_ekv: Element Key Value @SYNTAX_EKV: Element Key Value
@COLORTYPE_xmq_ans: Attribute NameSpace @SYNTAX_ANS: Attribute NameSpace
@COLORTYPE_xmq_ak: Attribute Key @SYNTAX_AK: Attribute Key
@COLORTYPE_xmq_akv: Attribute Key Value @SYNTAX_AKV: Attribute Key Value
@COLORTYPE_xmq_cp: Compound Parentheses @SYNTAX_CP: Compound Parentheses
@COLORTYPE_xmq_uw: Unicode Whitespace @SYNTAX_NDC: Namespace declaration
@COLORTYPE_xmq_tw: Tab Whitespace @SYNTAX_UW: Unicode Whitespace
*/ */
typedef enum typedef enum
{ {
COLORTYPE_xmq_c = 0, // Comments SYNTAX_C = 0, // Comments
COLORTYPE_xmq_q = 1, // Standalone quote. SYNTAX_Q = 1, // Standalone quote.
COLORTYPE_xmq_e = 2, // Entity SYNTAX_E = 2, // Entity
COLORTYPE_xmq_ens = 3, // Element Namespace SYNTAX_ENS = 3, // Element Namespace
COLORTYPE_xmq_en = 4, // Element Name SYNTAX_EN = 4, // Element Name
COLORTYPE_xmq_ek = 5, // Element Key SYNTAX_EK = 5, // Element Key
COLORTYPE_xmq_ekv = 6, // Element Key Value SYNTAX_EKV = 6, // Element Key Value
COLORTYPE_xmq_ans = 7, // Attribute NameSpace SYNTAX_ANS = 7, // Attribute NameSpace
COLORTYPE_xmq_ak = 8, // Attribute Key SYNTAX_AK = 8, // Attribute Key
COLORTYPE_xmq_akv = 9, // Attribute Key Value SYNTAX_AKV = 9, // Attribute Key Value
COLORTYPE_xmq_cp = 10, // Compound Parentheses SYNTAX_CP = 10, // Compound Parentheses
COLORTYPE_xmq_uw = 11, // Unicode Whitespace SYNTAX_NDC = 11, // Namespace declaration
} XMQColorType; SYNTAX_UW = 12, // Unicode Whitespace
} XMQSyntax;
/**
XMQColor:
Map token type into color index.
*/
typedef enum XMQColor {
COLOR_none,
COLOR_whitespace,
COLOR_unicode_whitespace,
COLOR_indentation_whitespace,
COLOR_equals,
COLOR_brace_left,
COLOR_brace_right,
COLOR_apar_left,
COLOR_apar_right,
COLOR_cpar_left,
COLOR_cpar_right,
COLOR_quote,
COLOR_entity,
COLOR_comment,
COLOR_comment_continuation,
COLOR_ns_colon,
COLOR_element_ns,
COLOR_element_name,
COLOR_element_key,
COLOR_element_value_text,
COLOR_element_value_quote,
COLOR_element_value_entity,
COLOR_element_value_compound_quote,
COLOR_element_value_compound_entity,
COLOR_attr_ns,
COLOR_attr_ns_declaration,
COLOR_attr_key,
COLOR_attr_value_text,
COLOR_attr_value_quote,
COLOR_attr_value_entity,
COLOR_attr_value_compound_quote,
COLOR_attr_value_compound_entity,
} XMQColor;
/** /**
XMQReader: XMQReader:
@ -281,21 +244,6 @@ typedef enum
*/ */
typedef XMQProceed (*XMQNodeCallback)(XMQDoc *doc, XMQNode *node, void *user_data); typedef XMQProceed (*XMQNodeCallback)(XMQDoc *doc, XMQNode *node, void *user_data);
///////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////// FUNCTIONS /////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
xmqDetectContentType:
@start: points to first byte of buffer to scan for content type
@stop: points to byte after buffer
Detect the content type xmq/xml/html/json by examining a few leading
non-whitespace words/characters.
*/
XMQContentType xmqDetectContentType(const char *start, const char *stop);
/** /**
XMQParseError: XMQParseError:
@XMQ_ERROR_CANNOT_READ_FILE: file not found or cannot be opened for reading. @XMQ_ERROR_CANNOT_READ_FILE: file not found or cannot be opened for reading.
@ -331,6 +279,7 @@ XMQContentType xmqDetectContentType(const char *start, const char *stop);
*/ */
typedef enum typedef enum
{ {
XMQ_ERROR_NONE = 0,
XMQ_ERROR_CANNOT_READ_FILE = 1, XMQ_ERROR_CANNOT_READ_FILE = 1,
XMQ_ERROR_OOM = 2, XMQ_ERROR_OOM = 2,
XMQ_ERROR_NOT_XMQ = 3, XMQ_ERROR_NOT_XMQ = 3,
@ -359,25 +308,43 @@ typedef enum
XMQ_ERROR_EXPECTED_HTML = 26, XMQ_ERROR_EXPECTED_HTML = 26,
XMQ_ERROR_EXPECTED_JSON = 27, XMQ_ERROR_EXPECTED_JSON = 27,
XMQ_ERROR_PARSING_XML = 28, XMQ_ERROR_PARSING_XML = 28,
XMQ_ERROR_PARSING_HTML = 29 XMQ_ERROR_PARSING_HTML = 29,
XMQ_WARNING_QUOTES_NEEDED = 100
} XMQParseError; } XMQParseError;
///////////////////////////////////////////////////////////////////////////////////////////////////
const char *xmqParseErrorToString(XMQParseError e); ////////////////////// FUNCTIONS /////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
/** Allocate an empty XMQParseCallback structure. All callbacks are NULL and none will be called. */
XMQParseCallbacks *xmqNewParseCallbacks();
/** Free the XMQParseCallback structure. */
void xmqFreeParseCallbacks(XMQParseCallbacks *cb);
/** /**
xmqSetupParseCallbacksNoopTokens: xmqDetectContentType:
@start: points to first byte of buffer to scan for content type
@stop: points to byte after buffer
When tokenizing only, for coloring or debugging, you can Detect the content type xmq/xml/html/json by examining a few leading
use the setup functions below for a few standardized handlers. non-whitespace words/characters.
*/
XMQContentType xmqDetectContentType(const char *start, const char *stop);
/**
xmqParseErrorToString:
@e: Translate this error to a human readable string.
*/ */
void xmqSetupParseCallbacksNoopTokens(XMQParseCallbacks *state); const char *xmqParseErrorToString(XMQParseError e);
/**
xmqNewParseCallbacks:
Allocate an empty XMQParseCallback structure. All callbacks are NULL and none will be called.
*/
XMQParseCallbacks *xmqNewParseCallbacks();
/**
xmqFreeParseCallbacks:
Free the XMQParseCallback structure.
*/
void xmqFreeParseCallbacks(XMQParseCallbacks *cb);
/** /**
xmqSetupParseCallbacksColorizeTokens: xmqSetupParseCallbacksColorizeTokens:
@ -469,6 +436,20 @@ XMQDoc *xmqNewDoc();
*/ */
void xmqSetDocSourceName(XMQDoc *doq, const char *source_name); void xmqSetDocSourceName(XMQDoc *doq, const char *source_name);
/**
xmqGetOriginalContentType:
If available, return the original content type (xmq/htmq/xml/html/json/text) of this document.
*/
XMQContentType xmqGetOriginalContentType(XMQDoc *doq);
/**
xmqGetOriginalSize:
If available, return the size of the original content, ie the loaded file size.
*/
size_t xmqGetOriginalSize(XMQDoc *doq);
/** /**
xmqGetRootNode: xmqGetRootNode:
@ -542,10 +523,10 @@ void xmqSetUseColor(XMQOutputSettings *os, bool use_color);
void xmqSetEscapeNewlines(XMQOutputSettings *os, bool escape_newlines); void xmqSetEscapeNewlines(XMQOutputSettings *os, bool escape_newlines);
void xmqSetEscapeNon7bit(XMQOutputSettings *os, bool escape_non_7bit); void xmqSetEscapeNon7bit(XMQOutputSettings *os, bool escape_non_7bit);
void xmqSetOutputFormat(XMQOutputSettings *os, XMQContentType output_format); void xmqSetOutputFormat(XMQOutputSettings *os, XMQContentType output_format);
//void xmqSetColoring(XMQOutputSettings *os, XMQColoring coloring);
void xmqSetRenderFormat(XMQOutputSettings *os, XMQRenderFormat render_to); void xmqSetRenderFormat(XMQOutputSettings *os, XMQRenderFormat render_to);
void xmqSetRenderRaw(XMQOutputSettings *os, bool render_raw); void xmqSetRenderRaw(XMQOutputSettings *os, bool render_raw);
void xmqSetRenderOnlyStyle(XMQOutputSettings *os, bool only_style); void xmqSetRenderOnlyStyle(XMQOutputSettings *os, bool only_style);
void xmqSetRenderStyle(XMQOutputSettings *os, const char *render_style);
void xmqSetWriterContent(XMQOutputSettings *os, XMQWriter content); void xmqSetWriterContent(XMQOutputSettings *os, XMQWriter content);
void xmqSetWriterError(XMQOutputSettings *os, XMQWriter error); void xmqSetWriterError(XMQOutputSettings *os, XMQWriter error);
@ -729,27 +710,21 @@ void xmqRenderHtmlSettings(XMQOutputSettings *settings,
const char *use_class); const char *use_class);
/** /**
xmqOverrideColorType: xmqOverrideColor:
@settings:
@render_style: Use "" for the default render_style
@sc: The syntax element you want to change the color for.
Change the color strings for the given color type. You have to run xmqSetupDefaultColors first. Change the color strings for the given color type. You have to run xmqSetupDefaultColors first.
*/ */
void xmqOverrideColorType(XMQOutputSettings *settings,
XMQColorType ct,
const char *pre,
const char *post,
const char *ns);
/**
xmqOverrideColor:
Change the color strings for the given color. You have to run xmqSetupDefaultColors first.
*/
void xmqOverrideColor(XMQOutputSettings *settings, void xmqOverrideColor(XMQOutputSettings *settings,
XMQColor c, const char *render_style,
XMQSyntax sc,
const char *pre, const char *pre,
const char *post, const char *post,
const char *ns); const char *ns);
#ifdef __cplusplus #ifdef __cplusplus
_hideRBfromEditor _hideRBfromEditor
#endif #endif

Wyświetl plik

@ -16,10 +16,10 @@ mkdir -p $TEST
TESTNAME="Test config override with oneshot" TESTNAME="Test config override with oneshot"
TESTRESULT="ERROR" TESTRESULT="ERROR"
cat simulations/serial_aes.msg | grep '^{' | jq --sort-keys . | tr -d '#' > $TEST/test_expected.txt cat simulations/serial_aes.msg | grep '^{' | jq . --sort-keys | tr -d '#' > $TEST/test_expected.txt
cat simulations/serial_aes.msg | grep '^[CT]' | tr -d '#' > $TEST/test_input.txt cat simulations/serial_aes.msg | grep '^[CT]' | tr -d '#' > $TEST/test_input.txt
cat $TEST/test_input.txt | $PROG --useconfig=tests/config9 --overridedevice=stdin:rtlwmbus --oneshot 2> $TEST/test_stderr.txt | jq --sort-keys . > $TEST/test_output.txt cat $TEST/test_input.txt | $PROG --useconfig=tests/config9 --overridedevice=stdin:rtlwmbus --oneshot 2> $TEST/test_stderr.txt | jq . --sort-keys > $TEST/test_output.txt
if ! grep -q "(main) all meters have received at least one update, stopping." $TEST/test_stderr.txt if ! grep -q "(main) all meters have received at least one update, stopping." $TEST/test_stderr.txt
then then
@ -35,6 +35,10 @@ then
echo "OK: $TESTNAME" echo "OK: $TESTNAME"
TESTRESULT="OK" TESTRESULT="OK"
else else
if [ "$USE_MELD" = "true" ]
then
meld $TEST/test_expected.txt $TEST/test_response.txt
fi
echo "ERROR: $TESTNAME" echo "ERROR: $TESTNAME"
exit 1 exit 1
fi fi
@ -42,11 +46,11 @@ fi
TESTNAME="Test config override with exitafter" TESTNAME="Test config override with exitafter"
TESTRESULT="ERROR" TESTRESULT="ERROR"
cat simulations/serial_aes.msg | grep '^{' | jq --sort-keys . | tr -d '#' > $TEST/test_expected.txt cat simulations/serial_aes.msg | grep '^{' | jq . --sort-keys | tr -d '#' > $TEST/test_expected.txt
cat simulations/serial_aes.msg | grep '^[CT]' | tr -d '#' > $TEST/test_input.txt cat simulations/serial_aes.msg | grep '^[CT]' | tr -d '#' > $TEST/test_input.txt
# Read from stdin # Read from stdin
{ cat $TEST/test_input.txt ; sleep 4; } | $PROG --useconfig=tests/config9 --overridedevice=stdin:rtlwmbus --exitafter=1s 2> $TEST/test_stderr.txt | jq --sort-keys . > $TEST/test_output.txt { cat $TEST/test_input.txt ; sleep 4; } | $PROG --useconfig=tests/config9 --overridedevice=stdin:rtlwmbus --exitafter=1s 2> $TEST/test_stderr.txt | jq . --sort-keys > $TEST/test_output.txt
if ! grep -q "(serial) exit after " $TEST/test_stderr.txt if ! grep -q "(serial) exit after " $TEST/test_stderr.txt
then then