From d5b24ddcc57857d9db5751c2f6e51f55633459e7 Mon Sep 17 00:00:00 2001 From: Robert Bieber Date: Tue, 25 May 2010 15:19:52 +0000 Subject: 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 --- utils/themeeditor/main.c | 17 + utils/themeeditor/skin_debug.c | 226 +++++++++++ utils/themeeditor/skin_debug.h | 37 ++ utils/themeeditor/skin_parser.c | 811 ++++++++++++++++++++++++++++++++++++++ utils/themeeditor/skin_parser.h | 124 ++++++ utils/themeeditor/skin_scan.c | 137 +++++++ utils/themeeditor/skin_scan.h | 32 ++ utils/themeeditor/symbols.h | 37 ++ utils/themeeditor/tag_table.c | 75 ++++ utils/themeeditor/tag_table.h | 73 ++++ utils/themeeditor/themeeditor.pro | 10 + 11 files changed, 1579 insertions(+) create mode 100644 utils/themeeditor/main.c create mode 100644 utils/themeeditor/skin_debug.c create mode 100644 utils/themeeditor/skin_debug.h create mode 100644 utils/themeeditor/skin_parser.c create mode 100644 utils/themeeditor/skin_parser.h create mode 100644 utils/themeeditor/skin_scan.c create mode 100644 utils/themeeditor/skin_scan.h create mode 100644 utils/themeeditor/symbols.h create mode 100644 utils/themeeditor/tag_table.c create mode 100644 utils/themeeditor/tag_table.h create mode 100644 utils/themeeditor/themeeditor.pro (limited to 'utils/themeeditor') 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 +#include + +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 +#include +#include + +#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 +#include +#include +#include + +#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 +#include +#include + +#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 + +/* 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 -- cgit v1.2.3