ff480b65e1fd1f9e58b77862603a54b1957e95a3
[platform/core/system/tizen-platform-config.git] / src / parser.c
1 /*
2  * Copyright (C) 2013-2014 Intel Corporation.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors:
19  *       José Bollo <jose.bollo@open.eurogiciel.org>
20  *       Stéphane Desneux <stephane.desneux@open.eurogiciel.org>
21  *       Jean-Benoit Martin <jean-benoit.martin@open.eurogiciel.org>
22  *
23  */
24 #define _GNU_SOURCE
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdlib.h>
31 #include <alloca.h>
32 #include <ctype.h>
33
34 #include "parser.h"
35
36 #ifndef MINIMUM_DATA_SIZE
37 # define MINIMUM_DATA_SIZE                         128
38 #endif
39 #ifndef DEFAULT_MAXIMUM_DATA_SIZE
40 # define DEFAULT_MAXIMUM_DATA_SIZE       32768
41 #endif
42
43 #ifndef _
44 # define _(x) x
45 #endif
46
47 int parse_utf8_config(struct parsing *parsing)
48 {
49         char c, q, acc, overflow, escape;
50         char *bdata;
51         const char *value, *head, *end, *skey, *svar, *bvar;
52         size_t lkey, lvar, ldata, datasz;
53         int  errors;
54
55 #define iskeybeg(x)             (isalpha(x) || (x) == '_')
56 #define iskey(x)                (isalnum(x) || (x) == '_')
57 #define atend                   ((head-end) >= 0)
58
59 #define pos(x)                  ((size_t)((x)-parsing->buffer))
60 #define error(p, x)             do { errors++; \
61                                                         if (parsing->error \
62                                                                 && !parsing->error(parsing, pos(p), x)) \
63                                                                 goto stop; \
64                                                 } while (0)
65
66         /* alloc data buffer */
67         datasz = parsing->maximum_data_size;
68         if (datasz == 0)
69                 datasz = DEFAULT_MAXIMUM_DATA_SIZE;
70         else if (datasz < MINIMUM_DATA_SIZE)
71                 datasz = MINIMUM_DATA_SIZE;
72         bdata = alloca(datasz);
73
74         /* init */
75         escape = parsing->should_escape ? 1 : 0;
76         errors = 0;
77         head = parsing->buffer;
78         end = head + parsing->length;
79         goto initial;
80
81 next_initial:
82
83         head++;
84
85 initial: /* expecting key, comment or ??? */
86
87         if (atend)
88                 goto end_ok;
89
90         c = *head;
91
92         if (iskeybeg(c)) {
93                 skey = head;
94                 goto key;
95         }
96
97         if (c == '#')
98                 goto comment;
99
100         if (!isspace(c))
101                 error(head, _("unexpected character while looking to a key start"));
102
103         goto next_initial;
104
105 comment: /* skipping a comment */
106
107         head++;
108         if (atend)
109                 goto end_ok;
110         c = *head;
111         if (c == '\n')
112                 goto next_initial;
113         goto comment;
114
115 key: /* reading a key */
116
117         head++;
118         if (atend) {
119                 error(head, _("end in a key"));
120                 goto stop;
121         }
122         c = *head;
123         if (iskey(c))
124                 goto key;
125         if (c != '=') {
126                 error(head, _("unexpected character while looking to ="));
127                 goto next_initial;
128         }
129         lkey = head - skey;
130         overflow = ldata = 0;
131         q = 0;
132         goto next_value;
133
134 escapable:
135
136         if (escape && ldata < datasz)
137                 bdata[ldata++] = '\\';
138
139 add_value: /* add the current char to data */
140
141         if (ldata < datasz)
142                 bdata[ldata++] = c;
143         else
144                 overflow = 1;
145
146 next_value:
147
148         head++;
149
150 value: /* reading the value */
151
152         if (atend) {
153                 /* end in the value */
154                 if (!q)
155                         goto end_of_value;
156
157                 error(head, _("end in quoted value"));
158                 goto stop;
159         }
160
161         c = *head;
162         switch (c) {
163
164         case '\\':
165                 if (q == '\'')
166                         goto escapable;
167                 ++head;
168                 if (atend) {
169                         error(head, _("end after escape char"));
170                         goto stop;
171                 }
172                 c = *head;
173                 goto escapable;
174
175         case '\'':
176                 if (q == '"')
177                         goto escapable;
178                 q = q ^ c;
179                 goto next_value;
180
181         case '"':
182                 if (q == '\'')
183                         goto escapable;
184                 q = q ^ c;
185                 goto next_value;
186
187         case '$':
188                 if (q == '\'')
189                         goto escapable;
190
191                 /* begin of a variable, just after $ */
192                 bvar = head++;
193                 if (atend) {
194                         error(head, _("end after $"));
195                         goto stop;
196                 }
197                 c = *head;
198                 acc = c;
199                 if (c == '{') {
200                         ++head;
201                         if (atend) {
202                                 error(head, _("end after ${"));
203                                 goto stop;
204                         }
205                         c = *head;
206                 }
207                 if (!iskeybeg(c)) {
208                         error(head, _("invalid character after $ or ${"));
209                         goto value;
210                 }
211                 svar = head;
212                 goto variable;
213
214         default:
215                 if (q || !isspace(c))
216                         goto add_value;
217
218                 goto end_of_value;
219         }
220
221 end_of_value: /* end of the value */
222
223         if (overflow)
224                 error(head, _("value too big"));
225         else if (parsing->put)
226                 parsing->put(parsing, skey, lkey, bdata, ldata, pos(skey), pos(head));
227         if (atend)
228                 goto initial;
229         goto next_initial;
230
231 variable: /* read a variable */
232
233         ++head;
234         if (atend) {
235                 if (acc == '{')
236                         error(head, _("unmatched pair { }"));
237                 lvar = head - svar;
238         } else {
239                 c = *head;
240                 if (iskey(c))
241                         goto variable;
242                 lvar = head - svar;
243                 if (acc == '{') {
244                         if (c == '}')
245                                 ++head;
246                         else
247                                 error(head, _("unmatched pair { }"));
248                 }
249         }
250         if (parsing->get) {
251                 value = parsing->get(parsing, svar, lvar, pos(bvar), pos(head));
252                 if (value == NULL)
253                         error(bvar, _("no value for the variable"));
254                 else {
255                         while (*value) {
256                                 if (ldata < datasz)
257                                         bdata[ldata++] = *value++;
258                                 else {
259                                         overflow = 1;
260                                         break;
261                                 }
262                         }
263                 }
264         }
265         goto value;
266
267 stop:
268 end_ok:
269         return -errors;
270
271 #undef error
272 #undef pos
273 #undef atend
274 #undef iskey
275 #undef iskeybeg
276 }
277
278 void parse_utf8_info(
279                         struct parsing *parsing,
280                         struct parsinfo *info,
281                         size_t pos
282 )
283 {
284         const char *buf, *begin, *end;
285         size_t length;
286         int lino, colno;
287
288         /* init */
289         lino = 1, colno = 1;
290         buf = begin = end = parsing->buffer;
291         length = parsing->length;
292         if (length < pos)
293                 pos = length;
294
295         /* search the begin of the line */
296         while ((end - buf) != pos) {
297                 /* dealing utf8 */
298                 colno += ((*end & '\xc0') != '\x80');
299                 /* dealing with lines */
300                 if (*end++ == '\n') {
301                         begin = end;
302                         lino++;
303                         colno = 1;
304                 }
305         }
306
307         /* search the end of the line */
308         while ((end - buf) < length && *end != '\n')
309                 end++;
310
311         /* record computed values */
312         info->begin = begin;
313         info->end = end;
314         info->length = end - begin;
315         info->lino = lino;
316         info->colno = colno;
317 }
318