~ubuntu-branches/ubuntu/hardy/stfl/hardy

« back to all changes in this revision

Viewing changes to parser.c

  • Committer: Bazaar Package Importer
  • Author(s): Nico Golde
  • Date: 2007-03-31 12:16:20 UTC
  • Revision ID: james.westby@ubuntu.com-20070331121620-nzaxq7a287387r54
Tags: upstream-0.8
ImportĀ upstreamĀ versionĀ 0.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  STFL - The Structured Terminal Forms Language/Library
 
3
 *  Copyright (C) 2006  Clifford Wolf <clifford@clifford.at>
 
4
 *
 
5
 *  This program is free software; you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation; either version 2 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 *
 
19
 *  parser.c: STFL Form description file parser
 
20
 */
 
21
 
 
22
#include "stfl_internals.h"
 
23
 
 
24
#include <stdio.h>
 
25
#include <string.h>
 
26
#include <stdlib.h>
 
27
 
 
28
static void extract_name(char **key, char **name)
 
29
{
 
30
        int len = strcspn(*key, "[");
 
31
 
 
32
        if ((*key)[len] == 0) {
 
33
                *name = 0;
 
34
                return;
 
35
        }
 
36
 
 
37
        *name = strdup(*key+len+1);
 
38
        *key = realloc(*key, len+1);
 
39
        (*key)[len] = 0;
 
40
 
 
41
        len = strcspn(*name, "]");
 
42
        (*name)[len] = 0;
 
43
}
 
44
 
 
45
static void extract_class(char **key, char **cls)
 
46
{
 
47
        int len = strcspn(*key, "#");
 
48
 
 
49
        if ((*key)[len] == 0) {
 
50
                *cls = 0;
 
51
                return;
 
52
        }
 
53
 
 
54
        *cls = strdup(*key+len+1);
 
55
        *key = realloc(*key, len+1);
 
56
        (*key)[len] = 0;
 
57
}
 
58
 
 
59
static int read_type(const char **text, char **type, char **name, char **cls)
 
60
{
 
61
        int len = strcspn(*text, " \t\r\n:{}");
 
62
 
 
63
        if ((*text)[len] == ':' || len == 0)
 
64
                return 0;
 
65
 
 
66
        *type = malloc(len+1);
 
67
        memcpy(*type, *text, len);
 
68
        (*type)[len] = 0;
 
69
        *text += len;
 
70
 
 
71
        extract_name(type, name);
 
72
        extract_class(type, cls);
 
73
 
 
74
        return 1;
 
75
}
 
76
 
 
77
static int read_kv(const char **text, char **key, char **name, char **value)
 
78
{
 
79
        int len_k = strcspn(*text, " \t\r\n:{}");
 
80
 
 
81
        if ((*text)[len_k] != ':' || len_k == 0)
 
82
                return 0;
 
83
 
 
84
        *key = malloc(len_k+1);
 
85
        memcpy(*key, *text, len_k);
 
86
        (*key)[len_k] = 0;
 
87
        *text += len_k+1;
 
88
 
 
89
        extract_name(key, name);
 
90
 
 
91
        int len_v = 0, i = 0, j = 0;
 
92
        while ((*text)[i] && (*text)[i] != ' ' && (*text)[i] != '{' && (*text)[i] != '}' &&
 
93
               (*text)[i] != '\t' && (*text)[i] != '\r' && (*text)[i] != '\n')
 
94
        {
 
95
                if ((*text)[i] == '\'')
 
96
                        while ((*text)[++i] != '\'') len_v++;
 
97
                else
 
98
                if ((*text)[i] == '\"')
 
99
                        while ((*text)[++i] != '\"') len_v++;
 
100
                len_v++;
 
101
                i++;
 
102
        }
 
103
 
 
104
        *value = malloc(len_v+1);
 
105
        i = 0;
 
106
 
 
107
        while ((*text)[i] && (*text)[i] != ' ' && (*text)[i] != '{' && (*text)[i] != '}' &&
 
108
               (*text)[i] != '\t' && (*text)[i] != '\r' && (*text)[i] != '\n')
 
109
        {
 
110
                if ((*text)[i] == '\'')
 
111
                        while ((*text)[++i] != '\'')
 
112
                                (*value)[j++] = (*text)[i];
 
113
                else
 
114
                if ((*text)[i] == '\"')
 
115
                        while ((*text)[++i] != '\"')
 
116
                                (*value)[j++] = (*text)[i];
 
117
                else
 
118
                        (*value)[j++] = (*text)[i];
 
119
                i++;
 
120
        }
 
121
        
 
122
        (*value)[j] = 0;
 
123
        *text += i;
 
124
 
 
125
        return 1;
 
126
}
 
