summaryrefslogtreecommitdiff
path: root/src/header_parser.cc
blob: 8d1735162a9b62f6726596d5162b337a3711ac78 (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
#include "common.hh"

#include "header_parser.hh"

namespace stuff {

namespace {

bool read_token(std::string::const_iterator* begin,
                const std::string::const_iterator& end,
                bool to_lower,
                std::string* out) {
    auto i = *begin;
    if (i == end) return false;
    auto last = i;
    out->clear();
    do {
        if ((*i >= '^' && *i <= 'z') ||
            (!to_lower && *i >= 'A' && *i <= 'Z') ||
            (*i >= '0' && *i <= '9') ||
            (*i >= '#' && *i <= '\'') ||
            *i == '!' || *i == '*' || *i == '+' || *i == '-' || *i == '.' ||
            *i == '|' || *i == '~') {
            ++i;
        } else if (to_lower && *i >= 'A' && *i <= 'Z') {
            out->insert(out->end(), last, i);
            out->push_back('a' + *i - 'A');
            last = ++i;
        } else {
            break;
        }
    } while (i != end);
    out->insert(out->end(), last, i);
    *begin = i;
    return true;
}

bool read_quoted(std::string::const_iterator* begin,
                 const std::string::const_iterator& end,
                 std::string* out) {
    auto i = *begin;
    if (i == end || *i != '"') return false;
    auto last = ++i;
    out->clear();
    while (true) {
        if (*i == '"') {
            out->insert(out->end(), last, i);
            *begin = ++i;
            return true;
        } else if (*i == '\\') {
            out->insert(out->end(), last, i);
            if (++i == end) return false;
            if ((*i >= ' ' && *i <= '~') ||
                *i == '\t' ||
                (*i & 0x80)) {
                out->push_back(*i);
                last = ++i;
            } else {
                return false;
            }
        } else if ((*i >= '^' && *i <= '~') ||
                   (*i >= '#' && *i <= '[') ||
                   *i == '\t' || *i == ' ' ||
                   (*i & 0x80)) {
            ++i;
        } else {
            return false;
        }
    }
}

}  // namespace

bool HeaderParser::parse(const std::string& in, std::string* token,
                         std::map<std::string, std::string>* parameters) {
    auto i = in.begin();
    while (i != in.end() && (*i == ' ' || *i == '\t')) ++i;
    if (!read_token(&i, in.end(), true, token)) return false;
    while (true) {
        if (i == in.end() || *i != '/') break;
        std::string tmp;
        token->push_back('/');
        ++i;
        if (!read_token(&i, in.end(), true, &tmp)) return false;
        token->append(tmp);
    }
    if (parameters) parameters->clear();
    while (i != in.end()) {
        while (i != in.end() && (*i == ' ' || *i == '\t')) ++i;
        if (i == in.end()) break;
        if (*i != ';') return false;
        ++i;
        while (i != in.end() && (*i == ' ' || *i == '\t')) ++i;
        if (i == in.end()) return false;
        std::string key, value;
        if (!read_token(&i, in.end(), true, &key)) return false;
        if (i == in.end() || *i != '=') return false;
        ++i;
        if (i != in.end() && *i == '"') {
            if (!read_quoted(&i, in.end(), &value)) return false;
        } else {
            if (!read_token(&i, in.end(), false, &value)) return false;
        }
        if (parameters) (*parameters)[key] = value;
    }
    return true;
}

}  // namespace stuff