summaryrefslogtreecommitdiffstats
path: root/utils/themeeditor
diff options
context:
space:
mode:
authorRobert Bieber <robby@bieberphoto.com>2010-05-25 15:19:52 +0000
committerRobert Bieber <robby@bieberphoto.com>2010-05-25 15:19:52 +0000
commitd5b24ddcc57857d9db5751c2f6e51f55633459e7 (patch)
tree1ee27a146004aed6788d38f688718783822cf1c1 /utils/themeeditor
parentfd9d7d0ac103dc27ac4c79bcd715c2985b0bc559 (diff)
downloadrockbox-d5b24ddcc57857d9db5751c2f6e51f55633459e7.tar.gz
rockbox-d5b24ddcc57857d9db5751c2f6e51f55633459e7.tar.bz2
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.c17
-rw-r--r--utils/themeeditor/skin_debug.c226
-rw-r--r--utils/themeeditor/skin_debug.h37
-rw-r--r--utils/themeeditor/skin_parser.c811
-rw-r--r--utils/themeeditor/skin_parser.h124
-rw-r--r--utils/themeeditor/skin_scan.c137
-rw-r--r--utils/themeeditor/skin_scan.h32
-rw-r--r--utils/themeeditor/symbols.h37
-rw-r--r--utils/themeeditor/tag_table.c75
-rw-r--r--utils/themeeditor/tag_table.h73
-rw-r--r--utils/themeeditor/themeeditor.pro10
11 files changed, 1579 insertions, 0 deletions
diff --git a/utils/themeeditor/main.c b/utils/themeeditor/main.c
new file mode 100644
index 0000000000..9f45c90317
--- /dev/null
+++ b/utils/themeeditor/main.c
@@ -0,0 +1,17 @@
+#include "skin_parser.h"
+#include "skin_debug.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc, char* argv[])
+{
+ char* doc = "This is a sample %V(1, 2, 3, 4, 5, six, seven)\n"
+ "WPS document, with ; sublines and a %?T(conditional| or| two)";
+
+ struct skin_element* test = skin_parse(doc);
+
+ skin_debug_tree(test);
+
+ return 0;
+}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "skin_parser.h"
+#include "skin_debug.h"
+
+/* Global variables for debug output */
+int debug_indent_level = 0;
+extern int skin_line;
+
+/* Debugging functions */
+void skin_error(enum skin_errorcode error)
+{
+
+ fprintf(stderr, "Error on line %d: ", skin_line);
+
+ switch(error)
+ {
+ case MEMORY_LIMIT_EXCEEDED:
+ fprintf(stderr, "Memory limit exceeded\n");
+ break;
+ case NEWLINE_EXPECTED:
+ fprintf(stderr, "Newline expected\n");
+ break;
+ case ILLEGAL_TAG:
+ fprintf(stderr, "Illegal tag\n");
+ break;
+ case ARGLIST_EXPECTED:
+ fprintf(stderr, "Argument list expected\n");
+ break;
+ case TOO_MANY_ARGS:
+ fprintf(stderr, "Too many arguments given\n");
+ break;
+ case DEFAULT_NOT_ALLOWED:
+ fprintf(stderr, "Argument can not be set to default\n");
+ break;
+ case UNEXPECTED_NEWLINE:
+ fprintf(stderr, "Unexpected newline\n");
+ break;
+ case INSUFFICIENT_ARGS:
+ fprintf(stderr, "Not enough arguments\n");
+ break;
+ case INT_EXPECTED:
+ fprintf(stderr, "Expected integer\n");
+ break;
+ case SEPERATOR_EXPECTED:
+ fprintf(stderr, "Expected argument seperator\n");
+ break;
+ case CLOSE_EXPECTED:
+ fprintf(stderr, "Expected list close\n");
+ break;
+ case MULTILINE_EXPECTED:
+ fprintf(stderr, "Expected subline seperator\n");
+ break;
+ };
+
+}
+
+void skin_debug_tree(struct skin_element* root)
+{
+ int i;
+
+ struct skin_element* current = root;
+
+ while(current)
+ {
+ skin_debug_indent();
+
+ switch(current->type)
+ {
+
+ case TEXT:
+ printf("[ Plain text on line %d : %s ]\n", current->line,
+ current->text);
+ break;
+
+ case NEWLINE:
+ printf("[ Newline on line %d ]\n", current->line);
+ break;
+
+ case COMMENT:
+ printf("[ Comment on line %d: ", current->line);
+ for(i = 0; i < (int)strlen(current->text); i++)
+ {
+ if(current->text[i] == '\n')
+ printf("\\n");
+ else
+ printf("%c", current->text[i]);
+ }
+ printf(" ]\n");
+ break;
+
+ case TAG:
+ printf("[ %s tag on line %d with %d arguments\n", current->name,
+ current->line, current->params_count);
+ debug_indent_level++;
+ skin_debug_params(current->params_count, current->params);
+ debug_indent_level--;
+ skin_debug_indent();
+ printf("]\n");
+
+ break;
+
+ case SUBLINES:
+ printf("[ Alternator on line %d with %d sublines \n", current->line,
+ current->children_count);
+ debug_indent_level++;
+ for(i = 0; i < current->children_count; i++)
+ {
+ skin_debug_indent();
+ printf("[ Subline %d\n", i);
+
+ debug_indent_level++;
+ skin_debug_tree(current->children[i]);
+ debug_indent_level--;
+
+ skin_debug_indent();
+ printf("]\n");
+ }
+ debug_indent_level--;
+ skin_debug_indent();
+ printf("]\n");
+ break;
+
+ case CONDITIONAL:
+ printf("[ Conditional tag on line %d with %d enumerations \n",
+ current->line, current->children_count - 1);
+ debug_indent_level++;
+
+ skin_debug_indent();
+ printf("[ Condition tag \n");
+ debug_indent_level++;
+ skin_debug_tree(current->children[0]);
+ debug_indent_level--;
+ skin_debug_indent();
+ printf("]\n");
+
+ for(i = 1; i < current->children_count; i++)
+ {
+ skin_debug_indent();
+ printf("[ Enumeration %d\n", i - 1);
+ debug_indent_level++;
+ skin_debug_tree(current->children[i]);
+ debug_indent_level--;
+ skin_debug_indent();
+ printf("]\n");
+ }
+
+ debug_indent_level--;
+ skin_debug_indent();
+ printf("]\n");
+
+
+ break;
+
+ }
+
+ current = current->next;
+ }
+
+}
+
+void skin_debug_params(int count, struct skin_tag_parameter params[])
+{
+ int i;
+ for(i = 0; i < count; i++)
+ {
+
+ skin_debug_indent();
+ switch(params[i].type)
+ {
+ case DEFAULT:
+ printf("[-]");
+ break;
+
+ case STRING:
+ printf("[%s]", params[i].data.text);
+ break;
+
+ case NUMERIC:
+ printf("[%d]", params[i].data.numeric);
+ break;
+
+ case CODE:
+ printf("[ WPS Code: \n");
+ debug_indent_level++;
+ skin_debug_tree(params[i].data.code);
+ debug_indent_level--;
+ skin_debug_indent();
+ printf("]");
+ break;
+ }
+
+ printf("\n");
+
+ }
+}
+
+void skin_debug_indent()
+{
+ int i;
+ for(i = 0; i < debug_indent_level; i++)
+ printf(" ");
+}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+
+#ifndef SKIN_DEBUG_H
+#define SKIN_DEBUG_H
+
+#include "skin_parser.h"
+
+/* Debugging functions */
+void skin_error(enum skin_errorcode error);
+void skin_debug_tree(struct skin_element* root);
+
+/* Auxiliary debug functions */
+void skin_debug_params(int count, struct skin_tag_parameter params[]);
+void skin_debug_indent();
+
+
+#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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "skin_parser.h"
+#include "skin_debug.h"
+#include "tag_table.h"
+#include "symbols.h"
+#include "skin_scan.h"
+
+/* Declaration of parse tree buffer */
+char skin_parse_tree[SKIN_MAX_MEMORY];
+int skin_current_block = 0;
+
+/* Global variables for the parser */
+int skin_line = 0;
+
+/* Auxiliary parsing functions (not visible at global scope) */
+struct skin_element* skin_parse_line(char** document);
+struct skin_element* skin_parse_line_optional(char** document, int conditional);
+struct skin_element* skin_parse_sublines(char** document);
+struct skin_element* skin_parse_sublines_optional(char** document,
+ int conditional);
+
+int skin_parse_tag(struct skin_element* element, char** document);
+int skin_parse_text(struct skin_element* element, char** document,
+ int conditional);
+int skin_parse_conditional(struct skin_element* element, char** document);
+int skin_parse_newline(struct skin_element* element, char** document);
+int skin_parse_comment(struct skin_element* element, char** document);
+struct skin_element* skin_parse_code_as_arg(char** document);
+
+struct skin_element* skin_parse(char* document)
+{
+
+ struct skin_element* root = NULL;
+ struct skin_element* last = NULL;
+
+ struct skin_element** to_write = 0;
+
+ char* cursor = document; /* Keeps track of location in the document */
+ char* bookmark; /* Used when we need to look ahead */
+
+ int sublines = 0; /* Flag for parsing sublines */
+
+ skin_line = 1;
+
+ while(*cursor != '\0')
+ {
+
+ /* First, we check to see if this line will contain sublines */
+ bookmark = cursor;
+ sublines = 0;
+ while(*cursor != '\n' && *cursor != '\0')
+ {
+ if(*cursor == MULTILINESYM)
+ {
+ sublines = 1;
+ break;
+ }
+ else if(*cursor == TAGSYM)
+ {
+ /* A ';' directly after a '%' doesn't count */
+ cursor ++;
+
+ if(*cursor == '\0')
+ break;
+
+ cursor++;
+ }
+ else
+ {
+ /* Advancing the cursor as normal */
+ cursor++;
+ }
+ }
+ cursor = bookmark;
+
+ if(!root)
+ to_write = &root;
+ else
+ to_write = &(last->next);
+
+ if(sublines)
+ {
+ *to_write = skin_parse_sublines(&cursor);
+ last = *to_write;
+ if(!last)
+ return NULL;
+ }
+ else
+ {
+
+ *to_write = skin_parse_line(&cursor);
+ last = *to_write;
+ if(!last)
+ return NULL;
+
+ }
+
+ /* Making sure last is at the end */
+ while(last->next)
+ last = last->next;
+
+ }
+
+ return root;
+
+}
+
+/* Auxiliary Parsing Functions */
+
+struct skin_element* skin_parse_line(char**document)
+{
+
+ return skin_parse_line_optional(document, 0);
+
+}
+
+
+/*
+ * If conditional is set to true, then this will break upon encountering
+ * SEPERATESYM. This should only be used when parsing a line inside a
+ * conditional, otherwise just use the wrapper function skin_parse_line()
+ */
+struct skin_element* skin_parse_line_optional(char** document, int conditional)
+{
+ char* cursor = *document;
+
+ struct skin_element* root = NULL;
+ struct skin_element* current = NULL;
+
+ while(*cursor != '\n' && *cursor != '\0' && *cursor != MULTILINESYM
+ && !((*cursor == ARGLISTSEPERATESYM || *cursor == ARGLISTCLOSESYM
+ || *cursor == ENUMLISTSEPERATESYM) && conditional))
+ {
+ /* Allocating memory if necessary */
+ if(root)
+ {
+ current->next = skin_alloc_element();
+ current = current->next;
+ }
+ else
+ {
+ current = skin_alloc_element();
+ root = current;
+ }
+
+ /* Parsing the current element */
+ if(*cursor == TAGSYM && cursor[1] == CONDITIONSYM)
+ {
+ if(!skin_parse_conditional(current, &cursor))
+ return NULL;
+ }
+ else if(*cursor == TAGSYM)
+ {
+ if(!skin_parse_tag(current, &cursor))
+ return NULL;
+ }
+ else if(*cursor == COMMENTSYM)
+ {
+ if(!skin_parse_comment(current, &cursor))
+ return NULL;
+ }
+ else
+ {
+ if(!skin_parse_text(current, &cursor, conditional))
+ return NULL;
+ }
+ }
+
+ if(*cursor == '\n')
+ {
+ /* Allocating memory if necessary */
+ if(root)
+ {
+ current->next = skin_alloc_element();
+ current = current->next;
+ }
+ else
+ {
+ current = skin_alloc_element();
+ root = current;
+ }
+ if(!skin_parse_newline(current, &cursor))
+ return NULL;
+ }
+
+ /* Moving up the calling function's pointer */
+ *document = cursor;
+
+ return root;
+}
+
+struct skin_element* skin_parse_sublines(char** document)
+{
+ return skin_parse_sublines_optional(document, 0);
+}
+
+struct skin_element* skin_parse_sublines_optional(char** document,
+ int conditional)
+{
+ struct skin_element* retval;
+ char* cursor = *document;
+ int sublines = 1;
+ int i;
+
+ retval = skin_alloc_element();
+ retval->type = SUBLINES;
+ retval->next = NULL;
+
+ /* First we count the sublines */
+ while(*cursor != '\0' && *cursor != '\n'
+ && !((*cursor == ARGLISTSEPERATESYM || *cursor == ARGLISTCLOSESYM
+ || *cursor == ENUMLISTSEPERATESYM) && conditional))
+ {
+ if(*cursor == COMMENTSYM)
+ skip_comment(&cursor);
+
+ /* Accounting for escaped subline symbols */
+ if(*cursor == TAGSYM)
+ {
+ cursor++;
+ if(*cursor == '\0' || *cursor == '\n')
+ break;
+ }
+
+ if(*cursor == MULTILINESYM)
+ {
+ sublines++;
+ }
+
+ cursor++;
+ }
+
+ /* ...and then we parse them */
+ retval->children_count = sublines;
+ retval->children = skin_alloc_children(sublines);
+
+ cursor = *document;
+ for(i = 0; i < sublines; i++)
+ {
+ retval->children[i] = skin_parse_line_optional(&cursor, conditional);
+ skip_whitespace(&cursor);
+
+ if(*cursor != MULTILINESYM && i != sublines - 1)
+ {
+ skin_error(MULTILINE_EXPECTED);
+ return NULL;
+ }
+ else
+ {
+ cursor++;
+ }
+ }
+
+ *document = cursor;
+
+ return retval;
+}
+
+int skin_parse_tag(struct skin_element* element, char** document)
+{
+
+ char* cursor = *document + 1;
+ char* bookmark;
+
+ char tag_name[3];
+ char* tag_args;
+
+ int num_args = 1;
+ int i;
+ int count;
+
+ int optional = 0;
+
+ /* Checking the tag name */
+ tag_name[0] = cursor[0];
+ tag_name[1] = cursor[1];
+ tag_name[2] = '\0';
+
+ /* First we check the two characters after the '%', then a single char */
+ tag_args = find_tag(tag_name);
+
+ if(!tag_args)
+ {
+ tag_name[1] = '\0';
+ tag_args = find_tag(tag_name);
+ cursor++;
+ }
+ else
+ {
+ cursor += 2;
+ }
+
+ if(!tag_args)
+ {
+ skin_error(ILLEGAL_TAG);
+ return 0;
+ }
+
+ /* Copying basic tag info */
+ element->type = TAG;
+ element->name = skin_alloc_string(strlen(tag_name));
+ strcpy(element->name, tag_name);
+ element->line = skin_line;
+
+ /* If this tag has no arguments, we can bail out now */
+ if(strlen(tag_args) == 0)
+ {
+ *document = cursor;
+ return 1;
+ }
+
+ /* Checking the number of arguments and allocating args */
+ if(*cursor != ARGLISTOPENSYM && tag_args[0] != '|')
+ {
+ skin_error(ARGLIST_EXPECTED);
+ return 0;
+ }
+ else
+ {
+ cursor++;
+ }
+
+ for(bookmark = cursor; *cursor != '\n' && *cursor != '\0' &&
+ *cursor != ARGLISTCLOSESYM; cursor++)
+ {
+ /* Skipping over escaped characters */
+ if(*cursor == TAGSYM)
+ {
+ cursor++;
+ if(*cursor == '\0')
+ break;
+ }
+
+ /* Skipping comments */
+ if(*cursor == COMMENTSYM)
+ skip_comment(&cursor);
+
+ /* Commas inside of contained lists don't count */
+ if(*cursor == ARGLISTOPENSYM)
+ while(*cursor != ARGLISTCLOSESYM && *cursor != '\0')
+ cursor++;
+
+ if(*cursor == ARGLISTSEPERATESYM)
+ num_args++;
+
+ }
+ cursor = bookmark; /* Restoring the cursor */
+ element->params_count = num_args;
+ element->params = skin_alloc_params(num_args);
+
+ /* Now we have to actually parse each argument */
+ i = 0;
+ while(i < num_args)
+ {
+ /* Making sure we haven't run out of arguments */
+ if(*tag_args == '\0')
+ {
+ skin_error(TOO_MANY_ARGS);
+ return 0;
+ }
+
+ /* Checking for the optional bar */
+ if(*tag_args == '|')
+ {
+ optional = 1;
+ tag_args++;
+ }
+
+ /* Checking for a repeated argument */
+ if(isdigit(*tag_args))
+ {
+ count = scan_int(&tag_args);
+ }
+ else
+ {
+ count = 1;
+ }
+
+ /* Scanning the arguments */
+ while(count > 0)
+ {
+
+ skip_whitespace(&cursor);
+
+ /* Checking for a premature end */
+ if(num_args - i < count)
+ {
+ if(optional && (num_args - i == 0))
+ {
+ break;
+ }
+ else
+ {
+ /*
+ We error out if there are too few arguments, or if there
+ is an optional argument that was supposed to be grouped
+ with another
+ */
+ skin_error(INSUFFICIENT_ARGS);
+ return 0;
+ }
+ }
+
+ /* Checking for comments */
+ if(*cursor == COMMENTSYM)
+ skip_comment(&cursor);
+
+ /* Checking a nullable argument for null */
+ if(*cursor == DEFAULTSYM)
+ {
+ if(islower(*tag_args))
+ {
+ element->params[i].type = DEFAULT;
+ cursor++;
+ }
+ else
+ {
+ skin_error(DEFAULT_NOT_ALLOWED);
+ return 0;
+ }
+ }
+ else if(tolower(*tag_args) == 'i')
+ {
+ /* Scanning an int argument */
+ if(!isdigit(*cursor))
+ {
+ skin_error(INT_EXPECTED);
+ return 0;
+ }
+
+ element->params[i].type = NUMERIC;
+ element->params[i].data.numeric = scan_int(&cursor);
+ }
+ else if(tolower(*tag_args) == 's' || tolower(*tag_args) == 'f')
+ {
+ /* Scanning a string argument */
+ element->params[i].type = STRING;
+ element->params[i].data.text = scan_string(&cursor);
+
+ }
+ else if(tolower(*tag_args) == 'c')
+ {
+ element->params[i].type = CODE;
+ element->params[i].data.code = skin_parse_code_as_arg(&cursor);
+ if(!element->params[i].data.code)
+ return 0;
+ }
+
+ i++;
+ count--;
+ skip_whitespace(&cursor);
+
+ if(*cursor != ARGLISTSEPERATESYM && i < num_args)
+ {
+ skin_error(SEPERATOR_EXPECTED);
+ return 0;
+ }
+ else if(*cursor != ARGLISTCLOSESYM && i == num_args)
+ {
+ skin_error(CLOSE_EXPECTED);
+ return 0;
+ }
+ else
+ {
+ cursor++;
+ }
+ }
+
+ tag_args++;
+
+ }
+
+ *document = cursor;
+
+ return 1;
+}
+
+/*
+ * If the conditional flag is set true, then parsing text will stop at an
+ * ARGLISTSEPERATESYM. Only set that flag when parsing within a conditional
+ */
+int skin_parse_text(struct skin_element* element, char** document,
+ int conditional)
+{
+ char* cursor = *document;
+
+ int length = 0;
+
+ int dest;
+
+ /* First figure out how much text we're copying */
+ while(*cursor != '\0' && *cursor != '\n' && *cursor != MULTILINESYM
+ && *cursor != COMMENTSYM
+ && !((*cursor == ARGLISTSEPERATESYM || *cursor == ARGLISTCLOSESYM
+ || *cursor == ENUMLISTSEPERATESYM) && conditional))
+ {
+ /* Dealing with possibility of escaped characters */
+ if(*cursor == TAGSYM)
+ {
+ if(find_escape_character(cursor[1]))
+ cursor++;
+ else
+ break;
+ }
+
+ length++;
+ cursor++;
+ }
+
+ cursor = *document;
+
+ /* Copying the text into the element struct */
+ element->type = TEXT;
+ element->line = skin_line;
+ element->next = NULL;
+ element->text = skin_alloc_string(length);
+
+ for(dest = 0; dest < length; dest++)
+ {
+ /* Advancing cursor if we've encountered an escaped character */
+ if(*cursor == TAGSYM)
+ cursor++;
+
+ element->text[dest] = *cursor;
+ cursor++;
+ }
+ element->text[length] = '\0';
+
+ *document = cursor;
+
+ return 1;
+}
+
+int skin_parse_conditional(struct skin_element* element, char** document)
+{
+
+ char* cursor = *document + 1; /* Starting past the "%" */
+ char* bookmark;
+ struct skin_element* tag = skin_alloc_element(); /* The tag to evaluate */
+ int children = 1;
+ int i;
+
+ element->type = CONDITIONAL;
+ element->line = skin_line;
+
+ /* Parsing the tag first */
+ if(!skin_parse_tag(tag, &cursor))
+ return 0;
+
+ /* Counting the children */
+ if(*(cursor++) != ARGLISTOPENSYM)
+ {
+ skin_error(ARGLIST_EXPECTED);
+ return 0;
+ }
+ bookmark = cursor;
+ while(*cursor != ARGLISTCLOSESYM && *cursor != '\n' && *cursor != '\0')
+ {
+ if(*cursor == COMMENTSYM)
+ {
+ skip_comment(&cursor);
+ continue;
+ }
+
+ if(*cursor == TAGSYM)
+ {
+ cursor++;
+ if(*cursor == '\0' || *cursor == '\n')
+ break;
+ cursor++;
+ continue;
+ }
+
+ if(*cursor == ENUMLISTSEPERATESYM)
+ children++;
+
+ cursor++;
+ }
+ cursor = bookmark;
+
+ /* Parsing the children */
+ element->children_count = children + 1; /* Make sure to include the tag */
+ element->children = skin_alloc_children(children + 1);
+ element->children[0] = tag;
+
+ for(i = 1; i < children + 1; i++)
+ {
+ element->children[i] = skin_parse_code_as_arg(&cursor);
+ skip_whitespace(&cursor);
+
+ if(i < children && *cursor != ENUMLISTSEPERATESYM)
+ {
+ skin_error(SEPERATOR_EXPECTED);
+ return 0;
+ }
+ else if(i == children && *cursor != ARGLISTCLOSESYM)
+ {
+ skin_error(CLOSE_EXPECTED);
+ return 0;
+ }
+ else
+ {
+ cursor++;
+ }
+ }
+
+ *document = cursor;
+
+ return 1;
+}
+
+int skin_parse_newline(struct skin_element* element, char** document)
+{
+
+ char* cursor = *document;
+ if(*cursor != '\n')
+ {
+ skin_error(NEWLINE_EXPECTED);
+ return 0;
+ }
+ cursor++;
+
+ /* Assembling a skin_element struct for a newline */
+ element->type = NEWLINE;
+ element->line = skin_line;
+ skin_line++;
+ element->text = skin_alloc_string(1);
+ element->text[0] = '\n';
+ element->text[1] = '\0';
+ element->next = NULL;
+
+ *document = cursor;
+
+ return 1;
+}
+
+int skin_parse_comment(struct skin_element* element, char** document)
+{
+ char* cursor = *document;
+
+ int length;
+ /*
+ * Finding the index of the ending newline or null-terminator
+ * The length of the string of interest doesn't include the leading #, the
+ * length we need to reserve is the same as the index of the last character
+ */
+ for(length = 0; cursor[length] != '\n' && cursor[length] != '\0'; length++);
+
+ element->type = COMMENT;
+ element->line = skin_line;
+ element->text = skin_alloc_string(length);
+ /* We copy from one char past cursor to leave out the # */
+ memcpy((void*)(element->text), (void*)(cursor + 1), sizeof(char) * length);
+ element->text[length] = '\0';
+
+ if(cursor[length] == '\n')
+ skin_line++;
+
+ *document += (length + 1); /* Move cursor up past # and all text */
+
+ return 1;
+}
+
+struct skin_element* skin_parse_code_as_arg(char** document)
+{
+
+ int sublines = 0;
+ char* cursor = *document;
+
+ /* Checking for sublines */
+ while(*cursor != '\n' && *cursor != '\0')
+ {
+ if(*cursor == MULTILINESYM)
+ {
+ sublines = 1;
+ break;
+ }
+ else if(*cursor == TAGSYM)
+ {
+ /* A ';' directly after a '%' doesn't count */
+ cursor ++;
+
+ if(*cursor == '\0')
+ break;
+
+ cursor++;
+ }
+ else
+ {
+ /* Advancing the cursor as normal */
+ cursor++;
+ }
+ }
+
+ if(sublines)
+ return skin_parse_sublines_optional(document, 1);
+ else
+ return skin_parse_line_optional(document, 1);
+}
+
+
+/* Memory management */
+struct skin_element* skin_alloc_element()
+{
+
+#if 0
+
+ char* retval = &skin_parse_tree[skin_current_block * 4];
+
+ int delta = sizeof(struct skin_element) / (sizeof(char) * 4);
+
+ /* If one block is partially filled, make sure to advance to the
+ * next one for the next allocation
+ */
+ if(sizeof(struct skin_element) % (sizeof(char) * 4) != 0)
+ delta++;
+
+ skin_current_block += delta;
+
+ return (struct skin_element*)retval;
+
+#endif
+
+ struct skin_element* retval = (struct skin_element*)
+ malloc(sizeof(struct skin_element));
+ retval->next = NULL;
+ retval->params_count = 0;
+ retval->children_count = 0;
+
+ return retval;
+
+}
+
+struct skin_tag_parameter* skin_alloc_params(int count)
+{
+#if 0
+
+ char* retval = &skin_parse_tree[skin_current_block * 4];
+
+ int delta = sizeof(struct skin_tag_parameter) / (sizeof(char) * 4);
+ delta *= count;
+
+ /* Correcting uneven alignment */
+ if(count * sizeof(struct skin_tag_parameter) % (sizeof(char) * 4) != 0)
+ delta++;
+
+ skin_current_block += delta;
+
+ return (struct skin_tag_parameter*) retval;
+
+#endif
+
+ return (struct skin_tag_parameter*)malloc(sizeof(struct skin_tag_parameter)
+ * count);
+
+}
+
+char* skin_alloc_string(int length)
+{
+
+#if 0
+ char* retval = &skin_parse_tree[skin_current_block * 4];
+
+ /* Checking alignment */
+ length++; /* Accounting for the null terminator */
+ int delta = length / 4;
+ if(length % 4 != 0)
+ delta++;
+
+ skin_current_block += delta;
+
+ if(skin_current_block >= SKIN_MAX_MEMORY / 4)
+ skin_error(MEMORY_LIMIT_EXCEEDED);
+
+ return retval;
+
+#endif
+
+ return (char*)malloc(sizeof(char) * (length + 1));
+
+}
+
+struct skin_element** skin_alloc_children(int count)
+{
+ return (struct skin_element**) malloc(sizeof(struct skin_element*) * count);
+}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef GENERIC_PARSER_H
+#define GENERIC_PARSER_H
+
+#define SKIN_MAX_MEMORY 1048576
+
+/********************************************************************
+ ****** A global buffer will be used to store the parse tree *******
+ *******************************************************************/
+extern char skin_parse_tree[];
+
+/********************************************************************
+ ****** Data Structures *********************************************
+ *******************************************************************/
+
+/* Possible types of element in a WPS file */
+enum skin_element_type
+{
+ TEXT,
+ NEWLINE,
+ COMMENT,
+ TAG,
+ CONDITIONAL,
+ SUBLINES
+};
+
+enum skin_errorcode
+{
+ MEMORY_LIMIT_EXCEEDED,
+ NEWLINE_EXPECTED,
+ ILLEGAL_TAG,
+ ARGLIST_EXPECTED,
+ TOO_MANY_ARGS,
+ DEFAULT_NOT_ALLOWED,
+ UNEXPECTED_NEWLINE,
+ INSUFFICIENT_ARGS,
+ INT_EXPECTED,
+ SEPERATOR_EXPECTED,
+ CLOSE_EXPECTED,
+ MULTILINE_EXPECTED
+};
+
+/* Holds a tag parameter, either numeric or text */
+struct skin_tag_parameter
+{
+ enum
+ {
+ NUMERIC,
+ STRING,
+ CODE,
+ DEFAULT
+ } type;
+
+ union
+ {
+ int numeric;
+ char* text;
+ struct skin_element* code;
+ } data;
+
+};
+
+/* Defines an element of a SKIN file */
+struct skin_element
+{
+ /* Defines what type of element it is */
+ enum skin_element_type type;
+
+ /* The line on which it's defined in the source file */
+ int line;
+
+ /* Text for comments and plaintext */
+ char* text;
+
+ /* The tag or conditional name */
+ char* name;
+
+ /* Pointer to and size of an array of parameters */
+ int params_count;
+ struct skin_tag_parameter* params;
+
+ /* Pointer to and size of an array of children */
+ int children_count;
+ struct skin_element** children;
+
+ /* Link to the next element */
+ struct skin_element* next;
+};
+
+/***********************************************************************
+ ***** Functions *******************************************************
+ **********************************************************************/
+
+/* Parses a WPS document and returns a list of skin_element
+ structures. */
+struct skin_element* skin_parse(char* document);
+
+/* Memory management functions */
+struct skin_element* skin_alloc_element();
+struct skin_element** skin_alloc_children(int count);
+struct skin_tag_parameter* skin_alloc_params(int count);
+char* skin_alloc_string(int length);
+
+#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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "skin_scan.h"
+#include "skin_debug.h"
+#include "symbols.h"
+#include "skin_parser.h"
+
+/* Scanning Functions */
+
+/* Simple function to advance a char* past a comment */
+void skip_comment(char** document)
+{
+ for(/*NO INIT*/;**document != '\n' && **document != '\0'; (*document)++);
+ if(**document == '\n')
+ (*document)++;
+}
+
+void skip_whitespace(char** document)
+{
+ for(/*NO INIT*/; **document == ' ' || **document == '\t'; (*document)++);
+}
+
+char* scan_string(char** document)
+{
+
+ char* cursor = *document;
+ int length = 0;
+ char* buffer = NULL;
+ int i;
+
+ while(*cursor != ARGLISTSEPERATESYM && *cursor != ARGLISTCLOSESYM &&
+ *cursor != '\0')
+ {
+ if(*cursor == COMMENTSYM)
+ {
+ skip_comment(&cursor);
+ continue;
+ }
+
+ if(*cursor == '\n')
+ {
+ skin_error(UNEXPECTED_NEWLINE);
+ return NULL;
+ }
+
+ length++;
+ cursor++;
+ }
+
+ /* Copying the string */
+ cursor = *document;
+ buffer = skin_alloc_string(length);
+ for(i = 0; i < length; i++)
+ {
+ if(*cursor == COMMENTSYM)
+ {
+ skip_comment(&cursor);
+ i--;
+ continue;
+ }
+
+ buffer[i] = *cursor;
+ cursor++;
+ }
+
+ *document = cursor;
+ return buffer;
+}
+
+int scan_int(char** document)
+{
+
+ char* cursor = *document;
+ int length = 0;
+ char* buffer = NULL;
+ int retval;
+ int i;
+
+ while(isdigit(*cursor) || *cursor == COMMENTSYM)
+ {
+ if(*cursor == COMMENTSYM)
+ {
+ skip_comment(&cursor);
+ continue;
+ }
+
+ length++;
+ cursor++;
+ }
+
+ buffer = skin_alloc_string(length);
+
+ /* Copying to the buffer while avoiding comments */
+ cursor = *document;
+ buffer[length] = '\0';
+ for(i = 0; i < length; i++)
+ {
+ if(*cursor == COMMENTSYM)
+ {
+ skip_comment(&cursor);
+ i--;
+ continue;
+ }
+
+ buffer[i] = *cursor;
+ cursor++;
+
+ }
+ retval = atoi(buffer);
+ free(buffer);
+
+ *document = cursor;
+ return retval;
+}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef SCANNING_H
+#define SCANNING_H
+
+/* Scanning functions */
+void skip_comment(char** document);
+void skip_whitespace(char** document);
+char* scan_string(char** document);
+int scan_int(char** document);
+
+
+#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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef SYMBOLS_H
+#define SYMBOLS_H
+
+/* Symbol definitions for WPS parsing */
+
+#define TAGSYM '%'
+#define COMMENTSYM '#'
+#define CONDITIONSYM '?'
+#define MULTILINESYM ';'
+#define ARGLISTOPENSYM '('
+#define ARGLISTCLOSESYM ')'
+#define ARGLISTSEPERATESYM ','
+#define ENUMLISTSEPERATESYM '|'
+#define DEFAULTSYM '-'
+
+#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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "tag_table.h"
+
+#include <string.h>
+
+/* The tag definition table */
+struct tag_info legal_tags[] =
+{
+ { "V" , "IIiii|2sc" },
+ { "Vi" , "SIIiii|2s" },
+ { "Vd" , "S" },
+ { "T" , "" },
+ { "" , ""} /* Keep this here to mark the end of the table */
+};
+
+/* A table of legal escapable characters */
+char legal_escape_characters[] = "%(|);#,";
+
+/*
+ * Just does a straight search through the tag table to find one by
+ * the given name
+ */
+char* find_tag(char* name)
+{
+
+ struct tag_info* current = legal_tags;
+
+ /*
+ * Continue searching so long as we have a non-empty name string
+ * and the name of the current element doesn't match the name
+ * we're searching for
+ */
+
+ while(strcmp(current->name, name) && current->name[0] != '\0')
+ current++;
+
+ if(current->name[0] == '\0')
+ return NULL;
+ else
+ return current->params;
+
+}
+
+/* Searches through the legal escape characters string */
+int find_escape_character(char lookup)
+{
+ char* current = legal_escape_characters;
+ while(*current != lookup && *current != '\0')
+ current++;
+
+ if(*current == lookup)
+ return 1;
+ else
+ return 0;
+}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef TAG_TABLE_H
+#define TAG_TABLE_H
+
+/*
+ * Struct for tag parsing information
+ * name - The name of the tag, i.e. V for %V
+ * params - A string specifying all of the tags parameters, each
+ * character representing a single parameter. Valid
+ * characters for parameters are:
+ * I - Required integer
+ * i - Nullable integer
+ * S - Required string
+ * s - Nullable string
+ * F - Required file name
+ * f - Nullable file name
+ * C - Required WPS code
+ * Any nullable parameter may be replaced in the WPS file
+ * with a '-'. To specify that parameters may be left off
+ * altogether, place a '|' in the parameter string. For
+ * instance, with the parameter string...
+ * Ii|Ss
+ * one integer must be specified, one integer can be
+ * specified or set to default with '-', and the user can
+ * stop providing parameters at any time after that.
+ * To specify multiple instances of the same type, put a
+ * number before the character. For instance, the string...
+ * 2s
+ * will specify two strings.
+ *
+ */
+struct tag_info
+{
+
+ char* name;
+ char* params;
+
+};
+
+/*
+ * Finds a tag by name and returns its parameter list, or an empty
+ * string if the tag is not found in the table
+ */
+char* find_tag(char* name);
+
+/*
+ * Determines whether a character is legal to escape or not. If
+ * lookup is not found in the legal escape characters string, returns
+ * false, otherwise returns true
+ */
+int find_escape_character(char lookup);
+
+#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 @@
+HEADERS += tag_table.h \
+ symbols.h \
+ skin_parser.h \
+ skin_scan.h \
+ skin_debug.h
+SOURCES += tag_table.c \
+ main.c \
+ skin_parser.c \
+ skin_scan.c \
+ skin_debug.c