diff options
author | Sven Eden <sven.eden@prydeworx.com> | 2018-10-24 07:43:37 +0200 |
---|---|---|
committer | Sven Eden <sven.eden@prydeworx.com> | 2018-11-08 08:02:57 +0100 |
commit | 3ab9309e18658e22c1322eef168871d26cd49fb3 (patch) | |
tree | 0bc4b954e1475b00ee962c46779fda824bb9488d /src/basic | |
parent | 00b618db56b496823d74a0cc61537138ad6cb367 (diff) |
Prep v240 : Add busctl to be shipped with elogind.
(emersion):
> sd-bus is shipped with elogind, so it makes sense to ship the
> busctl command, too.
This is not only a nice helper tool to take a closer look at what is
happening on the dbus, it will also prove to be usefull if something
like issue #59 happens ever again. There we had to use dbus-send
directly to dissect the bus traffic.
Bug: #86
Closes: #86
Signed-off-by: Sven Eden <sven.eden@prydeworx.com>
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/meson.build | 2 | ||||
-rw-r--r-- | src/basic/string-util.h | 2 | ||||
-rw-r--r-- | src/basic/xml.c | 238 | ||||
-rw-r--r-- | src/basic/xml.h | 14 |
4 files changed, 254 insertions, 2 deletions
diff --git a/src/basic/meson.build b/src/basic/meson.build index af146b574..9b36a1e0d 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -367,6 +367,8 @@ basic_sources = files(''' virt.h xattr-util.c xattr-util.h + xml.c + xml.h '''.split()) #endif // 0 diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 61d0d037c..f0f73dd47 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -52,11 +52,9 @@ static inline const char *empty_to_null(const char *p) { return isempty(p) ? NULL : p; } -#if 0 /// UNNEEDED by elogind static inline const char *empty_to_dash(const char *str) { return isempty(str) ? "-" : str; } -#endif // 0 static inline char *startswith(const char *s, const char *prefix) { size_t l; diff --git a/src/basic/xml.c b/src/basic/xml.c new file mode 100644 index 000000000..cb34d870c --- /dev/null +++ b/src/basic/xml.c @@ -0,0 +1,238 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <errno.h> +#include <stddef.h> +#include <string.h> + +#include "macro.h" +#include "string-util.h" +#include "xml.h" + +enum { + STATE_NULL, + STATE_TEXT, + STATE_TAG, + STATE_ATTRIBUTE, +}; + +static void inc_lines(unsigned *line, const char *s, size_t n) { + const char *p = s; + + if (!line) + return; + + for (;;) { + const char *f; + + f = memchr(p, '\n', n); + if (!f) + return; + + n -= (f - p) + 1; + p = f + 1; + (*line)++; + } +} + +/* We don't actually do real XML here. We only read a simplistic + * subset, that is a bit less strict that XML and lacks all the more + * complex features, like entities, or namespaces. However, we do + * support some HTML5-like simplifications */ + +int xml_tokenize(const char **p, char **name, void **state, unsigned *line) { + const char *c, *e, *b; + char *ret; + int t; + + assert(p); + assert(*p); + assert(name); + assert(state); + + t = PTR_TO_INT(*state); + c = *p; + + if (t == STATE_NULL) { + if (line) + *line = 1; + t = STATE_TEXT; + } + + for (;;) { + if (*c == 0) + return XML_END; + + switch (t) { + + case STATE_TEXT: { + int x; + + e = strchrnul(c, '<'); + if (e > c) { + /* More text... */ + ret = strndup(c, e - c); + if (!ret) + return -ENOMEM; + + inc_lines(line, c, e - c); + + *name = ret; + *p = e; + *state = INT_TO_PTR(STATE_TEXT); + + return XML_TEXT; + } + + assert(*e == '<'); + b = c + 1; + + if (startswith(b, "!--")) { + /* A comment */ + e = strstr(b + 3, "-->"); + if (!e) + return -EINVAL; + + inc_lines(line, b, e + 3 - b); + + c = e + 3; + continue; + } + + if (*b == '?') { + /* Processing instruction */ + + e = strstr(b + 1, "?>"); + if (!e) + return -EINVAL; + + inc_lines(line, b, e + 2 - b); + + c = e + 2; + continue; + } + + if (*b == '!') { + /* DTD */ + + e = strchr(b + 1, '>'); + if (!e) + return -EINVAL; + + inc_lines(line, b, e + 1 - b); + + c = e + 1; + continue; + } + + if (*b == '/') { + /* A closing tag */ + x = XML_TAG_CLOSE; + b++; + } else + x = XML_TAG_OPEN; + + e = strpbrk(b, WHITESPACE "/>"); + if (!e) + return -EINVAL; + + ret = strndup(b, e - b); + if (!ret) + return -ENOMEM; + + *name = ret; + *p = e; + *state = INT_TO_PTR(STATE_TAG); + + return x; + } + + case STATE_TAG: + + b = c + strspn(c, WHITESPACE); + if (*b == 0) + return -EINVAL; + + inc_lines(line, c, b - c); + + e = b + strcspn(b, WHITESPACE "=/>"); + if (e > b) { + /* An attribute */ + + ret = strndup(b, e - b); + if (!ret) + return -ENOMEM; + + *name = ret; + *p = e; + *state = INT_TO_PTR(STATE_ATTRIBUTE); + + return XML_ATTRIBUTE_NAME; + } + + if (startswith(b, "/>")) { + /* An empty tag */ + + *name = NULL; /* For empty tags we return a NULL name, the caller must be prepared for that */ + *p = b + 2; + *state = INT_TO_PTR(STATE_TEXT); + + return XML_TAG_CLOSE_EMPTY; + } + + if (*b != '>') + return -EINVAL; + + c = b + 1; + t = STATE_TEXT; + continue; + + case STATE_ATTRIBUTE: + + if (*c == '=') { + c++; + + if (IN_SET(*c, '\'', '\"')) { + /* Tag with a quoted value */ + + e = strchr(c+1, *c); + if (!e) + return -EINVAL; + + inc_lines(line, c, e - c); + + ret = strndup(c+1, e - c - 1); + if (!ret) + return -ENOMEM; + + *name = ret; + *p = e + 1; + *state = INT_TO_PTR(STATE_TAG); + + return XML_ATTRIBUTE_VALUE; + + } + + /* Tag with a value without quotes */ + + b = strpbrk(c, WHITESPACE ">"); + if (!b) + b = c; + + ret = strndup(c, b - c); + if (!ret) + return -ENOMEM; + + *name = ret; + *p = b; + *state = INT_TO_PTR(STATE_TAG); + return XML_ATTRIBUTE_VALUE; + } + + t = STATE_TAG; + continue; + } + + } + + assert_not_reached("Bad state"); +} diff --git a/src/basic/xml.h b/src/basic/xml.h new file mode 100644 index 000000000..8da2ff5f7 --- /dev/null +++ b/src/basic/xml.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +enum { + XML_END, + XML_TEXT, + XML_TAG_OPEN, + XML_TAG_CLOSE, + XML_TAG_CLOSE_EMPTY, + XML_ATTRIBUTE_NAME, + XML_ATTRIBUTE_VALUE, +}; + +int xml_tokenize(const char **p, char **name, void **state, unsigned *line); |