summaryrefslogtreecommitdiffstats
path: root/libnetdata/line_splitter
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libnetdata/line_splitter/Makefile.am8
-rw-r--r--libnetdata/line_splitter/README.md14
-rw-r--r--libnetdata/line_splitter/line_splitter.c69
-rw-r--r--libnetdata/line_splitter/line_splitter.h120
4 files changed, 211 insertions, 0 deletions
diff --git a/libnetdata/line_splitter/Makefile.am b/libnetdata/line_splitter/Makefile.am
new file mode 100644
index 000000000..161784b8f
--- /dev/null
+++ b/libnetdata/line_splitter/Makefile.am
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
diff --git a/libnetdata/line_splitter/README.md b/libnetdata/line_splitter/README.md
new file mode 100644
index 000000000..f811bb4b3
--- /dev/null
+++ b/libnetdata/line_splitter/README.md
@@ -0,0 +1,14 @@
+<!--
+title: "Log"
+custom_edit_url: https://github.com/netdata/netdata/edit/master/libnetdata/log/README.md
+sidebar_label: "Log"
+learn_status: "Published"
+learn_topic_type: "Tasks"
+learn_rel_path: "Developers/libnetdata"
+-->
+
+# Log
+
+The netdata log library supports debug, info, error and fatal error logging.
+By default we have an access log, an error log and a collectors log.
+
diff --git a/libnetdata/line_splitter/line_splitter.c b/libnetdata/line_splitter/line_splitter.c
new file mode 100644
index 000000000..a459d3347
--- /dev/null
+++ b/libnetdata/line_splitter/line_splitter.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "../libnetdata.h"
+
+
+bool line_splitter_reconstruct_line(BUFFER *wb, void *ptr) {
+ struct line_splitter *spl = ptr;
+ if(!spl) return false;
+
+ size_t added = 0;
+ for(size_t i = 0; i < spl->num_words ;i++) {
+ if(i) buffer_fast_strcat(wb, " ", 1);
+
+ buffer_fast_strcat(wb, "'", 1);
+ const char *s = get_word(spl->words, spl->num_words, i);
+ buffer_strcat(wb, s?s:"");
+ buffer_fast_strcat(wb, "'", 1);
+ added++;
+ }
+
+ return added > 0;
+}
+
+inline int pluginsd_isspace(char c) {
+ switch(c) {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ case '=':
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+inline int config_isspace(char c) {
+ switch (c) {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ case ',':
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+inline int group_by_label_isspace(char c) {
+ if(c == ',' || c == '|')
+ return 1;
+
+ return 0;
+}
+
+bool isspace_map_pluginsd[256] = {};
+bool isspace_map_config[256] = {};
+bool isspace_map_group_by_label[256] = {};
+
+__attribute__((constructor)) void initialize_is_space_arrays(void) {
+ for(int c = 0; c < 256 ; c++) {
+ isspace_map_pluginsd[c] = pluginsd_isspace((char) c);
+ isspace_map_config[c] = config_isspace((char) c);
+ isspace_map_group_by_label[c] = group_by_label_isspace((char) c);
+ }
+}
diff --git a/libnetdata/line_splitter/line_splitter.h b/libnetdata/line_splitter/line_splitter.h
new file mode 100644
index 000000000..b5a59ad3a
--- /dev/null
+++ b/libnetdata/line_splitter/line_splitter.h
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "../libnetdata.h"
+
+#ifndef NETDATA_LINE_SPLITTER_H
+#define NETDATA_LINE_SPLITTER_H
+
+#define PLUGINSD_MAX_WORDS 30
+
+struct line_splitter {
+ size_t count; // counts number of lines
+ char *words[PLUGINSD_MAX_WORDS]; // an array of pointers for the words in this line
+ size_t num_words; // the number of pointers used in this line
+};
+
+bool line_splitter_reconstruct_line(BUFFER *wb, void *ptr);
+
+static inline void line_splitter_reset(struct line_splitter *line) {
+ line->num_words = 0;
+}
+
+int pluginsd_isspace(char c);
+int config_isspace(char c);
+int group_by_label_isspace(char c);
+
+extern bool isspace_map_pluginsd[256];
+extern bool isspace_map_config[256];
+extern bool isspace_map_group_by_label[256];
+
+static inline size_t quoted_strings_splitter(char *str, char **words, size_t max_words, bool *isspace_map) {
+ char *s = str, quote = 0;
+ size_t i = 0;
+
+ // skip all white space
+ while (unlikely(isspace_map[(uint8_t)*s]))
+ s++;
+
+ if(unlikely(!*s)) {
+ words[i] = NULL;
+ return 0;
+ }
+
+ // check for quote
+ if (unlikely(*s == '\'' || *s == '"')) {
+ quote = *s; // remember the quote
+ s++; // skip the quote
+ }
+
+ // store the first word
+ words[i++] = s;
+
+ // while we have something
+ while (likely(*s)) {
+ // if it is an escape
+ if (unlikely(*s == '\\' && s[1])) {
+ s += 2;
+ continue;
+ }
+
+ // if it is a quote
+ else if (unlikely(*s == quote)) {
+ quote = 0;
+ *s = ' ';
+ continue;
+ }
+
+ // if it is a space
+ else if (unlikely(quote == 0 && isspace_map[(uint8_t)*s])) {
+ // terminate the word
+ *s++ = '\0';
+
+ // skip all white space
+ while (likely(isspace_map[(uint8_t)*s]))
+ s++;
+
+ // check for a quote
+ if (unlikely(*s == '\'' || *s == '"')) {
+ quote = *s; // remember the quote
+ s++; // skip the quote
+ }
+
+ // if we reached the end, stop
+ if (unlikely(!*s))
+ break;
+
+ // store the next word
+ if (likely(i < max_words))
+ words[i++] = s;
+ else
+ break;
+ }
+
+ // anything else
+ else
+ s++;
+ }
+
+ if (likely(i < max_words))
+ words[i] = NULL;
+
+ return i;
+}
+
+#define quoted_strings_splitter_query_group_by_label(str, words, max_words) \
+ quoted_strings_splitter(str, words, max_words, isspace_map_group_by_label)
+
+#define quoted_strings_splitter_config(str, words, max_words) \
+ quoted_strings_splitter(str, words, max_words, isspace_map_config)
+
+#define quoted_strings_splitter_pluginsd(str, words, max_words) \
+ quoted_strings_splitter(str, words, max_words, isspace_map_pluginsd)
+
+static inline char *get_word(char **words, size_t num_words, size_t index) {
+ if (unlikely(index >= num_words))
+ return NULL;
+
+ return words[index];
+}
+
+#endif //NETDATA_LINE_SPLITTER_H