summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJonathan Gordon <rockbox@jdgordon.info>2010-06-17 06:52:02 +0000
committerJonathan Gordon <rockbox@jdgordon.info>2010-06-17 06:52:02 +0000
commit36b934d241d2560be6693f90c9aba501a1ec0ae7 (patch)
tree39b57aa3bc373a967e4d1f7d29671226307294c8 /lib
parentca564287ee3f48945d45c7d92be7a83452f53745 (diff)
downloadrockbox-36b934d241d2560be6693f90c9aba501a1ec0ae7.tar.gz
rockbox-36b934d241d2560be6693f90c9aba501a1ec0ae7.tar.bz2
rockbox-36b934d241d2560be6693f90c9aba501a1ec0ae7.zip
Move the skin parser to a seperate library
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26877 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'lib')
-rw-r--r--lib/skin_parser/Makefile28
-rw-r--r--lib/skin_parser/skin_debug.c262
-rw-r--r--lib/skin_parser/skin_debug.h48
-rw-r--r--lib/skin_parser/skin_parser.c923
-rw-r--r--lib/skin_parser/skin_parser.h138
-rw-r--r--lib/skin_parser/skin_scan.c218
-rw-r--r--lib/skin_parser/skin_scan.h44
-rw-r--r--lib/skin_parser/symbols.h49
-rw-r--r--lib/skin_parser/tag_table.c256
-rw-r--r--lib/skin_parser/tag_table.h307
10 files changed, 2273 insertions, 0 deletions
diff --git a/lib/skin_parser/Makefile b/lib/skin_parser/Makefile
new file mode 100644
index 0000000000..5c1be67578
--- /dev/null
+++ b/lib/skin_parser/Makefile
@@ -0,0 +1,28 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+# $Id$
+#
+
+BUILDDIR ?= .
+
+SRC = skin_parser.c skin_debug.c skin_scan.c tag_table.c
+OBJ := $(patsubst %.c,$(BUILDDIR)/%.o,$(SRC))
+OUT = $(BUILDDIR)/libskin_parser.a
+CC = gcc
+AR = ar
+INCLUDES = -I.
+
+default: $(OUT)
+
+$(BUILDDIR)/%.o: %.c
+ $(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@
+
+$(OUT): $(OBJ)
+ $(AR) rcs $(OUT) $(OBJ)
+
+clean:
+ rm -f $(OBJ) $(OUT)
diff --git a/lib/skin_parser/skin_debug.c b/lib/skin_parser/skin_debug.c
new file mode 100644
index 0000000000..549f7b9e6c
--- /dev/null
+++ b/lib/skin_parser/skin_debug.c
@@ -0,0 +1,262 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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"
+#include "tag_table.h"
+
+/* Global variables for debug output */
+int debug_indent_level = 0;
+extern int skin_line;
+
+/* Global error variables */
+int error_line;
+char* error_message;
+
+/* Debugging functions */
+void skin_error(enum skin_errorcode error)
+{
+
+ error_line = skin_line;
+
+ switch(error)
+ {
+ case MEMORY_LIMIT_EXCEEDED:
+ error_message = "Memory limit exceeded";
+ break;
+ case NEWLINE_EXPECTED:
+ error_message = "Newline expected";
+ break;
+ case ILLEGAL_TAG:
+ error_message = "Illegal tag";
+ break;
+ case ARGLIST_EXPECTED:
+ error_message = "Argument list expected";
+ break;
+ case TOO_MANY_ARGS:
+ error_message = "Too many arguments given";
+ break;
+ case DEFAULT_NOT_ALLOWED:
+ error_message = "Argument can not be set to default";
+ break;
+ case UNEXPECTED_NEWLINE:
+ error_message = "Unexpected newline";
+ break;
+ case INSUFFICIENT_ARGS:
+ error_message = "Not enough arguments";
+ break;
+ case INT_EXPECTED:
+ error_message = "Expected integer";
+ break;
+ case SEPERATOR_EXPECTED:
+ error_message = "Expected argument seperator";
+ break;
+ case CLOSE_EXPECTED:
+ error_message = "Expected list close";
+ break;
+ case MULTILINE_EXPECTED:
+ error_message = "Expected subline seperator";
+ break;
+ };
+
+}
+
+int skin_error_line()
+{
+ return error_line;
+}
+
+char* skin_error_message()
+{
+ return error_message;
+}
+
+void skin_clear_errors()
+{
+ error_line = 0;
+ error_message = NULL;
+}
+
+void skin_debug_tree(struct skin_element* root)
+{
+ int i;
+ char *text;
+
+ struct skin_element* current = root;
+
+ while(current)
+ {
+ skin_debug_indent();
+
+ switch(current->type)
+ {
+ case UNKNOWN:
+ printf("[ Unknown element.. error\n]");
+ break;
+
+ case VIEWPORT:
+ printf("[ Viewport \n");
+
+ debug_indent_level++;
+ skin_debug_tree(current->children[0]);
+ debug_indent_level--;
+
+ printf("]");
+ break;
+
+ case TEXT:
+ text = current->data;
+ printf("[ Plain text on line %d : %s ]\n", current->line, text);
+ break;
+
+ case COMMENT:
+ text = current->data;
+ printf("[ Comment on line %d: ", current->line);
+ for(i = 0; i < (int)strlen(text); i++)
+ {
+ if(text[i] == '\n')
+ printf("\\n");
+ else
+ printf("%c", text[i]);
+ }
+ printf(" ]\n");
+ break;
+
+ case TAG:
+ printf("[ %s tag on line %d with %d arguments\n",
+ current->tag->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_tree(current->children[i]);
+ }
+ 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;
+
+ case LINE:
+ printf("[ Logical line on line %d\n", current->line);
+
+ debug_indent_level++;
+ skin_debug_tree(current->children[0]);
+ 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/lib/skin_parser/skin_debug.h b/lib/skin_parser/skin_debug.h
new file mode 100644
index 0000000000..a550dc4c7b
--- /dev/null
+++ b/lib/skin_parser/skin_debug.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "skin_parser.h"
+
+/* Debugging functions */
+void skin_error(enum skin_errorcode error);
+int skin_error_line();
+char* skin_error_message();
+void skin_clear_errors();
+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();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SKIN_DEBUG_H
diff --git a/lib/skin_parser/skin_parser.c b/lib/skin_parser/skin_parser.c
new file mode 100644
index 0000000000..93a71919bf
--- /dev/null
+++ b/lib/skin_parser/skin_parser.c
@@ -0,0 +1,923 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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"
+
+#ifdef ROCKBOX
+/* Declaration of parse tree buffer */
+#define SKIN_MAX_MEMORY (30*1024)
+static char skin_parse_tree[SKIN_MAX_MEMORY];
+static char *skin_buffer;
+#endif
+
+/* Global variables for the parser */
+int skin_line = 0;
+
+/* Auxiliary parsing functions (not visible at global scope) */
+static struct skin_element* skin_parse_viewport(char** document);
+static struct skin_element* skin_parse_line(char** document);
+static struct skin_element* skin_parse_line_optional(char** document,
+ int conditional);
+static struct skin_element* skin_parse_sublines(char** document);
+static struct skin_element* skin_parse_sublines_optional(char** document,
+ int conditional);
+
+static int skin_parse_tag(struct skin_element* element, char** document);
+static int skin_parse_text(struct skin_element* element, char** document,
+ int conditional);
+static int skin_parse_conditional(struct skin_element* element,
+ char** document);
+static int skin_parse_comment(struct skin_element* element, char** document);
+static struct skin_element* skin_parse_code_as_arg(char** document);
+
+struct skin_element* skin_parse(const char* document)
+{
+
+ struct skin_element* root = NULL;
+ struct skin_element* last = NULL;
+
+ struct skin_element** to_write = 0;
+
+ char* cursor = (char*)document; /*Keeps track of location in the document*/
+#ifdef ROCKBOX
+ /* FIXME */
+ skin_buffer = &skin_parse_tree[0];
+#endif
+
+ skin_line = 1;
+
+ skin_clear_errors();
+
+ while(*cursor != '\0')
+ {
+
+ if(!root)
+ to_write = &root;
+ else
+ to_write = &(last->next);
+
+
+ *to_write = skin_parse_viewport(&cursor);
+ last = *to_write;
+ if(!last)
+ {
+ skin_free_tree(root); /* Clearing any memory already used */
+ return NULL;
+ }
+
+ /* Making sure last is at the end */
+ while(last->next)
+ last = last->next;
+
+ }
+
+ return root;
+
+}
+
+static struct skin_element* skin_parse_viewport(char** document)
+{
+
+ struct skin_element* root = NULL;
+ struct skin_element* last = NULL;
+ struct skin_element* retval = NULL;
+
+ retval = skin_alloc_element();
+ retval->type = VIEWPORT;
+ retval->children_count = 1;
+ retval->line = skin_line;
+
+ 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 */
+
+ /* Parsing out the viewport tag if there is one */
+ if(check_viewport(cursor))
+ {
+ skin_parse_tag(retval, &cursor);
+ if(*cursor == '\n')
+ {
+ cursor++;
+ skin_line++;
+ }
+ }
+
+ retval->children_count = 1;
+ retval->children = skin_alloc_children(1);
+
+
+ do
+ {
+
+ /* First, we check to see if this line will contain sublines */
+ bookmark = cursor;
+ sublines = 0;
+ while(*cursor != '\n' && *cursor != '\0'
+ && !(check_viewport(cursor) && cursor != *document))
+ {
+ if(*cursor == MULTILINESYM)
+ {
+ sublines = 1;
+ break;
+ }
+ else if(*cursor == TAGSYM)
+ {
+ /* A ';' directly after a '%' doesn't count */
+ cursor ++;
+
+ if(*cursor == '\0')
+ break;
+
+ cursor++;
+ }
+ else if(*cursor == COMMENTSYM)
+ {
+ skip_comment(&cursor);
+ }
+ else if(*cursor == ARGLISTOPENSYM)
+ {
+ skip_arglist(&cursor);
+ }
+ else if(*cursor == ENUMLISTOPENSYM)
+ {
+ skip_enumlist(&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;
+
+ if(*cursor == '\n')
+ {
+ cursor++;
+ skin_line++;
+ }
+ }
+ while(*cursor != '\0' && !(check_viewport(cursor) && cursor != *document));
+
+ *document = cursor;
+
+ retval->children[0] = root;
+ return retval;
+
+}
+
+/* Auxiliary Parsing Functions */
+
+static 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()
+ */
+static struct skin_element* skin_parse_line_optional(char** document,
+ int conditional)
+{
+ char* cursor = *document;
+
+ struct skin_element* root = NULL;
+ struct skin_element* current = NULL;
+ struct skin_element* retval = NULL;
+
+ /* A wrapper for the line */
+ retval = skin_alloc_element();
+ retval->type = LINE;
+ retval->line = skin_line;
+ if(*cursor != '\0' && *cursor != '\n'
+ && !(conditional && (*cursor == ARGLISTSEPERATESYM
+ || *cursor == ARGLISTCLOSESYM
+ || *cursor == ENUMLISTSEPERATESYM
+ || *cursor == ENUMLISTCLOSESYM)))
+ {
+ retval->children_count = 1;
+ }
+ else
+ {
+ retval->children_count = 0;
+ }
+
+ if(retval->children_count > 0)
+ retval->children = skin_alloc_children(1);
+
+ while(*cursor != '\n' && *cursor != '\0' && *cursor != MULTILINESYM
+ && !((*cursor == ARGLISTSEPERATESYM
+ || *cursor == ARGLISTCLOSESYM
+ || *cursor == ENUMLISTSEPERATESYM
+ || *cursor == ENUMLISTCLOSESYM)
+ && conditional)
+ && !(check_viewport(cursor) && cursor != *document))
+ {
+ /* 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 && !find_escape_character(cursor[1]))
+ {
+ 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;
+ }
+ }
+
+ /* Moving up the calling function's pointer */
+ *document = cursor;
+
+ if(root)
+ retval->children[0] = root;
+ return retval;
+}
+
+static struct skin_element* skin_parse_sublines(char** document)
+{
+ return skin_parse_sublines_optional(document, 0);
+}
+
+static 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;
+ retval->line = skin_line;
+
+ /* First we count the sublines */
+ while(*cursor != '\0' && *cursor != '\n'
+ && !((*cursor == ARGLISTSEPERATESYM
+ || *cursor == ARGLISTCLOSESYM
+ || *cursor == ENUMLISTSEPERATESYM
+ || *cursor == ENUMLISTCLOSESYM)
+ && conditional)
+ && !(check_viewport(cursor) && cursor != *document))
+ {
+ if(*cursor == COMMENTSYM)
+ {
+ skip_comment(&cursor);
+ }
+ else if(*cursor == ENUMLISTOPENSYM)
+ {
+ skip_enumlist(&cursor);
+ }
+ else if(*cursor == ARGLISTOPENSYM)
+ {
+ skip_arglist(&cursor);
+ }
+ else if(*cursor == TAGSYM)
+ {
+ cursor++;
+ if(*cursor == '\0' || *cursor == '\n')
+ break;
+ cursor++;
+ }
+ else if(*cursor == MULTILINESYM)
+ {
+ sublines++;
+ cursor++;
+ }
+ else
+ {
+ 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 if(i != sublines - 1)
+ {
+ cursor++;
+ }
+ }
+
+ *document = cursor;
+
+ return retval;
+}
+
+static int skin_parse_tag(struct skin_element* element, char** document)
+{
+
+ char* cursor = *document + 1;
+ char* bookmark;
+
+ char tag_name[3];
+ char* tag_args;
+ struct tag_info *tag;
+
+ int num_args = 1;
+ int i;
+ int star = 0; /* Flag for the all-or-none option */
+ int req_args; /* To mark when we enter optional arguments */
+
+ 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 = find_tag(tag_name);
+
+ if(!tag)
+ {
+ tag_name[1] = '\0';
+ tag = find_tag(tag_name);
+ cursor++;
+ }
+ else
+ {
+ cursor += 2;
+ }
+
+ if(!tag)
+ {
+ skin_error(ILLEGAL_TAG);
+ return 0;
+ }
+
+ /* Copying basic tag info */
+ if(element->type != CONDITIONAL && element->type != VIEWPORT)
+ element->type = TAG;
+ element->tag = tag;
+ tag_args = tag->params;
+ element->line = skin_line;
+
+ /* Checking for the * flag */
+ if(tag_args[0] == '*')
+ {
+ star = 1;
+ tag_args++;
+ }
+
+ /* If this tag has no arguments, we can bail out now */
+ if(strlen(tag_args) == 0
+ || (tag_args[0] == '|' && *cursor != ARGLISTOPENSYM)
+ || (star && *cursor != ARGLISTOPENSYM))
+ {
+ *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++;
+ }
+
+ bookmark = cursor;
+ while(*cursor != '\n' && *cursor != '\0' && *cursor != ARGLISTCLOSESYM)
+ {
+ /* Skipping over escaped characters */
+ if(*cursor == TAGSYM)
+ {
+ cursor++;
+ if(*cursor == '\0')
+ break;
+ cursor++;
+ }
+ else if(*cursor == COMMENTSYM)
+ {
+ skip_comment(&cursor);
+ }
+ else if(*cursor == ARGLISTOPENSYM)
+ {
+ skip_arglist(&cursor);
+ }
+ else if(*cursor == ARGLISTSEPERATESYM)
+ {
+ num_args++;
+ cursor++;
+ }
+ else
+ {
+ cursor++;
+ }
+ }
+
+ 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 */
+ for(i = 0; i < num_args; i++)
+ {
+ /* 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;
+ req_args = i;
+ tag_args++;
+ }
+
+ /* Scanning the arguments */
+ skip_whitespace(&cursor);
+
+
+ /* Checking for comments */
+ if(*cursor == COMMENTSYM)
+ skip_comment(&cursor);
+
+ /* Storing the type code */
+ element->params[i].type_code = *tag_args;
+
+ /* Checking a nullable argument for null */
+ if(*cursor == DEFAULTSYM && !isdigit(cursor[1]))
+ {
+ 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) && *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) == 'n' ||
+ 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')
+ {
+ /* Recursively parsing a code argument */
+ element->params[i].type = CODE;
+ element->params[i].data.code = skin_parse_code_as_arg(&cursor);
+ if(!element->params[i].data.code)
+ return 0;
+ }
+
+ skip_whitespace(&cursor);
+
+ if(*cursor != ARGLISTSEPERATESYM && i < num_args - 1)
+ {
+ skin_error(SEPERATOR_EXPECTED);
+ return 0;
+ }
+ else if(*cursor != ARGLISTCLOSESYM && i == num_args - 1)
+ {
+ skin_error(CLOSE_EXPECTED);
+ return 0;
+ }
+ else
+ {
+ cursor++;
+ }
+
+ if (*tag_args != 'N')
+ tag_args++;
+
+ /* Checking for the optional bar */
+ if(*tag_args == '|')
+ {
+ optional = 1;
+ req_args = i + 1;
+ tag_args++;
+ }
+
+ }
+
+ /* Checking for a premature end */
+ if(*tag_args != '\0' && !optional)
+ {
+ skin_error(INSUFFICIENT_ARGS);
+ return 0;
+ }
+
+ *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
+ */
+static int skin_parse_text(struct skin_element* element, char** document,
+ int conditional)
+{
+ char* cursor = *document;
+ int length = 0;
+ int dest;
+ char *text = NULL;
+
+ /* First figure out how much text we're copying */
+ while(*cursor != '\0' && *cursor != '\n' && *cursor != MULTILINESYM
+ && *cursor != COMMENTSYM
+ && !((*cursor == ARGLISTSEPERATESYM
+ || *cursor == ARGLISTCLOSESYM
+ || *cursor == ENUMLISTSEPERATESYM
+ || *cursor == ENUMLISTCLOSESYM)
+ && 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->data = text = skin_alloc_string(length);
+
+ for(dest = 0; dest < length; dest++)
+ {
+ /* Advancing cursor if we've encountered an escaped character */
+ if(*cursor == TAGSYM)
+ cursor++;
+
+ text[dest] = *cursor;
+ cursor++;
+ }
+ text[length] = '\0';
+
+ *document = cursor;
+
+ return 1;
+}
+
+static int skin_parse_conditional(struct skin_element* element, char** document)
+{
+
+ char* cursor = *document + 1; /* Starting past the "%" */
+ char* bookmark;
+ int children = 1;
+ int i;
+
+ element->type = CONDITIONAL;
+ element->line = skin_line;
+
+ /* Parsing the tag first */
+ if(!skin_parse_tag(element, &cursor))
+ return 0;
+
+ /* Counting the children */
+ if(*(cursor++) != ENUMLISTOPENSYM)
+ {
+ skin_error(ARGLIST_EXPECTED);
+ return 0;
+ }
+ bookmark = cursor;
+ while(*cursor != ENUMLISTCLOSESYM && *cursor != '\n' && *cursor != '\0')
+ {
+ if(*cursor == COMMENTSYM)
+ {
+ skip_comment(&cursor);
+ }
+ else if(*cursor == ENUMLISTOPENSYM)
+ {
+ skip_enumlist(&cursor);
+ }
+ else if(*cursor == TAGSYM)
+ {
+ cursor++;
+ if(*cursor == '\0' || *cursor == '\n')
+ break;
+ cursor++;
+ }
+ else if(*cursor == ENUMLISTSEPERATESYM)
+ {
+ children++;
+ cursor++;
+ }
+ else
+ {
+ cursor++;
+ }
+ }
+ cursor = bookmark;
+
+ /* Parsing the children */
+ element->children = skin_alloc_children(children);
+ element->children_count = children;
+
+ for(i = 0; i < children; i++)
+ {
+ element->children[i] = skin_parse_code_as_arg(&cursor);
+ skip_whitespace(&cursor);
+
+ if(i < children - 1 && *cursor != ENUMLISTSEPERATESYM)
+ {
+ skin_error(SEPERATOR_EXPECTED);
+ return 0;
+ }
+ else if(i == children - 1 && *cursor != ENUMLISTCLOSESYM)
+ {
+ skin_error(CLOSE_EXPECTED);
+ return 0;
+ }
+ else
+ {
+ cursor++;
+ }
+ }
+
+ *document = cursor;
+
+ return 1;
+}
+
+static int skin_parse_comment(struct skin_element* element, char** document)
+{
+ char* cursor = *document;
+ char* text = NULL;
+
+ 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;
+#ifdef ROCKBOX
+ element->data = NULL;
+#else
+ element->data = text = skin_alloc_string(length);
+ /* We copy from one char past cursor to leave out the # */
+ memcpy((void*)text, (void*)(cursor + 1),
+ sizeof(char) * (length-1));
+ text[length - 1] = '\0';
+#endif
+ if(cursor[length] == '\n')
+ skin_line++;
+
+ *document += (length); /* Move cursor up past # and all text */
+ if(**document == '\n')
+ (*document)++;
+
+ return 1;
+}
+
+static struct skin_element* skin_parse_code_as_arg(char** document)
+{
+
+ int sublines = 0;
+ char* cursor = *document;
+
+ /* Checking for sublines */
+ while(*cursor != '\n' && *cursor != '\0'
+ && *cursor != ENUMLISTSEPERATESYM && *cursor != ARGLISTSEPERATESYM
+ && *cursor != ENUMLISTCLOSESYM && *cursor != ARGLISTCLOSESYM)
+ {
+ if(*cursor == MULTILINESYM)
+ {
+ sublines = 1;
+ break;
+ }
+ else if(*cursor == TAGSYM)
+ {
+ /* A ';' directly after a '%' doesn't count */
+ cursor ++;
+
+ if(*cursor == '\0')
+ break;
+
+ cursor++;
+ }
+ else if(*cursor == ARGLISTOPENSYM)
+ {
+ skip_arglist(&cursor);
+ }
+ else if(*cursor == ENUMLISTOPENSYM)
+ {
+ skip_enumlist(&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 */
+char* skin_alloc(size_t size)
+{
+#ifdef ROCKBOX
+ char *retval = skin_buffer;
+ skin_buffer = (void *)(((unsigned long)skin_buffer + 3) & ~3);
+ return retval;
+#else
+ return malloc(size);
+#endif
+}
+
+struct skin_element* skin_alloc_element()
+{
+ struct skin_element* retval = (struct skin_element*)
+ skin_alloc(sizeof(struct skin_element));
+ retval->type = UNKNOWN;
+ retval->next = NULL;
+ retval->tag = NULL;
+ retval->params_count = 0;
+ retval->children_count = 0;
+
+ return retval;
+
+}
+
+struct skin_tag_parameter* skin_alloc_params(int count)
+{
+ size_t size = sizeof(struct skin_tag_parameter) * count;
+ return (struct skin_tag_parameter*)skin_alloc(size);
+
+}
+
+char* skin_alloc_string(int length)
+{
+ return (char*)skin_alloc(sizeof(char) * (length + 1));
+}
+
+struct skin_element** skin_alloc_children(int count)
+{
+ return (struct skin_element**)
+ skin_alloc(sizeof(struct skin_element*) * count);
+}
+
+void skin_free_tree(struct skin_element* root)
+{
+#ifndef ROCKBOX
+ int i;
+
+ /* First make the recursive call */
+ if(!root)
+ return;
+ skin_free_tree(root->next);
+
+ /* Free any text */
+ if(root->type == TEXT || root->type == COMMENT)
+ free(root->data);
+
+ /* Then recursively free any children, before freeing their pointers */
+ for(i = 0; i < root->children_count; i++)
+ skin_free_tree(root->children[i]);
+ if(root->children_count > 0)
+ free(root->children);
+
+ /* Free any parameters, making sure to deallocate strings */
+ for(i = 0; i < root->params_count; i++)
+ if(root->params[i].type == STRING)
+ free(root->params[i].data.text);
+ if(root->params_count > 0)
+ free(root->params);
+
+ /* Finally, delete root's memory */
+ free(root);
+#else
+ (void)root;
+#endif
+}
diff --git a/lib/skin_parser/skin_parser.h b/lib/skin_parser/skin_parser.h
new file mode 100644
index 0000000000..1fc4a7ae6b
--- /dev/null
+++ b/lib/skin_parser/skin_parser.h
@@ -0,0 +1,138 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include <stdlib.h>
+
+/********************************************************************
+ ****** Data Structures *********************************************
+ *******************************************************************/
+
+/* Possible types of element in a WPS file */
+enum skin_element_type
+{
+ UNKNOWN = -1,
+ VIEWPORT,
+ LINE,
+ SUBLINES,
+ CONDITIONAL,
+ TAG,
+ TEXT,
+ COMMENT,
+};
+
+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;
+
+ char type_code;
+
+};
+
+/* 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;
+
+ /* Placeholder for element data
+ * TEXT and COMMENT uses it for the text string
+ * TAG, VIEWPORT, LINE, etc may use it for post parse extra storage
+ */
+ void* data;
+
+ /* The tag or conditional name */
+ struct tag_info *tag;
+
+ /* 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(const char* document);
+
+/* Memory management functions */
+char *skin_alloc(size_t size);
+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);
+
+void skin_free_tree(struct skin_element* root);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GENERIC_PARSER_H */
diff --git a/lib/skin_parser/skin_scan.c b/lib/skin_parser/skin_scan.c
new file mode 100644
index 0000000000..79f7162aab
--- /dev/null
+++ b/lib/skin_parser/skin_scan.c
@@ -0,0 +1,218 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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 <string.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)
+{
+ while(**document != '\n' && **document != '\0')
+ (*document)++;
+ if(**document == '\n')
+ (*document)++;
+}
+
+void skip_whitespace(char** document)
+{
+ while(**document == ' ' || **document == '\t')
+ (*document)++;
+}
+
+void skip_arglist(char** document)
+{
+ if(**document == ARGLISTOPENSYM)
+ (*document)++;
+ while(**document && **document != ARGLISTCLOSESYM)
+ {
+ if(**document == TAGSYM)
+ {
+ (*document)++;
+ if(**document == '\0')
+ break;
+ (*document)++;
+ }
+ else if(**document == ARGLISTOPENSYM)
+ skip_arglist(document);
+ else if(**document == ENUMLISTOPENSYM)
+ skip_enumlist(document);
+ else if(**document == COMMENTSYM)
+ skip_comment(document);
+ else
+ (*document)++;
+ }
+ if(**document == ARGLISTCLOSESYM)
+ (*document)++;
+}
+
+void skip_enumlist(char** document)
+{
+ if(**document == ENUMLISTOPENSYM)
+ (*document)++;
+ while(**document && **document != ENUMLISTCLOSESYM)
+ {
+ if(**document == TAGSYM)
+ {
+ (*document)++;
+ if(**document == '\0')
+ break;
+ (*document)++;
+ }
+ else if(**document == ARGLISTOPENSYM)
+ skip_arglist(document);
+ else if(**document == ENUMLISTOPENSYM)
+ skip_enumlist(document);
+ else if(**document == COMMENTSYM)
+ skip_comment(document);
+ else
+ (*document)++;
+ }
+
+ if(**document == ENUMLISTCLOSESYM)
+ (*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 == TAGSYM)
+ cursor++;
+
+ if(*cursor == '\n')
+ {
+ skin_error(UNEXPECTED_NEWLINE);
+ return NULL;
+ }
+
+ length++;
+ cursor++;
+ }
+
+ /* Copying the string */
+ cursor = *document;
+ buffer = skin_alloc_string(length);
+ buffer[length] = '\0';
+ for(i = 0; i < length; i++)
+ {
+ if(*cursor == TAGSYM)
+ cursor++;
+
+ if(*cursor == COMMENTSYM)
+ {
+ skip_comment(&cursor);
+ i--;
+ continue;
+ }
+
+ buffer[i] = *cursor;
+ cursor++;
+ }
+
+ *document = cursor;
+ return buffer;
+}
+
+int scan_int(char** document)
+{
+
+ char* cursor = *document, *end;
+ int length = 0;
+ char buffer[16];
+ int retval;
+ int i;
+
+ while(isdigit(*cursor) || *cursor == COMMENTSYM || *cursor == '-')
+ {
+ if(*cursor == COMMENTSYM)
+ {
+ skip_comment(&cursor);
+ continue;
+ }
+
+ length++;
+ cursor++;
+ }
+ if (length > 15)
+ length = 15;
+ end = cursor;
+ /* 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);
+
+ *document = end;
+ return retval;
+}
+
+int check_viewport(char* document)
+{
+ if(strlen(document) < 3)
+ return 0;
+
+ if(document[0] != TAGSYM)
+ return 0;
+
+ if(document[1] != 'V')
+ return 0;
+
+ if(document[2] != ARGLISTOPENSYM
+ && document[2] != 'l'
+ && document[2] != 'i')
+ return 0;
+
+ return 1;
+}
diff --git a/lib/skin_parser/skin_scan.h b/lib/skin_parser/skin_scan.h
new file mode 100644
index 0000000000..b1d04a6e34
--- /dev/null
+++ b/lib/skin_parser/skin_scan.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/* Scanning functions */
+void skip_comment(char** document);
+void skip_whitespace(char** document);
+void skip_arglist(char** document);
+void skip_enumlist(char** document);
+char* scan_string(char** document);
+int scan_int(char** document);
+int check_viewport(char* document); /* Checks for a viewport declaration */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SCANNING_H
diff --git a/lib/skin_parser/symbols.h b/lib/skin_parser/symbols.h
new file mode 100644
index 0000000000..b4f31289ef
--- /dev/null
+++ b/lib/skin_parser/symbols.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/* Symbol definitions for WPS parsing */
+
+#define TAGSYM '%'
+#define COMMENTSYM '#'
+#define CONDITIONSYM '?'
+#define MULTILINESYM ';'
+#define ARGLISTOPENSYM '('
+#define ARGLISTCLOSESYM ')'
+#define ARGLISTSEPERATESYM ','
+#define ENUMLISTSEPERATESYM '|'
+#define ENUMLISTOPENSYM '<'
+#define ENUMLISTCLOSESYM '>'
+#define DEFAULTSYM '-'
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SYMBOLS_H */
diff --git a/lib/skin_parser/tag_table.c b/lib/skin_parser/tag_table.c
new file mode 100644
index 0000000000..6d82b47cc3
--- /dev/null
+++ b/lib/skin_parser/tag_table.c
@@ -0,0 +1,256 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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>
+#define BAR_PARAMS "*|iiiiN"
+/* The tag definition table */
+struct tag_info legal_tags[] =
+{
+ { SKIN_TOKEN_ALIGN_CENTER, "ac", "" },
+ { SKIN_TOKEN_ALIGN_LEFT, "al", "" },
+ { SKIN_TOKEN_ALIGN_LEFT_RTL, "aL", "" },
+ { SKIN_TOKEN_ALIGN_RIGHT, "ar", "" },
+ { SKIN_TOKEN_ALIGN_RIGHT_RTL, "aR", "" },
+ { SKIN_TOKEN_ALIGN_LANGDIRECTION, "ax", "" },
+
+ { SKIN_TOKEN_BATTERY_PERCENT, "bl" , BAR_PARAMS },
+ { SKIN_TOKEN_BATTERY_VOLTS, "bv", "" },
+ { SKIN_TOKEN_BATTERY_TIME, "bt", "" },
+ { SKIN_TOKEN_BATTERY_SLEEPTIME, "bs", "" },
+ { SKIN_TOKEN_BATTERY_CHARGING, "bc", "" },
+ { SKIN_TOKEN_BATTERY_CHARGER_CONNECTED, "bp", "" },
+ { SKIN_TOKEN_USB_POWERED, "bu", "" },
+
+
+ { SKIN_TOKEN_RTC_PRESENT, "cc", "" },
+ { SKIN_TOKEN_RTC_DAY_OF_MONTH, "cd", "" },
+ { SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED, "ce", "" },
+ { SKIN_TOKEN_RTC_12HOUR_CFG, "cf", "" },
+ { SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", "" },
+ { SKIN_TOKEN_RTC_HOUR_24, "ck", "" },
+ { SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", "" },
+ { SKIN_TOKEN_RTC_HOUR_12, "cl", "" },
+ { SKIN_TOKEN_RTC_MONTH, "cm", "" },
+ { SKIN_TOKEN_RTC_MINUTE, "cM", "" },
+ { SKIN_TOKEN_RTC_SECOND, "cS", "" },
+ { SKIN_TOKEN_RTC_YEAR_2_DIGITS, "cy", "" },
+ { SKIN_TOKEN_RTC_YEAR_4_DIGITS, "cY", "" },
+ { SKIN_TOKEN_RTC_AM_PM_UPPER, "cP", "" },
+ { SKIN_TOKEN_RTC_AM_PM_LOWER, "cp", "" },
+ { SKIN_TOKEN_RTC_WEEKDAY_NAME, "ca", "" },
+ { SKIN_TOKEN_RTC_MONTH_NAME, "cb", "" },
+ { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", "" },
+ { SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", "" },
+
+ { SKIN_TOKEN_FILE_BITRATE, "fb", "" },
+ { SKIN_TOKEN_FILE_CODEC, "fc", "" },
+ { SKIN_TOKEN_FILE_FREQUENCY, "ff", "" },
+ { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "fk", "" },
+ { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", "" },
+ { SKIN_TOKEN_FILE_NAME, "fn", "" },
+ { SKIN_TOKEN_FILE_PATH, "fp", "" },
+ { SKIN_TOKEN_FILE_SIZE, "fs", "" },
+ { SKIN_TOKEN_FILE_VBR, "fv", "" },
+ { SKIN_TOKEN_FILE_DIRECTORY, "d" , "I" },
+
+ { SKIN_TOKEN_FILE_BITRATE, "Fb", "" },
+ { SKIN_TOKEN_FILE_CODEC, "Fc", "" },
+ { SKIN_TOKEN_FILE_FREQUENCY, "Ff", "" },
+ { SKIN_TOKEN_FILE_FREQUENCY_KHZ, "Fk", "" },
+ { SKIN_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", "" },
+ { SKIN_TOKEN_FILE_NAME, "Fn", "" },
+ { SKIN_TOKEN_FILE_PATH, "Fp", "" },
+ { SKIN_TOKEN_FILE_SIZE, "Fs", "" },
+ { SKIN_TOKEN_FILE_VBR, "Fv", "" },
+ { SKIN_TOKEN_FILE_DIRECTORY, "D" , "I" },
+
+
+ { SKIN_TOKEN_METADATA_ARTIST, "ia", "" },
+ { SKIN_TOKEN_METADATA_COMPOSER, "ic", "" },
+ { SKIN_TOKEN_METADATA_ALBUM, "id", "" },
+ { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "iA", "" },
+ { SKIN_TOKEN_METADATA_GROUPING, "iG", "" },
+ { SKIN_TOKEN_METADATA_GENRE, "ig", "" },
+ { SKIN_TOKEN_METADATA_DISC_NUMBER, "ik", "" },
+ { SKIN_TOKEN_METADATA_TRACK_NUMBER, "in", "" },
+ { SKIN_TOKEN_METADATA_TRACK_TITLE, "it", "" },
+ { SKIN_TOKEN_METADATA_VERSION, "iv", "" },
+ { SKIN_TOKEN_METADATA_YEAR, "iy", "" },
+ { SKIN_TOKEN_METADATA_COMMENT, "iC", "" },
+
+ { SKIN_TOKEN_METADATA_ARTIST, "Ia", "" },
+ { SKIN_TOKEN_METADATA_COMPOSER, "Ic", "" },
+ { SKIN_TOKEN_METADATA_ALBUM, "Id", "" },
+ { SKIN_TOKEN_METADATA_ALBUM_ARTIST, "IA", "" },
+ { SKIN_TOKEN_METADATA_GROUPING, "IG", "" },
+ { SKIN_TOKEN_METADATA_GENRE, "Ig", "" },
+ { SKIN_TOKEN_METADATA_DISC_NUMBER, "Ik", "" },
+ { SKIN_TOKEN_METADATA_TRACK_NUMBER, "In", "" },
+ { SKIN_TOKEN_METADATA_TRACK_TITLE, "It", "" },
+ { SKIN_TOKEN_METADATA_VERSION, "Iv", "" },
+ { SKIN_TOKEN_METADATA_YEAR, "Iy", "" },
+ { SKIN_TOKEN_METADATA_COMMENT, "IC", "" },
+
+ { SKIN_TOKEN_SOUND_PITCH, "Sp", "" },
+ { SKIN_TOKEN_SOUND_SPEED, "Ss", "" },
+
+ { SKIN_TOKEN_VLED_HDD, "lh", "" },
+
+ { SKIN_TOKEN_MAIN_HOLD, "mh", "" },
+ { SKIN_TOKEN_REMOTE_HOLD, "mr", "" },
+ { SKIN_TOKEN_REPEAT_MODE, "mm", "" },
+ { SKIN_TOKEN_PLAYBACK_STATUS, "mp", "" },
+ { SKIN_TOKEN_BUTTON_VOLUME, "mv", "|S" },
+
+ { SKIN_TOKEN_PEAKMETER, "pm", "" },
+ { SKIN_TOKEN_PLAYER_PROGRESSBAR, "pf", "" },
+ { SKIN_TOKEN_PROGRESSBAR, "pb" , BAR_PARAMS },
+ { SKIN_TOKEN_VOLUME, "pv" , BAR_PARAMS },
+
+ { SKIN_TOKEN_TRACK_ELAPSED_PERCENT, "px", "" },
+ { SKIN_TOKEN_TRACK_TIME_ELAPSED, "pc", "" },
+ { SKIN_TOKEN_TRACK_TIME_REMAINING, "pr", "" },
+ { SKIN_TOKEN_TRACK_LENGTH, "pt", "" },
+ { SKIN_TOKEN_TRACK_STARTING, "pS" , "|S"},
+ { SKIN_TOKEN_TRACK_ENDING, "pE" , "|S"},
+ { SKIN_TOKEN_PLAYLIST_POSITION, "pp", "" },
+ { SKIN_TOKEN_PLAYLIST_ENTRIES, "pe", "" },
+ { SKIN_TOKEN_PLAYLIST_NAME, "pn", "" },
+ { SKIN_TOKEN_PLAYLIST_SHUFFLE, "ps", "" },
+
+ { SKIN_TOKEN_DATABASE_PLAYCOUNT, "rp", "" },
+ { SKIN_TOKEN_DATABASE_RATING, "rr", "" },
+ { SKIN_TOKEN_DATABASE_AUTOSCORE, "ra", "" },
+
+ { SKIN_TOKEN_REPLAYGAIN, "rg", "" },
+ { SKIN_TOKEN_CROSSFADE, "xf", "" },
+
+ { SKIN_TOKEN_HAVE_TUNER, "tp", "" },
+ { SKIN_TOKEN_TUNER_TUNED, "tt", "" },
+ { SKIN_TOKEN_TUNER_SCANMODE, "tm", "" },
+ { SKIN_TOKEN_TUNER_STEREO, "ts", "" },
+ { SKIN_TOKEN_TUNER_MINFREQ, "ta", "" },
+ { SKIN_TOKEN_TUNER_MAXFREQ, "tb", "" },
+ { SKIN_TOKEN_TUNER_CURFREQ, "tf", "" },
+ { SKIN_TOKEN_PRESET_ID, "Ti", "" },
+ { SKIN_TOKEN_PRESET_NAME, "Tn", "" },
+ { SKIN_TOKEN_PRESET_FREQ, "Tf", "" },
+ { SKIN_TOKEN_PRESET_COUNT, "Tc", "" },
+ { SKIN_TOKEN_HAVE_RDS, "tx", "" },
+ { SKIN_TOKEN_RDS_NAME, "ty", "" },
+ { SKIN_TOKEN_RDS_TEXT, "tz", "" },
+
+ { SKIN_TOKEN_SUBLINE_SCROLL, "s", "" },
+ { SKIN_TOKEN_SUBLINE_TIMEOUT, "t" , "S" },
+
+ { SKIN_TOKEN_ENABLE_THEME, "we", "" },
+ { SKIN_TOKEN_DISABLE_THEME, "wd", "" },
+ { SKIN_TOKEN_DRAW_INBUILTBAR, "wi", "" },
+
+ { SKIN_TOKEN_IMAGE_PRELOAD, "xl", "SFII|I" },
+ { SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", "S" },
+ { SKIN_TOKEN_IMAGE_PRELOAD, "x", "SFII" },
+
+ { SKIN_TOKEN_LOAD_FONT, "Fl" , "IF"},
+ { SKIN_TOKEN_ALBUMART_LOAD, "Cl" , "IIII|ss"},
+ { SKIN_TOKEN_ALBUMART_DISPLAY, "Cd" , ""},
+ { SKIN_TOKEN_ALBUMART_FOUND, "C" , ""},
+
+ { SKIN_TOKEN_VIEWPORT_ENABLE, "Vd" , "S"},
+ { SKIN_TOKEN_UIVIEWPORT_ENABLE, "VI" , "S"},
+
+ { SKIN_TOKEN_VIEWPORT_CUSTOMLIST, "Vp" , "ICC"},
+ { SKIN_TOKEN_LIST_TITLE_TEXT, "Lt" , ""},
+ { SKIN_TOKEN_LIST_TITLE_ICON, "Li" , ""},
+
+ { SKIN_TOKEN_VIEWPORT_FGCOLOUR, "Vf" , "S"},
+ { SKIN_TOKEN_VIEWPORT_BGCOLOUR, "Vb" , "S"},
+
+ { SKIN_TOKEN_VIEWPORT_CONDITIONAL, "Vl" , "SIIiii|ii"},
+ { SKIN_TOKEN_UIVIEWPORT_LOAD, "Vi" , "sIIiii|ii"},
+ { SKIN_TOKEN_VIEWPORT_LOAD, "V" , "IIiii|ii"},
+
+ { SKIN_TOKEN_IMAGE_BACKDROP, "X" , "f"},
+
+ { SKIN_TOKEN_SETTING, "St" , "S"},
+ { SKIN_TOKEN_TRANSLATEDSTRING, "Sx" , "S"},
+ { SKIN_TOKEN_LANG_IS_RTL, "Sr" , ""},
+
+ { SKIN_TOKEN_LASTTOUCH, "Tl" , "|S"},
+ { SKIN_TOKEN_CURRENT_SCREEN, "cs", "" },
+ { SKIN_TOKEN_TOUCHREGION, "T" , "IIiiS"},
+
+ { SKIN_TOKEN_HAVE_RECORDING, "Rp" , ""},
+ { SKIN_TOKEN_IS_RECORDING, "Rr" , ""},
+ { SKIN_TOKEN_REC_FREQ, "Rf" , ""},
+ { SKIN_TOKEN_REC_ENCODER, "Re" , ""},
+ { SKIN_TOKEN_REC_BITRATE, "Rb" , ""},
+ { SKIN_TOKEN_REC_MONO, "Rm" , ""},
+ { SKIN_TOKEN_REC_SECONDS, "Rs" , ""},
+ { SKIN_TOKEN_REC_MINUTES, "Rn" , ""},
+ { SKIN_TOKEN_REC_HOURS, "Rh" , ""},
+
+ { SKIN_TOKEN_UNKNOWN, "" , ""}
+ /* 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
+ */
+struct tag_info* 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;
+
+}
+
+/* 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 && *current)
+ return 1;
+ else
+ return 0;
+}
diff --git a/lib/skin_parser/tag_table.h b/lib/skin_parser/tag_table.h
new file mode 100644
index 0000000000..ec9a1021ab
--- /dev/null
+++ b/lib/skin_parser/tag_table.h
@@ -0,0 +1,307 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+enum skin_token_type {
+
+ TOKEN_MARKER_CONTROL_TOKENS = -1,
+ SKIN_TOKEN_UNKNOWN,
+
+ /* Markers */
+ SKIN_TOKEN_CHARACTER,
+ SKIN_TOKEN_STRING,
+ SKIN_TOKEN_TRANSLATEDSTRING,
+
+ /* Alignment */
+ SKIN_TOKEN_ALIGN_LEFT,
+ SKIN_TOKEN_ALIGN_LEFT_RTL,
+ SKIN_TOKEN_ALIGN_CENTER,
+ SKIN_TOKEN_ALIGN_RIGHT,
+ SKIN_TOKEN_ALIGN_RIGHT_RTL,
+ SKIN_TOKEN_ALIGN_LANGDIRECTION,
+
+
+ /* Sublines */
+ SKIN_TOKEN_SUBLINE_TIMEOUT,
+ SKIN_TOKEN_SUBLINE_SCROLL,
+
+ /* Conditional */
+ SKIN_TOKEN_CONDITIONAL,
+ SKIN_TOKEN_CONDITIONAL_START,
+ SKIN_TOKEN_CONDITIONAL_OPTION,
+ SKIN_TOKEN_CONDITIONAL_END,
+
+ /* Viewport display */
+ SKIN_TOKEN_VIEWPORT_LOAD,
+ SKIN_TOKEN_VIEWPORT_CONDITIONAL,
+ SKIN_TOKEN_VIEWPORT_ENABLE,
+ SKIN_TOKEN_VIEWPORT_CUSTOMLIST,
+ SKIN_TOKEN_UIVIEWPORT_ENABLE,
+ SKIN_TOKEN_UIVIEWPORT_LOAD,
+ SKIN_TOKEN_VIEWPORT_FGCOLOUR,
+ SKIN_TOKEN_VIEWPORT_BGCOLOUR,
+
+ /* Battery */
+ TOKEN_MARKER_BATTERY,
+ SKIN_TOKEN_BATTERY_PERCENT,
+ SKIN_TOKEN_BATTERY_PERCENTBAR,
+ SKIN_TOKEN_BATTERY_VOLTS,
+ SKIN_TOKEN_BATTERY_TIME,
+ SKIN_TOKEN_BATTERY_CHARGER_CONNECTED,
+ SKIN_TOKEN_BATTERY_CHARGING,
+ SKIN_TOKEN_BATTERY_SLEEPTIME,
+ SKIN_TOKEN_USB_POWERED,
+
+ /* Sound */
+ TOKEN_MARKER_SOUND,
+ SKIN_TOKEN_SOUND_PITCH,
+ SKIN_TOKEN_SOUND_SPEED,
+ SKIN_TOKEN_REPLAYGAIN,
+ SKIN_TOKEN_CROSSFADE,
+
+ /* Time */
+ TOKEN_MARKER_RTC,
+ SKIN_TOKEN_RTC_PRESENT,
+
+ /* The begin/end values allow us to know if a token is an RTC one.
+ New RTC tokens should be added between the markers. */
+
+ SKIN_TOKENs_RTC_BEGIN, /* just the start marker, not an actual token */
+
+ SKIN_TOKEN_RTC_DAY_OF_MONTH,
+ SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED,
+ SKIN_TOKEN_RTC_12HOUR_CFG,
+ SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED,
+ SKIN_TOKEN_RTC_HOUR_24,
+ SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED,
+ SKIN_TOKEN_RTC_HOUR_12,
+ SKIN_TOKEN_RTC_MONTH,
+ SKIN_TOKEN_RTC_MINUTE,
+ SKIN_TOKEN_RTC_SECOND,
+ SKIN_TOKEN_RTC_YEAR_2_DIGITS,
+ SKIN_TOKEN_RTC_YEAR_4_DIGITS,
+ SKIN_TOKEN_RTC_AM_PM_UPPER,
+ SKIN_TOKEN_RTC_AM_PM_LOWER,
+ SKIN_TOKEN_RTC_WEEKDAY_NAME,
+ SKIN_TOKEN_RTC_MONTH_NAME,
+ SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON,
+ SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN,
+
+ SKIN_TOKENS_RTC_END, /* just the end marker, not an actual token */
+
+ /* Database */
+ TOKEN_MARKER_DATABASE,
+ SKIN_TOKEN_DATABASE_PLAYCOUNT,
+ SKIN_TOKEN_DATABASE_RATING,
+ SKIN_TOKEN_DATABASE_AUTOSCORE,
+
+ /* File */
+ TOKEN_MARKER_FILE,
+ SKIN_TOKEN_FILE_BITRATE,
+ SKIN_TOKEN_FILE_CODEC,
+ SKIN_TOKEN_FILE_FREQUENCY,
+ SKIN_TOKEN_FILE_FREQUENCY_KHZ,
+ SKIN_TOKEN_FILE_NAME,
+ SKIN_TOKEN_FILE_NAME_WITH_EXTENSION,
+ SKIN_TOKEN_FILE_PATH,
+ SKIN_TOKEN_FILE_SIZE,
+ SKIN_TOKEN_FILE_VBR,
+ SKIN_TOKEN_FILE_DIRECTORY,
+
+ /* Image */
+ TOKEN_MARKER_IMAGES,
+ SKIN_TOKEN_IMAGE_BACKDROP,
+ SKIN_TOKEN_IMAGE_PROGRESS_BAR,
+ SKIN_TOKEN_IMAGE_PRELOAD,
+ SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY,
+ SKIN_TOKEN_IMAGE_DISPLAY,
+
+ /* Albumart */
+ SKIN_TOKEN_ALBUMART_LOAD,
+ SKIN_TOKEN_ALBUMART_DISPLAY,
+ SKIN_TOKEN_ALBUMART_FOUND,
+
+ /* Metadata */
+ TOKEN_MARKER_METADATA,
+ SKIN_TOKEN_METADATA_ARTIST,
+ SKIN_TOKEN_METADATA_COMPOSER,
+ SKIN_TOKEN_METADATA_ALBUM_ARTIST,
+ SKIN_TOKEN_METADATA_GROUPING,
+ SKIN_TOKEN_METADATA_ALBUM,
+ SKIN_TOKEN_METADATA_GENRE,
+ SKIN_TOKEN_METADATA_DISC_NUMBER,
+ SKIN_TOKEN_METADATA_TRACK_NUMBER,
+ SKIN_TOKEN_METADATA_TRACK_TITLE,
+ SKIN_TOKEN_METADATA_VERSION,
+ SKIN_TOKEN_METADATA_YEAR,
+ SKIN_TOKEN_METADATA_COMMENT,
+
+ TOKEN_MARKER_PLAYBACK_INFO,
+ /* Mode */
+ SKIN_TOKEN_REPEAT_MODE,
+ SKIN_TOKEN_PLAYBACK_STATUS,
+ /* Progressbar */
+ SKIN_TOKEN_PROGRESSBAR,
+ SKIN_TOKEN_PLAYER_PROGRESSBAR,
+ /* Peakmeter */
+ SKIN_TOKEN_PEAKMETER,
+
+ /* Current track */
+ SKIN_TOKEN_TRACK_ELAPSED_PERCENT,
+ SKIN_TOKEN_TRACK_TIME_ELAPSED,
+ SKIN_TOKEN_TRACK_TIME_REMAINING,
+ SKIN_TOKEN_TRACK_LENGTH,
+ SKIN_TOKEN_TRACK_STARTING,
+ SKIN_TOKEN_TRACK_ENDING,
+
+ /* Playlist */
+ TOKEN_MARKER_PLAYLIST,
+ SKIN_TOKEN_PLAYLIST_ENTRIES,
+ SKIN_TOKEN_PLAYLIST_NAME,
+ SKIN_TOKEN_PLAYLIST_POSITION,
+ SKIN_TOKEN_PLAYLIST_SHUFFLE,
+
+
+ TOKEN_MARKER_MISC,
+ SKIN_TOKEN_ENABLE_THEME,
+ SKIN_TOKEN_DISABLE_THEME,
+ SKIN_TOKEN_DRAW_INBUILTBAR,
+ SKIN_TOKEN_LIST_TITLE_TEXT,
+ SKIN_TOKEN_LIST_TITLE_ICON,
+
+ SKIN_TOKEN_LOAD_FONT,
+
+ /* buttons */
+ SKIN_TOKEN_BUTTON_VOLUME,
+ SKIN_TOKEN_LASTTOUCH,
+ SKIN_TOKEN_TOUCHREGION,
+ /* Virtual LED */
+ SKIN_TOKEN_VLED_HDD,
+ /* Volume level */
+ SKIN_TOKEN_VOLUME,
+ SKIN_TOKEN_VOLUMEBAR,
+ /* hold */
+ SKIN_TOKEN_MAIN_HOLD,
+ SKIN_TOKEN_REMOTE_HOLD,
+
+ /* Setting option */
+ SKIN_TOKEN_SETTING,
+ SKIN_TOKEN_CURRENT_SCREEN,
+ SKIN_TOKEN_LANG_IS_RTL,
+
+ /* Recording Tokens */
+ TOKEN_MARKER_RECORDING,
+ SKIN_TOKEN_HAVE_RECORDING,
+ SKIN_TOKEN_IS_RECORDING,
+ SKIN_TOKEN_REC_FREQ,
+ SKIN_TOKEN_REC_ENCODER,
+ SKIN_TOKEN_REC_BITRATE, /* SWCODEC: MP3 bitrate, HWCODEC: MP3 "quality" */
+ SKIN_TOKEN_REC_MONO,
+ SKIN_TOKEN_REC_SECONDS,
+ SKIN_TOKEN_REC_MINUTES,
+ SKIN_TOKEN_REC_HOURS,
+
+
+ /* Radio Tokens */
+ TOKEN_MARKER_TUNER,
+ SKIN_TOKEN_HAVE_TUNER,
+ SKIN_TOKEN_TUNER_TUNED,
+ SKIN_TOKEN_TUNER_SCANMODE,
+ SKIN_TOKEN_TUNER_STEREO,
+ SKIN_TOKEN_TUNER_MINFREQ, /* changes based on "region" */
+ SKIN_TOKEN_TUNER_MAXFREQ, /* changes based on "region" */
+ SKIN_TOKEN_TUNER_CURFREQ,
+ SKIN_TOKEN_PRESET_ID, /* "id" of this preset.. really the array element number */
+ SKIN_TOKEN_PRESET_NAME,
+ SKIN_TOKEN_PRESET_FREQ,
+ SKIN_TOKEN_PRESET_COUNT,
+ /* RDS tokens */
+ SKIN_TOKEN_HAVE_RDS,
+ SKIN_TOKEN_RDS_NAME,
+ SKIN_TOKEN_RDS_TEXT,
+
+
+ TOKEN_MARKER_END, /* this needs to be the last value in this enum */
+};
+
+/*
+ * 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 skin code
+ * N - any amount of strings.. must be the last param in the list
+ * 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. An asterisk (*) at the beginning of the
+ * string will specify that you may choose to omit all arguments
+ *
+ */
+struct tag_info
+{
+ enum skin_token_type type;
+ 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
+ */
+struct tag_info* 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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TAG_TABLE_H */