Example #1
0
// script_english_number_*
String do_english_num(String input, String(*fun)(int)) {
	if (is_substr(input, 0, _("<param-"))) {
		// a keyword parameter, of the form "<param->123</param->"
		size_t start = skip_tag(input, 0);
		if (start != String::npos) {
			size_t end = input.find_first_of(_('<'), start);
			if (end != String::npos) {
				String is = input.substr(start, end - start);
				long i = 0;
				if (is.ToLong(&i)) {
					if (i == 1) {
						return _("<hint-1>") + substr_replace(input, start, end, fun(i));
					} else {
						return _("<hint-2>") + substr_replace(input, start, end, fun(i));
					}
				}
			}
		}
		return _("<hint-2>") + input;
	} else {
		long i = 0;
		if (input.ToLong(&i)) {
			return fun(i);
		}
		return input;
	}
}
Example #2
0
void Keyword::prepare(const vector<KeywordParamP>& param_types, bool force) {
	if (!force && !match_re.empty()) return;
	parameters.clear();
	// Prepare regex
	String regex;
	String text; // normal, non-regex, text
	vector<KeywordParamP>::const_iterator param = parameters.begin();
	#if USE_CASE_INSENSITIVE_KEYWORDS
		regex = _("(?i)"); // case insensitive matching
	#endif
	// Parse the 'match' string
	for (size_t i = 0 ; i < match.size() ;) {
		Char c = match.GetChar(i);
		if (is_substr(match, i, _("<atom-param"))) {
			// parameter, determine type...
			size_t start = skip_tag(match, i), end = match_close_tag(match, i);
			String type = match.substr(start, end-start);
			// find parameter type 'type'
			KeywordParamP param;
			FOR_EACH_CONST(pt, param_types) {
				if (pt->name == type) {
					param = pt;
					break;
				}
			}
			if (!param) {
				// throwing an error can mean a set will not be loaded!
				// instead, simply disable the keyword
				//throw InternalError(_("Unknown keyword parameter type: ") + type);
				handle_error(_("Unknown keyword parameter type: ") + type);
				valid = false;
				return;
			}
			parameters.push_back(param);
			// modify regex : match text before
			param->compile();
			// remove the separator from the text to prevent duplicates
			param->eat_separator_before(text);
			regex += _("(") + regex_escape(text) + _(")");
			text.clear();
			// modify regex : match parameter
			regex += _("(") + make_non_capturing(param->match) + (param->optional ? _(")?") : _(")"));
			i = skip_tag(match, end);
			// eat separator_after?
			param->eat_separator_after(match, i);
		} else {
Example #3
0
// script_english_singular/plural/singplur
String do_english(String input, String(*fun)(const String&)) {
	if (is_substr(input, 0, _("<param-"))) {
		// a keyword parameter, of the form "<param->123</param->"
		size_t start = skip_tag(input, 0);
		if (start != String::npos) {
			size_t end = input.find_first_of(_('<'), start);
			if (end != String::npos) {
				String is = input.substr(start, end - start);
				return substr_replace(input, start, end, fun(is));
			}
		}
		return input; // failed
	} else {
		return fun(input);
	}
}
Example #4
0
struct skin_element* skin_parse(const char* document, 
                                skin_callback cb, void* cb_data)
{
    callback = cb;
    callback_data = cb_data;
#else
struct skin_element* skin_parse(const char* document)
{
#endif
    struct skin_element* root = NULL;
    struct skin_element* last = NULL;

    const char* cursor = document; /*Keeps track of location in the document*/
    
    skin_line = 1;
    skin_start = (char*)document;
    viewport_line = 0;

    skin_clear_errors();

    while(*cursor != '\0')
    {
        struct skin_element* tree = skin_parse_viewport(&cursor);
        if(!root)
        {
            root = tree;
            last = root;
        }
        else
        {
            last->next = skin_buffer_to_offset(tree);
            last = tree;
        }

        if(!last)
        {
            skin_free_tree(root); /* Clearing any memory already used */
            return NULL;
        }

        /* Making sure last is at the end */
        while(IS_VALID_OFFSET(last->next))
            last = skin_buffer_from_offset(last->next);

    }
    return root;

}

static struct skin_element* skin_parse_viewport(const char** document)
{
    struct skin_element* root = NULL;
    struct skin_element* last = NULL;
    struct skin_element* retval = NULL;

    retval = skin_alloc_element();
    if (!retval)
        return NULL;
    retval->type = VIEWPORT;
    retval->children_count = 1;
    retval->line = skin_line;
    viewport_line = skin_line;

    OFFSETTYPE(struct skin_element*)* children;

    const char* cursor = *document; /* Keeps track of location in the document */
    const 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))
    {
        if (!skin_parse_tag(retval, &cursor))
            return NULL;
        if(*cursor == '\n')
        {
            cursor++;
            skin_line++;
        }
    }
#ifdef ROCKBOX
    else if (callback)
    {
        if (callback(retval, callback_data) == CALLBACK_ERROR)
        {
            skin_error(GOT_CALLBACK_ERROR, cursor);
            return NULL;
        }
    }
#endif

    if (check_viewport(cursor))
    {
        retval->children_count = 0;
        *document = cursor;
        return retval;
    }
    retval->children_count = 1;
    children = skin_alloc_children(1);
    if (!children)
        return NULL;
    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)
            {
                skip_tag(&cursor);
            }
            else if(*cursor == COMMENTSYM)
            {
                skip_comment(&cursor);
            }
            else
            {
                /* Advancing the cursor as normal */
                cursor++;
            }
        }
        cursor = bookmark;

        if(sublines)
        {
            struct skin_element* out = skin_parse_sublines(&cursor);
            if (!root)
            {
                root = out;
                last = root;
            }
            else
            {
                last->next = skin_buffer_to_offset(out);
                last = out;
            }
            if(!last)
                return NULL;
        }
        else
        {
#ifdef ROCKBOX
            /* strip all leading comments */
            while(*cursor == '#')
            {
                skip_comment(&cursor);
                skin_line++;
                
            }
            if (check_viewport(cursor))
                break;
#endif

            struct skin_element* out = skin_parse_line(&cursor);
            if (!root)
            {
                root = out;
                last = root;
            }
            else
            {
                last->next = skin_buffer_to_offset(out);
                last = out;
            }
            if(!last)
                return NULL;

        }
        /* Making sure last is at the end */
        while(IS_VALID_OFFSET(last->next))
            last = skin_buffer_from_offset(last->next);

        if(*cursor == '\n')
        {
            cursor++;
            skin_line++;
        }
#ifdef ROCKBOX
        /* strip all comments */
        while(*cursor == '#')
        {
            skip_comment(&cursor);
            skin_line++;
            
        }
        if (check_viewport(cursor))
            break;
#endif

    }
    while(*cursor != '\0' && !(check_viewport(cursor) && cursor != *document));

    *document = cursor;

    children[0] = skin_buffer_to_offset(root);
    retval->children = skin_buffer_to_offset(children);
    return retval;
}

