/** * Parse !important * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \param result Pointer to location to receive result * \return CSS_OK on success, * CSS_INVALID if "S* ! S* important" is not at the start of the vector * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. */ css_error css__parse_important(css_language *c, const parserutils_vector *vector, int *ctx, uint8_t *result) { int orig_ctx = *ctx; bool match = false; const css_token *token; consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if (token != NULL && tokenIsChar(token, '!')) { consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if (token == NULL || token->type != CSS_TOKEN_IDENT) { *ctx = orig_ctx; return CSS_INVALID; } if (lwc_string_caseless_isequal(token->idata, c->strings[IMPORTANT], &match) == lwc_error_ok && match) { *result |= FLAG_IMPORTANT; } else { *ctx = orig_ctx; return CSS_INVALID; } } else if (token != NULL) { *ctx = orig_ctx; return CSS_INVALID; } return CSS_OK; }
/** * Register a handler with the content factory * * \param mime_type MIME type to handle * \param handler Content handler for MIME type * \return NSERROR_OK on success, appropriate error otherwise * * \note Latest registration for a MIME type wins */ nserror content_factory_register_handler(const char *mime_type, const content_handler *handler) { lwc_string *imime_type; lwc_error lerror; content_handler_entry *entry; bool match; lerror = lwc_intern_string(mime_type, strlen(mime_type), &imime_type); if (lerror != lwc_error_ok) return NSERROR_NOMEM; for (entry = content_handlers; entry != NULL; entry = entry->next) { if (lwc_string_caseless_isequal(imime_type, entry->mime_type, &match) == lwc_error_ok && match) break; } if (entry == NULL) { entry = malloc(sizeof(content_handler_entry)); if (entry == NULL) return NSERROR_NOMEM; entry->next = content_handlers; content_handlers = entry; entry->mime_type = imime_type; } else { lwc_string_unref(imime_type); } entry->handler = handler; return NSERROR_OK; }
css_error node_has_class(void *pw, void *n, lwc_string *name, bool *match) { node *node = n; uint32_t i; line_ctx *ctx = pw; for (i = 0; i < node->n_attrs; i++) { bool amatch = false; assert(lwc_string_caseless_isequal( node->attrs[i].name, ctx->attr_class, &amatch) == lwc_error_ok); if (amatch == true) break; } /* Classes are case-sensitive in HTML */ if (i != node->n_attrs && name == node->attrs[i].value) *match = true; else *match = false; return CSS_OK; }
css_error node_classes(void *pw, void *n, lwc_string ***classes, uint32_t *n_classes) { node *node = n; uint32_t i; line_ctx *lc = pw; for (i = 0; i < node->n_attrs; i++) { bool amatch = false; assert(lwc_string_caseless_isequal( node->attrs[i].name, lc->attr_class, &amatch) == lwc_error_ok); if (amatch == true) break; } if (i != node->n_attrs) { *classes = realloc(NULL, sizeof(lwc_string **)); if (*classes == NULL) return CSS_NOMEM; *(classes[0]) = lwc_string_ref(node->attrs[i].value); *n_classes = 1; } else { *classes = NULL; *n_classes = 0; } return CSS_OK; }
css_error node_has_attribute_prefix(void *pw, void *n, const css_qname *qname, lwc_string *value, bool *match) { node *node = n; uint32_t i; UNUSED(pw); *match = false; for (i = 0; i < node->n_attrs; i++) { assert(lwc_string_caseless_isequal( node->attrs[i].name, qname->name, match) == lwc_error_ok); if (*match == true) break; } if (*match == true) { size_t len = lwc_string_length(node->attrs[i].value); const char *data = lwc_string_data(node->attrs[i].value); size_t vlen = lwc_string_length(value); const char *vdata = lwc_string_data(value); if (len < vlen) *match = false; else *match = (strncasecmp(data, vdata, vlen) == 0); } return CSS_OK; }
css_error node_count_siblings(void *pw, void *n, bool same_name, bool after, int32_t *count) { int32_t cnt = 0; bool match = false; node *node = n; lwc_string *name = node->name; UNUSED(pw); if (after) { while (node->next != NULL) { if (same_name) { assert(lwc_string_caseless_isequal( name, node->next->name, &match) == lwc_error_ok); if (match) cnt++; } else { cnt++; } node = node->next; } } else { while (node->prev != NULL) { if (same_name) { assert(lwc_string_caseless_isequal( name, node->prev->name, &match) == lwc_error_ok); if (match) cnt++; } else { cnt++; } node = node->prev; } } *count = cnt; return CSS_OK; }
/** * Parse z_index * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \param result resulting style * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion, * CSS_INVALID if the input is not valid * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. */ css_error css__parse_z_index(css_language *c, const parserutils_vector *vector, int *ctx, css_style *result) { int orig_ctx = *ctx; css_error error; const css_token *token; bool match; token = parserutils_vector_iterate(vector, ctx); if ((token == NULL) || ((token->type != CSS_TOKEN_IDENT) && (token->type != CSS_TOKEN_NUMBER))) { *ctx = orig_ctx; return CSS_INVALID; } if ((token->type == CSS_TOKEN_IDENT) && (lwc_string_caseless_isequal(token->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { error = css_stylesheet_style_inherit(result, CSS_PROP_Z_INDEX); } else if ((token->type == CSS_TOKEN_IDENT) && (lwc_string_caseless_isequal(token->idata, c->strings[AUTO], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_Z_INDEX, 0,Z_INDEX_AUTO); } else if (token->type == CSS_TOKEN_NUMBER) { css_fixed num = 0; size_t consumed = 0; num = css__number_from_lwc_string(token->idata, true, &consumed); /* Invalid if there are trailing characters */ if (consumed != lwc_string_length(token->idata)) { *ctx = orig_ctx; return CSS_INVALID; } error = css__stylesheet_style_appendOPV(result, CSS_PROP_Z_INDEX, 0, Z_INDEX_SET); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = css__stylesheet_style_append(result, num); } else { error = CSS_INVALID; } if (error != CSS_OK) *ctx = orig_ctx; return error; }
/** * Create a path from a nsurl using amiga file handling. * * @param[in] url The url to encode. * @param[out] path_out A string containing the result path which should * be freed by the caller. * @return NSERROR_OK and the path is written to \a path or error code * on faliure. */ static nserror amiga_nsurl_to_path(struct nsurl *url, char **path_out) { lwc_string *urlpath; char *path; bool match; lwc_string *scheme; nserror res; char *colon; char *slash; if ((url == NULL) || (path_out == NULL)) { return NSERROR_BAD_PARAMETER; } scheme = nsurl_get_component(url, NSURL_SCHEME); if (lwc_string_caseless_isequal(scheme, corestring_lwc_file, &match) != lwc_error_ok) { return NSERROR_BAD_PARAMETER; } lwc_string_unref(scheme); if (match == false) { return NSERROR_BAD_PARAMETER; } urlpath = nsurl_get_component(url, NSURL_PATH); if (urlpath == NULL) { return NSERROR_BAD_PARAMETER; } res = url_unescape(lwc_string_data(urlpath) + 1, &path); lwc_string_unref(urlpath); if (res != NSERROR_OK) { return res; } colon = strchr(path, ':'); if(colon == NULL) { slash = strchr(path, '/'); if(slash) { *slash = ':'; } else { int len = strlen(path); path[len] = ':'; path[len + 1] = '\0'; } } *path_out = path; return NSERROR_OK; }
/** * Parse break_after * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \param result resulting style * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion, * CSS_INVALID if the input is not valid * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. */ css_error css__parse_break_after(css_language *c, const parserutils_vector *vector, int *ctx, css_style *result) { int orig_ctx = *ctx; css_error error; const css_token *token; bool match; token = parserutils_vector_iterate(vector, ctx); if ((token == NULL) || ((token->type != CSS_TOKEN_IDENT))) { *ctx = orig_ctx; return CSS_INVALID; } if ((lwc_string_caseless_isequal(token->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { error = css_stylesheet_style_inherit(result, CSS_PROP_BREAK_AFTER); } else if ((lwc_string_caseless_isequal(token->idata, c->strings[AUTO], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_BREAK_AFTER, 0,BREAK_AFTER_AUTO); } else if ((lwc_string_caseless_isequal(token->idata, c->strings[ALWAYS], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_BREAK_AFTER, 0,BREAK_AFTER_ALWAYS); } else if ((lwc_string_caseless_isequal(token->idata, c->strings[AVOID], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_BREAK_AFTER, 0,BREAK_AFTER_AVOID); } else if ((lwc_string_caseless_isequal(token->idata, c->strings[LEFT], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_BREAK_AFTER, 0,BREAK_AFTER_LEFT); } else if ((lwc_string_caseless_isequal(token->idata, c->strings[RIGHT], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_BREAK_AFTER, 0,BREAK_AFTER_RIGHT); } else if ((lwc_string_caseless_isequal(token->idata, c->strings[PAGE], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_BREAK_AFTER, 0,BREAK_AFTER_PAGE); } else if ((lwc_string_caseless_isequal(token->idata, c->strings[COLUMN], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_BREAK_AFTER, 0,BREAK_AFTER_COLUMN); } else if ((lwc_string_caseless_isequal(token->idata, c->strings[AVOID_PAGE], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_BREAK_AFTER, 0,BREAK_AFTER_AVOID_PAGE); } else if ((lwc_string_caseless_isequal(token->idata, c->strings[AVOID_COLUMN], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_BREAK_AFTER, 0,BREAK_AFTER_AVOID_COLUMN); } else { error = CSS_INVALID; } if (error != CSS_OK) *ctx = orig_ctx; return error; }
css_error node_has_name(void *pw, void *n, const css_qname *qname, bool *match) { lwc_string *node = (lwc_string*)n; UNUSED(pw); assert(lwc_string_caseless_isequal(node, qname->name, match) == lwc_error_ok); return CSS_OK; }
END_TEST START_TEST (test_lwc_string_caseless_isequal_bad) { bool result = true; fail_unless(lwc_string_caseless_isequal(intern_YAY, intern_one, &result) == lwc_error_ok, "Failure comparing 'YAY' and 'one' caselessly"); fail_unless(result == false, "'YAY' ~= 'one' ?!"); }
/** * Parse voice-family * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \param result Pointer to location to receive resulting style * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion, * CSS_INVALID if the input is not valid * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. */ css_error css__parse_voice_family(css_language *c, const parserutils_vector *vector, int *ctx, css_style *result) { int orig_ctx = *ctx; css_error error; const css_token *token; bool match; /* [ IDENT+ | STRING ] [ ',' [ IDENT+ | STRING ] ]* | IDENT(inherit) * * In the case of IDENT+, any whitespace between tokens is collapsed to * a single space */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || (token->type != CSS_TOKEN_IDENT && token->type != CSS_TOKEN_STRING)) { *ctx = orig_ctx; return CSS_INVALID; } if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { error = css_stylesheet_style_inherit(result, CSS_PROP_VOICE_FAMILY); } else { *ctx = orig_ctx; error = css__comma_list_to_style(c, vector, ctx, voice_family_reserved, voice_family_value, result); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = css__stylesheet_style_append(result, VOICE_FAMILY_END); } if (error != CSS_OK) { *ctx = orig_ctx; return error; } return CSS_OK; }
/* exported interface documented in content/content.h */ struct content_rfc5988_link * content_find_rfc5988_link(hlcache_handle *h, lwc_string *rel) { struct content *c = hlcache_handle_get_content(h); struct content_rfc5988_link *link = c->links; bool rel_match = false; while (link != NULL) { if (lwc_string_caseless_isequal(link->rel, rel, &rel_match) == lwc_error_ok && rel_match) { break; } link = link->next; } return link; }
css_error node_has_name(void *pw, void *n, const css_qname *qname, bool *match) { node *node = n; UNUSED(pw); if (lwc_string_length(qname->name) == 1 && lwc_string_data(qname->name)[0] == '*') *match = true; else assert(lwc_string_caseless_isequal(node->name, qname->name, match) == lwc_error_ok); return CSS_OK; }
css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour) { unsigned int ccount; bool match; for (ccount = 0; ccount < colour_list_len; ccount++) { if (lwc_string_caseless_isequal(name, colour_list[ccount].lwcstr, &match) == lwc_error_ok && match) { *colour = colour_list[ccount].colour; return CSS_OK; } } return CSS_INVALID; }
css_error node_has_attribute_substring(void *pw, void *n, const css_qname *qname, lwc_string *value, bool *match) { node *node = n; uint32_t i; UNUSED(pw); *match = false; for (i = 0; i < node->n_attrs; i++) { assert(lwc_string_caseless_isequal( node->attrs[i].name, qname->name, match) == lwc_error_ok); if (*match == true) break; } if (*match == true) { size_t len = lwc_string_length(node->attrs[i].value); const char *data = lwc_string_data(node->attrs[i].value); size_t vlen = lwc_string_length(value); const char *vdata = lwc_string_data(value); const char *last_start = data + len - vlen; if (len < vlen) *match = false; else { while (data <= last_start) { if (strncasecmp(data, vdata, vlen) == 0) { *match = true; break; } data++; } if (data > last_start) *match = false; } } return CSS_OK; }
css_error node_has_attribute_dashmatch(void *pw, void *n, const css_qname *qname, lwc_string *value, bool *match) { node *node = n; uint32_t i; size_t vlen = lwc_string_length(value); UNUSED(pw); *match = false; for (i = 0; i < node->n_attrs; i++) { assert(lwc_string_caseless_isequal( node->attrs[i].name, qname->name, match) == lwc_error_ok); if (*match == true) break; } if (*match == true) { const char *p; const char *start = lwc_string_data(node->attrs[i].value); const char *end = start + lwc_string_length(node->attrs[i].value); *match = false; for (p = start; p < end; p++) { if (*p == '-') { if ((size_t) (p - start) == vlen && strncasecmp(start, lwc_string_data(value), vlen) == 0) { *match = true; break; } start = p + 1; } } } return CSS_OK; }
/** * Find a handler for a MIME type. * * \param mime_type MIME type to search for * \return Associated handler, or NULL if none */ static const content_handler *content_lookup(lwc_string *mime_type) { content_handler_entry *entry; bool match; for (entry = content_handlers; entry != NULL; entry = entry->next) { if (lwc_string_caseless_isequal(mime_type, entry->mime_type, &match) == lwc_error_ok && match) { break; } } if (entry != NULL) { return entry->handler; } return NULL; }
/** * Case insensitively compare two DOM strings * * \param s1 The first string to compare * \param s2 The second string to compare * \return true if strings match, false otherwise */ bool dom_string_caseless_isequal(const dom_string *s1, const dom_string *s2) { const uint8_t *d1 = NULL; const uint8_t *d2 = NULL; size_t len; const dom_string_internal *is1 = (dom_string_internal *) s1; const dom_string_internal *is2 = (dom_string_internal *) s2; if (s1 == NULL) is1 = &empty_string; if (s2 == NULL) is2 = &empty_string; if (is1->type == DOM_STRING_INTERNED && is2->type == DOM_STRING_INTERNED) { bool match; if (lwc_string_caseless_isequal(is1->data.intern, is2->data.intern, &match) != lwc_error_ok) return false; return match; } len = dom_string_byte_length((dom_string *) is1); if (len != dom_string_byte_length((dom_string *)is2)) return false; d1 = (const uint8_t *) dom_string_data((dom_string *) is1); d2 = (const uint8_t *) dom_string_data((dom_string *)is2); while (len > 0) { if (dolower(*d1) != dolower(*d2)) return false; d1++; d2++; len--; } return true; }
END_TEST START_TEST (test_lwc_string_caseless_isequal_ok1) { bool result = true; lwc_string *new_ONE; fail_unless(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok, "Failure interning 'ONE'"); fail_unless((lwc_string_isequal(intern_one, new_ONE, &result)) == lwc_error_ok); fail_unless(result == false, "'one' == 'ONE' ?!"); fail_unless((lwc_string_caseless_isequal(intern_one, new_ONE, &result)) == lwc_error_ok, "Failure comparing 'one' and 'ONE' caselessly"); fail_unless(result == true, "'one' !~= 'ONE' ?!"); }
css_error named_sibling_node(void *pw, void *n, const css_qname *qname, void **sibling) { node *node = n; UNUSED(pw); *sibling = NULL; if (node->prev != NULL) { bool match = false; assert(lwc_string_caseless_isequal( qname->name, node->prev->name, &match) == lwc_error_ok); if (match == true) *sibling = (void *) node->prev; } return CSS_OK; }
END_TEST START_TEST (test_lwc_string_caseless_isequal_ok2) { bool result = true; lwc_string *new_yay; fail_unless(lwc_intern_string("yay", 3, &new_yay) == lwc_error_ok, "Failure interning 'yay'"); fail_unless((lwc_string_isequal(intern_YAY, new_yay, &result)) == lwc_error_ok); fail_unless(result == false, "'yay' == 'YAY' ?!"); fail_unless((lwc_string_caseless_isequal(intern_YAY, new_yay, &result)) == lwc_error_ok, "Failure comparing 'yay' and 'YAY' caselessly"); fail_unless(result == true, "'yay' !~= 'YAY' ?!"); }
css_error named_parent_node(void *pw, void *n, const css_qname *qname, void **parent) { node *node = n; UNUSED(pw); *parent = NULL; if (node->parent != NULL) { bool match = false; assert(lwc_string_caseless_isequal( qname->name, node->parent->name, &match) == lwc_error_ok); if (match == true) *parent = (void *) node->parent; } return CSS_OK; }
css_error node_has_attribute(void *pw, void *n, const css_qname *qname, bool *match) { node *node = n; uint32_t i; UNUSED(pw); *match = false; for (i = 0; i < node->n_attrs; i++) { assert(lwc_string_caseless_isequal( node->attrs[i].name, qname->name, match) == lwc_error_ok); if (*match == true) break; } return CSS_OK; }
css_error named_generic_sibling_node(void *pw, void *n, const css_qname *qname, void **sibling) { node *node = n; UNUSED(pw); for (node = node->prev; node != NULL; node = node->prev) { bool match = false; assert(lwc_string_caseless_isequal( qname->name, node->name, &match) == lwc_error_ok); if (match == true) break; } *sibling = (void *) node; return CSS_OK; }
css_error named_ancestor_node(void *pw, void *n, const css_qname *qname, void **ancestor) { node *node = n; UNUSED(pw); for (node = node->parent; node != NULL; node = node->parent) { bool match = false; assert(lwc_string_caseless_isequal( qname->name, node->name, &match) == lwc_error_ok); if (match == true) break; } *ancestor = (void *) node; return CSS_OK; }
/** * Parse list-style-type * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \param result Pointer to location to receive resulting style * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion, * CSS_INVALID if the input is not valid * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. */ css_error css__parse_list_style_type(css_language *c, const parserutils_vector *vector, int *ctx, css_style *result) { int orig_ctx = *ctx; css_error error; const css_token *ident; uint8_t flags = 0; uint16_t value = 0; bool match; /* IDENT (disc, circle, square, decimal, decimal-leading-zero, * lower-roman, upper-roman, lower-greek, lower-latin, * upper-latin, armenian, georgian, lower-alpha, upper-alpha, * none, inherit) */ ident = parserutils_vector_iterate(vector, ctx); if (ident == NULL || ident->type != CSS_TOKEN_IDENT) { *ctx = orig_ctx; return CSS_INVALID; } if ((lwc_string_caseless_isequal( ident->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { flags |= FLAG_INHERIT; } else { error = css__parse_list_style_type_value(c, ident, &value); if (error != CSS_OK) { *ctx = orig_ctx; return error; } } error = css__stylesheet_style_appendOPV(result, CSS_PROP_LIST_STYLE_TYPE, flags, value); if (error != CSS_OK) *ctx = orig_ctx; return error; }
css_error node_id(void *pw, void *n, lwc_string **id) { node *node = n; uint32_t i; line_ctx *lc = pw; for (i = 0; i < node->n_attrs; i++) { bool amatch = false; assert(lwc_string_caseless_isequal( node->attrs[i].name, lc->attr_id, &amatch) == lwc_error_ok); if (amatch == true) break; } if (i != node->n_attrs) *id = lwc_string_ref(node->attrs[i].value); else *id = NULL; return CSS_OK; }
/** * Parse content * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \param result Pointer to location to receive resulting style * \return CSS_OK on success, * CSS_NOMEM on memory exhaustion, * CSS_INVALID if the input is not valid * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. */ css_error css__parse_content(css_language *c, const parserutils_vector *vector, int *ctx, css_style *result) { int orig_ctx = *ctx; css_error error; const css_token *token; bool match; /* IDENT(normal, none, inherit) | [ ... ]+ */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL) { *ctx = orig_ctx; return CSS_INVALID; } if ((token->type == CSS_TOKEN_IDENT) && (lwc_string_caseless_isequal(token->idata, c->strings[INHERIT], &match) == lwc_error_ok && match)) { error = css_stylesheet_style_inherit(result, CSS_PROP_CONTENT); } else if ((token->type == CSS_TOKEN_IDENT) && (lwc_string_caseless_isequal(token->idata, c->strings[NORMAL], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_CONTENT, 0, CONTENT_NORMAL); } else if ((token->type == CSS_TOKEN_IDENT) && (lwc_string_caseless_isequal(token->idata, c->strings[NONE], &match) == lwc_error_ok && match)) { error = css__stylesheet_style_appendOPV(result, CSS_PROP_CONTENT, 0, CONTENT_NONE); } else { /* Macro to output the value marker, awkward because we need to check * first to determine how the value is constructed. */ #define CSS_APPEND(CSSVAL) css__stylesheet_style_append(result, first?buildOPV(CSS_PROP_CONTENT, 0, CSSVAL):CSSVAL) bool first = true; int prev_ctx = orig_ctx; /* [ * IDENT(open-quote, close-quote, no-open-quote, * no-close-quote) | * STRING | * URI | * FUNCTION(attr) IDENT ')' | * FUNCTION(counter) IDENT IDENT? ')' | * FUNCTION(counters) IDENT STRING IDENT? ')' * ]+ */ while (token != NULL) { if ((token->type == CSS_TOKEN_IDENT) && (lwc_string_caseless_isequal( token->idata, c->strings[OPEN_QUOTE], &match) == lwc_error_ok && match)) { error = CSS_APPEND(CONTENT_OPEN_QUOTE); } else if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[CLOSE_QUOTE], &match) == lwc_error_ok && match)) { error = CSS_APPEND(CONTENT_CLOSE_QUOTE); } else if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[NO_OPEN_QUOTE], &match) == lwc_error_ok && match)) { error = CSS_APPEND(CONTENT_NO_OPEN_QUOTE); } else if (token->type == CSS_TOKEN_IDENT && (lwc_string_caseless_isequal( token->idata, c->strings[NO_CLOSE_QUOTE], &match) == lwc_error_ok && match)) { error = CSS_APPEND(CONTENT_NO_CLOSE_QUOTE); } else if (token->type == CSS_TOKEN_STRING) { uint32_t snumber; error = css__stylesheet_string_add(c->sheet, lwc_string_ref(token->idata), &snumber); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = CSS_APPEND(CONTENT_STRING); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = css__stylesheet_style_append(result, snumber); } else if (token->type == CSS_TOKEN_URI) { lwc_string *uri; uint32_t uri_snumber; error = c->sheet->resolve(c->sheet->resolve_pw, c->sheet->url, token->idata, &uri); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = css__stylesheet_string_add(c->sheet, uri, &uri_snumber); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = CSS_APPEND(CONTENT_URI); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = css__stylesheet_style_append(result, uri_snumber); } else if (token->type == CSS_TOKEN_FUNCTION && (lwc_string_caseless_isequal( token->idata, c->strings[ATTR], &match) == lwc_error_ok && match)) { uint32_t snumber; consumeWhitespace(vector, ctx); /* Expect IDENT */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || token->type != CSS_TOKEN_IDENT) { *ctx = orig_ctx; return CSS_INVALID; } error = css__stylesheet_string_add(c->sheet, lwc_string_ref(token->idata), &snumber); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = CSS_APPEND(CONTENT_ATTR); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = css__stylesheet_style_append(result, snumber); consumeWhitespace(vector, ctx); /* Expect ')' */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || tokenIsChar(token, ')') == false) { *ctx = orig_ctx; return CSS_INVALID; } } else if (token->type == CSS_TOKEN_FUNCTION && (lwc_string_caseless_isequal( token->idata, c->strings[COUNTER], &match) == lwc_error_ok && match)) { lwc_string *name; uint32_t snumber; uint32_t opv; opv = CONTENT_COUNTER; consumeWhitespace(vector, ctx); /* Expect IDENT */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || token->type != CSS_TOKEN_IDENT) { *ctx = orig_ctx; return CSS_INVALID; } name = token->idata; consumeWhitespace(vector, ctx); /* Possible ',' */ token = parserutils_vector_peek(vector, *ctx); if (token == NULL || (tokenIsChar(token, ',') == false && tokenIsChar(token, ')') == false)) { *ctx = orig_ctx; return CSS_INVALID; } if (tokenIsChar(token, ',')) { uint16_t v; parserutils_vector_iterate(vector, ctx); consumeWhitespace(vector, ctx); /* Expect IDENT */ token = parserutils_vector_peek(vector, *ctx); if (token == NULL || token->type != CSS_TOKEN_IDENT) { *ctx = orig_ctx; return CSS_INVALID; } error = css__parse_list_style_type_value(c, token, &v); if (error != CSS_OK) { *ctx = orig_ctx; return error; } opv |= v << CONTENT_COUNTER_STYLE_SHIFT; parserutils_vector_iterate(vector, ctx); consumeWhitespace(vector, ctx); } else { opv |= LIST_STYLE_TYPE_DECIMAL << CONTENT_COUNTER_STYLE_SHIFT; } /* Expect ')' */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || tokenIsChar(token, ')') == false) { *ctx = orig_ctx; return CSS_INVALID; } error = css__stylesheet_string_add(c->sheet, lwc_string_ref(name), &snumber); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = CSS_APPEND(opv); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = css__stylesheet_style_append(result, snumber); } else if (token->type == CSS_TOKEN_FUNCTION && (lwc_string_caseless_isequal( token->idata, c->strings[COUNTERS], &match) == lwc_error_ok && match)) { lwc_string *name; lwc_string *sep; uint32_t name_snumber; uint32_t sep_snumber; uint32_t opv; opv = CONTENT_COUNTERS; consumeWhitespace(vector, ctx); /* Expect IDENT */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || token->type != CSS_TOKEN_IDENT) { *ctx = orig_ctx; return CSS_INVALID; } name = token->idata; consumeWhitespace(vector, ctx); /* Expect ',' */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || tokenIsChar(token, ',') == false) { *ctx = orig_ctx; return CSS_INVALID; } consumeWhitespace(vector, ctx); /* Expect STRING */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || token->type != CSS_TOKEN_STRING) { *ctx = orig_ctx; return CSS_INVALID; } sep = token->idata; consumeWhitespace(vector, ctx); /* Possible ',' */ token = parserutils_vector_peek(vector, *ctx); if (token == NULL || (tokenIsChar(token, ',') == false && tokenIsChar(token, ')') == false)) { *ctx = orig_ctx; return CSS_INVALID; } if (tokenIsChar(token, ',')) { uint16_t v; parserutils_vector_iterate(vector, ctx); consumeWhitespace(vector, ctx); /* Expect IDENT */ token = parserutils_vector_peek(vector, *ctx); if (token == NULL || token->type != CSS_TOKEN_IDENT) { *ctx = orig_ctx; return CSS_INVALID; } error = css__parse_list_style_type_value(c, token, &v); if (error != CSS_OK) { *ctx = orig_ctx; return error; } opv |= v << CONTENT_COUNTERS_STYLE_SHIFT; parserutils_vector_iterate(vector, ctx); consumeWhitespace(vector, ctx); } else { opv |= LIST_STYLE_TYPE_DECIMAL << CONTENT_COUNTERS_STYLE_SHIFT; } /* Expect ')' */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || tokenIsChar(token, ')') == false) { *ctx = orig_ctx; return CSS_INVALID; } error = css__stylesheet_string_add(c->sheet, lwc_string_ref(name), &name_snumber); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = css__stylesheet_string_add(c->sheet, lwc_string_ref(sep), &sep_snumber); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = CSS_APPEND(opv); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = css__stylesheet_style_append(result, name_snumber); if (error != CSS_OK) { *ctx = orig_ctx; return error; } error = css__stylesheet_style_append(result, sep_snumber); } else if (first) { /* Invalid if this is the first iteration */ error = CSS_INVALID; } else { /* Give up, ensuring current token is reprocessed */ *ctx = prev_ctx; error = CSS_OK; break; } /* if there was an error bail */ if (error != CSS_OK) { *ctx = orig_ctx; return error; } first = false; consumeWhitespace(vector, ctx); prev_ctx = *ctx; token = parserutils_vector_iterate(vector, ctx); } /* while */ /* Write list terminator */ css__stylesheet_style_append(result, CONTENT_NORMAL); } if (error != CSS_OK) *ctx = orig_ctx; return error; }
void css__parse_tree_data(line_ctx *ctx, const char *data, size_t len) { const char *p = data; const char *end = data + len; const char *name = NULL; const char *value = NULL; size_t namelen = 0; size_t valuelen = 0; uint32_t depth = 0; bool target = false; /* ' '{depth+1} [ <element> '*'? | <attr> ] * * <element> ::= [^=*[:space:]]+ * <attr> ::= [^=*[:space:]]+ '=' [^[:space:]]* */ while (p < end && isspace(*p)) { depth++; p++; } depth--; /* Get element/attribute name */ name = p; while (p < end && *p != '=' && *p != '*' && isspace(*p) == false) { namelen++; p++; } /* Skip whitespace */ while (p < end && isspace(*p)) p++; if (p < end && *p == '=') { /* Attribute value */ p++; value = p; while (p < end && isspace(*p) == false) { valuelen++; p++; } } else if (p < end && *p == '*') { /* Element is target node */ target = true; } if (value == NULL) { /* We have an element, so create it */ node *n = malloc(sizeof(node)); assert(n != NULL); memset(n, 0, sizeof(node)); lwc_intern_string(name, namelen, &n->name); /* Insert it into tree */ if (ctx->tree == NULL) { ctx->tree = n; } else { assert(depth > 0); assert(depth <= ctx->depth + 1); /* Find node to insert into */ while (depth <= ctx->depth) { ctx->depth--; ctx->current = ctx->current->parent; } /* Insert into current node */ if (ctx->current->children == NULL) { ctx->current->children = n; ctx->current->last_child = n; } else { ctx->current->last_child->next = n; n->prev = ctx->current->last_child; ctx->current->last_child = n; } n->parent = ctx->current; } ctx->current = n; ctx->depth = depth; /* Mark the target, if it's us */ if (target) ctx->target = n; } else { /* New attribute */ bool amatch = false; attribute *attr; node *n = ctx->current; attribute *temp = realloc(n->attrs, (n->n_attrs + 1) * sizeof(attribute)); assert(temp != NULL); n->attrs = temp; attr = &n->attrs[n->n_attrs]; lwc_intern_string(name, namelen, &attr->name); lwc_intern_string(value, valuelen, &attr->value); assert(lwc_string_caseless_isequal( n->attrs[n->n_attrs].name, ctx->attr_class, &amatch) == lwc_error_ok); if (amatch == true) { n->classes = realloc(NULL, sizeof(lwc_string **)); assert(n->classes != NULL); n->classes[0] = lwc_string_ref( n->attrs[n->n_attrs]. value); n->n_classes = 1; } n->n_attrs++; } }