Merge commit 'garage/master'
[connman] / gatchat / gatresult.c
1 /*
2  *
3  *  AT chat library with GLib integration
4  *
5  *  Copyright (C) 2008-2009  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program 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
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27 #include <stdio.h>
28
29 #include <glib.h>
30
31 #include "gatresult.h"
32
33 void g_at_result_iter_init(GAtResultIter *iter, GAtResult *result)
34 {
35         iter->result = result;
36         iter->pre.next = result->lines;
37         iter->pre.data = NULL;
38         iter->l = &iter->pre;
39         iter->line_pos = 0;
40 }
41
42 gboolean g_at_result_iter_next(GAtResultIter *iter, const char *prefix)
43 {
44         char *line;
45         int prefix_len = prefix ? strlen(prefix) : 0;
46
47         while ((iter->l = iter->l->next)) {
48                 line = iter->l->data;
49
50                 if (prefix_len == 0) {
51                         iter->line_pos = 0;
52                         return TRUE;
53                 }
54
55                 if (g_str_has_prefix(line, prefix) == FALSE)
56                         continue;
57
58                 iter->line_pos = prefix_len;
59
60                 while (iter->line_pos < strlen(line) &&
61                         line[iter->line_pos] == ' ')
62                         iter->line_pos += 1;
63
64                 return TRUE;
65         }
66
67         return FALSE;
68 }
69
70 const char *g_at_result_iter_raw_line(GAtResultIter *iter)
71 {
72         const char *line;
73
74         if (!iter)
75                 return NULL;
76
77         if (!iter->l)
78                 return NULL;
79
80         line = iter->l->data;
81
82         line += iter->line_pos;
83
84         return line;
85 }
86
87 static inline int skip_to_next_field(const char *line, int pos, int len)
88 {
89         if (pos < len && line[pos] == ',')
90                 pos += 1;
91
92         while (pos < len && line[pos] == ' ')
93                 pos += 1;
94
95         return pos;
96 }
97
98 gboolean g_at_result_iter_next_string(GAtResultIter *iter, const char **str)
99 {
100         unsigned int pos;
101         unsigned int end;
102         unsigned int len;
103         char *line;
104
105         if (!iter)
106                 return FALSE;
107
108         if (!iter->l)
109                 return FALSE;
110
111         line = iter->l->data;
112         len = strlen(line);
113
114         pos = iter->line_pos;
115
116         /* Omitted string */
117         if (line[pos] == ',') {
118                 end = pos;
119                 memset(iter->buf, 0, sizeof(iter->buf));
120                 goto out;
121         }
122
123         if (line[pos++] != '"')
124                 return FALSE;
125
126         end = pos;
127
128         while (end < len && line[end] != '"')
129                 end += 1;
130
131         if (line[end] != '"')
132                 return FALSE;
133
134         if (end - pos >= sizeof(iter->buf))
135                 return FALSE;
136
137         strncpy(iter->buf, line+pos, end-pos);
138         memset(iter->buf + end - pos, 0, sizeof(iter->buf) - end + pos);
139
140         /* Skip " */
141         end += 1;
142
143 out:
144         iter->line_pos = skip_to_next_field(line, end, len);
145
146         if (str)
147                 *str = iter->buf;
148
149         return TRUE;
150 }
151
152 gboolean g_at_result_iter_next_hexstring(GAtResultIter *iter,
153                 const guint8 **str, gint *length)
154 {
155         unsigned int pos;
156         unsigned int end;
157         unsigned int len;
158         char *line;
159         char *bufpos;
160
161         if (!iter)
162                 return FALSE;
163
164         if (!iter->l)
165                 return FALSE;
166
167         line = iter->l->data;
168         len = strlen(line);
169
170         pos = iter->line_pos;
171
172         /* Omitted string */
173         if (line[pos] == ',') {
174                 end = pos;
175                 memset(iter->buf, 0, sizeof(iter->buf));
176                 goto out;
177         }
178
179         end = pos;
180
181         while (end < len && g_ascii_isxdigit(line[end]))
182                 end += 1;
183
184         if ((end - pos) & 1)
185                 return FALSE;
186
187         if ((end - pos) / 2 >= sizeof(iter->buf))
188                 return FALSE;
189         *length = (end - pos) / 2;
190
191         for (bufpos = iter->buf; pos < end; pos += 2)
192                 sscanf(line + pos, "%02hhx", bufpos++);
193         memset(bufpos, 0, sizeof(iter->buf) - (bufpos - iter->buf));
194
195 out:
196         iter->line_pos = skip_to_next_field(line, end, len);
197
198         if (str)
199                 *str = (guint8 *) iter->buf;
200
201         return TRUE;
202 }
203
204 gboolean g_at_result_iter_next_number(GAtResultIter *iter, gint *number)
205 {
206         int pos;
207         int end;
208         int len;
209         int value = 0;
210         char *line;
211
212         if (!iter)
213                 return FALSE;
214
215         if (!iter->l)
216                 return FALSE;
217
218         line = iter->l->data;
219         len = strlen(line);
220
221         pos = iter->line_pos;
222         end = pos;
223
224         while (line[end] >= '0' && line[end] <= '9') {
225                 value = value * 10 + (int)(line[end] - '0');
226                 end += 1;
227         }
228
229         if (pos == end)
230                 return FALSE;
231
232         iter->line_pos = skip_to_next_field(line, end, len);
233
234         if (number)
235                 *number = value;
236
237         return TRUE;
238 }
239
240 gboolean g_at_result_iter_next_range(GAtResultIter *iter, gint *min, gint *max)
241 {
242         int pos;
243         int end;
244         int len;
245         int low = 0;
246         int high = 0;
247         char *line;
248
249         if (!iter)
250                 return FALSE;
251
252         if (!iter->l)
253                 return FALSE;
254
255         line = iter->l->data;
256         len = strlen(line);
257
258         pos = iter->line_pos;
259
260         while (pos < len && line[pos] == ' ')
261                 pos += 1;
262
263         end = pos;
264
265         while (line[end] >= '0' && line[end] <= '9') {
266                 low = low * 10 + (int)(line[end] - '0');
267                 end += 1;
268         }
269
270         if (pos == end)
271                 return FALSE;
272
273         if (line[end] == ',') {
274                 high = low;
275                 goto out;
276         }
277
278         if (line[end] == '-')
279                 pos = end = end + 1;
280         else
281                 return FALSE;
282
283         while (line[end] >= '0' && line[end] <= '9') {
284                 high = high * 10 + (int)(line[end] - '0');
285                 end += 1;
286         }
287
288         if (pos == end)
289                 return FALSE;
290
291 out:
292         iter->line_pos = skip_to_next_field(line, end, len);
293
294         if (min)
295                 *min = low;
296
297         if (max)
298                 *max = high;
299
300         return TRUE;
301 }
302
303 static gint skip_until(const char *line, int start, const char delim)
304 {
305         int len = strlen(line);
306         int i = start;
307
308         while (i < len) {
309                 if (line[i] == delim)
310                         return i;
311
312                 if (line[i] != '(') {
313                         i += 1;
314                         continue;
315                 }
316
317                 i = skip_until(line, i+1, ')');
318
319                 if (i < len)
320                         i += 1;
321         }
322
323         return i;
324 }
325
326 gboolean g_at_result_iter_skip_next(GAtResultIter *iter)
327 {
328         unsigned int skipped_to;
329         char *line;
330
331         if (!iter)
332                 return FALSE;
333
334         if (!iter->l)
335                 return FALSE;
336
337         line = iter->l->data;
338
339         skipped_to = skip_until(line, iter->line_pos, ',');
340
341         if (skipped_to == iter->line_pos && line[skipped_to] != ',')
342                 return FALSE;
343
344         iter->line_pos = skip_to_next_field(line, skipped_to, strlen(line));
345
346         return TRUE;
347 }
348
349 gboolean g_at_result_iter_open_list(GAtResultIter *iter)
350 {
351         char *line;
352         unsigned int len;
353
354         if (!iter)
355                 return FALSE;
356
357         if (!iter->l)
358                 return FALSE;
359
360         line = iter->l->data;
361         len = strlen(line);
362
363         if (iter->line_pos >= len)
364                 return FALSE;
365
366         if (line[iter->line_pos] != '(')
367                 return FALSE;
368
369         iter->line_pos += 1;
370
371         while (iter->line_pos < strlen(line) &&
372                 line[iter->line_pos] == ' ')
373                 iter->line_pos += 1;
374
375         return TRUE;
376 }
377
378 gboolean g_at_result_iter_close_list(GAtResultIter *iter)
379 {
380         char *line;
381         unsigned int len;
382
383         if (!iter)
384                 return FALSE;
385
386         if (!iter->l)
387                 return FALSE;
388
389         line = iter->l->data;
390         len = strlen(line);
391
392         if (iter->line_pos >= len)
393                 return FALSE;
394
395         if (line[iter->line_pos] != ')')
396                 return FALSE;
397
398         iter->line_pos += 1;
399
400         iter->line_pos = skip_to_next_field(line, iter->line_pos, len);
401
402         return TRUE;
403 }
404
405 const char *g_at_result_final_response(GAtResult *result)
406 {
407         if (!result)
408                 return NULL;
409
410         return result->final_or_pdu;
411 }
412
413 const char *g_at_result_pdu(GAtResult *result)
414 {
415         if (!result)
416                 return NULL;
417
418         return result->final_or_pdu;
419 }
420
421 gint g_at_result_num_response_lines(GAtResult *result)
422 {
423         if (!result)
424                 return 0;
425
426         if (!result->lines)
427                 return 0;
428
429         return g_slist_length(result->lines);
430 }