version 1.0
[platform/core/system/tizen-platform-wrapper.git] / src / parser.c
1 /*
2  * Copyright (C) 2013 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     }
239     else {
240         c = *head;
241         if (iskey(c))
242             goto variable;
243         lvar = head - svar;
244         if (acc == '{') {
245             if (c == '}')
246                 ++head;
247             else
248                 error(head,_("unmatched pair { }"));
249         }
250     }
251     if (parsing->get) {
252         value = parsing->get( parsing, svar,lvar,pos(bvar),pos(head));
253         if (value == NULL)
254             error(bvar,_("no value for the variable"));
255         else {
256             while (*value) {
257                 if (ldata < datasz)
258                     bdata[ldata++] = *value++;
259                 else {
260                     overflow = 1;
261                     break;
262                 }
263             }
264         }
265     }
266     goto value;
267
268 stop:
269 end_ok:
270     return -errors;
271     
272 #undef error
273 #undef pos
274 #undef atend
275 #undef iskey
276 #undef iskeybeg
277 }
278
279 void parse_utf8_info(
280             struct parsing *parsing,
281             struct parsinfo *info,
282             size_t pos
283 )
284 {
285     const char *buf, *begin, *end;
286     size_t length;
287     int lino, colno;
288
289     /* init */
290     lino = 1, colno = 1;
291     buf = begin = end = parsing->buffer;
292     length = parsing->length;
293     if (length < pos)
294         pos = length;
295
296     /* search the begin of the line */
297     while ((end - buf) != pos) {
298         /* dealing utf8 */
299         colno += ((*end & '\xc0') != '\x80');
300         /* dealing with lines */
301         if(*end++ == '\n') { 
302             begin = end; 
303             lino++;
304             colno = 1;
305         }
306     }
307
308     /* search the end of the line */
309     while ((end - buf) < length && *end != '\n') 
310         end++;
311
312     /* record computed values */
313     info->begin = begin;
314     info->end = end;
315     info->length = end - begin;
316     info->lino = lino;
317     info->colno = colno;
318 }
319