Bug Summary

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