diff options
author | Robert Bieber <robby@bieberphoto.com> | 2010-05-25 15:19:52 +0000 |
---|---|---|
committer | Robert Bieber <robby@bieberphoto.com> | 2010-05-25 15:19:52 +0000 |
commit | d5b24ddcc57857d9db5751c2f6e51f55633459e7 (patch) | |
tree | 1ee27a146004aed6788d38f688718783822cf1c1 /utils/themeeditor | |
parent | fd9d7d0ac103dc27ac4c79bcd715c2985b0bc559 (diff) | |
download | rockbox-d5b24ddcc57857d9db5751c2f6e51f55633459e7.tar.gz rockbox-d5b24ddcc57857d9db5751c2f6e51f55633459e7.zip |
Adding the new WPS parser, code works but need to build the tag table
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26281 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils/themeeditor')
-rw-r--r-- | utils/themeeditor/main.c | 17 | ||||
-rw-r--r-- | utils/themeeditor/skin_debug.c | 226 | ||||
-rw-r--r-- | utils/themeeditor/skin_debug.h | 37 | ||||
-rw-r--r-- | utils/themeeditor/skin_parser.c | 811 | ||||
-rw-r--r-- | utils/themeeditor/skin_parser.h | 124 | ||||
-rw-r--r-- | utils/themeeditor/skin_scan.c | 137 | ||||
-rw-r--r-- | utils/themeeditor/skin_scan.h | 32 | ||||
-rw-r--r-- | utils/themeeditor/symbols.h | 37 | ||||
-rw-r--r-- | utils/themeeditor/tag_table.c | 75 | ||||
-rw-r--r-- | utils/themeeditor/tag_table.h | 73 | ||||
-rw-r--r-- | utils/themeeditor/themeeditor.pro | 10 |
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 | |||
7 | int 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 */ | ||
30 | int debug_indent_level = 0; | ||
31 | extern int skin_line; | ||
32 | |||
33 | /* Debugging functions */ | ||
34 | void 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 | |||
81 | void 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 | |||
185 | void 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 | |||
221 | void 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 */ | ||
29 | void skin_error(enum skin_errorcode error); | ||
30 | void skin_debug_tree(struct skin_element* root); | ||
31 | |||
32 | /* Auxiliary debug functions */ | ||
33 | void skin_debug_params(int count, struct skin_tag_parameter params[]); | ||
34 | void 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 */ | ||
34 | char skin_parse_tree[SKIN_MAX_MEMORY]; | ||
35 | int skin_current_block = 0; | ||
36 | |||
37 | /* Global variables for the parser */ | ||
38 | int skin_line = 0; | ||
39 | |||
40 | /* Auxiliary parsing functions (not visible at global scope) */ | ||
41 | struct skin_element* skin_parse_line(char** document); | ||
42 | struct skin_element* skin_parse_line_optional(char** document, int conditional); | ||
43 | struct skin_element* skin_parse_sublines(char** document); | ||
44 | struct skin_element* skin_parse_sublines_optional(char** document, | ||
45 | int conditional); | ||
46 | |||
47 | int skin_parse_tag(struct skin_element* element, char** document); | ||
48 | int skin_parse_text(struct skin_element* element, char** document, | ||
49 | int conditional); | ||
50 | int skin_parse_conditional(struct skin_element* element, char** document); | ||
51 | int skin_parse_newline(struct skin_element* element, char** document); | ||
52 | int skin_parse_comment(struct skin_element* element, char** document); | ||
53 | struct skin_element* skin_parse_code_as_arg(char** document); | ||
54 | |||
55 | struct 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 | |||
135 | struct 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 | */ | ||
148 | struct 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 | |||
217 | struct skin_element* skin_parse_sublines(char** document) | ||
218 | { | ||
219 | return skin_parse_sublines_optional(document, 0); | ||
220 | } | ||
221 | |||
222 | struct 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 | |||
284 | int 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 | */ | ||
507 | int 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 | |||
559 | int 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 | |||
637 | int 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 | |||
662 | int 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 | |||
689 | struct 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 */ | ||
728 | struct 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 | |||
759 | struct 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 | |||
783 | char* 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 | |||
808 | struct 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 | *******************************************************************/ | ||
30 | extern char skin_parse_tree[]; | ||
31 | |||
32 | /******************************************************************** | ||
33 | ****** Data Structures ********************************************* | ||
34 | *******************************************************************/ | ||
35 | |||
36 | /* Possible types of element in a WPS file */ | ||
37 | enum skin_element_type | ||
38 | { | ||
39 | TEXT, | ||
40 | NEWLINE, | ||
41 | COMMENT, | ||
42 | TAG, | ||
43 | CONDITIONAL, | ||
44 | SUBLINES | ||
45 | }; | ||
46 | |||
47 | enum 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 */ | ||
64 | struct 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 */ | ||
84 | struct 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. */ | ||
116 | struct skin_element* skin_parse(char* document); | ||
117 | |||
118 | /* Memory management functions */ | ||
119 | struct skin_element* skin_alloc_element(); | ||
120 | struct skin_element** skin_alloc_children(int count); | ||
121 | struct skin_tag_parameter* skin_alloc_params(int count); | ||
122 | char* 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 */ | ||
34 | void skip_comment(char** document) | ||
35 | { | ||
36 | for(/*NO INIT*/;**document != '\n' && **document != '\0'; (*document)++); | ||
37 | if(**document == '\n') | ||
38 | (*document)++; | ||
39 | } | ||
40 | |||
41 | void skip_whitespace(char** document) | ||
42 | { | ||
43 | for(/*NO INIT*/; **document == ' ' || **document == '\t'; (*document)++); | ||
44 | } | ||
45 | |||
46 | char* 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 | |||
93 | int 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 */ | ||
26 | void skip_comment(char** document); | ||
27 | void skip_whitespace(char** document); | ||
28 | char* scan_string(char** document); | ||
29 | int 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 */ | ||
27 | struct 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 */ | ||
37 | char legal_escape_characters[] = "%(|);#,"; | ||
38 | |||
39 | /* | ||
40 | * Just does a straight search through the tag table to find one by | ||
41 | * the given name | ||
42 | */ | ||
43 | char* 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 */ | ||
65 | int 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 | */ | ||
52 | struct 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 | */ | ||
64 | char* 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 | */ | ||
71 | int 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 @@ | |||
1 | HEADERS += tag_table.h \ | ||
2 | symbols.h \ | ||
3 | skin_parser.h \ | ||
4 | skin_scan.h \ | ||
5 | skin_debug.h | ||
6 | SOURCES += tag_table.c \ | ||
7 | main.c \ | ||
8 | skin_parser.c \ | ||
9 | skin_scan.c \ | ||
10 | skin_debug.c | ||