summaryrefslogtreecommitdiff
path: root/lib/skin_parser/skin_parser.c
diff options
context:
space:
mode:
authorJonathan Gordon <rockbox@jdgordon.info>2010-07-29 12:37:48 +0000
committerJonathan Gordon <rockbox@jdgordon.info>2010-07-29 12:37:48 +0000
commit2d31d77a8ba231cb03ec35863c4c4ce2024f6509 (patch)
treeb85ca1bede3e83695619064ee9a323f0a8da1865 /lib/skin_parser/skin_parser.c
parente436483b66a931fef6436e9cd3e69eb2b3ff1f7b (diff)
downloadrockbox-2d31d77a8ba231cb03ec35863c4c4ce2024f6509.tar.gz
rockbox-2d31d77a8ba231cb03ec35863c4c4ce2024f6509.zip
FS#11470 - new skin code, finally svn uses the new parser from the theme editor. This means that a skin that passes the editor WILL pass svn and checkwps (unless the target runs out of skin buffer or something.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27613 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'lib/skin_parser/skin_parser.c')
-rw-r--r--lib/skin_parser/skin_parser.c169
1 files changed, 158 insertions, 11 deletions
diff --git a/lib/skin_parser/skin_parser.c b/lib/skin_parser/skin_parser.c
index 3e23067258..13c7b55e5e 100644
--- a/lib/skin_parser/skin_parser.c
+++ b/lib/skin_parser/skin_parser.c
@@ -21,6 +21,7 @@
21 21
22#include <stdlib.h> 22#include <stdlib.h>
23#include <stdio.h> 23#include <stdio.h>
24#include <stdbool.h>
24#include <string.h> 25#include <string.h>
25#include <ctype.h> 26#include <ctype.h>
26#include <stdbool.h> 27#include <stdbool.h>
@@ -37,6 +38,11 @@ int skin_line = 0;
37char* skin_start = 0; 38char* skin_start = 0;
38int viewport_line = 0; 39int viewport_line = 0;
39 40
41#ifdef ROCKBOX
42static skin_callback callback = NULL;
43static void* callback_data;
44#endif
45
40/* Auxiliary parsing functions (not visible at global scope) */ 46/* Auxiliary parsing functions (not visible at global scope) */
41static struct skin_element* skin_parse_viewport(char** document); 47static struct skin_element* skin_parse_viewport(char** document);
42static struct skin_element* skin_parse_line(char** document); 48static struct skin_element* skin_parse_line(char** document);
@@ -55,10 +61,23 @@ static int skin_parse_comment(struct skin_element* element, char** document);
55static struct skin_element* skin_parse_code_as_arg(char** document); 61static struct skin_element* skin_parse_code_as_arg(char** document);
56 62
57 63
64static void skip_whitespace(char** document)
65{
66 while(**document == ' ' || **document == '\t')
67 (*document)++;
68}
58 69
70#ifdef ROCKBOX
71struct skin_element* skin_parse(const char* document,
72 skin_callback cb, void* cb_data)
73
74{
75 callback = cb;
76 callback_data = cb_data;
77#else
59struct skin_element* skin_parse(const char* document) 78struct skin_element* skin_parse(const char* document)
60{ 79{
61 80#endif
62 struct skin_element* root = NULL; 81 struct skin_element* root = NULL;
63 struct skin_element* last = NULL; 82 struct skin_element* last = NULL;
64 83
@@ -94,7 +113,6 @@ struct skin_element* skin_parse(const char* document)
94 last = last->next; 113 last = last->next;
95 114
96 } 115 }
97
98 return root; 116 return root;
99 117
100} 118}
@@ -107,6 +125,8 @@ static struct skin_element* skin_parse_viewport(char** document)
107 struct skin_element* retval = NULL; 125 struct skin_element* retval = NULL;
108 126
109 retval = skin_alloc_element(); 127 retval = skin_alloc_element();
128 if (!retval)
129 return NULL;
110 retval->type = VIEWPORT; 130 retval->type = VIEWPORT;
111 retval->children_count = 1; 131 retval->children_count = 1;
112 retval->line = skin_line; 132 retval->line = skin_line;
@@ -129,11 +149,18 @@ static struct skin_element* skin_parse_viewport(char** document)
129 skin_line++; 149 skin_line++;
130 } 150 }
131 } 151 }
152#ifdef ROCKBOX
153 else if (callback)
154 {
155 if (callback(retval, callback_data) == CALLBACK_ERROR)
156 return NULL;
157 }
158#endif
132 159
133 retval->children_count = 1; 160 retval->children_count = 1;
134 retval->children = skin_alloc_children(1); 161 retval->children = skin_alloc_children(1);
135 162 if (!retval->children)
136 163 return NULL;
137 do 164 do
138 { 165 {
139 166
@@ -199,7 +226,6 @@ static struct skin_element* skin_parse_viewport(char** document)
199 return NULL; 226 return NULL;
200 227
201 } 228 }
202
203 /* Making sure last is at the end */ 229 /* Making sure last is at the end */
204 while(last->next) 230 while(last->next)
205 last = last->next; 231 last = last->next;
@@ -245,6 +271,8 @@ static struct skin_element* skin_parse_line_optional(char** document,
245 271
246 /* A wrapper for the line */ 272 /* A wrapper for the line */
247 retval = skin_alloc_element(); 273 retval = skin_alloc_element();
274 if (!retval)
275 return NULL;
248 retval->type = LINE; 276 retval->type = LINE;
249 retval->line = skin_line; 277 retval->line = skin_line;
250 if(*cursor != '\0' && *cursor != '\n' && *cursor != MULTILINESYM 278 if(*cursor != '\0' && *cursor != '\n' && *cursor != MULTILINESYM
@@ -261,7 +289,24 @@ static struct skin_element* skin_parse_line_optional(char** document,
261 } 289 }
262 290
263 if(retval->children_count > 0) 291 if(retval->children_count > 0)
292 {
264 retval->children = skin_alloc_children(1); 293 retval->children = skin_alloc_children(1);
294 if (!retval->children)
295 return NULL;
296 }
297
298#ifdef ROCKBOX
299 if (callback)
300 {
301 switch (callback(retval, callback_data))
302 {
303 case CALLBACK_ERROR:
304 return NULL;
305 default:
306 break;
307 }
308 }
309#endif
265 310
266 while(*cursor != '\n' && *cursor != '\0' && *cursor != MULTILINESYM 311 while(*cursor != '\n' && *cursor != '\0' && *cursor != MULTILINESYM
267 && !((*cursor == ARGLISTSEPERATESYM 312 && !((*cursor == ARGLISTSEPERATESYM
@@ -275,11 +320,15 @@ static struct skin_element* skin_parse_line_optional(char** document,
275 if(root) 320 if(root)
276 { 321 {
277 current->next = skin_alloc_element(); 322 current->next = skin_alloc_element();
323 if (!current->next)
324 return NULL;
278 current = current->next; 325 current = current->next;
279 } 326 }
280 else 327 else
281 { 328 {
282 current = skin_alloc_element(); 329 current = skin_alloc_element();
330 if (!current)
331 return NULL;
283 root = current; 332 root = current;
284 } 333 }
285 334
@@ -306,9 +355,10 @@ static struct skin_element* skin_parse_line_optional(char** document,
306 } 355 }
307 } 356 }
308 357
358
309 /* Moving up the calling function's pointer */ 359 /* Moving up the calling function's pointer */
310 *document = cursor; 360 *document = cursor;
311 361
312 if(root) 362 if(root)
313 retval->children[0] = root; 363 retval->children[0] = root;
314 return retval; 364 return retval;
@@ -328,6 +378,8 @@ static struct skin_element* skin_parse_sublines_optional(char** document,
328 int i; 378 int i;
329 379
330 retval = skin_alloc_element(); 380 retval = skin_alloc_element();
381 if (!retval)
382 return NULL;
331 retval->type = LINE_ALTERNATOR; 383 retval->type = LINE_ALTERNATOR;
332 retval->next = NULL; 384 retval->next = NULL;
333 retval->line = skin_line; 385 retval->line = skin_line;
@@ -374,6 +426,8 @@ static struct skin_element* skin_parse_sublines_optional(char** document,
374 /* ...and then we parse them */ 426 /* ...and then we parse them */
375 retval->children_count = sublines; 427 retval->children_count = sublines;
376 retval->children = skin_alloc_children(sublines); 428 retval->children = skin_alloc_children(sublines);
429 if (!retval->children)
430 return NULL;
377 431
378 cursor = *document; 432 cursor = *document;
379 for(i = 0; i < sublines; i++) 433 for(i = 0; i < sublines; i++)
@@ -392,6 +446,13 @@ static struct skin_element* skin_parse_sublines_optional(char** document,
392 } 446 }
393 } 447 }
394 448
449#ifdef ROCKBOX
450 if (callback)
451 {
452 if (callback(retval, callback_data) == CALLBACK_ERROR)
453 return NULL;
454 }
455#endif
395 *document = cursor; 456 *document = cursor;
396 457
397 return retval; 458 return retval;
@@ -458,6 +519,14 @@ static int skin_parse_tag(struct skin_element* element, char** document)
458 || (tag_args[0] == '|' && *cursor != ARGLISTOPENSYM) 519 || (tag_args[0] == '|' && *cursor != ARGLISTOPENSYM)
459 || (star && *cursor != ARGLISTOPENSYM)) 520 || (star && *cursor != ARGLISTOPENSYM))
460 { 521 {
522
523#ifdef ROCKBOX
524 if (callback)
525 {
526 if (callback(element, callback_data) == CALLBACK_ERROR)
527 return 0;
528 }
529#endif
461 *document = cursor; 530 *document = cursor;
462 return 1; 531 return 1;
463 } 532 }
@@ -507,6 +576,8 @@ static int skin_parse_tag(struct skin_element* element, char** document)
507 cursor = bookmark; /* Restoring the cursor */ 576 cursor = bookmark; /* Restoring the cursor */
508 element->params_count = num_args; 577 element->params_count = num_args;
509 element->params = skin_alloc_params(num_args); 578 element->params = skin_alloc_params(num_args);
579 if (!element->params)
580 return 0;
510 581
511 /* Now we have to actually parse each argument */ 582 /* Now we have to actually parse each argument */
512 for(i = 0; i < num_args; i++) 583 for(i = 0; i < num_args; i++)
@@ -587,7 +658,6 @@ static int skin_parse_tag(struct skin_element* element, char** document)
587 } 658 }
588 if (have_tenth == false) 659 if (have_tenth == false)
589 val *= 10; 660 val *= 10;
590
591 element->params[i].type = DECIMAL; 661 element->params[i].type = DECIMAL;
592 element->params[i].data.number = val; 662 element->params[i].data.number = val;
593 } 663 }
@@ -644,7 +714,13 @@ static int skin_parse_tag(struct skin_element* element, char** document)
644 skin_error(INSUFFICIENT_ARGS, cursor); 714 skin_error(INSUFFICIENT_ARGS, cursor);
645 return 0; 715 return 0;
646 } 716 }
647 717#ifdef ROCKBOX
718 if (callback)
719 {
720 if (callback(element, callback_data) == CALLBACK_ERROR)
721 return 0;
722 }
723#endif
648 *document = cursor; 724 *document = cursor;
649 725
650 return 1; 726 return 1;
@@ -691,6 +767,8 @@ static int skin_parse_text(struct skin_element* element, char** document,
691 element->line = skin_line; 767 element->line = skin_line;
692 element->next = NULL; 768 element->next = NULL;
693 element->data = text = skin_alloc_string(length); 769 element->data = text = skin_alloc_string(length);
770 if (!element->data)
771 return 0;
694 772
695 for(dest = 0; dest < length; dest++) 773 for(dest = 0; dest < length; dest++)
696 { 774 {
@@ -702,6 +780,14 @@ static int skin_parse_text(struct skin_element* element, char** document,
702 cursor++; 780 cursor++;
703 } 781 }
704 text[length] = '\0'; 782 text[length] = '\0';
783
784#ifdef ROCKBOX
785 if (callback)
786 {
787 if (callback(element, callback_data) == CALLBACK_ERROR)
788 return 0;
789 }
790#endif
705 791
706 *document = cursor; 792 *document = cursor;
707 793
@@ -715,14 +801,40 @@ static int skin_parse_conditional(struct skin_element* element, char** document)
715 char* bookmark; 801 char* bookmark;
716 int children = 1; 802 int children = 1;
717 int i; 803 int i;
804
805#ifdef ROCKBOX
806 bool feature_available = true;
807 char *false_branch = NULL;
808#endif
718 809
719 element->type = CONDITIONAL; 810 /* Some conditional tags allow for target feature checking,
811 * so to handle that call the callback as usual with type == TAG
812 * then call it a second time with type == CONDITIONAL and check the return
813 * value */
814 element->type = TAG;
720 element->line = skin_line; 815 element->line = skin_line;
721 816
722 /* Parsing the tag first */ 817 /* Parsing the tag first */
723 if(!skin_parse_tag(element, &cursor)) 818 if(!skin_parse_tag(element, &cursor))
724 return 0; 819 return 0;
725 820
821 element->type = CONDITIONAL;
822#ifdef ROCKBOX
823 if (callback)
824 {
825 switch (callback(element, callback_data))
826 {
827 case FEATURE_NOT_AVAILABLE:
828 feature_available = false;
829 break;
830 case CALLBACK_ERROR:
831 return 0;
832 default:
833 break;
834 }
835 }
836#endif
837
726 /* Counting the children */ 838 /* Counting the children */
727 if(*(cursor++) != ENUMLISTOPENSYM) 839 if(*(cursor++) != ENUMLISTOPENSYM)
728 { 840 {
@@ -751,16 +863,35 @@ static int skin_parse_conditional(struct skin_element* element, char** document)
751 { 863 {
752 children++; 864 children++;
753 cursor++; 865 cursor++;
866#ifdef ROCKBOX
867 if (false_branch == NULL && !feature_available)
868 {
869 false_branch = cursor;
870 children--;
871 }
872#endif
754 } 873 }
755 else 874 else
756 { 875 {
757 cursor++; 876 cursor++;
758 } 877 }
759 } 878 }
879#ifdef ROCKBOX
880 if (*cursor == ENUMLISTCLOSESYM &&
881 false_branch == NULL && !feature_available)
882 {
883 false_branch = cursor+1;
884 children--;
885 }
886 /* if we are skipping the true branch fix that up */
887 cursor = false_branch ? false_branch : bookmark;
888#else
760 cursor = bookmark; 889 cursor = bookmark;
761 890#endif
762 /* Parsing the children */ 891 /* Parsing the children */
763 element->children = skin_alloc_children(children); 892 element->children = skin_alloc_children(children);
893 if (!element->children)
894 return 0;
764 element->children_count = children; 895 element->children_count = children;
765 896
766 for(i = 0; i < children; i++) 897 for(i = 0; i < children; i++)
@@ -809,6 +940,8 @@ static int skin_parse_comment(struct skin_element* element, char** document)
809 element->data = NULL; 940 element->data = NULL;
810#else 941#else
811 element->data = text = skin_alloc_string(length); 942 element->data = text = skin_alloc_string(length);
943 if (!element->data)
944 return 0;
812 /* We copy from one char past cursor to leave out the # */ 945 /* We copy from one char past cursor to leave out the # */
813 memcpy((void*)text, (void*)(cursor + 1), 946 memcpy((void*)text, (void*)(cursor + 1),
814 sizeof(char) * (length-1)); 947 sizeof(char) * (length-1));
@@ -877,6 +1010,8 @@ struct skin_element* skin_alloc_element()
877{ 1010{
878 struct skin_element* retval = (struct skin_element*) 1011 struct skin_element* retval = (struct skin_element*)
879 skin_buffer_alloc(sizeof(struct skin_element)); 1012 skin_buffer_alloc(sizeof(struct skin_element));
1013 if (!retval)
1014 return NULL;
880 retval->type = UNKNOWN; 1015 retval->type = UNKNOWN;
881 retval->next = NULL; 1016 retval->next = NULL;
882 retval->tag = NULL; 1017 retval->tag = NULL;
@@ -886,9 +1021,21 @@ struct skin_element* skin_alloc_element()
886 return retval; 1021 return retval;
887 1022
888} 1023}
889 1024/* On a ROCKBOX build we try to save space as much as possible
1025 * so if we can, use a shared param pool which should be more then large
1026 * enough for any tag. params should be used straight away by the callback
1027 * so this is safe.
1028 */
890struct skin_tag_parameter* skin_alloc_params(int count) 1029struct skin_tag_parameter* skin_alloc_params(int count)
891{ 1030{
1031#ifdef ROCKBOX
1032 static struct skin_tag_parameter params[MAX_TAG_PARAMS];
1033 if (count <= MAX_TAG_PARAMS)
1034 {
1035 memset(params, 0, sizeof(params));
1036 return params;
1037 }
1038#endif
892 size_t size = sizeof(struct skin_tag_parameter) * count; 1039 size_t size = sizeof(struct skin_tag_parameter) * count;
893 return (struct skin_tag_parameter*)skin_buffer_alloc(size); 1040 return (struct skin_tag_parameter*)skin_buffer_alloc(size);
894 1041