/* Auxiliary Parsing Functions */

static struct skin_element* skin_parse_line(const char**document)
{
    return skin_parse_line_optional(document, 0);
}

/*
 * If conditional is set to true, then this will break upon encountering
 * SEPARATESYM.  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(const char** document,
                                                     int conditional)
{
    const char* cursor = *document;

    struct skin_element* root = NULL;
    struct skin_element* current = NULL;
    struct skin_element* retval = NULL;
    OFFSETTYPE(struct skin_element*)* children = NULL;

    /* A wrapper for the line */
    retval = skin_alloc_element();
    if (!retval)
        return NULL;
    retval->type = LINE;
    retval->line = skin_line;
    while (*cursor == '\t')
        cursor++;

    if(*cursor != '\0' && *cursor != '\n' && *cursor != MULTILINESYM
       && !(conditional && (*cursor == ARGLISTSEPARATESYM
                            || *cursor == ARGLISTCLOSESYM
                            || *cursor == ENUMLISTSEPARATESYM
                            || *cursor == ENUMLISTCLOSESYM)))
    {
        retval->children_count = 1;
    }
    else
    {
        retval->children_count = 0;
    }

    if(retval->children_count > 0)
    {
        children = skin_alloc_children(1);
        if (!children)
            return NULL;
    }

#ifdef ROCKBOX
    if (callback)
    {
        switch (callback(retval, callback_data))
        {
            case CALLBACK_ERROR:
                skin_error(GOT_CALLBACK_ERROR, cursor);
                return NULL;
            default:
                break;
        }
    }
