File: | parse/language.c |
Warning: | line 1606, column 6 Access to field 'insensitive' results in a dereference of a null pointer (loaded from field 'name') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * This file is part of LibCSS. | |||
3 | * Licensed under the MIT License, | |||
4 | * http://www.opensource.org/licenses/mit-license.php | |||
5 | * Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org> | |||
6 | */ | |||
7 | ||||
8 | #include <assert.h> | |||
9 | #include <string.h> | |||
10 | ||||
11 | #include <parserutils/utils/stack.h> | |||
12 | ||||
13 | #include "stylesheet.h" | |||
14 | #include "lex/lex.h" | |||
15 | #include "parse/font_face.h" | |||
16 | #include "parse/important.h" | |||
17 | #include "parse/language.h" | |||
18 | #include "parse/mq.h" | |||
19 | #include "parse/parse.h" | |||
20 | #include "parse/propstrings.h" | |||
21 | #include "parse/properties/properties.h" | |||
22 | #include "parse/properties/utils.h" | |||
23 | ||||
24 | #include "utils/parserutilserror.h" | |||
25 | #include "utils/utils.h" | |||
26 | ||||
27 | typedef struct context_entry { | |||
28 | css_parser_event type; /**< Type of entry */ | |||
29 | void *data; /**< Data for context */ | |||
30 | } context_entry; | |||
31 | ||||
32 | /* Event handlers */ | |||
33 | static css_error language_handle_event(css_parser_event type, | |||
34 | const parserutils_vector *tokens, void *pw); | |||
35 | static css_error handleStartStylesheet(css_language *c, | |||
36 | const parserutils_vector *vector); | |||
37 | static css_error handleEndStylesheet(css_language *c, | |||
38 | const parserutils_vector *vector); | |||
39 | static css_error handleStartRuleset(css_language *c, | |||
40 | const parserutils_vector *vector); | |||
41 | static css_error handleEndRuleset(css_language *c, | |||
42 | const parserutils_vector *vector); | |||
43 | static css_error handleStartAtRule(css_language *c, | |||
44 | const parserutils_vector *vector); | |||
45 | static css_error handleEndAtRule(css_language *c, | |||
46 | const parserutils_vector *vector); | |||
47 | static css_error handleStartBlock(css_language *c, | |||
48 | const parserutils_vector *vector); | |||
49 | static css_error handleEndBlock(css_language *c, | |||
50 | const parserutils_vector *vector); | |||
51 | static css_error handleBlockContent(css_language *c, | |||
52 | const parserutils_vector *vector); | |||
53 | static css_error handleEndBlockContent(css_language *c, | |||
54 | const parserutils_vector *vector); | |||
55 | static css_error handleDeclaration(css_language *c, | |||
56 | const parserutils_vector *vector); | |||
57 | ||||
58 | /* At-rule parsing */ | |||
59 | static css_error addNamespace(css_language *c, | |||
60 | lwc_string *prefix, lwc_string *uri); | |||
61 | static css_error lookupNamespace(css_language *c, | |||
62 | lwc_string *prefix, lwc_string **uri); | |||
63 | ||||
64 | /* Selector list parsing */ | |||
65 | static css_error parseClass(css_language *c, | |||
66 | const parserutils_vector *vector, int32_t *ctx, | |||
67 | css_selector_detail *specific); | |||
68 | static css_error parseAttrib(css_language *c, | |||
69 | const parserutils_vector *vector, int32_t *ctx, | |||
70 | css_selector_detail *specific); | |||
71 | static css_error parseNth(css_language *c, | |||
72 | const parserutils_vector *vector, int32_t *ctx, | |||
73 | css_selector_detail_value *value); | |||
74 | static css_error parsePseudo(css_language *c, | |||
75 | const parserutils_vector *vector, int32_t *ctx, | |||
76 | bool_Bool in_not, css_selector_detail *specific); | |||
77 | static css_error parseSpecific(css_language *c, | |||
78 | const parserutils_vector *vector, int32_t *ctx, | |||
79 | bool_Bool in_not, css_selector_detail *specific); | |||
80 | static css_error parseAppendSpecific(css_language *c, | |||
81 | const parserutils_vector *vector, int32_t *ctx, | |||
82 | css_selector **parent); | |||
83 | static css_error parseSelectorSpecifics(css_language *c, | |||
84 | const parserutils_vector *vector, int32_t *ctx, | |||
85 | css_selector **parent); | |||
86 | static css_error parseTypeSelector(css_language *c, | |||
87 | const parserutils_vector *vector, int32_t *ctx, | |||
88 | css_qname *qname); | |||
89 | static css_error parseSimpleSelector(css_language *c, | |||
90 | const parserutils_vector *vector, int32_t *ctx, | |||
91 | css_selector **result); | |||
92 | static css_error parseCombinator(css_language *c, | |||
93 | const parserutils_vector *vector, int32_t *ctx, | |||
94 | css_combinator *result); | |||
95 | static css_error parseSelector(css_language *c, | |||
96 | const parserutils_vector *vector, int32_t *ctx, | |||
97 | css_selector **result); | |||
98 | static css_error parseSelectorList(css_language *c, | |||
99 | const parserutils_vector *vector, css_rule *rule); | |||
100 | ||||
101 | /* Declaration parsing */ | |||
102 | static css_error parseProperty(css_language *c, | |||
103 | const css_token *property, const parserutils_vector *vector, | |||
104 | int32_t *ctx, css_rule *rule); | |||
105 | ||||
106 | /** | |||
107 | * Create a CSS language parser | |||
108 | * | |||
109 | * \param sheet The stylesheet object to parse for | |||
110 | * \param parser The core parser object to use | |||
111 | * \param language Pointer to location to receive parser object | |||
112 | * \return CSS_OK on success, | |||
113 | * CSS_BADPARM on bad parameters, | |||
114 | * CSS_NOMEM on memory exhaustion | |||
115 | */ | |||
116 | css_error css__language_create(css_stylesheet *sheet, css_parser *parser, | |||
117 | void **language) | |||
118 | { | |||
119 | css_language *c; | |||
120 | css_parser_optparams params; | |||
121 | parserutils_error perror; | |||
122 | css_error error; | |||
123 | ||||
124 | if (sheet == NULL((void*)0) || parser == NULL((void*)0) || language == NULL((void*)0)) | |||
125 | return CSS_BADPARM; | |||
126 | ||||
127 | c = malloc(sizeof(css_language)); | |||
128 | if (c == NULL((void*)0)) | |||
129 | return CSS_NOMEM; | |||
130 | ||||
131 | perror = parserutils_stack_create(sizeof(context_entry), | |||
132 | STACK_CHUNK32, &c->context); | |||
133 | if (perror != PARSERUTILS_OK) { | |||
134 | free(c); | |||
135 | return css_error_from_parserutils_error(perror); | |||
136 | } | |||
137 | ||||
138 | params.event_handler.handler = language_handle_event; | |||
139 | params.event_handler.pw = c; | |||
140 | error = css__parser_setopt(parser, CSS_PARSER_EVENT_HANDLER, ¶ms); | |||
141 | if (error != CSS_OK) { | |||
142 | parserutils_stack_destroy(c->context); | |||
143 | free(c); | |||
144 | return error; | |||
145 | } | |||
146 | ||||
147 | c->sheet = sheet; | |||
148 | c->state = CHARSET_PERMITTED; | |||
149 | c->default_namespace = NULL((void*)0); | |||
150 | c->namespaces = NULL((void*)0); | |||
151 | c->num_namespaces = 0; | |||
152 | c->strings = sheet->propstrings; | |||
153 | ||||
154 | *language = c; | |||
155 | ||||
156 | return CSS_OK; | |||
157 | } | |||
158 | ||||
159 | /** | |||
160 | * Destroy a CSS language parser | |||
161 | * | |||
162 | * \param language The parser to destroy | |||
163 | * \return CSS_OK on success, appropriate error otherwise | |||
164 | */ | |||
165 | css_error css__language_destroy(css_language *language) | |||
166 | { | |||
167 | uint32_t i; | |||
168 | ||||
169 | if (language == NULL((void*)0)) | |||
170 | return CSS_BADPARM; | |||
171 | ||||
172 | if (language->default_namespace != NULL((void*)0)) | |||
173 | lwc_string_unref(language->default_namespace){ lwc_string *__lwc_s = (language->default_namespace); ((__lwc_s != ((void*)0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL" , "src/parse/language.c", 173, __extension__ __PRETTY_FUNCTION__ )); __lwc_s->refcnt--; if ((__lwc_s->refcnt == 0) || (( __lwc_s->refcnt == 1) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy(__lwc_s); }; | |||
174 | ||||
175 | if (language->namespaces != NULL((void*)0)) { | |||
176 | for (i = 0; i < language->num_namespaces; i++) { | |||
177 | lwc_string_unref(language->namespaces[i].prefix){ lwc_string *__lwc_s = (language->namespaces[i].prefix); ( (__lwc_s != ((void*)0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL" , "src/parse/language.c", 177, __extension__ __PRETTY_FUNCTION__ )); __lwc_s->refcnt--; if ((__lwc_s->refcnt == 0) || (( __lwc_s->refcnt == 1) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy(__lwc_s); }; | |||
178 | lwc_string_unref(language->namespaces[i].uri){ lwc_string *__lwc_s = (language->namespaces[i].uri); ((__lwc_s != ((void*)0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL" , "src/parse/language.c", 178, __extension__ __PRETTY_FUNCTION__ )); __lwc_s->refcnt--; if ((__lwc_s->refcnt == 0) || (( __lwc_s->refcnt == 1) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy(__lwc_s); }; | |||
179 | } | |||
180 | ||||
181 | free(language->namespaces); | |||
182 | } | |||
183 | ||||
184 | parserutils_stack_destroy(language->context); | |||
185 | ||||
186 | free(language); | |||
187 | ||||
188 | return CSS_OK; | |||
189 | } | |||
190 | ||||
191 | /** | |||
192 | * Handler for core parser events | |||
193 | * | |||
194 | * \param type The event type | |||
195 | * \param tokens Vector of tokens read since last event, or NULL | |||
196 | * \param pw Pointer to handler context | |||
197 | * \return CSS_OK on success, CSS_INVALID to indicate parse error, | |||
198 | * appropriate error otherwise. | |||
199 | */ | |||
200 | css_error language_handle_event(css_parser_event type, | |||
201 | const parserutils_vector *tokens, void *pw) | |||
202 | { | |||
203 | css_language *language = (css_language *) pw; | |||
204 | ||||
205 | switch (type) { | |||
206 | case CSS_PARSER_START_STYLESHEET: | |||
207 | return handleStartStylesheet(language, tokens); | |||
208 | case CSS_PARSER_END_STYLESHEET: | |||
209 | return handleEndStylesheet(language, tokens); | |||
210 | case CSS_PARSER_START_RULESET: | |||
211 | return handleStartRuleset(language, tokens); | |||
212 | case CSS_PARSER_END_RULESET: | |||
213 | return handleEndRuleset(language, tokens); | |||
214 | case CSS_PARSER_START_ATRULE: | |||
215 | return handleStartAtRule(language, tokens); | |||
216 | case CSS_PARSER_END_ATRULE: | |||
217 | return handleEndAtRule(language, tokens); | |||
218 | case CSS_PARSER_START_BLOCK: | |||
219 | return handleStartBlock(language, tokens); | |||
220 | case CSS_PARSER_END_BLOCK: | |||
221 | return handleEndBlock(language, tokens); | |||
222 | case CSS_PARSER_BLOCK_CONTENT: | |||
223 | return handleBlockContent(language, tokens); | |||
224 | case CSS_PARSER_END_BLOCK_CONTENT: | |||
225 | return handleEndBlockContent(language, tokens); | |||
226 | case CSS_PARSER_DECLARATION: | |||
227 | return handleDeclaration(language, tokens); | |||
228 | } | |||
229 | ||||
230 | return CSS_OK; | |||
231 | } | |||
232 | ||||
233 | /****************************************************************************** | |||
234 | * Parser stages * | |||
235 | ******************************************************************************/ | |||
236 | ||||
237 | css_error handleStartStylesheet(css_language *c, | |||
238 | const parserutils_vector *vector) | |||
239 | { | |||
240 | parserutils_error perror; | |||
241 | context_entry entry = { CSS_PARSER_START_STYLESHEET, NULL((void*)0) }; | |||
242 | ||||
243 | UNUSED(vector)((void)(vector)); | |||
244 | ||||
245 | assert(c != NULL)((c != ((void*)0)) ? (void) (0) : __assert_fail ("c != NULL", "src/parse/language.c", 245, __extension__ __PRETTY_FUNCTION__ )); | |||
246 | ||||
247 | perror = parserutils_stack_push(c->context, (void *) &entry); | |||
248 | if (perror != PARSERUTILS_OK) { | |||
249 | return css_error_from_parserutils_error(perror); | |||
250 | } | |||
251 | ||||
252 | return CSS_OK; | |||
253 | } | |||
254 | ||||
255 | css_error handleEndStylesheet(css_language *c, const parserutils_vector *vector) | |||
256 | { | |||
257 | parserutils_error perror; | |||
258 | context_entry *entry; | |||
259 | ||||
260 | UNUSED(vector)((void)(vector)); | |||
261 | ||||
262 | assert(c != NULL)((c != ((void*)0)) ? (void) (0) : __assert_fail ("c != NULL", "src/parse/language.c", 262, __extension__ __PRETTY_FUNCTION__ )); | |||
263 | ||||
264 | entry = parserutils_stack_get_current(c->context); | |||
265 | if (entry == NULL((void*)0) || entry->type != CSS_PARSER_START_STYLESHEET) | |||
266 | return CSS_INVALID; | |||
267 | ||||
268 | perror = parserutils_stack_pop(c->context, NULL((void*)0)); | |||
269 | if (perror != PARSERUTILS_OK) { | |||
270 | return css_error_from_parserutils_error(perror); | |||
271 | } | |||
272 | ||||
273 | return CSS_OK; | |||
274 | } | |||
275 | ||||
276 | css_error handleStartRuleset(css_language *c, const parserutils_vector *vector) | |||
277 | { | |||
278 | parserutils_error perror; | |||
279 | css_error error; | |||
280 | context_entry entry = { CSS_PARSER_START_RULESET, NULL((void*)0) }; | |||
281 | context_entry *cur; | |||
282 | css_rule *parent_rule = NULL((void*)0); | |||
283 | css_rule *rule = NULL((void*)0); | |||
284 | ||||
285 | assert(c != NULL)((c != ((void*)0)) ? (void) (0) : __assert_fail ("c != NULL", "src/parse/language.c", 285, __extension__ __PRETTY_FUNCTION__ )); | |||
286 | ||||
287 | /* Retrieve parent rule from stack, if any */ | |||
288 | cur = parserutils_stack_get_current(c->context); | |||
289 | if (cur != NULL((void*)0) && cur->type != CSS_PARSER_START_STYLESHEET) | |||
290 | parent_rule = cur->data; | |||
291 | ||||
292 | error = css__stylesheet_rule_create(c->sheet, CSS_RULE_SELECTOR, &rule); | |||
293 | if (error != CSS_OK) | |||
294 | return error; | |||
295 | ||||
296 | if (vector != NULL((void*)0)) { | |||
297 | /* Parse selectors, if there are any */ | |||
298 | error = parseSelectorList(c, vector, rule); | |||
299 | if (error != CSS_OK) { | |||
300 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
301 | return error; | |||
302 | } | |||
303 | } | |||
304 | ||||
305 | entry.data = rule; | |||
306 | ||||
307 | perror = parserutils_stack_push(c->context, (void *) &entry); | |||
308 | if (perror != PARSERUTILS_OK) { | |||
309 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
310 | return css_error_from_parserutils_error(perror); | |||
311 | } | |||
312 | ||||
313 | error = css__stylesheet_add_rule(c->sheet, rule, parent_rule); | |||
314 | if (error != CSS_OK) { | |||
315 | parserutils_stack_pop(c->context, NULL((void*)0)); | |||
316 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
317 | return error; | |||
318 | } | |||
319 | ||||
320 | /* Flag that we've had a valid rule, so @import/@namespace/@charset | |||
321 | * have no effect. */ | |||
322 | c->state = HAD_RULE; | |||
323 | ||||
324 | /* Rule is now owned by the sheet, so no need to destroy it */ | |||
325 | ||||
326 | return CSS_OK; | |||
327 | } | |||
328 | ||||
329 | css_error handleEndRuleset(css_language *c, const parserutils_vector *vector) | |||
330 | { | |||
331 | parserutils_error perror; | |||
332 | context_entry *entry; | |||
333 | ||||
334 | UNUSED(vector)((void)(vector)); | |||
335 | ||||
336 | assert(c != NULL)((c != ((void*)0)) ? (void) (0) : __assert_fail ("c != NULL", "src/parse/language.c", 336, __extension__ __PRETTY_FUNCTION__ )); | |||
337 | ||||
338 | entry = parserutils_stack_get_current(c->context); | |||
339 | if (entry == NULL((void*)0) || entry->type != CSS_PARSER_START_RULESET) | |||
340 | return CSS_INVALID; | |||
341 | ||||
342 | perror = parserutils_stack_pop(c->context, NULL((void*)0)); | |||
343 | if (perror != PARSERUTILS_OK) { | |||
344 | return css_error_from_parserutils_error(perror); | |||
345 | } | |||
346 | ||||
347 | return CSS_OK; | |||
348 | } | |||
349 | ||||
350 | css_error handleStartAtRule(css_language *c, const parserutils_vector *vector) | |||
351 | { | |||
352 | parserutils_error perror; | |||
353 | context_entry entry = { CSS_PARSER_START_ATRULE, NULL((void*)0) }; | |||
354 | const css_token *token = NULL((void*)0); | |||
355 | const css_token *atkeyword = NULL((void*)0); | |||
356 | int32_t ctx = 0; | |||
357 | bool_Bool match = false0; | |||
358 | css_rule *rule; | |||
359 | css_error error; | |||
360 | ||||
361 | /* vector contains: ATKEYWORD ws any0 */ | |||
362 | ||||
363 | assert(c != NULL)((c != ((void*)0)) ? (void) (0) : __assert_fail ("c != NULL", "src/parse/language.c", 363, __extension__ __PRETTY_FUNCTION__ )); | |||
364 | ||||
365 | atkeyword = parserutils_vector_iterate(vector, &ctx); | |||
366 | ||||
367 | consumeWhitespace(vector, &ctx); | |||
368 | ||||
369 | /* We now have an ATKEYWORD and the context for the start of any0, if | |||
370 | * there is one */ | |||
371 | assert(atkeyword != NULL && atkeyword->type == CSS_TOKEN_ATKEYWORD)((atkeyword != ((void*)0) && atkeyword->type == CSS_TOKEN_ATKEYWORD ) ? (void) (0) : __assert_fail ("atkeyword != NULL && atkeyword->type == CSS_TOKEN_ATKEYWORD" , "src/parse/language.c", 371, __extension__ __PRETTY_FUNCTION__ )); | |||
372 | ||||
373 | if (lwc_string_caseless_isequal(atkeyword->idata, c->strings[CHARSET],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [CHARSET]); _Bool *__lwc_ret = (&match); if (__lwc_str1-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
374 | &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [CHARSET]); _Bool *__lwc_ret = (&match); if (__lwc_str1-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) == lwc_error_ok && match) { | |||
375 | if (c->state == CHARSET_PERMITTED) { | |||
376 | const css_token *charset; | |||
377 | ||||
378 | /* any0 = STRING */ | |||
379 | if (ctx == 0) | |||
380 | return CSS_INVALID; | |||
381 | ||||
382 | charset = parserutils_vector_iterate(vector, &ctx); | |||
383 | if (charset == NULL((void*)0) || | |||
384 | charset->type != CSS_TOKEN_STRING) | |||
385 | return CSS_INVALID; | |||
386 | ||||
387 | token = parserutils_vector_iterate(vector, &ctx); | |||
388 | if (token != NULL((void*)0)) | |||
389 | return CSS_INVALID; | |||
390 | ||||
391 | error = css__stylesheet_rule_create(c->sheet, | |||
392 | CSS_RULE_CHARSET, &rule); | |||
393 | if (error != CSS_OK) | |||
394 | return error; | |||
395 | ||||
396 | error = css__stylesheet_rule_set_charset(c->sheet, rule, | |||
397 | charset->idata); | |||
398 | if (error != CSS_OK) { | |||
399 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
400 | return error; | |||
401 | } | |||
402 | ||||
403 | error = css__stylesheet_add_rule(c->sheet, rule, NULL((void*)0)); | |||
404 | if (error != CSS_OK) { | |||
405 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
406 | return error; | |||
407 | } | |||
408 | ||||
409 | /* Rule is now owned by the sheet, | |||
410 | * so no need to destroy it */ | |||
411 | ||||
412 | c->state = IMPORT_PERMITTED; | |||
413 | } else { | |||
414 | return CSS_INVALID; | |||
415 | } | |||
416 | } else if (lwc_string_caseless_isequal(atkeyword->idata,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [LIBCSS_IMPORT]); _Bool *__lwc_ret = (&match); if (__lwc_str1 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
417 | c->strings[LIBCSS_IMPORT], &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [LIBCSS_IMPORT]); _Bool *__lwc_ret = (&match); if (__lwc_str1 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) == lwc_error_ok && | |||
418 | match) { | |||
419 | if (c->state <= IMPORT_PERMITTED) { | |||
420 | lwc_string *url; | |||
421 | css_mq_query *media = NULL((void*)0); | |||
422 | ||||
423 | /* any0 = (STRING | URI) ws (media query)? */ | |||
424 | const css_token *uri = | |||
425 | parserutils_vector_iterate(vector, &ctx); | |||
426 | if (uri == NULL((void*)0) || (uri->type != CSS_TOKEN_STRING && | |||
427 | uri->type != CSS_TOKEN_URI)) | |||
428 | return CSS_INVALID; | |||
429 | ||||
430 | consumeWhitespace(vector, &ctx); | |||
431 | ||||
432 | /* Parse media list */ | |||
433 | error = css__mq_parse_media_list( | |||
434 | c->strings, vector, &ctx, &media); | |||
435 | if (error == CSS_NOMEM) { | |||
436 | return error; | |||
437 | } else if (media == NULL((void*)0)) { | |||
438 | /* Fall back to default media: "all". */ | |||
439 | media = calloc(1, sizeof(*media)); | |||
440 | if (media == NULL((void*)0)) { | |||
441 | return CSS_NOMEM; | |||
442 | } | |||
443 | media->type = CSS_MEDIA_ALL; | |||
444 | } | |||
445 | ||||
446 | /* Create rule */ | |||
447 | error = css__stylesheet_rule_create(c->sheet, | |||
448 | CSS_RULE_IMPORT, &rule); | |||
449 | if (error != CSS_OK) { | |||
450 | css__mq_query_destroy(media); | |||
451 | return error; | |||
452 | } | |||
453 | ||||
454 | /* Resolve import URI */ | |||
455 | error = c->sheet->resolve(c->sheet->resolve_pw, | |||
456 | c->sheet->url, | |||
457 | uri->idata, &url); | |||
458 | if (error != CSS_OK) { | |||
459 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
460 | css__mq_query_destroy(media); | |||
461 | return error; | |||
462 | } | |||
463 | ||||
464 | /* Inform rule of it */ | |||
465 | error = css__stylesheet_rule_set_nascent_import(c->sheet, | |||
466 | rule, url, media); | |||
467 | if (error != CSS_OK) { | |||
468 | lwc_string_unref(url){ lwc_string *__lwc_s = (url); ((__lwc_s != ((void*)0)) ? (void ) (0) : __assert_fail ("__lwc_s != NULL", "src/parse/language.c" , 468, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt --; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1 ) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy (__lwc_s); }; | |||
469 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
470 | css__mq_query_destroy(media); | |||
471 | return error; | |||
472 | } | |||
473 | ||||
474 | /* Inform client of need for import */ | |||
475 | if (c->sheet->import != NULL((void*)0)) { | |||
476 | error = c->sheet->import(c->sheet->import_pw, | |||
477 | c->sheet, url); | |||
478 | if (error != CSS_OK) { | |||
479 | lwc_string_unref(url){ lwc_string *__lwc_s = (url); ((__lwc_s != ((void*)0)) ? (void ) (0) : __assert_fail ("__lwc_s != NULL", "src/parse/language.c" , 479, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt --; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1 ) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy (__lwc_s); }; | |||
480 | css__stylesheet_rule_destroy(c->sheet, | |||
481 | rule); | |||
482 | return error; | |||
483 | } | |||
484 | } | |||
485 | ||||
486 | /* No longer care about url */ | |||
487 | lwc_string_unref(url){ lwc_string *__lwc_s = (url); ((__lwc_s != ((void*)0)) ? (void ) (0) : __assert_fail ("__lwc_s != NULL", "src/parse/language.c" , 487, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt --; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1 ) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy (__lwc_s); }; | |||
488 | ||||
489 | /* Add rule to sheet */ | |||
490 | error = css__stylesheet_add_rule(c->sheet, rule, NULL((void*)0)); | |||
491 | if (error != CSS_OK) { | |||
492 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
493 | return error; | |||
494 | } | |||
495 | ||||
496 | /* Rule is now owned by the sheet, | |||
497 | * so no need to destroy it */ | |||
498 | ||||
499 | c->state = IMPORT_PERMITTED; | |||
500 | } else { | |||
501 | return CSS_INVALID; | |||
502 | } | |||
503 | } else if (lwc_string_caseless_isequal(atkeyword->idata,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [NAMESPACE]); _Bool *__lwc_ret = (&match); if (__lwc_str1 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
504 | c->strings[NAMESPACE], &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [NAMESPACE]); _Bool *__lwc_ret = (&match); if (__lwc_str1 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) == lwc_error_ok && | |||
505 | match) { | |||
506 | if (c->state <= NAMESPACE_PERMITTED) { | |||
507 | lwc_string *prefix = NULL((void*)0); | |||
508 | ||||
509 | /* any0 = (IDENT ws)? (STRING | URI) ws */ | |||
510 | ||||
511 | token = parserutils_vector_iterate(vector, &ctx); | |||
512 | if (token == NULL((void*)0)) | |||
513 | return CSS_INVALID; | |||
514 | ||||
515 | if (token->type == CSS_TOKEN_IDENT) { | |||
516 | prefix = token->idata; | |||
517 | ||||
518 | consumeWhitespace(vector, &ctx); | |||
519 | ||||
520 | token = parserutils_vector_iterate(vector, | |||
521 | &ctx); | |||
522 | } | |||
523 | ||||
524 | if (token == NULL((void*)0) || (token->type != CSS_TOKEN_STRING && | |||
525 | token->type != CSS_TOKEN_URI)) { | |||
526 | return CSS_INVALID; | |||
527 | } | |||
528 | ||||
529 | consumeWhitespace(vector, &ctx); | |||
530 | ||||
531 | error = addNamespace(c, prefix, token->idata); | |||
532 | if (error != CSS_OK) | |||
533 | return error; | |||
534 | ||||
535 | c->state = NAMESPACE_PERMITTED; | |||
536 | ||||
537 | /* Namespaces are special, and do not generate rules */ | |||
538 | return CSS_OK; | |||
539 | } else { | |||
540 | return CSS_INVALID; | |||
541 | } | |||
542 | } else if (lwc_string_caseless_isequal(atkeyword->idata, c->strings[MEDIA],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [MEDIA]); _Bool *__lwc_ret = (&match); if (__lwc_str1-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
543 | &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [MEDIA]); _Bool *__lwc_ret = (&match); if (__lwc_str1-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) == lwc_error_ok && match) { | |||
544 | css_mq_query *media = NULL((void*)0); | |||
545 | ||||
546 | /* any0 = media query */ | |||
547 | error = css__mq_parse_media_list( | |||
548 | c->strings, vector, &ctx, &media); | |||
549 | if (error != CSS_OK) | |||
550 | return error; | |||
551 | ||||
552 | error = css__stylesheet_rule_create(c->sheet, | |||
553 | CSS_RULE_MEDIA, &rule); | |||
554 | if (error != CSS_OK) { | |||
555 | css__mq_query_destroy(media); | |||
556 | return error; | |||
557 | } | |||
558 | ||||
559 | error = css__stylesheet_rule_set_media(c->sheet, rule, media); | |||
560 | if (error != CSS_OK) { | |||
561 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
562 | css__mq_query_destroy(media); | |||
563 | return error; | |||
564 | } | |||
565 | ||||
566 | error = css__stylesheet_add_rule(c->sheet, rule, NULL((void*)0)); | |||
567 | if (error != CSS_OK) { | |||
568 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
569 | return error; | |||
570 | } | |||
571 | ||||
572 | /* Rule is now owned by the sheet, | |||
573 | * so no need to destroy it */ | |||
574 | ||||
575 | c->state = HAD_RULE; | |||
576 | } else if (lwc_string_caseless_isequal(atkeyword->idata,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [FONT_FACE]); _Bool *__lwc_ret = (&match); if (__lwc_str1 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
577 | c->strings[FONT_FACE], &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [FONT_FACE]); _Bool *__lwc_ret = (&match); if (__lwc_str1 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) == lwc_error_ok && | |||
578 | match) { | |||
579 | error = css__stylesheet_rule_create(c->sheet, | |||
580 | CSS_RULE_FONT_FACE, &rule); | |||
581 | if (error != CSS_OK) | |||
582 | return error; | |||
583 | ||||
584 | consumeWhitespace(vector, &ctx); | |||
585 | ||||
586 | error = css__stylesheet_add_rule(c->sheet, rule, NULL((void*)0)); | |||
587 | if (error != CSS_OK) { | |||
588 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
589 | return error; | |||
590 | } | |||
591 | ||||
592 | /* Rule is now owned by the sheet, | |||
593 | * so no need to destroy it */ | |||
594 | ||||
595 | c->state = HAD_RULE; | |||
596 | } else if (lwc_string_caseless_isequal(atkeyword->idata, c->strings[PAGE],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [PAGE]); _Bool *__lwc_ret = (&match); if (__lwc_str1-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
597 | &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (atkeyword->idata); lwc_string *__lwc_str2 = (c->strings [PAGE]); _Bool *__lwc_ret = (&match); if (__lwc_str1-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) == lwc_error_ok && match) { | |||
598 | const css_token *token; | |||
599 | ||||
600 | /* any0 = (':' IDENT)? ws */ | |||
601 | ||||
602 | error = css__stylesheet_rule_create(c->sheet, | |||
603 | CSS_RULE_PAGE, &rule); | |||
604 | if (error != CSS_OK) | |||
605 | return error; | |||
606 | ||||
607 | consumeWhitespace(vector, &ctx); | |||
608 | ||||
609 | token = parserutils_vector_peek(vector, ctx); | |||
610 | if (token != NULL((void*)0)) { | |||
611 | css_selector *sel = NULL((void*)0); | |||
612 | ||||
613 | error = parseSelector(c, vector, &ctx, &sel); | |||
614 | if (error != CSS_OK) { | |||
615 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
616 | return error; | |||
617 | } | |||
618 | ||||
619 | error = css__stylesheet_rule_set_page_selector(c->sheet, | |||
620 | rule, sel); | |||
621 | if (error != CSS_OK) { | |||
622 | css__stylesheet_selector_destroy(c->sheet, sel); | |||
623 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
624 | return error; | |||
625 | } | |||
626 | } | |||
627 | ||||
628 | error = css__stylesheet_add_rule(c->sheet, rule, NULL((void*)0)); | |||
629 | if (error != CSS_OK) { | |||
630 | css__stylesheet_rule_destroy(c->sheet, rule); | |||
631 | return error; | |||
632 | } | |||
633 | ||||
634 | /* Rule is now owned by the sheet, | |||
635 | * so no need to destroy it */ | |||
636 | ||||
637 | c->state = HAD_RULE; | |||
638 | } else { | |||
639 | return CSS_INVALID; | |||
640 | } | |||
641 | ||||
642 | entry.data = rule; | |||
643 | ||||
644 | perror = parserutils_stack_push(c->context, (void *) &entry); | |||
645 | if (perror != PARSERUTILS_OK) { | |||
646 | return css_error_from_parserutils_error(perror); | |||
647 | } | |||
648 | ||||
649 | return CSS_OK; | |||
650 | } | |||
651 | ||||
652 | css_error handleEndAtRule(css_language *c, const parserutils_vector *vector) | |||
653 | { | |||
654 | parserutils_error perror; | |||
655 | context_entry *entry; | |||
656 | ||||
657 | UNUSED(vector)((void)(vector)); | |||
658 | ||||
659 | assert(c != NULL)((c != ((void*)0)) ? (void) (0) : __assert_fail ("c != NULL", "src/parse/language.c", 659, __extension__ __PRETTY_FUNCTION__ )); | |||
660 | ||||
661 | entry = parserutils_stack_get_current(c->context); | |||
662 | if (entry == NULL((void*)0) || entry->type != CSS_PARSER_START_ATRULE) | |||
663 | return CSS_INVALID; | |||
664 | ||||
665 | perror = parserutils_stack_pop(c->context, NULL((void*)0)); | |||
666 | if (perror != PARSERUTILS_OK) { | |||
667 | return css_error_from_parserutils_error(perror); | |||
668 | } | |||
669 | ||||
670 | return CSS_OK; | |||
671 | } | |||
672 | ||||
673 | css_error handleStartBlock(css_language *c, const parserutils_vector *vector) | |||
674 | { | |||
675 | parserutils_error perror; | |||
676 | context_entry entry = { CSS_PARSER_START_BLOCK, NULL((void*)0) }; | |||
677 | context_entry *cur; | |||
678 | ||||
679 | UNUSED(vector)((void)(vector)); | |||
680 | ||||
681 | /* If the current item on the stack isn't a block, | |||
682 | * then clone its data field. This ensures that the relevant rule | |||
683 | * is available when parsing the block contents. */ | |||
684 | cur = parserutils_stack_get_current(c->context); | |||
685 | if (cur != NULL((void*)0) && cur->type != CSS_PARSER_START_BLOCK) | |||
686 | entry.data = cur->data; | |||
687 | ||||
688 | perror = parserutils_stack_push(c->context, (void *) &entry); | |||
689 | if (perror != PARSERUTILS_OK) { | |||
690 | return css_error_from_parserutils_error(perror); | |||
691 | } | |||
692 | ||||
693 | return CSS_OK; | |||
694 | } | |||
695 | ||||
696 | css_error handleEndBlock(css_language *c, const parserutils_vector *vector) | |||
697 | { | |||
698 | parserutils_error perror; | |||
699 | context_entry *entry; | |||
700 | css_rule *rule; | |||
701 | ||||
702 | entry = parserutils_stack_get_current(c->context); | |||
703 | if (entry == NULL((void*)0) || entry->type != CSS_PARSER_START_BLOCK) | |||
704 | return CSS_INVALID; | |||
705 | ||||
706 | rule = entry->data; | |||
707 | ||||
708 | perror = parserutils_stack_pop(c->context, NULL((void*)0)); | |||
709 | if (perror != PARSERUTILS_OK) { | |||
710 | return css_error_from_parserutils_error(perror); | |||
711 | } | |||
712 | ||||
713 | /* If the block we just popped off the stack was associated with a | |||
714 | * non-block stack entry, and that entry is not a top-level statement, | |||
715 | * then report the end of that entry, too. */ | |||
716 | if (rule != NULL((void*)0) && rule->ptype != CSS_RULE_PARENT_STYLESHEET) { | |||
717 | if (rule->type == CSS_RULE_SELECTOR) | |||
718 | return handleEndRuleset(c, vector); | |||
719 | } | |||
720 | ||||
721 | return CSS_OK; | |||
722 | } | |||
723 | ||||
724 | css_error handleBlockContent(css_language *c, const parserutils_vector *vector) | |||
725 | { | |||
726 | context_entry *entry; | |||
727 | css_rule *rule; | |||
728 | ||||
729 | /* Block content comprises either declarations (if the current block is | |||
730 | * associated with @page, @font-face or a selector), or rulesets (if the | |||
731 | * current block is associated with @media). */ | |||
732 | ||||
733 | entry = parserutils_stack_get_current(c->context); | |||
734 | if (entry == NULL((void*)0) || entry->data == NULL((void*)0)) | |||
735 | return CSS_INVALID; | |||
736 | ||||
737 | rule = entry->data; | |||
738 | if (rule == NULL((void*)0) || (rule->type != CSS_RULE_SELECTOR && | |||
739 | rule->type != CSS_RULE_PAGE && | |||
740 | rule->type != CSS_RULE_MEDIA && | |||
741 | rule->type != CSS_RULE_FONT_FACE)) | |||
742 | return CSS_INVALID; | |||
743 | ||||
744 | if (rule->type == CSS_RULE_MEDIA) { | |||
745 | /* Expect rulesets */ | |||
746 | return handleStartRuleset(c, vector); | |||
747 | } else { | |||
748 | /* Expect declarations */ | |||
749 | return handleDeclaration(c, vector); | |||
750 | } | |||
751 | ||||
752 | return CSS_OK; | |||
753 | } | |||
754 | ||||
755 | css_error handleEndBlockContent(css_language *c, const parserutils_vector *vector) | |||
756 | { | |||
757 | context_entry *entry; | |||
758 | parserutils_error perror; | |||
759 | css_error ret; | |||
760 | ||||
761 | /* First we call handleBlockContent() to deal with any intermediate | |||
762 | * tokens we have left | |||
763 | */ | |||
764 | ret = handleBlockContent(c, vector); | |||
765 | if (ret != CSS_OK) { | |||
766 | return ret; | |||
767 | } | |||
768 | ||||
769 | /* Our goal here is to ensure that the language parse stack is in the | |||
770 | * right state. We've encountered the end of a BlockContent such as | |||
771 | * @media ... { ... } | |||
772 | * and we need to ensure that the language stack reflects the end of | |||
773 | * that block, not any unfinished business within it such as | |||
774 | * @media ... { d } | |||
775 | */ | |||
776 | ||||
777 | entry = parserutils_stack_get_current(c->context); | |||
778 | while (entry != NULL((void*)0) && entry->type != CSS_PARSER_START_BLOCK) { | |||
779 | perror = parserutils_stack_pop(c->context, NULL((void*)0)); | |||
780 | if (perror != PARSERUTILS_OK) { | |||
781 | return css_error_from_parserutils_error(perror); | |||
782 | } | |||
783 | entry = parserutils_stack_get_current(c->context); | |||
784 | } | |||
785 | ||||
786 | return CSS_OK; | |||
787 | } | |||
788 | ||||
789 | css_error handleDeclaration(css_language *c, const parserutils_vector *vector) | |||
790 | { | |||
791 | css_error error; | |||
792 | const css_token *token, *ident; | |||
793 | int32_t ctx = 0; | |||
794 | context_entry *entry; | |||
795 | css_rule *rule; | |||
796 | ||||
797 | /* Locations where declarations are permitted: | |||
798 | * | |||
799 | * + In @page | |||
800 | * + In @font-face | |||
801 | * + In ruleset | |||
802 | */ | |||
803 | entry = parserutils_stack_get_current(c->context); | |||
804 | if (entry == NULL((void*)0) || entry->data == NULL((void*)0)) | |||
805 | return CSS_INVALID; | |||
806 | ||||
807 | rule = entry->data; | |||
808 | if (rule == NULL((void*)0) || (rule->type != CSS_RULE_SELECTOR && | |||
809 | rule->type != CSS_RULE_PAGE && | |||
810 | rule->type != CSS_RULE_FONT_FACE)) | |||
811 | return CSS_INVALID; | |||
812 | ||||
813 | /* Strip any leading whitespace (can happen if in nested block) */ | |||
814 | consumeWhitespace(vector, &ctx); | |||
815 | ||||
816 | /* IDENT ws ':' ws value | |||
817 | * | |||
818 | * In CSS 2.1, value is any1, so '{' or ATKEYWORD => parse error | |||
819 | */ | |||
820 | ident = parserutils_vector_iterate(vector, &ctx); | |||
821 | if (ident == NULL((void*)0) || ident->type != CSS_TOKEN_IDENT) | |||
822 | return CSS_INVALID; | |||
823 | ||||
824 | consumeWhitespace(vector, &ctx); | |||
825 | ||||
826 | token = parserutils_vector_iterate(vector, &ctx); | |||
827 | if (token == NULL((void*)0) || tokenIsChar(token, ':') == false0) | |||
828 | return CSS_INVALID; | |||
829 | ||||
830 | consumeWhitespace(vector, &ctx); | |||
831 | ||||
832 | if (rule->type == CSS_RULE_FONT_FACE) { | |||
833 | css_rule_font_face * ff_rule = (css_rule_font_face *) rule; | |||
834 | error = css__parse_font_descriptor( | |||
835 | c, ident, vector, &ctx, ff_rule); | |||
836 | } else { | |||
837 | error = parseProperty(c, ident, vector, &ctx, rule); | |||
838 | } | |||
839 | if (error != CSS_OK) | |||
840 | return error; | |||
841 | ||||
842 | return CSS_OK; | |||
843 | } | |||
844 | ||||
845 | /****************************************************************************** | |||
846 | * At-rule parsing functions * | |||
847 | ******************************************************************************/ | |||
848 | ||||
849 | /** | |||
850 | * Add a namespace mapping | |||
851 | * | |||
852 | * \param c Parsing context to add to | |||
853 | * \param prefix Namespace prefix, or NULL for default namespace | |||
854 | * \param uri Namespace URI | |||
855 | * \return CSS_OK on success, CSS_NOMEM on memory exhaustion. | |||
856 | */ | |||
857 | css_error addNamespace(css_language *c, lwc_string *prefix, lwc_string *uri) | |||
858 | { | |||
859 | if (prefix == NULL((void*)0)) { | |||
860 | /* Replace default namespace */ | |||
861 | if (c->default_namespace != NULL((void*)0)) | |||
862 | lwc_string_unref(c->default_namespace){ lwc_string *__lwc_s = (c->default_namespace); ((__lwc_s != ((void*)0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "src/parse/language.c", 862, __extension__ __PRETTY_FUNCTION__ )); __lwc_s->refcnt--; if ((__lwc_s->refcnt == 0) || (( __lwc_s->refcnt == 1) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy(__lwc_s); }; | |||
863 | ||||
864 | /* Special case: if new namespace uri is "", use NULL */ | |||
865 | if (lwc_string_length(uri)({((uri != ((void*)0)) ? (void) (0) : __assert_fail ("uri != NULL" , "src/parse/language.c", 865, __extension__ __PRETTY_FUNCTION__ )); (uri)->len;}) == 0) | |||
866 | c->default_namespace = NULL((void*)0); | |||
867 | else | |||
868 | c->default_namespace = lwc_string_ref(uri)({lwc_string *__lwc_s = (uri); ((__lwc_s != ((void*)0)) ? (void ) (0) : __assert_fail ("__lwc_s != NULL", "src/parse/language.c" , 868, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt ++; __lwc_s;}); | |||
869 | } else { | |||
870 | /* Replace, or add mapping */ | |||
871 | bool_Bool match; | |||
872 | uint32_t idx; | |||
873 | ||||
874 | for (idx = 0; idx < c->num_namespaces; idx++) { | |||
875 | if (lwc_string_isequal(c->namespaces[idx].prefix,((*(&match) = ((c->namespaces[idx].prefix) == (prefix) )), lwc_error_ok) | |||
876 | prefix, &match)((*(&match) = ((c->namespaces[idx].prefix) == (prefix) )), lwc_error_ok) == lwc_error_ok && | |||
877 | match) | |||
878 | break; | |||
879 | } | |||
880 | ||||
881 | if (idx == c->num_namespaces) { | |||
882 | /* Not found, create a new mapping */ | |||
883 | css_namespace *ns = realloc(c->namespaces, | |||
884 | sizeof(css_namespace) * | |||
885 | (c->num_namespaces + 1)); | |||
886 | ||||
887 | if (ns == NULL((void*)0)) | |||
888 | return CSS_NOMEM; | |||
889 | ||||
890 | ns[idx].prefix = lwc_string_ref(prefix)({lwc_string *__lwc_s = (prefix); ((__lwc_s != ((void*)0)) ? ( void) (0) : __assert_fail ("__lwc_s != NULL", "src/parse/language.c" , 890, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt ++; __lwc_s;}); | |||
891 | ns[idx].uri = NULL((void*)0); | |||
892 | ||||
893 | c->namespaces = ns; | |||
894 | c->num_namespaces++; | |||
895 | } | |||
896 | ||||
897 | /* Replace namespace URI */ | |||
898 | if (c->namespaces[idx].uri != NULL((void*)0)) | |||
899 | lwc_string_unref(c->namespaces[idx].uri){ lwc_string *__lwc_s = (c->namespaces[idx].uri); ((__lwc_s != ((void*)0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL" , "src/parse/language.c", 899, __extension__ __PRETTY_FUNCTION__ )); __lwc_s->refcnt--; if ((__lwc_s->refcnt == 0) || (( __lwc_s->refcnt == 1) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy(__lwc_s); }; | |||
900 | ||||
901 | /* Special case: if new namespace uri is "", use NULL */ | |||
902 | if (lwc_string_length(uri)({((uri != ((void*)0)) ? (void) (0) : __assert_fail ("uri != NULL" , "src/parse/language.c", 902, __extension__ __PRETTY_FUNCTION__ )); (uri)->len;}) == 0) | |||
903 | c->namespaces[idx].uri = NULL((void*)0); | |||
904 | else | |||
905 | c->namespaces[idx].uri = lwc_string_ref(uri)({lwc_string *__lwc_s = (uri); ((__lwc_s != ((void*)0)) ? (void ) (0) : __assert_fail ("__lwc_s != NULL", "src/parse/language.c" , 905, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt ++; __lwc_s;}); | |||
906 | } | |||
907 | ||||
908 | return CSS_OK; | |||
909 | } | |||
910 | ||||
911 | /** | |||
912 | * Look up a namespace prefix | |||
913 | * | |||
914 | * \param c Language parser context | |||
915 | * \param prefix Namespace prefix to find, or NULL for none | |||
916 | * \param uri Pointer to location to receive namespace URI | |||
917 | * \return CSS_OK on success, CSS_INVALID if prefix is not found | |||
918 | */ | |||
919 | css_error lookupNamespace(css_language *c, lwc_string *prefix, lwc_string **uri) | |||
920 | { | |||
921 | uint32_t idx; | |||
922 | bool_Bool match; | |||
923 | ||||
924 | if (prefix == NULL((void*)0)) { | |||
925 | *uri = NULL((void*)0); | |||
926 | } else { | |||
927 | for (idx = 0; idx < c->num_namespaces; idx++) { | |||
928 | if (lwc_string_isequal(c->namespaces[idx].prefix,((*(&match) = ((c->namespaces[idx].prefix) == (prefix) )), lwc_error_ok) | |||
929 | prefix, &match)((*(&match) = ((c->namespaces[idx].prefix) == (prefix) )), lwc_error_ok) == lwc_error_ok && | |||
930 | match) | |||
931 | break; | |||
932 | } | |||
933 | ||||
934 | if (idx == c->num_namespaces) | |||
935 | return CSS_INVALID; | |||
936 | ||||
937 | *uri = c->namespaces[idx].uri; | |||
938 | } | |||
939 | ||||
940 | return CSS_OK; | |||
941 | } | |||
942 | ||||
943 | /****************************************************************************** | |||
944 | * Selector list parsing functions * | |||
945 | ******************************************************************************/ | |||
946 | ||||
947 | css_error parseClass(css_language *c, const parserutils_vector *vector, | |||
948 | int32_t *ctx, css_selector_detail *specific) | |||
949 | { | |||
950 | css_qname qname; | |||
951 | css_selector_detail_value detail_value; | |||
952 | const css_token *token; | |||
953 | ||||
954 | /* class -> '.' IDENT */ | |||
955 | token = parserutils_vector_iterate(vector, ctx); | |||
956 | if (token == NULL((void*)0) || tokenIsChar(token, '.') == false0) | |||
957 | return CSS_INVALID; | |||
958 | ||||
959 | token = parserutils_vector_iterate(vector, ctx); | |||
960 | if (token == NULL((void*)0) || token->type != CSS_TOKEN_IDENT) | |||
961 | return CSS_INVALID; | |||
962 | ||||
963 | detail_value.string = NULL((void*)0); | |||
964 | ||||
965 | qname.ns = NULL((void*)0); | |||
966 | qname.name = token->idata; | |||
967 | ||||
968 | /* Ensure lwc insensitive string is available for class names */ | |||
969 | if (qname.name->insensitive == NULL((void*)0) && | |||
970 | lwc__intern_caseless_string(qname.name) != lwc_error_ok) | |||
971 | return CSS_NOMEM; | |||
972 | ||||
973 | return css__stylesheet_selector_detail_init(c->sheet, | |||
974 | CSS_SELECTOR_CLASS, &qname, detail_value, | |||
975 | CSS_SELECTOR_DETAIL_VALUE_STRING, false0, specific); | |||
976 | } | |||
977 | ||||
978 | css_error parseAttrib(css_language *c, const parserutils_vector *vector, | |||
979 | int32_t *ctx, css_selector_detail *specific) | |||
980 | { | |||
981 | css_qname qname; | |||
982 | css_selector_detail_value detail_value; | |||
983 | const css_token *token, *value = NULL((void*)0); | |||
984 | css_selector_type type = CSS_SELECTOR_ATTRIBUTE; | |||
985 | css_error error; | |||
986 | lwc_string *prefix = NULL((void*)0); | |||
987 | ||||
988 | /* attrib -> '[' ws namespace_prefix? IDENT ws [ | |||
989 | * [ '=' | | |||
990 | * INCLUDES | | |||
991 | * DASHMATCH | | |||
992 | * PREFIXMATCH | | |||
993 | * SUFFIXMATCH | | |||
994 | * SUBSTRINGMATCH | |||
995 | * ] ws | |||
996 | * [ IDENT | STRING ] ws ]? ']' | |||
997 | * namespace_prefix -> [ IDENT | '*' ]? '|' | |||
998 | */ | |||
999 | token = parserutils_vector_iterate(vector, ctx); | |||
1000 | if (token == NULL((void*)0) || tokenIsChar(token, '[') == false0) | |||
1001 | return CSS_INVALID; | |||
1002 | ||||
1003 | consumeWhitespace(vector, ctx); | |||
1004 | ||||
1005 | token = parserutils_vector_iterate(vector, ctx); | |||
1006 | if (token == NULL((void*)0) || (token->type != CSS_TOKEN_IDENT && | |||
1007 | tokenIsChar(token, '*') == false0 && | |||
1008 | tokenIsChar(token, '|') == false0)) | |||
1009 | return CSS_INVALID; | |||
1010 | ||||
1011 | if (tokenIsChar(token, '|')) { | |||
1012 | token = parserutils_vector_iterate(vector, ctx); | |||
1013 | } else { | |||
1014 | const css_token *temp; | |||
1015 | ||||
1016 | temp = parserutils_vector_peek(vector, *ctx); | |||
1017 | if (temp != NULL((void*)0) && tokenIsChar(temp, '|')) { | |||
1018 | prefix = token->idata; | |||
1019 | ||||
1020 | parserutils_vector_iterate(vector, ctx); | |||
1021 | ||||
1022 | token = parserutils_vector_iterate(vector, ctx); | |||
1023 | } | |||
1024 | } | |||
1025 | ||||
1026 | if (token == NULL((void*)0) || token->type != CSS_TOKEN_IDENT) | |||
1027 | return CSS_INVALID; | |||
1028 | ||||
1029 | error = lookupNamespace(c, prefix, &qname.ns); | |||
1030 | if (error != CSS_OK) | |||
1031 | return error; | |||
1032 | ||||
1033 | qname.name = token->idata; | |||
1034 | ||||
1035 | consumeWhitespace(vector, ctx); | |||
1036 | ||||
1037 | token = parserutils_vector_iterate(vector, ctx); | |||
1038 | if (token == NULL((void*)0)) | |||
1039 | return CSS_INVALID; | |||
1040 | ||||
1041 | if (tokenIsChar(token, ']') == false0) { | |||
1042 | if (tokenIsChar(token, '=')) | |||
1043 | type = CSS_SELECTOR_ATTRIBUTE_EQUAL; | |||
1044 | else if (token->type == CSS_TOKEN_INCLUDES) | |||
1045 | type = CSS_SELECTOR_ATTRIBUTE_INCLUDES; | |||
1046 | else if (token->type == CSS_TOKEN_DASHMATCH) | |||
1047 | type = CSS_SELECTOR_ATTRIBUTE_DASHMATCH; | |||
1048 | else if (token->type == CSS_TOKEN_PREFIXMATCH) | |||
1049 | type = CSS_SELECTOR_ATTRIBUTE_PREFIX; | |||
1050 | else if (token->type == CSS_TOKEN_SUFFIXMATCH) | |||
1051 | type = CSS_SELECTOR_ATTRIBUTE_SUFFIX; | |||
1052 | else if (token->type == CSS_TOKEN_SUBSTRINGMATCH) | |||
1053 | type = CSS_SELECTOR_ATTRIBUTE_SUBSTRING; | |||
1054 | else | |||
1055 | return CSS_INVALID; | |||
1056 | ||||
1057 | consumeWhitespace(vector, ctx); | |||
1058 | ||||
1059 | token = parserutils_vector_iterate(vector, ctx); | |||
1060 | if (token == NULL((void*)0) || (token->type != CSS_TOKEN_IDENT && | |||
1061 | token->type != CSS_TOKEN_STRING)) | |||
1062 | return CSS_INVALID; | |||
1063 | ||||
1064 | value = token; | |||
1065 | ||||
1066 | consumeWhitespace(vector, ctx); | |||
1067 | ||||
1068 | token = parserutils_vector_iterate(vector, ctx); | |||
1069 | if (token == NULL((void*)0) || tokenIsChar(token, ']') == false0) | |||
1070 | return CSS_INVALID; | |||
1071 | } | |||
1072 | ||||
1073 | detail_value.string = value != NULL((void*)0) ? value->idata : NULL((void*)0); | |||
1074 | ||||
1075 | return css__stylesheet_selector_detail_init(c->sheet, type, | |||
1076 | &qname, detail_value, | |||
1077 | CSS_SELECTOR_DETAIL_VALUE_STRING, false0, specific); | |||
1078 | } | |||
1079 | ||||
1080 | css_error parseNth(css_language *c, | |||
1081 | const parserutils_vector *vector, int32_t *ctx, | |||
1082 | css_selector_detail_value *value) | |||
1083 | { | |||
1084 | const css_token *token; | |||
1085 | bool_Bool match; | |||
1086 | ||||
1087 | /* nth -> [ DIMENSION | IDENT ] ws [ [ CHAR ws ]? NUMBER ws ]? | |||
1088 | * (e.g. DIMENSION: 2n-1, 2n- 1, 2n -1, 2n - 1) | |||
1089 | * (e.g. IDENT: -n-1, -n- 1, -n -1, -n - 1) | |||
1090 | * -> NUMBER ws | |||
1091 | * -> IDENT(odd) ws | |||
1092 | * -> IDENT(even) ws | |||
1093 | */ | |||
1094 | ||||
1095 | token = parserutils_vector_iterate(vector, ctx); | |||
1096 | if (token == NULL((void*)0) || (token->type != CSS_TOKEN_IDENT && | |||
1097 | token->type != CSS_TOKEN_NUMBER && | |||
1098 | token->type != CSS_TOKEN_DIMENSION)) | |||
1099 | return CSS_INVALID; | |||
1100 | ||||
1101 | if (token->type == CSS_TOKEN_IDENT && | |||
1102 | lwc_string_caseless_isequal(token->idata,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (token->idata); lwc_string *__lwc_str2 = (c->strings [ODD]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1 ); } if (__lwc_err == lwc_error_ok && __lwc_str2-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
1103 | c->strings[ODD], &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (token->idata); lwc_string *__lwc_str2 = (c->strings [ODD]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1 ); } if (__lwc_err == lwc_error_ok && __lwc_str2-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) == lwc_error_ok && | |||
1104 | match) { | |||
1105 | /* Odd */ | |||
1106 | value->nth.a = 2; | |||
1107 | value->nth.b = 1; | |||
1108 | } else if (token->type == CSS_TOKEN_IDENT && | |||
1109 | lwc_string_caseless_isequal(token->idata,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (token->idata); lwc_string *__lwc_str2 = (c->strings [EVEN]); _Bool *__lwc_ret = (&match); if (__lwc_str1-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
1110 | c->strings[EVEN], &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (token->idata); lwc_string *__lwc_str2 = (c->strings [EVEN]); _Bool *__lwc_ret = (&match); if (__lwc_str1-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) == lwc_error_ok && | |||
1111 | match) { | |||
1112 | /* Even */ | |||
1113 | value->nth.a = 2; | |||
1114 | value->nth.b = 0; | |||
1115 | } else if (token->type == CSS_TOKEN_NUMBER) { | |||
1116 | size_t consumed = 0; | |||
1117 | css_fixed val = 0; | |||
1118 | ||||
1119 | val = css__number_from_lwc_string(token->idata, | |||
1120 | true1, &consumed); | |||
1121 | if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail ("token->idata != NULL", "src/parse/language.c", 1121, __extension__ __PRETTY_FUNCTION__)); (token->idata)->len;})) | |||
1122 | return CSS_INVALID; | |||
1123 | ||||
1124 | value->nth.a = 0; | |||
1125 | value->nth.b = FIXTOINT(val)((val) >> 10); | |||
1126 | } else { | |||
1127 | /* [ DIMENSION | IDENT ] ws [ [ CHAR ws ]? NUMBER ws ]? | |||
1128 | * | |||
1129 | * (e.g. DIMENSION: 2n-1, 2n- 1, 2n -1, 2n - 1) | |||
1130 | * (e.g. IDENT: n, -n-1, -n- 1, -n -1, -n - 1) | |||
1131 | */ | |||
1132 | size_t consumed = 0, len; | |||
1133 | const char *data; | |||
1134 | css_fixed a = 0, b = 0; | |||
1135 | int sign = 1; | |||
1136 | bool_Bool had_sign = false0, had_b = false0; | |||
1137 | ||||
1138 | len = lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail ("token->idata != NULL", "src/parse/language.c", 1138, __extension__ __PRETTY_FUNCTION__)); (token->idata)->len;}); | |||
1139 | data = lwc_string_data(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail ("token->idata != NULL", "src/parse/language.c", 1139, __extension__ __PRETTY_FUNCTION__)); (const char *)((token->idata)+1);} ); | |||
1140 | ||||
1141 | /* Compute a */ | |||
1142 | if (token->type == CSS_TOKEN_IDENT) { | |||
1143 | if (len < 2) { | |||
1144 | if (data[0] != 'n' && data[0] != 'N') | |||
1145 | return CSS_INVALID; | |||
1146 | ||||
1147 | /* n */ | |||
1148 | a = INTTOFIX(1)(css_int_to_fixed(1)); | |||
1149 | ||||
1150 | data += 1; | |||
1151 | len -= 1; | |||
1152 | } else { | |||
1153 | if (data[0] != '-' || | |||
1154 | (data[1] != 'n' && data[1] != 'N')) | |||
1155 | return CSS_INVALID; | |||
1156 | ||||
1157 | /* -n */ | |||
1158 | a = INTTOFIX(-1)(css_int_to_fixed(-1)); | |||
1159 | ||||
1160 | data += 2; | |||
1161 | len -= 2; | |||
1162 | } | |||
1163 | ||||
1164 | if (len > 0) { | |||
1165 | if (data[0] != '-') | |||
1166 | return CSS_INVALID; | |||
1167 | ||||
1168 | /* -n- */ | |||
1169 | sign = -1; | |||
1170 | had_sign = true1; | |||
1171 | ||||
1172 | if (len > 1) { | |||
1173 | /* Reject additional sign */ | |||
1174 | if (data[1] == '-' || data[1] == '+') | |||
1175 | return CSS_INVALID; | |||
1176 | ||||
1177 | /* -n-b */ | |||
1178 | b = css__number_from_string( | |||
1179 | (const uint8_t *) data + 1, | |||
1180 | len - 1, | |||
1181 | true1, | |||
1182 | &consumed); | |||
1183 | if (consumed != len - 1) | |||
1184 | return CSS_INVALID; | |||
1185 | ||||
1186 | had_b = true1; | |||
1187 | } | |||
1188 | } | |||
1189 | } else { | |||
1190 | /* 2n */ | |||
1191 | a = css__number_from_lwc_string(token->idata, | |||
1192 | true1, &consumed); | |||
1193 | if (consumed == 0 || (data[consumed] != 'n' && | |||
1194 | data[consumed] != 'N')) | |||
1195 | return CSS_INVALID; | |||
1196 | ||||
1197 | if (len - (++consumed) > 0) { | |||
1198 | if (data[consumed] != '-') | |||
1199 | return CSS_INVALID; | |||
1200 | ||||
1201 | /* 2n- */ | |||
1202 | sign = -1; | |||
1203 | had_sign = true1; | |||
1204 | ||||
1205 | if (len - (++consumed) > 0) { | |||
1206 | size_t bstart; | |||
1207 | ||||
1208 | /* Reject additional sign */ | |||
1209 | if (data[consumed] == '-' || | |||
1210 | data[consumed] == '+') | |||
1211 | return CSS_INVALID; | |||
1212 | ||||
1213 | /* 2n-b */ | |||
1214 | bstart = consumed; | |||
1215 | ||||
1216 | b = css__number_from_string( | |||
1217 | (const uint8_t *) data + bstart, | |||
1218 | len - bstart, | |||
1219 | true1, | |||
1220 | &consumed); | |||
1221 | if (consumed != len - bstart) | |||
1222 | return CSS_INVALID; | |||
1223 | ||||
1224 | had_b = true1; | |||
1225 | } | |||
1226 | } | |||
1227 | } | |||
1228 | ||||
1229 | if (had_b == false0) { | |||
1230 | consumeWhitespace(vector, ctx); | |||
1231 | ||||
1232 | /* Look for optional b : [ [ CHAR ws ]? NUMBER ws ]? */ | |||
1233 | token = parserutils_vector_peek(vector, *ctx); | |||
1234 | ||||
1235 | if (had_sign == false0 && token != NULL((void*)0) && | |||
1236 | (tokenIsChar(token, '-') || | |||
1237 | tokenIsChar(token, '+'))) { | |||
1238 | parserutils_vector_iterate(vector, ctx); | |||
1239 | ||||
1240 | had_sign = true1; | |||
1241 | ||||
1242 | if (tokenIsChar(token, '-')) | |||
1243 | sign = -1; | |||
1244 | ||||
1245 | consumeWhitespace(vector, ctx); | |||
1246 | ||||
1247 | token = parserutils_vector_peek(vector, *ctx); | |||
1248 | } | |||
1249 | ||||
1250 | /* Expect NUMBER */ | |||
1251 | if (token != NULL((void*)0) && token->type == CSS_TOKEN_NUMBER) { | |||
1252 | parserutils_vector_iterate(vector, ctx); | |||
1253 | ||||
1254 | /* If we've already seen a sign, ensure one | |||
1255 | * does not occur at the start of this token | |||
1256 | */ | |||
1257 | if (had_sign && lwc_string_length(({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail ("token->idata != NULL", "src/parse/language.c", 1258, __extension__ __PRETTY_FUNCTION__)); (token->idata)->len;}) | |||
1258 | token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail ("token->idata != NULL", "src/parse/language.c", 1258, __extension__ __PRETTY_FUNCTION__)); (token->idata)->len;}) > 0) { | |||
1259 | data = lwc_string_data(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail ("token->idata != NULL", "src/parse/language.c", 1259, __extension__ __PRETTY_FUNCTION__)); (const char *)((token->idata)+1);} ); | |||
1260 | ||||
1261 | if (data[0] == '-' || data[0] == '+') | |||
1262 | return CSS_INVALID; | |||
1263 | } | |||
1264 | ||||
1265 | b = css__number_from_lwc_string(token->idata, | |||
1266 | true1, &consumed); | |||
1267 | if (consumed != lwc_string_length(token->idata)({((token->idata != ((void*)0)) ? (void) (0) : __assert_fail ("token->idata != NULL", "src/parse/language.c", 1267, __extension__ __PRETTY_FUNCTION__)); (token->idata)->len;})) | |||
1268 | return CSS_INVALID; | |||
1269 | } | |||
1270 | } | |||
1271 | ||||
1272 | value->nth.a = FIXTOINT(a)((a) >> 10); | |||
1273 | value->nth.b = FIXTOINT(b)((b) >> 10) * sign; | |||
1274 | } | |||
1275 | ||||
1276 | consumeWhitespace(vector, ctx); | |||
1277 | ||||
1278 | return CSS_OK; | |||
1279 | } | |||
1280 | ||||
1281 | css_error parsePseudo(css_language *c, const parserutils_vector *vector, | |||
1282 | int32_t *ctx, bool_Bool in_not, css_selector_detail *specific) | |||
1283 | { | |||
1284 | static const struct | |||
1285 | { | |||
1286 | int index; | |||
1287 | css_selector_type type; | |||
1288 | } pseudo_lut[] = { | |||
1289 | { FIRST_CHILD, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1290 | { LINK, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1291 | { VISITED, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1292 | { HOVER, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1293 | { ACTIVE, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1294 | { FOCUS, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1295 | { LANG, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1296 | { LEFT, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1297 | { RIGHT, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1298 | { FIRST, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1299 | { ROOT, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1300 | { NTH_CHILD, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1301 | { NTH_LAST_CHILD, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1302 | { NTH_OF_TYPE, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1303 | { NTH_LAST_OF_TYPE, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1304 | { LAST_CHILD, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1305 | { FIRST_OF_TYPE, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1306 | { LAST_OF_TYPE, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1307 | { ONLY_CHILD, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1308 | { ONLY_OF_TYPE, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1309 | { EMPTY, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1310 | { TARGET, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1311 | { ENABLED, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1312 | { DISABLED, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1313 | { CHECKED, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1314 | { NOT, CSS_SELECTOR_PSEUDO_CLASS }, | |||
1315 | ||||
1316 | { FIRST_LINE, CSS_SELECTOR_PSEUDO_ELEMENT }, | |||
1317 | { FIRST_LETTER, CSS_SELECTOR_PSEUDO_ELEMENT }, | |||
1318 | { BEFORE, CSS_SELECTOR_PSEUDO_ELEMENT }, | |||
1319 | { AFTER, CSS_SELECTOR_PSEUDO_ELEMENT } | |||
1320 | }; | |||
1321 | css_selector_detail_value detail_value; | |||
1322 | css_selector_detail_value_type value_type = | |||
1323 | CSS_SELECTOR_DETAIL_VALUE_STRING; | |||
1324 | css_qname qname; | |||
1325 | const css_token *token; | |||
1326 | bool_Bool match = false0, require_element = false0, negate = false0; | |||
1327 | uint32_t lut_idx; | |||
1328 | css_selector_type type = CSS_SELECTOR_PSEUDO_CLASS;/* GCC's braindead */ | |||
1329 | css_error error; | |||
1330 | ||||
1331 | /* pseudo -> ':' ':'? [ IDENT | FUNCTION ws any1 ws ')' ] */ | |||
1332 | ||||
1333 | detail_value.string = NULL((void*)0); | |||
1334 | ||||
1335 | token = parserutils_vector_iterate(vector, ctx); | |||
1336 | if (token == NULL((void*)0) || tokenIsChar(token, ':') == false0) | |||
1337 | return CSS_INVALID; | |||
1338 | ||||
1339 | /* Optional second colon before pseudo element names */ | |||
1340 | token = parserutils_vector_iterate(vector, ctx); | |||
1341 | if (token != NULL((void*)0) && tokenIsChar(token, ':')) { | |||
1342 | /* If present, we require a pseudo element */ | |||
1343 | require_element = true1; | |||
1344 | ||||
1345 | /* Consume subsequent token */ | |||
1346 | token = parserutils_vector_iterate(vector, ctx); | |||
1347 | } | |||
1348 | ||||
1349 | /* Expect IDENT or FUNCTION */ | |||
1350 | if (token == NULL((void*)0) || (token->type != CSS_TOKEN_IDENT && | |||
1351 | token->type != CSS_TOKEN_FUNCTION)) | |||
1352 | return CSS_INVALID; | |||
1353 | ||||
1354 | qname.ns = NULL((void*)0); | |||
1355 | qname.name = token->idata; | |||
1356 | ||||
1357 | /* Search lut for selector type */ | |||
1358 | for (lut_idx = 0; lut_idx < N_ELEMENTS(pseudo_lut)(sizeof((pseudo_lut)) / sizeof((pseudo_lut)[0])); lut_idx++) { | |||
1359 | if ((lwc_string_caseless_isequal(qname.name,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (qname.name); lwc_string *__lwc_str2 = (c->strings[pseudo_lut [lut_idx].index]); _Bool *__lwc_ret = (&match); if (__lwc_str1 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
1360 | c->strings[pseudo_lut[lut_idx].index],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (qname.name); lwc_string *__lwc_str2 = (c->strings[pseudo_lut [lut_idx].index]); _Bool *__lwc_ret = (&match); if (__lwc_str1 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
1361 | &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (qname.name); lwc_string *__lwc_str2 = (c->strings[pseudo_lut [lut_idx].index]); _Bool *__lwc_ret = (&match); if (__lwc_str1 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2 ->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) == lwc_error_ok) && match) { | |||
1362 | type = pseudo_lut[lut_idx].type; | |||
1363 | break; | |||
1364 | } | |||
1365 | } | |||
1366 | ||||
1367 | /* Not found: invalid */ | |||
1368 | if (lut_idx == N_ELEMENTS(pseudo_lut)(sizeof((pseudo_lut)) / sizeof((pseudo_lut)[0]))) | |||
1369 | return CSS_INVALID; | |||
1370 | ||||
1371 | /* Required a pseudo element, but didn't find one: invalid */ | |||
1372 | if (require_element && type != CSS_SELECTOR_PSEUDO_ELEMENT) | |||
1373 | return CSS_INVALID; | |||
1374 | ||||
1375 | /* :not() and pseudo elements are not permitted in :not() */ | |||
1376 | if (in_not && (type == CSS_SELECTOR_PSEUDO_ELEMENT || | |||
1377 | pseudo_lut[lut_idx].index == NOT)) | |||
1378 | return CSS_INVALID; | |||
1379 | ||||
1380 | if (token->type == CSS_TOKEN_FUNCTION) { | |||
1381 | int fun_type = pseudo_lut[lut_idx].index; | |||
1382 | ||||
1383 | consumeWhitespace(vector, ctx); | |||
1384 | ||||
1385 | if (fun_type == LANG) { | |||
1386 | /* IDENT */ | |||
1387 | token = parserutils_vector_iterate(vector, ctx); | |||
1388 | if (token == NULL((void*)0) || token->type != CSS_TOKEN_IDENT) | |||
1389 | return CSS_INVALID; | |||
1390 | ||||
1391 | detail_value.string = token->idata; | |||
1392 | value_type = CSS_SELECTOR_DETAIL_VALUE_STRING; | |||
1393 | ||||
1394 | consumeWhitespace(vector, ctx); | |||
1395 | } else if (fun_type == NTH_CHILD || | |||
1396 | fun_type == NTH_LAST_CHILD || | |||
1397 | fun_type == NTH_OF_TYPE || | |||
1398 | fun_type == NTH_LAST_OF_TYPE) { | |||
1399 | /* an + b */ | |||
1400 | error = parseNth(c, vector, ctx, &detail_value); | |||
1401 | if (error != CSS_OK) | |||
1402 | return error; | |||
1403 | ||||
1404 | value_type = CSS_SELECTOR_DETAIL_VALUE_NTH; | |||
1405 | } else if (fun_type == NOT) { | |||
1406 | /* type_selector | specific */ | |||
1407 | token = parserutils_vector_peek(vector, *ctx); | |||
1408 | if (token == NULL((void*)0)) | |||
1409 | return CSS_INVALID; | |||
1410 | ||||
1411 | if (token->type == CSS_TOKEN_IDENT || | |||
1412 | tokenIsChar(token, '*') || | |||
1413 | tokenIsChar(token, '|')) { | |||
1414 | /* Have type selector */ | |||
1415 | error = parseTypeSelector(c, vector, ctx, | |||
1416 | &qname); | |||
1417 | if (error != CSS_OK) | |||
1418 | return error; | |||
1419 | ||||
1420 | type = CSS_SELECTOR_ELEMENT; | |||
1421 | ||||
1422 | /* Ensure lwc insensitive string is available | |||
1423 | * for element names */ | |||
1424 | if (qname.name->insensitive == NULL((void*)0) && | |||
1425 | lwc__intern_caseless_string( | |||
1426 | qname.name) != lwc_error_ok) | |||
1427 | return CSS_NOMEM; | |||
1428 | ||||
1429 | detail_value.string = NULL((void*)0); | |||
1430 | value_type = CSS_SELECTOR_DETAIL_VALUE_STRING; | |||
1431 | } else { | |||
1432 | /* specific */ | |||
1433 | css_selector_detail det; | |||
1434 | ||||
1435 | error = parseSpecific(c, vector, ctx, true1, | |||
1436 | &det); | |||
1437 | if (error != CSS_OK) | |||
1438 | return error; | |||
1439 | ||||
1440 | qname = det.qname; | |||
1441 | type = det.type; | |||
1442 | detail_value = det.value; | |||
1443 | value_type = det.value_type; | |||
1444 | } | |||
1445 | ||||
1446 | negate = true1; | |||
1447 | ||||
1448 | consumeWhitespace(vector, ctx); | |||
1449 | } | |||
1450 | ||||
1451 | token = parserutils_vector_iterate(vector, ctx); | |||
1452 | if (token == NULL((void*)0) || tokenIsChar(token, ')') == false0) | |||
1453 | return CSS_INVALID; | |||
1454 | } | |||
1455 | ||||
1456 | return css__stylesheet_selector_detail_init(c->sheet, | |||
1457 | type, &qname, detail_value, value_type, | |||
1458 | negate, specific); | |||
1459 | } | |||
1460 | ||||
1461 | css_error parseSpecific(css_language *c, | |||
1462 | const parserutils_vector *vector, int32_t *ctx, | |||
1463 | bool_Bool in_not, css_selector_detail *specific) | |||
1464 | { | |||
1465 | css_error error; | |||
1466 | const css_token *token; | |||
1467 | ||||
1468 | /* specific -> [ HASH | class | attrib | pseudo ] */ | |||
1469 | ||||
1470 | token = parserutils_vector_peek(vector, *ctx); | |||
1471 | if (token == NULL((void*)0)) | |||
1472 | return CSS_INVALID; | |||
1473 | ||||
1474 | if (token->type == CSS_TOKEN_HASH) { | |||
1475 | css_qname qname; | |||
1476 | css_selector_detail_value detail_value; | |||
1477 | ||||
1478 | detail_value.string = NULL((void*)0); | |||
1479 | ||||
1480 | qname.ns = NULL((void*)0); | |||
1481 | qname.name = token->idata; | |||
1482 | ||||
1483 | /* Ensure lwc insensitive string is available for id names */ | |||
1484 | if (qname.name->insensitive == NULL((void*)0) && | |||
1485 | lwc__intern_caseless_string( | |||
1486 | qname.name) != lwc_error_ok) | |||
1487 | return CSS_NOMEM; | |||
1488 | ||||
1489 | error = css__stylesheet_selector_detail_init(c->sheet, | |||
1490 | CSS_SELECTOR_ID, &qname, detail_value, | |||
1491 | CSS_SELECTOR_DETAIL_VALUE_STRING, false0, | |||
1492 | specific); | |||
1493 | if (error != CSS_OK) | |||
1494 | return error; | |||
1495 | ||||
1496 | parserutils_vector_iterate(vector, ctx); | |||
1497 | } else if (tokenIsChar(token, '.')) { | |||
1498 | error = parseClass(c, vector, ctx, specific); | |||
1499 | if (error != CSS_OK) | |||
1500 | return error; | |||
1501 | } else if (tokenIsChar(token, '[')) { | |||
1502 | error = parseAttrib(c, vector, ctx, specific); | |||
1503 | if (error != CSS_OK) | |||
1504 | return error; | |||
1505 | } else if (tokenIsChar(token, ':')) { | |||
1506 | error = parsePseudo(c, vector, ctx, in_not, specific); | |||
1507 | if (error != CSS_OK) | |||
1508 | return error; | |||
1509 | } else { | |||
1510 | return CSS_INVALID; | |||
1511 | } | |||
1512 | ||||
1513 | return CSS_OK; | |||
1514 | } | |||
1515 | ||||
1516 | css_error parseAppendSpecific(css_language *c, | |||
1517 | const parserutils_vector *vector, int32_t *ctx, | |||
1518 | css_selector **parent) | |||
1519 | { | |||
1520 | css_error error; | |||
1521 | css_selector_detail specific; | |||
1522 | ||||
1523 | error = parseSpecific(c, vector, ctx, false0, &specific); | |||
1524 | if (error != CSS_OK) | |||
1525 | return error; | |||
1526 | ||||
1527 | return css__stylesheet_selector_append_specific(c->sheet, parent, | |||
1528 | &specific); | |||
1529 | } | |||
1530 | ||||
1531 | css_error parseSelectorSpecifics(css_language *c, | |||
1532 | const parserutils_vector *vector, int32_t *ctx, | |||
1533 | css_selector **parent) | |||
1534 | { | |||
1535 | css_error error; | |||
1536 | const css_token *token; | |||
1537 | ||||
1538 | /* specifics -> specific* */ | |||
1539 | while ((token = parserutils_vector_peek(vector, *ctx)) != NULL((void*)0) && | |||
1540 | token->type != CSS_TOKEN_S && | |||
1541 | tokenIsChar(token, '+') == false0 && | |||
1542 | tokenIsChar(token, '>') == false0 && | |||
1543 | tokenIsChar(token, '~') == false0 && | |||
1544 | tokenIsChar(token, ',') == false0) { | |||
1545 | error = parseAppendSpecific(c, vector, ctx, parent); | |||
1546 | if (error != CSS_OK) | |||
1547 | return error; | |||
1548 | } | |||
1549 | ||||
1550 | return CSS_OK; | |||
1551 | } | |||
1552 | ||||
1553 | css_error parseTypeSelector(css_language *c, const parserutils_vector *vector, | |||
1554 | int32_t *ctx, css_qname *qname) | |||
1555 | { | |||
1556 | const css_token *token; | |||
1557 | css_error error; | |||
1558 | lwc_string *prefix = NULL((void*)0); | |||
| ||||
1559 | ||||
1560 | /* type_selector -> namespace_prefix? element_name | |||
1561 | * namespace_prefix -> [ IDENT | '*' ]? '|' | |||
1562 | * element_name -> IDENT | '*' | |||
1563 | */ | |||
1564 | ||||
1565 | token = parserutils_vector_peek(vector, *ctx); | |||
1566 | if (token == NULL((void*)0)) | |||
1567 | return CSS_INVALID; | |||
1568 | ||||
1569 | if (tokenIsChar(token, '|') == false0) { | |||
1570 | prefix = token->idata; | |||
1571 | ||||
1572 | parserutils_vector_iterate(vector, ctx); | |||
1573 | ||||
1574 | token = parserutils_vector_peek(vector, *ctx); | |||
1575 | } | |||
1576 | ||||
1577 | if (token
| |||
1578 | /* Have namespace prefix */ | |||
1579 | parserutils_vector_iterate(vector, ctx); | |||
1580 | ||||
1581 | /* Expect element_name */ | |||
1582 | token = parserutils_vector_iterate(vector, ctx); | |||
1583 | ||||
1584 | if (token == NULL((void*)0) || (token->type != CSS_TOKEN_IDENT && | |||
1585 | tokenIsChar(token, '*') == false0)) { | |||
1586 | return CSS_INVALID; | |||
1587 | } | |||
1588 | ||||
1589 | error = lookupNamespace(c, prefix, &qname->ns); | |||
1590 | if (error != CSS_OK) | |||
1591 | return error; | |||
1592 | ||||
1593 | qname->name = token->idata; | |||
1594 | } else { | |||
1595 | /* No namespace prefix */ | |||
1596 | if (c->default_namespace == NULL((void*)0)) { | |||
1597 | qname->ns = c->strings[UNIVERSAL]; | |||
1598 | } else { | |||
1599 | qname->ns = c->default_namespace; | |||
1600 | } | |||
1601 | ||||
1602 | qname->name = prefix; | |||
1603 | } | |||
1604 | ||||
1605 | /* Ensure lwc insensitive string is available for element names */ | |||
1606 | if (qname->name->insensitive == NULL((void*)0) && | |||
| ||||
1607 | lwc__intern_caseless_string( | |||
1608 | qname->name) != lwc_error_ok) | |||
1609 | return CSS_NOMEM; | |||
1610 | ||||
1611 | return CSS_OK; | |||
1612 | } | |||
1613 | ||||
1614 | css_error parseSimpleSelector(css_language *c, | |||
1615 | const parserutils_vector *vector, int32_t *ctx, | |||
1616 | css_selector **result) | |||
1617 | { | |||
1618 | int32_t orig_ctx = *ctx; | |||
1619 | css_error error; | |||
1620 | const css_token *token; | |||
1621 | css_selector *selector; | |||
1622 | css_qname qname; | |||
1623 | ||||
1624 | /* simple_selector -> type_selector specifics | |||
1625 | * -> specific specifics | |||
1626 | */ | |||
1627 | ||||
1628 | token = parserutils_vector_peek(vector, *ctx); | |||
1629 | if (token == NULL((void*)0)) | |||
1630 | return CSS_INVALID; | |||
1631 | ||||
1632 | if (token->type == CSS_TOKEN_IDENT || tokenIsChar(token, '*') || | |||
1633 | tokenIsChar(token, '|')) { | |||
1634 | /* Have type selector */ | |||
1635 | error = parseTypeSelector(c, vector, ctx, &qname); | |||
1636 | if (error != CSS_OK) { | |||
1637 | *ctx = orig_ctx; | |||
1638 | return error; | |||
1639 | } | |||
1640 | ||||
1641 | error = css__stylesheet_selector_create(c->sheet, | |||
1642 | &qname, &selector); | |||
1643 | if (error != CSS_OK) { | |||
1644 | *ctx = orig_ctx; | |||
1645 | return error; | |||
1646 | } | |||
1647 | } else { | |||
1648 | /* Universal selector */ | |||
1649 | if (c->default_namespace == NULL((void*)0)) | |||
1650 | qname.ns = c->strings[UNIVERSAL]; | |||
1651 | else | |||
1652 | qname.ns = c->default_namespace; | |||
1653 | ||||
1654 | qname.name = c->strings[UNIVERSAL]; | |||
1655 | ||||
1656 | error = css__stylesheet_selector_create(c->sheet, | |||
1657 | &qname, &selector); | |||
1658 | if (error != CSS_OK) | |||
1659 | return error; | |||
1660 | ||||
1661 | /* Ensure we have at least one specific selector */ | |||
1662 | error = parseAppendSpecific(c, vector, ctx, &selector); | |||
1663 | if (error != CSS_OK) { | |||
1664 | css__stylesheet_selector_destroy(c->sheet, selector); | |||
1665 | return error; | |||
1666 | } | |||
1667 | } | |||
1668 | ||||
1669 | error = parseSelectorSpecifics(c, vector, ctx, &selector); | |||
1670 | if (error != CSS_OK) { | |||
1671 | css__stylesheet_selector_destroy(c->sheet, selector); | |||
1672 | return error; | |||
1673 | } | |||
1674 | ||||
1675 | *result = selector; | |||
1676 | ||||
1677 | return CSS_OK; | |||
1678 | } | |||
1679 | ||||
1680 | css_error parseCombinator(css_language *c, const parserutils_vector *vector, | |||
1681 | int32_t *ctx, css_combinator *result) | |||
1682 | { | |||
1683 | const css_token *token; | |||
1684 | css_combinator comb = CSS_COMBINATOR_NONE; | |||
1685 | ||||
1686 | /* combinator -> ws '+' ws | ws '>' ws | ws '~' ws | ws1 */ | |||
1687 | ||||
1688 | UNUSED(c)((void)(c)); | |||
1689 | ||||
1690 | while ((token = parserutils_vector_peek(vector, *ctx)) != NULL((void*)0)) { | |||
1691 | if (tokenIsChar(token, '+')) | |||
1692 | comb = CSS_COMBINATOR_SIBLING; | |||
1693 | else if (tokenIsChar(token, '>')) | |||
1694 | comb = CSS_COMBINATOR_PARENT; | |||
1695 | else if (tokenIsChar(token, '~')) | |||
1696 | comb = CSS_COMBINATOR_GENERIC_SIBLING; | |||
1697 | else if (token->type == CSS_TOKEN_S) | |||
1698 | comb = CSS_COMBINATOR_ANCESTOR; | |||
1699 | else | |||
1700 | break; | |||
1701 | ||||
1702 | parserutils_vector_iterate(vector, ctx); | |||
1703 | ||||
1704 | /* If we've seen a '+', '>', or '~', we're done. */ | |||
1705 | if (comb != CSS_COMBINATOR_ANCESTOR) | |||
1706 | break; | |||
1707 | } | |||
1708 | ||||
1709 | /* No valid combinator found */ | |||
1710 | if (comb == CSS_COMBINATOR_NONE) | |||
1711 | return CSS_INVALID; | |||
1712 | ||||
1713 | /* Consume any trailing whitespace */ | |||
1714 | consumeWhitespace(vector, ctx); | |||
1715 | ||||
1716 | *result = comb; | |||
1717 | ||||
1718 | return CSS_OK; | |||
1719 | } | |||
1720 | ||||
1721 | css_error parseSelector(css_language *c, const parserutils_vector *vector, | |||
1722 | int32_t *ctx, css_selector **result) | |||
1723 | { | |||
1724 | css_error error; | |||
1725 | const css_token *token = NULL((void*)0); | |||
1726 | css_selector *selector = NULL((void*)0); | |||
1727 | ||||
1728 | /* selector -> simple_selector [ combinator simple_selector ]* ws | |||
1729 | * | |||
1730 | * Note, however, that, as combinator can be wholly whitespace, | |||
1731 | * there's an ambiguity as to whether "ws" has been reached. We | |||
1732 | * resolve this by attempting to extract a combinator, then | |||
1733 | * recovering when we detect that we've reached the end of the | |||
1734 | * selector. | |||
1735 | */ | |||
1736 | ||||
1737 | error = parseSimpleSelector(c, vector, ctx, &selector); | |||
1738 | if (error != CSS_OK) | |||
1739 | return error; | |||
1740 | *result = selector; | |||
1741 | ||||
1742 | while ((token = parserutils_vector_peek(vector, *ctx)) != NULL((void*)0) && | |||
1743 | tokenIsChar(token, ',') == false0) { | |||
1744 | css_combinator comb = CSS_COMBINATOR_NONE; | |||
1745 | css_selector *other = NULL((void*)0); | |||
1746 | ||||
1747 | error = parseCombinator(c, vector, ctx, &comb); | |||
1748 | if (error != CSS_OK) | |||
1749 | return error; | |||
1750 | ||||
1751 | /* In the case of "html , body { ... }", the whitespace after | |||
1752 | * "html" and "body" will be considered an ancestor combinator. | |||
1753 | * This clearly is not the case, however. Therefore, as a | |||
1754 | * special case, if we've got an ancestor combinator and there | |||
1755 | * are no further tokens, or if the next token is a comma, | |||
1756 | * we ignore the supposed combinator and continue. */ | |||
1757 | if (comb == CSS_COMBINATOR_ANCESTOR && | |||
1758 | ((token = parserutils_vector_peek(vector, | |||
1759 | *ctx)) == NULL((void*)0) || | |||
1760 | tokenIsChar(token, ','))) | |||
1761 | continue; | |||
1762 | ||||
1763 | error = parseSimpleSelector(c, vector, ctx, &other); | |||
1764 | if (error != CSS_OK) | |||
1765 | return error; | |||
1766 | ||||
1767 | *result = other; | |||
1768 | ||||
1769 | error = css__stylesheet_selector_combine(c->sheet, | |||
1770 | comb, selector, other); | |||
1771 | if (error != CSS_OK) { | |||
1772 | css__stylesheet_selector_destroy(c->sheet, selector); | |||
1773 | return error; | |||
1774 | } | |||
1775 | ||||
1776 | selector = other; | |||
1777 | } | |||
1778 | ||||
1779 | return CSS_OK; | |||
1780 | } | |||
1781 | ||||
1782 | css_error parseSelectorList(css_language *c, const parserutils_vector *vector, | |||
1783 | css_rule *rule) | |||
1784 | { | |||
1785 | css_error error; | |||
1786 | const css_token *token = NULL((void*)0); | |||
1787 | css_selector *selector = NULL((void*)0); | |||
1788 | int32_t ctx = 0; | |||
1789 | ||||
1790 | /* Strip any leading whitespace (can happen if in nested block) */ | |||
1791 | consumeWhitespace(vector, &ctx); | |||
1792 | ||||
1793 | /* selector_list -> selector [ ',' ws selector ]* */ | |||
1794 | ||||
1795 | error = parseSelector(c, vector, &ctx, &selector); | |||
1796 | if (error != CSS_OK) { | |||
1797 | if (selector != NULL((void*)0)) | |||
1798 | css__stylesheet_selector_destroy(c->sheet, selector); | |||
1799 | return error; | |||
1800 | } | |||
1801 | ||||
1802 | assert(selector != NULL)((selector != ((void*)0)) ? (void) (0) : __assert_fail ("selector != NULL" , "src/parse/language.c", 1802, __extension__ __PRETTY_FUNCTION__ )); | |||
1803 | ||||
1804 | error = css__stylesheet_rule_add_selector(c->sheet, rule, selector); | |||
1805 | if (error != CSS_OK) { | |||
1806 | css__stylesheet_selector_destroy(c->sheet, selector); | |||
1807 | return error; | |||
1808 | } | |||
1809 | ||||
1810 | while (parserutils_vector_peek(vector, ctx) != NULL((void*)0)) { | |||
1811 | token = parserutils_vector_iterate(vector, &ctx); | |||
1812 | if (tokenIsChar(token, ',') == false0) | |||
1813 | return CSS_INVALID; | |||
1814 | ||||
1815 | consumeWhitespace(vector, &ctx); | |||
1816 | ||||
1817 | selector = NULL((void*)0); | |||
1818 | ||||
1819 | error = parseSelector(c, vector, &ctx, &selector); | |||
1820 | if (error != CSS_OK) { | |||
1821 | if (selector != NULL((void*)0)) { | |||
1822 | css__stylesheet_selector_destroy(c->sheet, | |||
1823 | selector); | |||
1824 | } | |||
1825 | return error; | |||
1826 | } | |||
1827 | ||||
1828 | assert(selector != NULL)((selector != ((void*)0)) ? (void) (0) : __assert_fail ("selector != NULL" , "src/parse/language.c", 1828, __extension__ __PRETTY_FUNCTION__ )); | |||
1829 | ||||
1830 | error = css__stylesheet_rule_add_selector(c->sheet, rule, | |||
1831 | selector); | |||
1832 | if (error != CSS_OK) { | |||
1833 | css__stylesheet_selector_destroy(c->sheet, selector); | |||
1834 | return error; | |||
1835 | } | |||
1836 | } | |||
1837 | ||||
1838 | return CSS_OK; | |||
1839 | } | |||
1840 | ||||
1841 | /****************************************************************************** | |||
1842 | * Property parsing functions * | |||
1843 | ******************************************************************************/ | |||
1844 | ||||
1845 | css_error parseProperty(css_language *c, const css_token *property, | |||
1846 | const parserutils_vector *vector, int32_t *ctx, css_rule *rule) | |||
1847 | { | |||
1848 | css_error error; | |||
1849 | css_prop_handler handler = NULL((void*)0); | |||
1850 | int i = 0; | |||
1851 | uint8_t flags = 0; | |||
1852 | css_style *style = NULL((void*)0); | |||
1853 | const css_token *token; | |||
1854 | ||||
1855 | /* Find property index */ | |||
1856 | /** \todo improve on this linear search */ | |||
1857 | for (i = FIRST_PROP; i <= LAST_PROP; i++) { | |||
1858 | bool_Bool match = false0; | |||
1859 | ||||
1860 | if (lwc_string_caseless_isequal(property->idata, c->strings[i],({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (property->idata); lwc_string *__lwc_str2 = (c->strings [i]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1 ); } if (__lwc_err == lwc_error_ok && __lwc_str2-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
1861 | &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (property->idata); lwc_string *__lwc_str2 = (c->strings [i]); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1 ); } if (__lwc_err == lwc_error_ok && __lwc_str2-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) == lwc_error_ok && match) | |||
1862 | break; | |||
1863 | } | |||
1864 | if (i == LAST_PROP + 1) | |||
1865 | return CSS_INVALID; | |||
1866 | ||||
1867 | /* Get handler */ | |||
1868 | handler = property_handlers[i - FIRST_PROP]; | |||
1869 | assert(handler != NULL)((handler != ((void*)0)) ? (void) (0) : __assert_fail ("handler != NULL" , "src/parse/language.c", 1869, __extension__ __PRETTY_FUNCTION__ )); | |||
1870 | ||||
1871 | /* allocate style */ | |||
1872 | error = css__stylesheet_style_create(c->sheet, &style); | |||
1873 | if (error != CSS_OK) | |||
1874 | return error; | |||
1875 | ||||
1876 | assert (style != NULL)((style != ((void*)0)) ? (void) (0) : __assert_fail ("style != NULL" , "src/parse/language.c", 1876, __extension__ __PRETTY_FUNCTION__ )); | |||
1877 | ||||
1878 | /* Call the handler */ | |||
1879 | error = handler(c, vector, ctx, style); | |||
1880 | if (error != CSS_OK) { | |||
1881 | css__stylesheet_style_destroy(style); | |||
1882 | return error; | |||
1883 | } | |||
1884 | ||||
1885 | /* Determine if this declaration is important or not */ | |||
1886 | error = css__parse_important(c, vector, ctx, &flags); | |||
1887 | if (error != CSS_OK) { | |||
1888 | css__stylesheet_style_destroy(style); | |||
1889 | return error; | |||
1890 | } | |||
1891 | ||||
1892 | /* Ensure that we've exhausted all the input */ | |||
1893 | consumeWhitespace(vector, ctx); | |||
1894 | token = parserutils_vector_iterate(vector, ctx); | |||
1895 | if (token != NULL((void*)0)) { | |||
1896 | /* Trailing junk, so discard declaration */ | |||
1897 | css__stylesheet_style_destroy(style); | |||
1898 | return CSS_INVALID; | |||
1899 | } | |||
1900 | ||||
1901 | /* If it's important, then mark the style appropriately */ | |||
1902 | if (flags != 0) | |||
1903 | css__make_style_important(style); | |||
1904 | ||||
1905 | /* Append style to rule */ | |||
1906 | error = css__stylesheet_rule_append_style(c->sheet, rule, style); | |||
1907 | if (error != CSS_OK) { | |||
1908 | css__stylesheet_style_destroy(style); | |||
1909 | return error; | |||
1910 | } | |||
1911 | ||||
1912 | /* Style owned or destroyed by stylesheet, so forget about it */ | |||
1913 | ||||
1914 | return CSS_OK; | |||
1915 | } | |||
1916 |