Bug Summary

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')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name language.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-libcss -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -D _BSD_SOURCE -D _DEFAULT_SOURCE -I /var/lib/jenkins/workspace/scan-build-libcss/include/ -I /var/lib/jenkins/workspace/scan-build-libcss/src -D _ALIGNED=__attribute__((aligned)) -D STMTEXPR=1 -D DEBUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Og -Wwrite-strings -Wno-error -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-libcss -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-libcss/clangScanBuildReports/2024-12-27-083052-3296037-1 -x c src/parse/language.c
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
27typedef struct context_entry {
28 css_parser_event type; /**< Type of entry */
29 void *data; /**< Data for context */
30} context_entry;
31
32/* Event handlers */
33static css_error language_handle_event(css_parser_event type,
34 const parserutils_vector *tokens, void *pw);
35static css_error handleStartStylesheet(css_language *c,
36 const parserutils_vector *vector);
37static css_error handleEndStylesheet(css_language *c,
38 const parserutils_vector *vector);
39static css_error handleStartRuleset(css_language *c,
40 const parserutils_vector *vector);
41static css_error handleEndRuleset(css_language *c,
42 const parserutils_vector *vector);
43static css_error handleStartAtRule(css_language *c,
44 const parserutils_vector *vector);
45static css_error handleEndAtRule(css_language *c,
46 const parserutils_vector *vector);
47static css_error handleStartBlock(css_language *c,
48 const parserutils_vector *vector);
49static css_error handleEndBlock(css_language *c,
50 const parserutils_vector *vector);
51static css_error handleBlockContent(css_language *c,
52 const parserutils_vector *vector);
53static css_error handleEndBlockContent(css_language *c,
54 const parserutils_vector *vector);
55static css_error handleDeclaration(css_language *c,
56 const parserutils_vector *vector);
57
58/* At-rule parsing */
59static css_error addNamespace(css_language *c,
60 lwc_string *prefix, lwc_string *uri);
61static css_error lookupNamespace(css_language *c,
62 lwc_string *prefix, lwc_string **uri);
63
64/* Selector list parsing */
65static css_error parseClass(css_language *c,
66 const parserutils_vector *vector, int32_t *ctx,
67 css_selector_detail *specific);
68static css_error parseAttrib(css_language *c,
69 const parserutils_vector *vector, int32_t *ctx,
70 css_selector_detail *specific);
71static css_error parseNth(css_language *c,
72 const parserutils_vector *vector, int32_t *ctx,
73 css_selector_detail_value *value);
74static css_error parsePseudo(css_language *c,
75 const parserutils_vector *vector, int32_t *ctx,
76 bool_Bool in_not, css_selector_detail *specific);
77static css_error parseSpecific(css_language *c,
78 const parserutils_vector *vector, int32_t *ctx,
79 bool_Bool in_not, css_selector_detail *specific);
80static css_error parseAppendSpecific(css_language *c,
81 const parserutils_vector *vector, int32_t *ctx,
82 css_selector **parent);
83static css_error parseSelectorSpecifics(css_language *c,
84 const parserutils_vector *vector, int32_t *ctx,
85 css_selector **parent);
86static css_error parseTypeSelector(css_language *c,
87 const parserutils_vector *vector, int32_t *ctx,
88 css_qname *qname);
89static css_error parseSimpleSelector(css_language *c,
90 const parserutils_vector *vector, int32_t *ctx,
91 css_selector **result);
92static css_error parseCombinator(css_language *c,
93 const parserutils_vector *vector, int32_t *ctx,
94 css_combinator *result);
95static css_error parseSelector(css_language *c,
96 const parserutils_vector *vector, int32_t *ctx,
97 css_selector **result);
98static css_error parseSelectorList(css_language *c,
99 const parserutils_vector *vector, css_rule *rule);
100
101/* Declaration parsing */
102static 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 */
116css_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, &params);
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 */
165css_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 */
200css_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
237css_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
255css_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
276css_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
329css_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
350css_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
652css_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
673css_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
696css_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
724css_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
755css_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
789css_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 */
857css_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 */
919css_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
947css_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
978css_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
1080css_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
1281css_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
1461css_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
1516css_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
1531css_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
1553css_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);
1
'prefix' initialized to a null pointer value
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))
2
Assuming 'token' is not equal to NULL
3
Taking false branch
1567 return CSS_INVALID;
1568
1569 if (tokenIsChar(token, '|') == false0) {
4
Assuming the condition is false
1570 prefix = token->idata;
1571
1572 parserutils_vector_iterate(vector, ctx);
1573
1574 token = parserutils_vector_peek(vector, *ctx);
1575 }
1576
1577 if (token
4.1
'token' is not equal to NULL
!= NULL((void*)0) && tokenIsChar(token, '|')) {
5
Assuming the condition is false
6
Taking false branch
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)) {
7
Assuming field 'default_namespace' is not equal to NULL
8
Taking false branch
1597 qname->ns = c->strings[UNIVERSAL];
1598 } else {
1599 qname->ns = c->default_namespace;
1600 }
1601
1602 qname->name = prefix;
9
Null pointer value stored to field 'name'
1603 }
1604
1605 /* Ensure lwc insensitive string is available for element names */
1606 if (qname->name->insensitive == NULL((void*)0) &&
10
Access to field 'insensitive' results in a dereference of a null pointer (loaded from field 'name')
1607 lwc__intern_caseless_string(
1608 qname->name) != lwc_error_ok)
1609 return CSS_NOMEM;
1610
1611 return CSS_OK;
1612}
1613
1614css_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
1680css_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
1721css_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
1782css_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
1845css_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