1 | /* -*- c-basic-offset: 2 -*- */ |
2 | /* |
3 | Copyright(C) 2011-2013 Kentoku SHIBA |
4 | Copyright(C) 2011-2015 Kouhei Sutou <kou@clear-code.com> |
5 | |
6 | This library is free software; you can redistribute it and/or |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either |
9 | version 2.1 of the License, or (at your option) any later version. |
10 | |
11 | This library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | Lesser General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with this library; if not, write to the Free Software |
18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | */ |
20 | |
21 | #include "mrn_parameters_parser.hpp" |
22 | |
23 | #include <mrn_mysql_compat.h> |
24 | #include <mrn_variables.hpp> |
25 | |
26 | namespace mrn { |
27 | class Parameter { |
28 | public: |
29 | char *key_; |
30 | char *value_; |
31 | |
32 | Parameter(const char *key, unsigned int key_length, |
33 | const char *value, unsigned int value_length) |
34 | : key_(mrn_my_strndup(key, key_length, MYF(0))), |
35 | value_(mrn_my_strndup(value, value_length, MYF(0))) { |
36 | }; |
37 | ~Parameter() { |
38 | if (key_) { |
39 | my_free(key_); |
40 | } |
41 | if (value_) { |
42 | my_free(value_); |
43 | } |
44 | }; |
45 | }; |
46 | |
47 | ParametersParser::ParametersParser(const char *input, |
48 | unsigned int input_length) |
49 | : input_(input), |
50 | input_length_(input_length), |
51 | parameters_(NULL) { |
52 | } |
53 | |
54 | ParametersParser::~ParametersParser() { |
55 | for (LIST *next = parameters_; next; next = next->next) { |
56 | Parameter *parameter = static_cast<Parameter *>(next->data); |
57 | delete parameter; |
58 | } |
59 | list_free(parameters_, false); |
60 | } |
61 | |
62 | void ParametersParser::parse() { |
63 | const char *current = input_; |
64 | const char *end = input_ + input_length_; |
65 | for (; current < end; ++current) { |
66 | if (is_white_space(current[0])) { |
67 | continue; |
68 | } |
69 | |
70 | const char *key = current; |
71 | unsigned int key_length = 0; |
72 | while (current < end && |
73 | !is_white_space(current[0]) && |
74 | current[0] != '\'' && current[0] != '"' && current[0] != ',') { |
75 | ++current; |
76 | ++key_length; |
77 | } |
78 | if (current == end) { |
79 | break; |
80 | } |
81 | |
82 | while (current < end && is_white_space(current[0])) { |
83 | ++current; |
84 | } |
85 | if (current == end) { |
86 | break; |
87 | } |
88 | current = parse_value(current, end, key, key_length); |
89 | if (!current) { |
90 | break; |
91 | } |
92 | |
93 | while (current < end && is_white_space(current[0])) { |
94 | ++current; |
95 | } |
96 | if (current == end) { |
97 | break; |
98 | } |
99 | if (current[0] != ',') { |
100 | // TODO: report error |
101 | break; |
102 | } |
103 | } |
104 | } |
105 | |
106 | const char *ParametersParser::parse_value(const char *current, |
107 | const char *end, |
108 | const char *key, |
109 | unsigned int key_length) { |
110 | char quote = current[0]; |
111 | if (quote != '\'' && quote != '"') { |
112 | // TODO: report error |
113 | return NULL; |
114 | } |
115 | ++current; |
116 | |
117 | bool found = false; |
118 | static const unsigned int max_value_length = 4096; |
119 | char value[max_value_length]; |
120 | unsigned int value_length = 0; |
121 | for (; current < end && value_length < max_value_length; ++current) { |
122 | if (current[0] == quote) { |
123 | Parameter *parameter = new Parameter(key, key_length, |
124 | value, value_length); |
125 | list_push(parameters_, parameter); |
126 | found = true; |
127 | ++current; |
128 | break; |
129 | } |
130 | |
131 | switch (current[0]) { |
132 | case '\\': |
133 | if (current + 1 == end) { |
134 | break; |
135 | } |
136 | switch (current[1]) { |
137 | case 'b': |
138 | value[value_length] = '\b'; |
139 | break; |
140 | case 'n': |
141 | value[value_length] = '\n'; |
142 | break; |
143 | case 'r': |
144 | value[value_length] = '\r'; |
145 | break; |
146 | case 't': |
147 | value[value_length] = '\t'; |
148 | break; |
149 | default: |
150 | value[value_length] = current[1]; |
151 | break; |
152 | } |
153 | break; |
154 | default: |
155 | value[value_length] = current[0]; |
156 | break; |
157 | } |
158 | ++value_length; |
159 | } |
160 | |
161 | if (!found) { |
162 | // TODO: report error |
163 | } |
164 | |
165 | return current; |
166 | } |
167 | |
168 | const char *ParametersParser::operator[](const char *key) { |
169 | for (LIST *next = parameters_; next; next = next->next) { |
170 | Parameter *parameter = static_cast<Parameter *>(next->data); |
171 | if (strcasecmp(parameter->key_, key) == 0) { |
172 | return parameter->value_; |
173 | } |
174 | } |
175 | return NULL; |
176 | } |
177 | } |
178 | |