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
26namespace 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