#endif

    while(*cursor != '\n' && *cursor != '\0' && *cursor != MULTILINESYM
          && !((*cursor == ARGLISTSEPARATESYM
                || *cursor == ARGLISTCLOSESYM
                || *cursor == ENUMLISTSEPARATESYM
                || *cursor == ENUMLISTCLOSESYM)
               && conditional)
          && !(check_viewport(cursor) && cursor != *document))
    {
        /* Allocating memory if necessary */
        if(root)
        {
            struct skin_element *next = skin_alloc_element();
            if (!next)
                return NULL;
            current->next = skin_buffer_to_offset(next);
            current = next;
        }
        else
        {
            current = skin_alloc_element();
            if (!current)
                return NULL;
            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)
    {
        children[0] = skin_buffer_to_offset(root);
        retval->children = skin_buffer_to_offset(children);
    }
    return retval;
}

static struct skin_element* skin_parse_sublines(const char** document)
{
    return skin_parse_sublines_optional(document, 0);
}

static struct skin_element* skin_parse_sublines_optional(const char** document,
                                                  int conditional)
{
    struct skin_element* retval;
    OFFSETTYPE(struct skin_element*)* children;
    const char* cursor = *document;
    int sublines = 1;
    int i;

    retval = skin_alloc_element();
    if (!retval)
        return NULL;
    retval->type = LINE_ALTERNATOR;
    retval->next = skin_buffer_to_offset(NULL);
    retval->line = skin_line;
    while (*cursor == '\t')
        cursor++;

    /* First we count the sublines */
    while(*cursor != '\0' && *cursor != '\n'
          && !((*cursor == ARGLISTSEPARATESYM
                || *cursor == ARGLISTCLOSESYM
                || *cursor == ENUMLISTSEPARATESYM
                || *cursor == ENUMLISTCLOSESYM)
               && conditional)
          && !(check_viewport(cursor) && cursor != *document))
    {
        if(*cursor == COMMENTSYM)
        {
            skip_comment(&cursor);
        }
        else if(*cursor == TAGSYM)
        {
            skip_tag(&cursor);
        }
        else if(*cursor == MULTILINESYM)
        {
            sublines++;
            cursor++;
        }
        else
        {
            cursor++;
        }
    }

    /* ...and then we parse them */
    retval->children_count = sublines;
    children = skin_alloc_children(sublines);
    if (!children)
        return NULL;

    cursor = *document;
    for(i = 0; i < sublines; i++)
    {
        children[i] = skin_buffer_to_offset(skin_parse_line_optional(&cursor, conditional));
        if (children[i] < 0)
            return NULL;
        skip_whitespace(&cursor);

        if(*cursor != MULTILINESYM && i != sublines - 1)
        {
            skin_error(MULTILINE_EXPECTED, cursor);
            return NULL;
        }
        else if(i != sublines - 1)
        {
            cursor++;
        }
    }

#ifdef ROCKBOX
    if (callback)
    {
        if (callback(retval, callback_data) == CALLBACK_ERROR)
        {
            skin_error(GOT_CALLBACK_ERROR, *document);
            return NULL;
        }
    }
#endif
    *document = cursor;
    retval->children = skin_buffer_to_offset(children);

    return retval;
}

