summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--utils/themeeditor/main.c17
-rw-r--r--utils/themeeditor/skin_debug.c226
-rw-r--r--utils/themeeditor/skin_debug.h37
-rw-r--r--utils/themeeditor/skin_parser.c811
-rw-r--r--utils/themeeditor/skin_parser.h124
-rw-r--r--utils/themeeditor/skin_scan.c137
-rw-r--r--utils/themeeditor/skin_scan.h32
-rw-r--r--utils/themeeditor/symbols.h37
-rw-r--r--utils/themeeditor/tag_table.c75
-rw-r--r--utils/themeeditor/tag_table.h73
-rw-r--r--utils/themeeditor/themeeditor.pro10
11 files changed, 1579 insertions, 0 deletions
diff --git a/utils/themeeditor/main.c b/utils/themeeditor/main.c
new file mode 100644
index 0000000000..9f45c90317
--- /dev/null
+++ b/utils/themeeditor/main.c
@@ -0,0 +1,17 @@
1#include "skin_parser.h"
2#include "skin_debug.h"
3
4#include <stdlib.h>
5#include <stdio.h>
6
7int main(int argc, char* argv[])
8{
9 char* doc = "This is a sample %V(1, 2, 3, 4, 5, six, seven)\n"
10 "WPS document, with ; sublines and a %?T(conditional| or| two)";
11
12 struct skin_element* test = skin_parse(doc);
13
14 skin_debug_tree(test);
15
16 return 0;
17}
diff --git a/utils/themeeditor/skin_debug.c b/utils/themeeditor/skin_debug.c
new file mode 100644
index 0000000000..f275b0403d
--- /dev/null
+++ b/utils/themeeditor/skin_debug.c
@@ -0,0 +1,226 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Robert Bieber
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include "skin_parser.h"
27#include "skin_debug.h"
28
29/* Global variables for debug output */
30int debug_indent_level = 0;
31extern int skin_line;
32
33/* Debugging functions */
34void skin_error(enum skin_errorcode error)
35{
36
37 fprintf(stderr, "Error on line %d: ", skin_line);
38
39 switch(error)
40 {
41 case MEMORY_LIMIT_EXCEEDED:
42 fprintf(stderr, "Memory limit exceeded\n");
43 break;
44 case NEWLINE_EXPECTED:
45 fprintf(stderr, "Newline expected\n");
46 break;
47 case ILLEGAL_TAG:
48 fprintf(stderr, "Illegal tag\n");
49 break;
50 case ARGLIST_EXPECTED:
51 fprintf(stderr, "Argument list expected\n");
52 break;
53 case TOO_MANY_ARGS:
54 fprintf(stderr, "Too many arguments given\n");
55 break;
56 case DEFAULT_NOT_ALLOWED:
57 fprintf(stderr, "Argument can not be set to default\n");
58 break;
59 case UNEXPECTED_NEWLINE:
60 fprintf(stderr, "Unexpected newline\n");
61 break;
62 case INSUFFICIENT_ARGS:
63 fprintf(stderr, "Not enough arguments\n");
64 break;
65 case INT_EXPECTED:
66 fprintf(stderr, "Expected integer\n");
67 break;
68 case SEPERATOR_EXPECTED:
69 fprintf(stderr, "Expected argument seperator\n");
70 break;
71 case CLOSE_EXPECTED:
72 fprintf(stderr, "Expected list close\n");
73 break;
74 case MULTILINE_EXPECTED:
75 fprintf(stderr, "Expected subline seperator\n");
76 break;
77 };
78
79}
80
81void skin_debug_tree(struct skin_element* root)
82{
83 int i;
84
85 struct skin_element* current = root;
86
87 while(current)
88 {
89 skin_debug_indent();
90
91 switch(current->type)
92 {
93
94 case TEXT:
95 printf("[ Plain text on line %d : %s ]\n", current->line,
96 current->text);
97 break;
98
99 case NEWLINE:
100 printf("[ Newline on line %d ]\n", current->line);
101 break;
102
103 case COMMENT:
104 printf("[ Comment on line %d: ", current->line);
105 for(i = 0; i < (int)strlen(current->text); i++)
106 {
107 if(current->text[i] == '\n')
108 printf("\\n");
109 else
110 printf("%c", current->text[i]);
111 }
112 printf(" ]\n");
113 break;
114
115 case TAG:
116 printf("[ %s tag on line %d with %d arguments\n", current->name,
117 current->line, current->params_count);
118 debug_indent_level++;
119 skin_debug_params(current->params_count, current->params);
120 debug_indent_level--;
121 skin_debug_indent();
122 printf("]\n");
123
124 break;
125
126 case SUBLINES:
127 printf("[ Alternator on line %d with %d sublines \n", current->line,
128 current->children_count);
129 debug_indent_level++;
130 for(i = 0; i < current->children_count; i++)
131 {
132 skin_debug_indent();
133 printf("[ Subline %d\n", i);
134
135 debug_indent_level++;
136 skin_debug_tree(current->children[i]);
137 debug_indent_level--;
138
139 skin_debug_indent();
140 printf("]\n");
141 }
142 debug_indent_level--;
143 skin_debug_indent();
144 printf("]\n");
145 break;
146
147 case CONDITIONAL:
148 printf("[ Conditional tag on line %d with %d enumerations \n",
149 current->line, current->children_count - 1);
150 debug_indent_level++;
151
152 skin_debug_indent();
153 printf("[ Condition tag \n");
154 debug_indent_level++;
155 skin_debug_tree(current->children[0]);
156 debug_indent_level--;
157 skin_debug_indent();
158 printf("]\n");
159
160 for(i = 1; i < current->children_count; i++)
161 {
162 skin_debug_indent();
163 printf("[ Enumeration %d\n", i - 1);
164 debug_indent_level++;
165 skin_debug_tree(current->children[i]);
166 debug_indent_level--;
167 skin_debug_indent();
168 printf("]\n");
169 }
170
171 debug_indent_level--;
172 skin_debug_indent();
173 printf("]\n");
174
175
176 break;
177
178 }
179
180 current = current->next;
181 }
182
183}
184
185void skin_debug_params(int count, struct skin_tag_parameter params[])
186{
187 int i;
188 for(i = 0; i < count; i++)
189 {
190
191 skin_debug_indent();
192 switch(params[i].type)
193 {
194 case DEFAULT:
195 printf("[-]");
196 break;
197
198 case STRING:
199 printf("[%s]", params[i].data.text);
200 break;
201
202 case NUMERIC:
203 printf("[%d]", params[i].data.numeric);
204 break;
205
206 case CODE:
207 printf("[ WPS Code: \n");
208 debug_indent_level++;
209 skin_debug_tree(params[i].data.code);
210 debug_indent_level--;
211 skin_debug_indent();
212 printf("]");
213 break;
214 }
215
216 printf("\n");
217
218 }
219}
220
221void skin_debug_indent()
222{
223 int i;
224 for(i = 0; i < debug_indent_level; i++)
225 printf(" ");
226}
diff --git a/utils/themeeditor/skin_debug.h b/utils/themeeditor/skin_debug.h
new file mode 100644
index 0000000000..e5bac1ede1
--- /dev/null
+++ b/utils/themeeditor/skin_debug.h
@@ -0,0 +1,37 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Robert Bieber
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22
23#ifndef SKIN_DEBUG_H
24#define SKIN_DEBUG_H
25
26#include "skin_parser.h"
27
28/* Debugging functions */
29void skin_error(enum skin_errorcode error);
30void skin_debug_tree(struct skin_element* root);
31
32/* Auxiliary debug functions */
33void skin_debug_params(int count, struct skin_tag_parameter params[]);
34void skin_debug_indent();
35
36
37#endif // SKIN_DEBUG_H
diff --git a/utils/themeeditor/skin_parser.c b/utils/themeeditor/skin_parser.c
new file mode 100644
index 0000000000..89952a615b
--- /dev/null
+++ b/utils/themeeditor/skin_parser.c
@@ -0,0 +1,811 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Robert Bieber
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <ctype.h>
26
27#include "skin_parser.h"
28#include "skin_debug.h"
29#include "tag_table.h"
30#include "symbols.h"
31#include "skin_scan.h"
32
33/* Declaration of parse tree buffer */
34char skin_parse_tree[SKIN_MAX_MEMORY];
35int skin_current_block = 0;
36
37/* Global variables for the parser */
38int skin_line = 0;
39
40/* Auxiliary parsing functions (not visible at global scope) */
41struct skin_element* skin_parse_line(char** document);
42struct skin_element* skin_parse_line_optional(char** document, int conditional);
43struct skin_element* skin_parse_sublines(char** document);
44struct skin_element* skin_parse_sublines_optional(char** document,
45 int conditional);
46
47int skin_parse_tag(struct skin_element* element, char** document);
48int skin_parse_text(struct skin_element* element, char** document,
49 int conditional);
50int skin_parse_conditional(struct skin_element* element, char** document);
51int skin_parse_newline(struct skin_element* element, char** document);
52int skin_parse_comment(struct skin_element* element, char** document);
53struct skin_element* skin_parse_code_as_arg(char** document);
54
55struct skin_element* skin_parse(char* document)
56{
57
58 struct skin_element* root = NULL;
59 struct skin_element* last = NULL;
60
61 struct skin_element** to_write = 0;
62
63 char* cursor = document; /* Keeps track of location in the document */
64 char* bookmark; /* Used when we need to look ahead */
65
66 int sublines = 0; /* Flag for parsing sublines */
67
68 skin_line = 1;
69
70 while(*cursor != '\0')
71 {
72
73 /* First, we check to see if this line will contain sublines */
74 bookmark = cursor;
75 sublines = 0;
76 while(*cursor != '\n' && *cursor != '\0')
77 {
78 if(*cursor == MULTILINESYM)
79 {
80 sublines = 1;
81 break;
82 }
83 else if(*cursor == TAGSYM)
84 {
85 /* A ';' directly after a '%' doesn't count */
86 cursor ++;
87
88 if(*cursor == '\0')
89 break;
90
91 cursor++;
92 }
93 else
94 {
95 /* Advancing the cursor as normal */
96 cursor++;
97 }
98 }
99 cursor = bookmark;
100
101 if(!root)
102 to_write = &root;
103 else
104 to_write = &(last->next);
105
106 if(sublines)
107 {
108 *to_write = skin_parse_sublines(&cursor);
109 last = *to_write;
110 if(!last)
111 return NULL;
112 }
113 else
114 {
115
116 *to_write = skin_parse_line(&cursor);
117 last = *to_write;
118 if(!last)
119 return NULL;
120
121 }
122
123 /* Making sure last is at the end */
124 while(last->next)
125 last = last->next;
126
127 }
128
129 return root;
130
131}
132
133/* Auxiliary Parsing Functions */
134
135struct skin_element* skin_parse_line(char**document)
136{
137
138 return skin_parse_line_optional(document, 0);
139
140}
141
142
143/*
144 * If conditional is set to true, then this will break upon encountering
145 * SEPERATESYM. This should only be used when parsing a line inside a
146 * conditional, otherwise just use the wrapper function skin_parse_line()
147 */
148struct skin_element* skin_parse_line_optional(char** document, int conditional)
149{
150 char* cursor = *document;
151
152 struct skin_element* root = NULL;
153 struct skin_element* current = NULL;
154
155 while(*cursor != '\n' && *cursor != '\0' && *cursor != MULTILINESYM
156 && !((*cursor == ARGLISTSEPERATESYM || *cursor == ARGLISTCLOSESYM
157 || *cursor == ENUMLISTSEPERATESYM) && conditional))
158 {
159 /* Allocating memory if necessary */
160 if(root)
161 {
162 current->next = skin_alloc_element();
163 current = current->next;
164 }
165 else
166 {
167 current = skin_alloc_element();
168 root = current;
169 }
170
171 /* Parsing the current element */
172 if(*cursor == TAGSYM && cursor[1] == CONDITIONSYM)
173 {
174 if(!skin_parse_conditional(current, &cursor))
175 return NULL;
176 }
177 else if(*cursor == TAGSYM)
178 {
179 if(!skin_parse_tag(current, &cursor))
180 return NULL;
181 }
182 else if(*cursor == COMMENTSYM)
183 {
184 if(!skin_parse_comment(current, &cursor))
185 return NULL;
186 }
187 else
188 {
189 if(!skin_parse_text(current, &cursor, conditional))
190 return NULL;
191 }
192 }
193
194 if(*cursor == '\n')
195 {
196 /* Allocating memory if necessary */
197 if(root)
198 {
199 current->next = skin_alloc_element();
200 current = current->next;
201 }
202 else
203 {
204 current = skin_alloc_element();
205 root = current;
206 }
207 if(!skin_parse_newline(current, &cursor))
208 return NULL;
209 }
210
211 /* Moving up the calling function's pointer */
212 *document = cursor;
213
214 return root;
215}
216
217struct skin_element* skin_parse_sublines(char** document)
218{
219 return skin_parse_sublines_optional(document, 0);
220}
221
222struct skin_element* skin_parse_sublines_optional(char** document,
223 int conditional)
224{
225 struct skin_element* retval;
226 char* cursor = *document;
227 int sublines = 1;
228 int i;
229
230 retval = skin_alloc_element();
231 retval->type = SUBLINES;
232 retval->next = NULL;
233
234 /* First we count the sublines */
235 while(*cursor != '\0' && *cursor != '\n'
236 && !((*cursor == ARGLISTSEPERATESYM || *cursor == ARGLISTCLOSESYM
237 || *cursor == ENUMLISTSEPERATESYM) && conditional))
238 {
239 if(*cursor == COMMENTSYM)
240 skip_comment(&cursor);
241
242 /* Accounting for escaped subline symbols */
243 if(*cursor == TAGSYM)
244 {
245 cursor++;
246 if(*cursor == '\0' || *cursor == '\n')
247 break;
248 }
249
250 if(*cursor == MULTILINESYM)
251 {
252 sublines++;
253 }
254
255 cursor++;
256 }
257
258 /* ...and then we parse them */
259 retval->children_count = sublines;
260 retval->children = skin_alloc_children(sublines);
261
262 cursor = *document;
263 for(i = 0; i < sublines; i++)
264 {
265 retval->children[i] = skin_parse_line_optional(&cursor, conditional);
266 skip_whitespace(&cursor);
267
268 if(*cursor != MULTILINESYM && i != sublines - 1)
269 {
270 skin_error(MULTILINE_EXPECTED);
271 return NULL;
272 }
273 else
274 {
275 cursor++;
276 }
277 }
278
279 *document = cursor;
280
281 return retval;
282}
283
284int skin_parse_tag(struct skin_element* element, char** document)
285{
286
287 char* cursor = *document + 1;
288 char* bookmark;
289
290 char tag_name[3];
291 char* tag_args;
292
293 int num_args = 1;
294 int i;
295 int count;
296
297 int optional = 0;
298
299 /* Checking the tag name */
300 tag_name[0] = cursor[0];
301 tag_name[1] = cursor[1];
302 tag_name[2] = '\0';
303
304 /* First we check the two characters after the '%', then a single char */
305 tag_args = find_tag(tag_name);
306
307 if(!tag_args)
308 {
309 tag_name[1] = '\0';
310 tag_args = find_tag(tag_name);
311 cursor++;
312 }
313 else
314 {
315 cursor += 2;
316 }
317
318 if(!tag_args)
319 {
320 skin_error(ILLEGAL_TAG);
321 return 0;
322 }
323
324 /* Copying basic tag info */
325 element->type = TAG;
326 element->name = skin_alloc_string(strlen(tag_name));
327 strcpy(element->name, tag_name);
328 element->line = skin_line;
329
330 /* If this tag has no arguments, we can bail out now */
331 if(strlen(tag_args) == 0)
332 {
333 *document = cursor;
334 return 1;
335 }
336
337 /* Checking the number of arguments and allocating args */
338 if(*cursor != ARGLISTOPENSYM && tag_args[0] != '|')
339 {
340 skin_error(ARGLIST_EXPECTED);
341 return 0;
342 }
343 else
344 {
345 cursor++;
346 }
347
348 for(bookmark = cursor; *cursor != '\n' && *cursor != '\0' &&
349 *cursor != ARGLISTCLOSESYM; cursor++)
350 {
351 /* Skipping over escaped characters */
352 if(*cursor == TAGSYM)
353 {
354 cursor++;
355 if(*cursor == '\0')
356 break;
357 }
358
359 /* Skipping comments */
360 if(*cursor == COMMENTSYM)
361 skip_comment(&cursor);
362
363 /* Commas inside of contained lists don't count */
364 if(*cursor == ARGLISTOPENSYM)
365 while(*cursor != ARGLISTCLOSESYM && *cursor != '\0')
366 cursor++;
367
368 if(*cursor == ARGLISTSEPERATESYM)
369 num_args++;
370
371 }
372 cursor = bookmark; /* Restoring the cursor */
373 element->params_count = num_args;
374 element->params = skin_alloc_params(num_args);
375
376 /* Now we have to actually parse each argument */
377 i = 0;
378 while(i < num_args)
379 {
380 /* Making sure we haven't run out of arguments */
381 if(*tag_args == '\0')
382 {
383 skin_error(TOO_MANY_ARGS);
384 return 0;
385 }
386
387 /* Checking for the optional bar */
388 if(*tag_args == '|')
389 {
390 optional = 1;
391 tag_args++;
392 }
393
394 /* Checking for a repeated argument */
395 if(isdigit(*tag_args))
396 {
397 count = scan_int(&tag_args);
398 }
399 else
400 {
401 count = 1;
402 }
403
404 /* Scanning the arguments */
405 while(count > 0)
406 {
407
408 skip_whitespace(&cursor);
409
410 /* Checking for a premature end */
411 if(num_args - i < count)
412 {
413 if(optional && (num_args - i == 0))
414 {
415 break;
416 }
417 else
418 {
419 /*
420 We error out if there are too few arguments, or if there
421 is an optional argument that was supposed to be grouped
422 with another
423 */
424 skin_error(INSUFFICIENT_ARGS);
425 return 0;
426 }
427 }
428
429 /* Checking for comments */
430 if(*cursor == COMMENTSYM)
431 skip_comment(&cursor);
432
433 /* Checking a nullable argument for null */
434 if(*cursor == DEFAULTSYM)
435 {
436 if(islower(*tag_args))
437 {
438 element->params[i].type = DEFAULT;
439 cursor++;
440 }
441 else
442 {
443 skin_error(DEFAULT_NOT_ALLOWED);
444 return 0;
445 }
446 }
447 else if(tolower(*tag_args) == 'i')
448 {
449 /* Scanning an int argument */
450 if(!isdigit(*cursor))
451 {
452 skin_error(INT_EXPECTED);
453 return 0;
454 }
455
456 element->params[i].type = NUMERIC;
457 element->params[i].data.numeric = scan_int(&cursor);
458 }
459 else if(tolower(*tag_args) == 's' || tolower(*tag_args) == 'f')
460 {
461 /* Scanning a string argument */
462 element->params[i].type = STRING;
463 element->params[i].data.text = scan_string(&cursor);
464
465 }
466 else if(tolower(*tag_args) == 'c')
467 {
468 element->params[i].type = CODE;
469 element->params[i].data.code = skin_parse_code_as_arg(&cursor);
470 if(!element->params[i].data.code)
471 return 0;
472 }
473
474 i++;
475 count--;
476 skip_whitespace(&cursor);
477
478 if(*cursor != ARGLISTSEPERATESYM && i < num_args)
479 {
480 skin_error(SEPERATOR_EXPECTED);
481 return 0;
482 }
483 else if(*cursor != ARGLISTCLOSESYM && i == num_args)
484 {
485 skin_error(CLOSE_EXPECTED);
486 return 0;
487 }
488 else
489 {
490 cursor++;
491 }
492 }
493
494 tag_args++;
495
496 }
497
498 *document = cursor;
499
500 return 1;
501}
502
503/*
504 * If the conditional flag is set true, then parsing text will stop at an
505 * ARGLISTSEPERATESYM. Only set that flag when parsing within a conditional
506 */
507int skin_parse_text(struct skin_element* element, char** document,
508 int conditional)
509{
510 char* cursor = *document;
511
512 int length = 0;
513
514 int dest;
515
516 /* First figure out how much text we're copying */
517 while(*cursor != '\0' && *cursor != '\n' && *cursor != MULTILINESYM
518 && *cursor != COMMENTSYM
519 && !((*cursor == ARGLISTSEPERATESYM || *cursor == ARGLISTCLOSESYM
520 || *cursor == ENUMLISTSEPERATESYM) && conditional))
521 {
522 /* Dealing with possibility of escaped characters */
523 if(*cursor == TAGSYM)
524 {
525 if(find_escape_character(cursor[1]))
526 cursor++;
527 else
528 break;
529 }
530
531 length++;
532 cursor++;
533 }
534
535 cursor = *document;
536
537 /* Copying the text into the element struct */
538 element->type = TEXT;
539 element->line = skin_line;
540 element->next = NULL;
541 element->text = skin_alloc_string(length);
542
543 for(dest = 0; dest < length; dest++)
544 {
545 /* Advancing cursor if we've encountered an escaped character */
546 if(*cursor == TAGSYM)
547 cursor++;
548
549 element->text[dest] = *cursor;
550 cursor++;
551 }
552 element->text[length] = '\0';
553
554 *document = cursor;
555
556 return 1;
557}
558
559int skin_parse_conditional(struct skin_element* element, char** document)
560{
561
562 char* cursor = *document + 1; /* Starting past the "%" */
563 char* bookmark;
564 struct skin_element* tag = skin_alloc_element(); /* The tag to evaluate */
565 int children = 1;
566 int i;
567
568 element->type = CONDITIONAL;
569 element->line = skin_line;
570
571 /* Parsing the tag first */
572 if(!skin_parse_tag(tag, &cursor))
573 return 0;
574
575 /* Counting the children */
576 if(*(cursor++) != ARGLISTOPENSYM)
577 {
578 skin_error(ARGLIST_EXPECTED);
579 return 0;
580 }
581 bookmark = cursor;
582 while(*cursor != ARGLISTCLOSESYM && *cursor != '\n' && *cursor != '\0')
583 {
584 if(*cursor == COMMENTSYM)
585 {
586 skip_comment(&cursor);
587 continue;
588 }
589
590 if(*cursor == TAGSYM)
591 {
592 cursor++;
593 if(*cursor == '\0' || *cursor == '\n')
594 break;
595 cursor++;
596 continue;
597 }
598
599 if(*cursor == ENUMLISTSEPERATESYM)
600 children++;
601
602 cursor++;
603 }
604 cursor = bookmark;
605
606 /* Parsing the children */
607 element->children_count = children + 1; /* Make sure to include the tag */
608 element->children = skin_alloc_children(children + 1);
609 element->children[0] = tag;
610
611 for(i = 1; i < children + 1; i++)
612 {
613 element->children[i] = skin_parse_code_as_arg(&cursor);
614 skip_whitespace(&cursor);
615
616 if(i < children && *cursor != ENUMLISTSEPERATESYM)
617 {
618 skin_error(SEPERATOR_EXPECTED);
619 return 0;
620 }
621 else if(i == children && *cursor != ARGLISTCLOSESYM)
622 {
623 skin_error(CLOSE_EXPECTED);
624 return 0;
625 }
626 else
627 {
628 cursor++;
629 }
630 }
631
632 *document = cursor;
633
634 return 1;
635}
636
637int skin_parse_newline(struct skin_element* element, char** document)
638{
639
640 char* cursor = *document;
641 if(*cursor != '\n')
642 {
643 skin_error(NEWLINE_EXPECTED);
644 return 0;
645 }
646 cursor++;
647
648 /* Assembling a skin_element struct for a newline */
649 element->type = NEWLINE;
650 element->line = skin_line;
651 skin_line++;
652 element->text = skin_alloc_string(1);
653 element->text[0] = '\n';
654 element->text[1] = '\0';
655 element->next = NULL;
656
657 *document = cursor;
658
659 return 1;
660}
661
662int skin_parse_comment(struct skin_element* element, char** document)
663{
664 char* cursor = *document;
665
666 int length;
667 /*
668 * Finding the index of the ending newline or null-terminator
669 * The length of the string of interest doesn't include the leading #, the
670 * length we need to reserve is the same as the index of the last character
671 */
672 for(length = 0; cursor[length] != '\n' && cursor[length] != '\0'; length++);
673
674 element->type = COMMENT;
675 element->line = skin_line;
676 element->text = skin_alloc_string(length);
677 /* We copy from one char past cursor to leave out the # */
678 memcpy((void*)(element->text), (void*)(cursor + 1), sizeof(char) * length);
679 element->text[length] = '\0';
680
681 if(cursor[length] == '\n')
682 skin_line++;
683
684 *document += (length + 1); /* Move cursor up past # and all text */
685
686 return 1;
687}
688
689struct skin_element* skin_parse_code_as_arg(char** document)
690{
691
692 int sublines = 0;
693 char* cursor = *document;
694
695 /* Checking for sublines */
696 while(*cursor != '\n' && *cursor != '\0')
697 {
698 if(*cursor == MULTILINESYM)
699 {
700 sublines = 1;
701 break;
702 }
703 else if(*cursor == TAGSYM)
704 {
705 /* A ';' directly after a '%' doesn't count */
706 cursor ++;
707
708 if(*cursor == '\0')
709 break;
710
711 cursor++;
712 }
713 else
714 {
715 /* Advancing the cursor as normal */
716 cursor++;
717 }
718 }
719
720 if(sublines)
721 return skin_parse_sublines_optional(document, 1);
722 else
723 return skin_parse_line_optional(document, 1);
724}
725
726
727/* Memory management */
728struct skin_element* skin_alloc_element()
729{
730
731#if 0
732
733 char* retval = &skin_parse_tree[skin_current_block * 4];
734
735 int delta = sizeof(struct skin_element) / (sizeof(char) * 4);
736
737 /* If one block is partially filled, make sure to advance to the
738 * next one for the next allocation
739 */
740 if(sizeof(struct skin_element) % (sizeof(char) * 4) != 0)
741 delta++;
742
743 skin_current_block += delta;
744
745 return (struct skin_element*)retval;
746
747#endif
748
749 struct skin_element* retval = (struct skin_element*)
750 malloc(sizeof(struct skin_element));
751 retval->next = NULL;
752 retval->params_count = 0;
753 retval->children_count = 0;
754
755 return retval;
756
757}
758
759struct skin_tag_parameter* skin_alloc_params(int count)
760{
761#if 0
762
763 char* retval = &skin_parse_tree[skin_current_block * 4];
764
765 int delta = sizeof(struct skin_tag_parameter) / (sizeof(char) * 4);
766 delta *= count;
767
768 /* Correcting uneven alignment */
769 if(count * sizeof(struct skin_tag_parameter) % (sizeof(char) * 4) != 0)
770 delta++;
771
772 skin_current_block += delta;
773
774 return (struct skin_tag_parameter*) retval;
775
776#endif
777
778 return (struct skin_tag_parameter*)malloc(sizeof(struct skin_tag_parameter)
779 * count);
780
781}
782
783char* skin_alloc_string(int length)
784{
785
786#if 0
787 char* retval = &skin_parse_tree[skin_current_block * 4];
788
789 /* Checking alignment */
790 length++; /* Accounting for the null terminator */
791 int delta = length / 4;
792 if(length % 4 != 0)
793 delta++;
794
795 skin_current_block += delta;
796
797 if(skin_current_block >= SKIN_MAX_MEMORY / 4)
798 skin_error(MEMORY_LIMIT_EXCEEDED);
799
800 return retval;
801
802#endif
803
804 return (char*)malloc(sizeof(char) * (length + 1));
805
806}
807
808struct skin_element** skin_alloc_children(int count)
809{
810 return (struct skin_element**) malloc(sizeof(struct skin_element*) * count);
811}
diff --git a/utils/themeeditor/skin_parser.h b/utils/themeeditor/skin_parser.h
new file mode 100644
index 0000000000..a6fd1aa206
--- /dev/null
+++ b/utils/themeeditor/skin_parser.h
@@ -0,0 +1,124 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Robert Bieber
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef GENERIC_PARSER_H
23#define GENERIC_PARSER_H
24
25#define SKIN_MAX_MEMORY 1048576
26
27/********************************************************************
28 ****** A global buffer will be used to store the parse tree *******
29 *******************************************************************/
30extern char skin_parse_tree[];
31
32/********************************************************************
33 ****** Data Structures *********************************************
34 *******************************************************************/
35
36/* Possible types of element in a WPS file */
37enum skin_element_type
38{
39 TEXT,
40 NEWLINE,
41 COMMENT,
42 TAG,
43 CONDITIONAL,
44 SUBLINES
45};
46
47enum skin_errorcode
48{
49 MEMORY_LIMIT_EXCEEDED,
50 NEWLINE_EXPECTED,
51 ILLEGAL_TAG,
52 ARGLIST_EXPECTED,
53 TOO_MANY_ARGS,
54 DEFAULT_NOT_ALLOWED,
55 UNEXPECTED_NEWLINE,
56 INSUFFICIENT_ARGS,
57 INT_EXPECTED,
58 SEPERATOR_EXPECTED,
59 CLOSE_EXPECTED,
60 MULTILINE_EXPECTED
61};
62
63/* Holds a tag parameter, either numeric or text */
64struct skin_tag_parameter
65{
66 enum
67 {
68 NUMERIC,
69 STRING,
70 CODE,
71 DEFAULT
72 } type;
73
74 union
75 {
76 int numeric;
77 char* text;
78 struct skin_element* code;
79 } data;
80
81};
82
83/* Defines an element of a SKIN file */
84struct skin_element
85{
86 /* Defines what type of element it is */
87 enum skin_element_type type;
88
89 /* The line on which it's defined in the source file */
90 int line;
91
92 /* Text for comments and plaintext */
93 char* text;
94
95 /* The tag or conditional name */
96 char* name;
97
98 /* Pointer to and size of an array of parameters */
99 int params_count;
100 struct skin_tag_parameter* params;
101
102 /* Pointer to and size of an array of children */
103 int children_count;
104 struct skin_element** children;
105
106 /* Link to the next element */
107 struct skin_element* next;
108};
109
110/***********************************************************************
111 ***** Functions *******************************************************
112 **********************************************************************/
113
114/* Parses a WPS document and returns a list of skin_element
115 structures. */
116struct skin_element* skin_parse(char* document);
117
118/* Memory management functions */
119struct skin_element* skin_alloc_element();
120struct skin_element** skin_alloc_children(int count);
121struct skin_tag_parameter* skin_alloc_params(int count);
122char* skin_alloc_string(int length);
123
124#endif /* GENERIC_PARSER_H */
diff --git a/utils/themeeditor/skin_scan.c b/utils/themeeditor/skin_scan.c
new file mode 100644
index 0000000000..92ee521176
--- /dev/null
+++ b/utils/themeeditor/skin_scan.c
@@ -0,0 +1,137 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Robert Bieber
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <ctype.h>
24#include <stdlib.h>
25
26#include "skin_scan.h"
27#include "skin_debug.h"
28#include "symbols.h"
29#include "skin_parser.h"
30
31/* Scanning Functions */
32
33/* Simple function to advance a char* past a comment */
34void skip_comment(char** document)
35{
36 for(/*NO INIT*/;**document != '\n' && **document != '\0'; (*document)++);
37 if(**document == '\n')
38 (*document)++;
39}
40
41void skip_whitespace(char** document)
42{
43 for(/*NO INIT*/; **document == ' ' || **document == '\t'; (*document)++);
44}
45
46char* scan_string(char** document)
47{
48
49 char* cursor = *document;
50 int length = 0;
51 char* buffer = NULL;
52 int i;
53
54 while(*cursor != ARGLISTSEPERATESYM && *cursor != ARGLISTCLOSESYM &&
55 *cursor != '\0')
56 {
57 if(*cursor == COMMENTSYM)
58 {
59 skip_comment(&cursor);
60 continue;
61 }
62
63 if(*cursor == '\n')
64 {
65 skin_error(UNEXPECTED_NEWLINE);
66 return NULL;
67 }
68
69 length++;
70 cursor++;
71 }
72
73 /* Copying the string */
74 cursor = *document;
75 buffer = skin_alloc_string(length);
76 for(i = 0; i < length; i++)
77 {
78 if(*cursor == COMMENTSYM)
79 {
80 skip_comment(&cursor);
81 i--;
82 continue;
83 }
84
85 buffer[i] = *cursor;
86 cursor++;
87 }
88
89 *document = cursor;
90 return buffer;
91}
92
93int scan_int(char** document)
94{
95
96 char* cursor = *document;
97 int length = 0;
98 char* buffer = NULL;
99 int retval;
100 int i;
101
102 while(isdigit(*cursor) || *cursor == COMMENTSYM)
103 {
104 if(*cursor == COMMENTSYM)
105 {
106 skip_comment(&cursor);
107 continue;
108 }
109
110 length++;
111 cursor++;
112 }
113
114 buffer = skin_alloc_string(length);
115
116 /* Copying to the buffer while avoiding comments */
117 cursor = *document;
118 buffer[length] = '\0';
119 for(i = 0; i < length; i++)
120 {
121 if(*cursor == COMMENTSYM)
122 {
123 skip_comment(&cursor);
124 i--;
125 continue;
126 }
127
128 buffer[i] = *cursor;
129 cursor++;
130
131 }
132 retval = atoi(buffer);
133 free(buffer);
134
135 *document = cursor;
136 return retval;
137}
diff --git a/utils/themeeditor/skin_scan.h b/utils/themeeditor/skin_scan.h
new file mode 100644
index 0000000000..863e9b7d64
--- /dev/null
+++ b/utils/themeeditor/skin_scan.h
@@ -0,0 +1,32 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Robert Bieber
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef SCANNING_H
23#define SCANNING_H
24
25/* Scanning functions */
26void skip_comment(char** document);
27void skip_whitespace(char** document);
28char* scan_string(char** document);
29int scan_int(char** document);
30
31
32#endif // SCANNING_H
diff --git a/utils/themeeditor/symbols.h b/utils/themeeditor/symbols.h
new file mode 100644
index 0000000000..a82bb09393
--- /dev/null
+++ b/utils/themeeditor/symbols.h
@@ -0,0 +1,37 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Robert Bieber
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef SYMBOLS_H
23#define SYMBOLS_H
24
25/* Symbol definitions for WPS parsing */
26
27#define TAGSYM '%'
28#define COMMENTSYM '#'
29#define CONDITIONSYM '?'
30#define MULTILINESYM ';'
31#define ARGLISTOPENSYM '('
32#define ARGLISTCLOSESYM ')'
33#define ARGLISTSEPERATESYM ','
34#define ENUMLISTSEPERATESYM '|'
35#define DEFAULTSYM '-'
36
37#endif /* SYMBOLS_H */
diff --git a/utils/themeeditor/tag_table.c b/utils/themeeditor/tag_table.c
new file mode 100644
index 0000000000..ac0537f4a1
--- /dev/null
+++ b/utils/themeeditor/tag_table.c
@@ -0,0 +1,75 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Robert Bieber
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "tag_table.h"
23
24#include <string.h>
25
26/* The tag definition table */
27struct tag_info legal_tags[] =
28{
29 { "V" , "IIiii|2sc" },
30 { "Vi" , "SIIiii|2s" },
31 { "Vd" , "S" },
32 { "T" , "" },
33 { "" , ""} /* Keep this here to mark the end of the table */
34};
35
36/* A table of legal escapable characters */
37char legal_escape_characters[] = "%(|);#,";
38
39/*
40 * Just does a straight search through the tag table to find one by
41 * the given name
42 */
43char* find_tag(char* name)
44{
45
46 struct tag_info* current = legal_tags;
47
48 /*
49 * Continue searching so long as we have a non-empty name string
50 * and the name of the current element doesn't match the name
51 * we're searching for
52 */
53
54 while(strcmp(current->name, name) && current->name[0] != '\0')
55 current++;
56
57 if(current->name[0] == '\0')
58 return NULL;
59 else
60 return current->params;
61
62}
63
64/* Searches through the legal escape characters string */
65int find_escape_character(char lookup)
66{
67 char* current = legal_escape_characters;
68 while(*current != lookup && *current != '\0')
69 current++;
70
71 if(*current == lookup)
72 return 1;
73 else
74 return 0;
75}
diff --git a/utils/themeeditor/tag_table.h b/utils/themeeditor/tag_table.h
new file mode 100644
index 0000000000..935380ddd9
--- /dev/null
+++ b/utils/themeeditor/tag_table.h
@@ -0,0 +1,73 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Robert Bieber
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef TAG_TABLE_H
23#define TAG_TABLE_H
24
25/*
26 * Struct for tag parsing information
27 * name - The name of the tag, i.e. V for %V
28 * params - A string specifying all of the tags parameters, each
29 * character representing a single parameter. Valid
30 * characters for parameters are:
31 * I - Required integer
32 * i - Nullable integer
33 * S - Required string
34 * s - Nullable string
35 * F - Required file name
36 * f - Nullable file name
37 * C - Required WPS code
38 * Any nullable parameter may be replaced in the WPS file
39 * with a '-'. To specify that parameters may be left off
40 * altogether, place a '|' in the parameter string. For
41 * instance, with the parameter string...
42 * Ii|Ss
43 * one integer must be specified, one integer can be
44 * specified or set to default with '-', and the user can
45 * stop providing parameters at any time after that.
46 * To specify multiple instances of the same type, put a
47 * number before the character. For instance, the string...
48 * 2s
49 * will specify two strings.
50 *
51 */
52struct tag_info
53{
54
55 char* name;
56 char* params;
57
58};
59
60/*
61 * Finds a tag by name and returns its parameter list, or an empty
62 * string if the tag is not found in the table
63 */
64char* find_tag(char* name);
65
66/*
67 * Determines whether a character is legal to escape or not. If
68 * lookup is not found in the legal escape characters string, returns
69 * false, otherwise returns true
70 */
71int find_escape_character(char lookup);
72
73#endif /* TAG_TABLE_H */
diff --git a/utils/themeeditor/themeeditor.pro b/utils/themeeditor/themeeditor.pro
new file mode 100644
index 0000000000..14b001db12
--- /dev/null
+++ b/utils/themeeditor/themeeditor.pro
@@ -0,0 +1,10 @@
1HEADERS += tag_table.h \
2 symbols.h \
3 skin_parser.h \
4 skin_scan.h \
5 skin_debug.h
6SOURCES += tag_table.c \
7 main.c \
8 skin_parser.c \
9 skin_scan.c \
10 skin_debug.c