summaryrefslogtreecommitdiffstats
path: root/libnetdata/line_splitter/line_splitter.h
blob: b5a59ad3a35e4cf95bf393b8ef0a6f2a23626e6f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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