static int skin_parse_tag(struct skin_element* element, const char** document)
{
    const char* cursor = *document + 1;
    const char* bookmark;
    char *open_square_bracket = NULL;

    char tag_name[MAX_TAG_LENGTH];
    char* tag_args;
    const struct tag_info *tag;
    struct skin_tag_parameter* params = NULL;

    int num_args = 1;
    int i;
    int qmark = 0; /* Flag for the all-or-none option */

    int optional = 0;

    /* Checking the tag name */
    for (i=0; cursor[i] && i<MAX_TAG_LENGTH; i++)
        tag_name[i] = cursor[i];

    /* First we check the two characters after the '%', then a single char */
    tag = NULL;
    i = MAX_TAG_LENGTH;
    while (!tag && i > 1)
    {
        tag_name[i-1] = '\0';
        tag = find_tag(tag_name);
        i--;
    }

    if(!tag)
    {
        skin_error(ILLEGAL_TAG, cursor);
        return 0;
    }
    cursor += i;

    /* 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] == '?')
    {
        qmark = 1;
        tag_args++;
    }

    /* If this tag has no arguments, we can bail out now */
    if(strlen(tag_args) == 0
       || (tag_args[0] == '|' && *cursor != ARGLISTOPENSYM)
       || (qmark && *cursor != ARGLISTOPENSYM))
    {
        
#ifdef ROCKBOX
        if (callback)
        {
            if (callback(element, callback_data) == CALLBACK_ERROR)
            {
                skin_error(GOT_CALLBACK_ERROR, cursor);
                return 0;
            }
        }
#endif
        *document = cursor;
        return 1;
    }

    /* Checking the number of arguments and allocating args */
    if(*cursor != ARGLISTOPENSYM && tag_args[0] != '|')
    {
        skin_error(ARGLIST_EXPECTED, cursor);
        return 0;
    }
    else
    {
        cursor++;
    }

    bookmark = cursor;
    while(*cursor != '\n' && *cursor != '\0' && *cursor != ARGLISTCLOSESYM)
    {
        /* Skipping over escaped characters */
        if(*cursor == TAGSYM && *(cursor+1) != ARGLISTSEPARATESYM)
        {
            skip_tag(&cursor);
        }
        else if(*cursor == COMMENTSYM)
        {
            skip_comment(&cursor);
        }
        else if(*cursor == ARGLISTSEPARATESYM)
        {
            num_args++;
            cursor++;
        }
        else
        {
            cursor++;
        }
    }

    cursor = bookmark; /* Restoring the cursor */
    element->params_count = num_args;
    params = skin_alloc_params(num_args);
    if (!params)
        return 0;

    /* Now we have to actually parse each argument */
    for(i = 0; i < num_args; i++)
    {
        char type_code;
        /* Making sure we haven't run out of arguments */
        if(*tag_args == '\0')
        {
            skin_error(TOO_MANY_ARGS, cursor);
            return 0;
        }

        /* Checking for the optional bar */
        if(*tag_args == '|')
        {
            optional = 1;
            tag_args++;
        }

        /* Scanning the arguments */
        skip_whitespace(&cursor);

        /* Checking for comments */
        if(*cursor == COMMENTSYM)
            skip_comment(&cursor);

        if (*tag_args == '[')
        {
            /* we need to guess which type of param it is. 
             * guess using this priority:
             * default > decimal/integer > single tag/code > string
             */
            int j=0;
            bool canbedefault = false, last_char_is_percent = false;
            bool haspercent = false, number = true, hasdecimal = false;
            char temp_params[8];
            open_square_bracket = tag_args;
            tag_args++;
            while (*tag_args != ']')
            {
                if (*tag_args >= 'a' && *tag_args <= 'z')
                    canbedefault = true;
                temp_params[j++] = tolower(*tag_args++);
            }
            temp_params[j] = '\0';
            j = 0;
            while (cursor[j] && cursor[j] != ',' && cursor[j] != ')')
            {
                haspercent = haspercent || (cursor[j] == '%');
                hasdecimal = hasdecimal || (cursor[j] == '.');
                number = number && (isdigit(cursor[j]) || 
                                    (cursor[j] == '.') ||
                                    (cursor[j] == '-') ||
                                    (cursor[j] == '%'));
                j++;
            }
            last_char_is_percent = cursor[j-1] == '%';
            type_code = '?';
            if (canbedefault && *cursor == DEFAULTSYM && !isdigit(cursor[1]))
            {
                type_code = 'i';
            }
            else if (number && hasdecimal && strchr(temp_params, 'd'))
            {
                type_code = 'd';
            }
            else if (number && last_char_is_percent && strchr(temp_params, 'p'))
            {
                type_code = 'p';
            }
            else if (number && 
                     (strchr(temp_params, 'i') || strchr(temp_params, 'd')))
            {
                type_code = strchr(temp_params, 'i') ? 'i' : 'd';
            }
            else if (haspercent && 
                    (strchr(temp_params, 't') || strchr(temp_params, 'c')))
            {
                type_code = strchr(temp_params, 't') ? 't' : 'c';
            }
            else if (strchr(temp_params, 's'))
            {
                type_code = 's';
            }
            if (type_code == '?')
            {
                skin_error(INSUFFICIENT_ARGS, cursor);
                return 0;
            }   
        }
        else
            type_code = *tag_args;
        /* Storing the type code */
        params[i].type_code = type_code;

        /* Checking a nullable argument for null. */
        if(*cursor == DEFAULTSYM && !isdigit(cursor[1]))
        {
            if(islower(type_code))
            {
                params[i].type = DEFAULT;
                cursor++;
            }
            else
            {
                skin_error(DEFAULT_NOT_ALLOWED, cursor);
                return 0;
            }
        }
        else if(tolower(type_code) == 'i')
        {
            /* Scanning an int argument */
            if(!isdigit(*cursor) && *cursor != '-')
            {
                skin_error(INT_EXPECTED, cursor);
                return 0;
            }

            params[i].type = INTEGER;
            params[i].data.number = scan_int(&cursor);
        }
        else if(tolower(type_code) == 'd' || tolower(type_code) == 'p')
        {
            int val = 0;
            bool have_point = false;
            bool have_tenth = false;
            while ( isdigit(*cursor) || *cursor == '.' )
            {
                if (*cursor != '.')
                {
                    val *= 10;
                    val += *cursor - '0';
                    if (have_point)
                    {
                        have_tenth = true;
                        cursor++;
                        break;
                    }
                }
                else
                    have_point = true;
                cursor++;
            }
            if (have_tenth == false)
                val *= 10;
            if (tolower(type_code) == 'd')
                params[i].type = DECIMAL;
            else
            {
                params[i].type = PERCENT;
                cursor++; /* skip trailing % sign */
            }
            params[i].data.number = val;
        }
        else if(tolower(type_code) == 's' || tolower(type_code) == 'f')
        {
            /* Scanning a string argument */
            params[i].type = STRING;
            params[i].data.text = skin_buffer_to_offset(scan_string(&cursor));

        }
        else if(tolower(type_code) == 'c')
        {
            /* Recursively parsing a code argument */
            params[i].type = CODE;
            params[i].data.code = skin_buffer_to_offset(skin_parse_code_as_arg(&cursor));
            if(params[i].data.code < 0)
                return 0;
        }
        else if (tolower(type_code) == 't')
        {
            struct skin_element* child = skin_alloc_element();
            child->type = TAG;
            if (!skin_parse_tag(child, &cursor))
                return 0;
            child->next = skin_buffer_to_offset(NULL);
            params[i].type = CODE;
            params[i].data.code = skin_buffer_to_offset(child);
        }
            

        skip_whitespace(&cursor);

        if(*cursor != ARGLISTSEPARATESYM && i < num_args - 1)
        {
            skin_error(SEPARATOR_EXPECTED, cursor);
            return 0;
        }
        else if(*cursor != ARGLISTCLOSESYM && i == num_args - 1)
        {
            skin_error(CLOSE_EXPECTED, cursor);
            return 0;
        }
        else
        {
            cursor++;
        }

        if (*(tag_args + 1) == '*')
        {
            if (i+1 == num_args)
                tag_args += 2;
            else if (open_square_bracket  && *tag_args == ']')
            {
                tag_args = open_square_bracket;
                open_square_bracket = NULL;
            }
        }
        else
            tag_args++;

        /* Checking for the optional bar */
        if(*tag_args == '|')
        {
            optional = 1;
            tag_args++;
        }
    }
    element->params = skin_buffer_to_offset(params);

    /* Checking for a premature end */
    if(*tag_args != '\0' && !optional)
    {
        skin_error(INSUFFICIENT_ARGS, cursor);
        return 0;
    }
#ifdef ROCKBOX
    if (callback)
    {
        if (callback(element, callback_data) == CALLBACK_ERROR)
        {
            skin_error(GOT_CALLBACK_ERROR, *document);
            return 0;
        }
    }
#endif
    *document = cursor;

    return 1;
}