127
 
 
128
struct stfl_widget *stfl_parser(const char *text)
 
129
{
 
130
        struct stfl_widget *root = 0;
 
131
        struct stfl_widget *current = 0;
 
132
        int bracket_indenting = -1;
 
133
        int bracket_level = 0;
 
134
 
 
135
        while (1)
 
136
        {
 
137
                int indenting = 0;
 
138
 
 
139
                if (bracket_indenting >= 0)
 
140
                {
 
141
                        while (*text == ' ' || *text == '\t') text++;
 
142
 
 
143
                        while (*text == '}') {
 
144
                                bracket_level--; text++;
 
145
                                while (*text == ' ' || *text == '\t') text++;
 
146
                        }
 
147
 
 
148
                        while (*text == '{') {
 
149
                                bracket_level++; text++;
 
150
                                while (*text == ' ' || *text == '\t') text++;
 
151
                        }
 
152
 
 
153
                        if (bracket_level == 0)
 
154
                                bracket_indenting = -1;
 
155
 
 
156
                        if (bracket_level < 0)
 
157
                                goto parser_error;
 
158
                }
 
159
                else
 
160
                        if (*text == '}')
 
161
                                goto parser_error;
 
162
 
 
163
                if (bracket_indenting >= 0)
 
164
                {
 
165
                        while (*text == ' ' || *text == '\t')
 
166
                                text++;
 
167
 
 
168
                        if (*text == '\r' || *text == '\n')
 
169
                                goto parser_error;
 
170
 
 
171
                        indenting = bracket_indenting + (bracket_level-1);
 
172
                }
 
173
                else
 
174
                {
 
175
                        while (*text == ' ' || *text == '\t' || *text == '\r' || *text == '\n') {
 
176
                                if (*text == '\r' || *text == '\n')
 
177
                                        indenting = 0;
 
178
                                else
 
179
                                if (*text == '\t')
 
180
                                        indenting = -1;
 
181
                                else
 
182
                                if (indenting >= 0)
 
183
                                        indenting++;
 
184
                                text++;
 
185
                        }
 
186
 
 
187
                        if (*text == '*') {
 
188
                                while (*text && *text != '\r' && *text != '\n')
 
189
                                        text++;
 
190
                                continue;
 
191
                        }
 
192
 
 
193
                        if (*text == '{') {
 
194
                                bracket_indenting = indenting;
 
195
                                continue;
 
196
                        }
 
197
                }
 
198
 
 
199
                if (*text == 0)
 
200
                        break;
 
201
 
 
202
                char *key, *name, *cls, *value;
 
203
                if (indenting < 0)
 
204
                        goto parser_error;
 
205
 
 
206
                if (*text == '<')
 
207
                {
 
208
                        int filename_len = strcspn(++text, ">");
 
209
                        char filename[filename_len+1];
 
210
 
 
211
                        memcpy(filename, text, filename_len);
 
212
                        filename[filename_len] = 0;
 
213
 
 
214
                        text += filename_len;
 
215
                        if (*text) text++;
 
216
 
 
217
                        struct stfl_widget *n = stfl_parser_file(filename);
 
218
                        if (!n) return 0;
 
219
 
 
220
                        if (root)
 
221
                        {
 
222
                                while (current->parser_indent >= indenting) {
 
223
                                        current = current->parent;
 
224
                                        if (!current)
 
225
                                                goto parser_error;
 
226
                                }
 
227
 
 
228
                                n->parent = current;
 
229
                                if (current->last_child) {
 
230
                                        current->last_child->next_sibling = n;
 
231
                                        current->last_child = n;
 
232
                                } else {
 
233
                                        current->first_child = n;
 
234
                                        current->last_child = n;
 
235
                                }
 
236
 
 
237
                                n->parser_indent = indenting;
 
238
                                current = n;
 
239
                        }
 
240
                        else
 
241
                                root = n;
 
242
                }
 
243
                else
 
244
                if (root)
 
245
                {
 
246
                        while (current->parser_indent >= indenting) {
 
247
                                current = current->parent;
 
248
                                if (!current)
 
249
                                        goto parser_error;
 
250
                        }
 
251
 
 
252
                        if (read_type(&text, &key, &name, &cls) == 1)
 
253
                        {
 
254
                                struct stfl_widget *n = stfl_widget_new(key);
 
255
                                if (!n)
 
256
                                        goto parser_error;
 
257
                                free(key);
 
258
 
 
259
                                n->parent = current;
 
260
                                if (current->last_child) {
 
261
                                        current->last_child->next_sibling = n;
 
262
                                        current->last_child = n;
 
263
                                } else {
 
264
                                        current->first_child = n;
 
265
                                        current->last_child = n;
 
266
                                }
 
267
 
 
268
                                n->parser_indent = indenting;
 
269
                                n->name = name;
 
270
                                n->cls = cls;
 
271
                                current = n;
 
272
                        }
 
273
                        else
 
274
                        if (read_kv(&text, &key, &name, &value) == 1)
 
275
                        {
 
276
                                struct stfl_kv *kv = stfl_widget_setkv_str(current, key, value);
 
277
                                if (kv->name)
 
278
                                        free(kv->name);
 
279
                                kv->name = name;
 
280
 
 
281
                                free(key);
 
282
                                free(value);
 
283
                        }
 
284
                        else
 
285
                                goto parser_error;
 
286
                }
 
287
                else
 
288
                {
 
289
                        if (read_type(&text, &key, &name, &cls) == 0)
 
290
                                goto parser_error;
 
291
 
 
292
                        struct stfl_widget *n = stfl_widget_new(key);
 
293
                        if (!n)
 
294
                                goto parser_error;
 
295
                        free(key);
 
296
 
 
297
                        root = n;
 
298
                        current = n;
 
299
                        n->name = name;
 
300
                        n->cls = cls;
 
301
                }
 
302
 
 
303
                while (*text && *text != '\n' && *text != '\r' && *text != '{' && *text != '}')
 
304
                {
 
305
                        while (*text == ' ' || *text == '\t')
 
306
                                text++;
 
307
 
 
308
                        if (*text && *text != '\n' && *text != '\r' && *text != '{' && *text != '}')
 
309
                        {
 
310
                                if (read_kv(&text, &key, &name, &value) == 0)
 
311
                                        goto parser_error;
 
312
 
 
313
                                struct stfl_kv *kv = stfl_widget_setkv_str(current, key, value);
 
314
                                if (kv->name)
 
315
                                        free(kv->name);
 
316
                                kv->name = name;
 
317
 
 
318
                                free(key);
 
319
                                free(value);
 
320
                        }
 
321
                }
 
322
        }
 
323
 
 
324
        if (root)
 
325
                return root;
 
326
 
 
327
parser_error:;
 
328
        int i;
 
329
 
 
330
        fprintf(stderr, "STFL Parser Error near '");
 
331
 
 
332
        for (i=0; *text && i<20; i++, text++)
 
333
                if (*text == '\n')
 
334
                        fprintf(stderr, "\\n");
 
335
                else
 
336
                if (*text == '\t')
 
337
                        fprintf(stderr, " ");
 
338
                else
 
339
                if (*text < 32)
 
340
                        fprintf(stderr, "\\%03o", *text);
 
341
                else
 
342
                        fprintf(stderr, "%c", *text);
 
343
 
 
344
        fprintf(stderr, "'.\r\n");
 
345
        abort();
 
346
 
 
347
        return 0;
 
348
}
 
349
 
 
350
struct stfl_widget *stfl_parser_file(const char *filename)
 
351
{
 
352
        FILE *f = fopen(filename, "r");
 
353
 
 
354
        if (!f) {
 
355
                fprintf(stderr, "STFL Parser Error: Can't read file '%s'!\n", filename);
 
356
                abort();
 
357
                return 0;
 
358
        }
 
359
 
 
360
        int len = 0;
 
361
        char *text = 0;
 
362
 
 
363
        while (1) {
 
364
                int pos = len;
 
365
                text = realloc(text, len += 4096);
 
366
                pos += fread(text+pos, 1, 4096, f);
 
367
                if (pos < len) {
 
368
                        text[pos] = 0;
 
369
                        fclose(f);
 
370
                        break;
 
371
                }
 
372
        }
 
373
 
 
374
        struct stfl_widget *w = stfl_parser(text);
 
375
        free(text);
 
376
 
 
377
        return w;
 
378
}
 
379