parse: replace Q3MemArrays (Qt3) with QVector<char> (Qt4)
[opensuse:qinternet.git] / src / parse.cpp
1
2 /***************************************************************************
3  *                                                                         *
4  *   Copyright: SuSE Linux AG, Nuernberg                                   *
5  *                                                                         *
6  *   Author: Arvin Schnell <arvin@suse.de>                                 *
7  *                                                                         *
8  ***************************************************************************/
9
10 /***************************************************************************
11  *                                                                         *
12  *   This program is free software; you can redistribute it and/or modify  *
13  *   it under the terms of the GNU General Public License as published by  *
14  *   the Free Software Foundation; either version 2 of the License, or     *
15  *   (at your option) any later version.                                   *
16  *                                                                         *
17  ***************************************************************************/
18
19
20 #include <ctype.h>
21
22 #include "parse.h"
23 #include <QVector>
24 #include <QtAlgorithms>
25
26
27 const QChar*
28 unicode0 (QVector <QChar>* tmp, const QString& str)
29 {
30     const int len = str.length ();
31     tmp->resize (len);
32     qCopy (str.unicode (), str.unicode () + len, tmp->begin());
33     tmp->append(0);
34     return tmp->data ();
35 }
36
37
38 static void
39 skip_spaces (const QChar** p)
40 {
41     while (!(*p)->isNull() && (*p)->isSpace())
42         (*p)++;
43 }
44
45
46 static bool
47 parse_sh_key (const QChar** p, QString* key)
48 {
49     *key = "";
50
51     if ((*p)->isNull() || (!(*p)->isLetter() && **p != '_'))
52         return false;
53
54     while (!(*p)->isNull() && ((*p)->isLetterOrNumber() || **p == '_'))
55         *key += *(*p)++;
56
57     return true;
58 }
59
60
61 static bool
62 parse_conf_key (const QChar** p, QString* key)
63 {
64     *key = "";
65
66     if ((*p)->isNull() || (!(*p)->isLetter() && **p != '_'))
67         return false;
68
69     while (!(*p)->isNull() && ((*p)->isLetterOrNumber() || (**p == '_') || (**p == '-')))
70         *key += *(*p)++;
71
72     return true;
73 }
74
75
76 static bool
77 parse_value (const QChar** p, QString* value)
78 {
79     *value = "";
80
81     enum { NQ, NQAB, QWRQ, QWDQ, QWDQAB } state = NQ;
82
83     while (!(*p)->isNull())
84     {
85         switch (state)
86         {
87             case NQ:            // not quoted
88                 if ((*p)->isSpace())
89                     return true;
90                 else if (**p == '\'')
91                     state = QWRQ;
92                 else if (**p == '"')
93                     state = QWDQ;
94                 else if (**p == '\\')
95                     state = NQAB;
96                 else
97                     *value += **p;
98                 break;
99
100             case NQAB:          // not quoted after backslash
101                 state = NQ;
102                 *value += **p;
103                 break;
104
105             case QWRQ:          // quoted with right-quote
106                 if (**p == '\'')
107                     state = NQ;
108                 else
109                     *value += **p;
110                 break;
111
112             case QWDQ:          // quoted with double-quote
113                 if (**p == '"')
114                     state = NQ;
115                 else if (**p == '\\')
116                     state = QWDQAB;
117                 else
118                     *value += **p;
119                 break;
120
121             case QWDQAB:        // quoted with double-quote after backslash
122                 state = QWDQ;
123                 *value += **p;
124                 break;
125         }
126
127         (*p)++;
128     }
129
130     return state == NQ;
131 }
132
133
134 bool
135 set_qap_style (const char* name, QAP_STYLE* qap_style)
136 {
137     if (strcmp (name, "c") == 0) {
138         *qap_style = QAP_C;
139         return true;
140     }
141
142     if (strcmp (name, "sh") == 0) {
143         *qap_style = QAP_SH;
144         return true;
145     }
146
147     return false;
148 }
149
150
151 QString
152 qap (const char* str, QAP_STYLE qap_style)
153 {
154     return qap (QString::fromUtf8 (str), qap_style);
155 }
156
157
158 QString
159 qap (const QString& str, QAP_STYLE qap_style)
160 {
161     QVector <QChar> tmp;
162     const QChar* p = unicode0 (&tmp, str);
163
164     QString ret;
165
166     switch (qap_style)
167     {
168         case QAP_C:
169             // quote with " and protect " and \ with \ within string.
170             ret = "\"";
171             while (!p->isNull())
172             {
173                 if (*p == '\\' || *p == '"')
174                     ret += "\\";
175                 ret += *p++;
176             }
177             ret += "\"";
178             break;
179
180         case QAP_SH:
181             // quote with ' and replace ' by '\'' within string.
182             ret = "'";
183             while (!p->isNull())
184             {
185                 if (*p == '\'')
186                     ret += "'\\''";
187                 else
188                     ret += *p;
189                 p++;
190             }
191             ret += "'";
192             break;
193     }
194
195     return ret;
196 }
197
198
199 int
200 parse_values (const QString& line, QStringList* values)
201 {
202     QVector <QChar> tmp;
203     const QChar* p = unicode0 (&tmp, line);
204
205     values->clear ();
206
207     while (!p->isNull())
208     {
209         // skip spaces
210         skip_spaces (&p);
211         if (p->isNull())
212             break;
213
214         // parse value
215         QString t;
216         if (!parse_value (&p, &t))
217             return -1;
218         values->push_back (t);
219     }
220
221     return values->size ();
222 }
223
224
225 int
226 parse_sh_keyvalue (const QString& line, QString* key, QString* value)
227 {
228     QVector <QChar> tmp;
229     const QChar* p = unicode0 (&tmp, line);
230
231     // skip spaces
232     skip_spaces (&p);
233     if (p->isNull() || *p == '#')
234         return 0;
235
236     // parse key
237     if (!parse_sh_key (&p, key))
238         return -1;
239
240     // skip equal sign
241     if (p->isNull() || *p != '=')
242         return -1;
243     p++;
244
245     // parse value
246     if (!parse_value (&p, value))
247         return -1;
248
249     // skip spaces and check comment
250     skip_spaces (&p);
251     if (!p->isNull() && *p != '#')
252         return -1;
253
254     return 1;
255 }
256
257
258 int
259 parse_conf_keyvalue (const QString& line, QString* key, QString* value)
260 {
261     QVector <QChar> tmp;
262     const QChar* p = unicode0 (&tmp, line);
263
264     // skip spaces
265     skip_spaces (&p);
266     if (p->isNull() || *p == '#')
267         return 0;
268
269     // parse key
270     if (!parse_conf_key (&p, key))
271         return -1;
272
273     // skip equal sign and surrounding spaces
274     skip_spaces (&p);
275     if (p->isNull() || *p != '=')
276         return -1;
277     p++;
278
279     // skip spaces and check comment
280     skip_spaces (&p);
281     if (p->isNull() || *p == '#') {
282         *value = "";
283         return 1;
284     }
285
286     // parse value
287     if (!parse_value (&p, value))
288         return -1;
289
290     // skip spaces and check comment
291     skip_spaces (&p);
292     if (!p->isNull() && *p != '#')
293         return -1;
294
295     return 1;
296 }
297
298
299 int
300 parse_conf_keyvalues (const QString& line, QString* key, QStringList* values)
301 {
302     QVector <QChar> tmp;
303     const QChar* p = unicode0 (&tmp, line);
304
305     // skip spaces
306     skip_spaces (&p);
307     if (p->isNull() || *p == '#')
308         return 0;
309
310     // parse key
311     if (!parse_conf_key (&p, key))
312         return -1;
313
314     // skip equal sign and surrounding spaces
315     skip_spaces (&p);
316     if (p->isNull() || *p != '=')
317         return -1;
318     p++;
319
320     values->clear ();
321
322     while (true)
323     {
324         // skip spaces and check comment
325         skip_spaces (&p);
326         if (p->isNull() || *p == '#')
327             return 1;
328
329         // parse single value
330         QString tmp;
331         if (!parse_value (&p, &tmp))
332             return -1;
333         values->push_back (tmp);
334     }
335 }