diff options
Diffstat (limited to 'utils/themeeditor/skin_parser.c')
-rw-r--r-- | utils/themeeditor/skin_parser.c | 811 |
1 files changed, 811 insertions, 0 deletions
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 | } | ||