/*
 * If the conditional flag is set true, then parsing text will stop at an
 * ARGLISTSEPARATESYM.  Only set that flag when parsing within a conditional
 */
static int skin_parse_text(struct skin_element* element, const char** document,
                           int conditional)
{
    const 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 == ARGLISTSEPARATESYM
                || *cursor == ARGLISTCLOSESYM
                || *cursor == ENUMLISTSEPARATESYM
                || *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 = skin_buffer_to_offset(NULL);
    text = skin_alloc_string(length);
    element->data = skin_buffer_to_offset(text);
    if (element->data < 0)
        return 0;
    
    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';
    
#ifdef ROCKBOX
    if (callback)
    {
        if (callback(element, callback_data) == CALLBACK_ERROR)
        {
            skin_error(GOT_CALLBACK_ERROR, *document);
            return 0;
        }
    }
#endif

    *document = cursor;

    return 1;
}

static int skin_parse_conditional(struct skin_element* element, const char** document)
{
    const char* cursor = *document + 1; /* Starting past the "%" */
    const char* bookmark;
    int children = 1;
    int i;
    
#ifdef ROCKBOX
    bool feature_available = true;
    const char *false_branch = NULL;
    const char *conditional_end = NULL;
#endif
    OFFSETTYPE(struct skin_element*)* children_array = NULL;

    /* Some conditional tags allow for target feature checking,
     * so to handle that call the callback as usual with type == TAG
     * then call it a second time with type == CONDITIONAL and check the return
     * value */
    element->type = TAG;
    element->line = skin_line;

    /* Parsing the tag first */
    if(!skin_parse_tag(element, &cursor))
        return 0;

    element->type = CONDITIONAL;
#ifdef ROCKBOX
    if (callback)
    {
        switch (callback(element, callback_data))
        {
            case FEATURE_NOT_AVAILABLE:
                feature_available = false;
                break;
            case CALLBACK_ERROR:
                return 0;
            default:
                break;
        }
    }
#endif
    
    /* Counting the children */
    if(*(cursor++) != ENUMLISTOPENSYM)
    {
        skin_error(ARGLIST_EXPECTED, cursor);
        return 0;
    }
    bookmark = cursor;
    while(*cursor != ENUMLISTCLOSESYM && *cursor != '\0')
    {
        if(*cursor == COMMENTSYM)
        {
            skip_comment(&cursor);
        }
        else if(*cursor == TAGSYM)
        {
            skip_tag(&cursor);
        }
        else if(*cursor == ENUMLISTSEPARATESYM)
        {
            children++;
            cursor++;
            if (*cursor == '\n')
                cursor++;
#ifdef ROCKBOX
            if (false_branch == NULL && !feature_available)
            {
                false_branch = cursor;
                children--;
            }
#endif
        }
        else
        {
            cursor++;
        }
    }
#ifdef ROCKBOX
    if (*cursor == ENUMLISTCLOSESYM && 
        false_branch == NULL && !feature_available)
    {
        false_branch = cursor+1;
        children--;
    }
    if (element->tag->flags&FEATURE_TAG)
    {
        if (feature_available && children > 1)
            children--;
    }
    conditional_end = cursor;
    /* if we are skipping the true branch fix that up */
    cursor = false_branch ? false_branch : bookmark;
#else
    cursor = bookmark;
#endif
    /* Parsing the children */
    
    /* Feature tags could end up having 0 children which breaks
     * the render in dangerous ways. Minor hack, but insert an empty
     * child.  (e.g %?xx<foo> when xx isnt available ) */
    
    if (children == 0)
    {
        const char* emptyline= "";
        children = 1;
        children_array = skin_alloc_children(children);
        if (!children_array)
            return 0;
        element->children_count = children;
        children_array[0] = skin_buffer_to_offset(skin_parse_code_as_arg(&emptyline));
    }
    else
    {    
        children_array = skin_alloc_children(children);
        if (!children_array)
            return 0;
        element->children_count = children;

        for(i = 0; i < children; i++)
        {
            if (*cursor == '\n')
            {
                skin_line++;
                cursor++;
            }
            children_array[i] = skin_buffer_to_offset(skin_parse_code_as_arg(&cursor));
            if (children_array[i] < 0)
                return 0;
            skip_whitespace(&cursor);
#ifdef ROCKBOX
            if ((element->tag->flags&FEATURE_TAG) && feature_available)
                cursor = conditional_end;
#endif

            if(i < children - 1 && *cursor != ENUMLISTSEPARATESYM)
            {
                skin_error(SEPARATOR_EXPECTED, cursor);
                return 0;
            }
            else if(i == children - 1 && *cursor != ENUMLISTCLOSESYM)
            {
                skin_error(CLOSE_EXPECTED, cursor);
                return 0;
            }
            else
            {
                cursor++;
            }
        }
    }
    *document = cursor;
    element->children = skin_buffer_to_offset(children_array);

    return 1;
}

static int skin_parse_comment(struct skin_element* element, const char** document)
{
    const char* cursor = *document;
#ifndef ROCKBOX
    char* text = NULL;
#endif
    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 = INVALID_OFFSET;
#else    
    element->data = text = skin_alloc_string(length);
    if (!element->data)
        return 0;
    /* 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(const char** document)
{
    int sublines = 0;
    const char* cursor = *document;

    /* Checking for sublines */
    while(*cursor != '\n' && *cursor != '\0'
          && *cursor != ENUMLISTSEPARATESYM && *cursor != ARGLISTSEPARATESYM
          && *cursor != ENUMLISTCLOSESYM && *cursor != ARGLISTCLOSESYM)
    {
        if(*cursor == MULTILINESYM)
        {
            sublines = 1;
            break;
        }
        else if(*cursor == TAGSYM)
        {
            skip_tag(&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);
}
Example #5
0
aku_Status SeriesParser::to_normal_form(const char* begin, const char* end,
                                        char* out_begin, char* out_end,
                                        const char** keystr_begin,
                                        const char** keystr_end)
{
    // Verify args
    if (end < begin) {
        return AKU_EBAD_ARG;
    }
    if (out_end < out_begin) {
        return AKU_EBAD_ARG;
    }
    int series_name_len = end - begin;
    if (series_name_len > AKU_LIMITS_MAX_SNAME) {
        return AKU_EBAD_DATA;
    }
    if (series_name_len > (out_end - out_begin)) {
        return AKU_EBAD_ARG;
    }

    char* it_out = out_begin;
    const char* it = begin;
    // Get metric name
    it = skip_space(it, end);
    it = copy_until(it, end, ' ', &it_out);
    it = skip_space(it, end);

    if (it == end) {
        // At least one tag should be specified
        return AKU_EBAD_DATA;
    }

    *keystr_begin = it_out;

    // Get pointers to the keys
    const char* tags[AKU_LIMITS_MAX_TAGS];
    auto ix_tag = 0u;
    bool error = false;
    while(it < end && ix_tag < AKU_LIMITS_MAX_TAGS) {
        tags[ix_tag] = it;
        it = skip_tag(it, end, &error);
        it = skip_space(it, end);
        if (!error) {
            ix_tag++;
        } else {
            break;
        }
    }
    if (error) {
        // Bad string
        return AKU_EBAD_DATA;
    }
    if (ix_tag == 0) {
        // User should specify at least one tag
        return AKU_EBAD_DATA;
    }

    std::sort(tags, tags + ix_tag, [tags, end](const char* lhs, const char* rhs) {
        // lhs should be always less thenn rhs
        auto lenl = 0u;
        auto lenr = 0u;
        if (lhs < rhs) {
            lenl = rhs - lhs;
            lenr = end - rhs;
        } else {
            lenl = end - lhs;
            lenr = lhs - rhs;
        }
        auto it = 0u;
        while(true) {
            if (it >= lenl || it >= lenr) {
                return it < lenl;
            }
            if (lhs[it] == '=' || rhs[it] == '=') {
                return lhs[it] == '=';
            }
            if (lhs[it] < rhs[it]) {
                return true;
            } else if (lhs[it] > rhs[it]) {
                return false;
            }
            it++;
        }
        return true;
    });

    // Copy tags to output string
    for (auto i = 0u; i < ix_tag; i++) {
        // insert space
        *it_out++ = ' ';
        // insert tag
        const char* tag = tags[i];
        copy_until(tag, end, ' ', &it_out);
    }
    *keystr_begin = skip_space(*keystr_begin, out_end);
    *keystr_end = it_out;
    return AKU_SUCCESS;
}
Example #6
0
static void dump_info_headers( const char *input, uint length )
/*************************************************************/
{
    const uint_8 *p;
    uint_32     abbrev_code;
    uint_32     abbrev_offset;
    uint_8 *    abbrev;
    uint_32     tag;
    uint_32     unit_length;
    uint_32     tag_offset;
    const uint_8 *unit_base;
    info_state  state;
    bool        found;

    p = input;
    state.addr_size = 0;
    found = false;
    while( p - input < length ) {
        state.cu_header = p - input;
        unit_length = get_u32( (uint_32 *)p );
        unit_base = p + sizeof( uint_32 );
        Wdputs( "Length: " );
        Puthex( unit_length, 8 );
        Wdputslc( "\nVersion: " );
        Puthex( get_u16( (uint_16 *)(p + 4) ), 4 );
        Wdputslc( "\nAbbrev: " );
        abbrev_offset =  get_u32( (uint_32 *)(p + 6) );
        Puthex( abbrev_offset, 8 );
        state.addr_size = *(p + 10);
        Wdputslc( "\nAddress Size " );
        Puthex( *(p + 10), 2 );
        Wdputslc( "\n" );
        p += 11;
        while( p - unit_base < unit_length ) {
            tag_offset = p - input;
            p = DecodeULEB128( p, &abbrev_code );
            if( abbrev_code == 0 ) continue;
            abbrev = find_abbrev( abbrev_offset, abbrev_code );
            if( abbrev == NULL ) {
                Wdputs( "can't find abbreviation " );
                Puthex( abbrev_code, 8 );
                Wdputslc( "\n" );
                break;
            }
            if( p >= input + length ) break;
            abbrev = DecodeULEB128( abbrev, &tag );
            abbrev++;
            state.abbrev = abbrev;
            state.p = p;
            if( tag_offset == 0x59a125 ) {
                found = true;
            }
            if( found ) {
                Wdputs( "Offset: " );
                Puthex(  tag_offset, 8 );
                Wdputs( "  Code: " );
                Puthex( abbrev_code, 8 );
                Wdputslc( "\n" );
                Wdputs( "        " );
                getTAG( tag );
                Wdputslc( "\n" );
               if( !dump_tag( &state ) )break;
            } else {
                skip_tag( &state );
            }
            p = state.p;
        }
        if( found )break;
    }
}
Example #7
0
/** A hint is formed by
 *    1. an insertion of a parameter, <param-..>...</param->.
 *    2. a <hint-1> or <hint-2> tag
 *   
 *  Hints have the following meaning:
 *   -  "<hint-1>xxx(yyy)zzz"       ---> "xxxzzz"     (singular)
 *   -  "<hint-2>xxx(yyy)zzz"       ---> "xxxyyyzzz"  (plural)
 *   -  "[^., ]a <param-..>[aeiou]" ---> "\1 an \2"   (articla 'an', case insensitive)
 *   -  "<hint-?>"                  ---> ""           (remove <hint>s afterwards)
 *
 *  Note: there is no close tags for hints
 */
String process_english_hints(const String& str) {
	String ret; ret.reserve(str.size());
	// have we seen a <hint-1/2>?
	// 1 for singular, 2 for plural
	int singplur = 0;
	for (size_t i = 0 ; i < str.size() ; ) {
		Char c = str.GetChar(i);
		if (is_substr(str, i, _("<hint-"))) {
			Char h = str.GetChar(i + 6); // hint code
			if (h == _('1')) {
				singplur = 1;
			} else if (h == _('2')) {
				singplur = 2;
			}
			i = skip_tag(str, i);
		} else if (is_substr(str, i, _("<param-"))) {
			size_t after = skip_tag(str, i);
			if (after != String::npos) {
				Char c = str.GetChar(after);
				if (singplur == 1 && is_substr(str, after, _("a</param-"))) {
					// a -> an, where the a originates from english_number_a(1)
					size_t after_end = skip_tag(str,after+1);
					if (after_end == String::npos) {
						throw Error(_("Incomplete </param> tag"));
					}
					if (after_end != String::npos && after_end + 1 < str.size()
					&& isSpace(str.GetChar(after_end)) && is_vowel(str.GetChar(after_end+1))) {
						ret.append(str,i,after-i);
						ret += _("an");
						i = after + 1;
						continue;
					}
				} else if (is_vowel(c) && ret.size() >= 2) {
					// a -> an?
					// is there "a" before this?
					String last = ret.substr(ret.size() - 2);
					if ( (ret.size() == 2 || !isAlpha(ret.GetChar(ret.size() - 3))) &&
						(last == _("a ") || last == _("A ")) ) {
						ret.insert(ret.size() - 1, _('n'));
					}
				} else if (is_substr(str, after, _("</param-")) && ret.size() >= 1 &&
							ret.GetChar(ret.size() - 1) == _(' ')) {
					// empty param, drop space before it
					ret.resize(ret.size() - 1);
				}
			}
			ret.append(str,i,min(after,str.size())-i);
			i = after;
		} else if (is_substr(str, i, _("<singular>"))) {
			// singular -> keep, plural -> drop
			size_t start = skip_tag(str, i);
			size_t end   = match_close_tag(str, start);
			if (singplur == 1 && end != String::npos) {
				ret += str.substr(start, end - start);
			}
			singplur = 0;
			i = skip_tag(str, end);
		} else if (is_substr(str, i, _("<plural>"))) {
			// singular -> drop, plural -> keep
			size_t start = skip_tag(str, i);
			size_t end   = match_close_tag(str, start);
			if (singplur == 2 && end != String::npos) {
				ret += str.substr(start, end - start);
			}
			singplur = 0;
			i = skip_tag(str, end);
		} else if (c == _('(') && singplur) {
			// singular -> drop (...), plural -> keep it
			size_t end = str.find_first_of(_(')'), i);
			if (end != String::npos) {
				if (singplur == 2) {
					ret += str.substr(i + 1, end - i - 1);
				}
				i = end + 1;
			} else { // handle like normal
				ret += c;
				++i;
			}
			singplur = 0;
		} else if (c == _('<')) {
			size_t after = skip_tag(str, i);
			ret.append(str,i,min(after,str.size())-i);
			i = after;
		} else {
			ret += c;
			++i;
		}
	}
	return ret;
}