Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7639 views
1
#include "mupdf/html.h"
2
3
struct lexbuf
4
{
5
fz_context *ctx;
6
const char *s;
7
const char *file;
8
int line;
9
int lookahead;
10
int c;
11
int color;
12
int string_len;
13
char string[1024];
14
};
15
16
FZ_NORETURN static void fz_css_error(struct lexbuf *buf, const char *msg)
17
{
18
fz_throw(buf->ctx, FZ_ERROR_SYNTAX, "css syntax error: %s (%s:%d)", msg, buf->file, buf->line);
19
}
20
21
static fz_css_rule *fz_new_css_rule(fz_context *ctx, fz_css_selector *selector, fz_css_property *declaration)
22
{
23
fz_css_rule *rule = fz_malloc_struct(ctx, fz_css_rule);
24
rule->selector = selector;
25
rule->declaration = declaration;
26
rule->garbage = NULL;
27
rule->next = NULL;
28
return rule;
29
}
30
31
static fz_css_selector *fz_new_css_selector(fz_context *ctx, const char *name)
32
{
33
fz_css_selector *sel = fz_malloc_struct(ctx, fz_css_selector);
34
sel->name = name ? fz_strdup(ctx, name) : NULL;
35
sel->combine = 0;
36
sel->cond = NULL;
37
sel->left = NULL;
38
sel->right = NULL;
39
sel->next = NULL;
40
return sel;
41
}
42
43
static fz_css_condition *fz_new_css_condition(fz_context *ctx, int type, const char *key, const char *val)
44
{
45
fz_css_condition *cond = fz_malloc_struct(ctx, fz_css_condition);
46
cond->type = type;
47
cond->key = key ? fz_strdup(ctx, key) : NULL;
48
cond->val = val ? fz_strdup(ctx, val) : NULL;
49
cond->next = NULL;
50
return cond;
51
}
52
53
static fz_css_property *fz_new_css_property(fz_context *ctx, const char *name, fz_css_value *value, int spec)
54
{
55
fz_css_property *prop = fz_malloc_struct(ctx, fz_css_property);
56
prop->name = fz_strdup(ctx, name);
57
prop->value = value;
58
prop->spec = spec;
59
prop->next = NULL;
60
return prop;
61
}
62
63
static fz_css_value *fz_new_css_value(fz_context *ctx, int type, const char *data)
64
{
65
fz_css_value *val = fz_malloc_struct(ctx, fz_css_value);
66
val->type = type;
67
val->data = fz_strdup(ctx, data);
68
val->args = NULL;
69
val->next = NULL;
70
return val;
71
}
72
73
static void fz_drop_css_value(fz_context *ctx, fz_css_value *val)
74
{
75
while (val)
76
{
77
fz_css_value *next = val->next;
78
fz_drop_css_value(ctx, val->args);
79
fz_free(ctx, val->data);
80
fz_free(ctx, val);
81
val = next;
82
}
83
}
84
85
static void fz_drop_css_condition(fz_context *ctx, fz_css_condition *cond)
86
{
87
while (cond)
88
{
89
fz_css_condition *next = cond->next;
90
fz_free(ctx, cond->key);
91
fz_free(ctx, cond->val);
92
fz_free(ctx, cond);
93
cond = next;
94
}
95
}
96
97
static void fz_drop_css_selector(fz_context *ctx, fz_css_selector *sel)
98
{
99
while (sel)
100
{
101
fz_css_selector *next = sel->next;
102
fz_free(ctx, sel->name);
103
fz_drop_css_condition(ctx, sel->cond);
104
fz_drop_css_selector(ctx, sel->left);
105
fz_drop_css_selector(ctx, sel->right);
106
fz_free(ctx, sel);
107
sel = next;
108
}
109
}
110
111
static void fz_drop_css_property(fz_context *ctx, fz_css_property *prop)
112
{
113
while (prop)
114
{
115
fz_css_property *next = prop->next;
116
fz_free(ctx, prop->name);
117
fz_drop_css_value(ctx, prop->value);
118
fz_free(ctx, prop);
119
prop = next;
120
}
121
}
122
123
void fz_drop_css(fz_context *ctx, fz_css_rule *rule)
124
{
125
while (rule)
126
{
127
fz_css_rule *next = rule->next;
128
fz_drop_css_selector(ctx, rule->selector);
129
fz_drop_css_property(ctx, rule->declaration);
130
fz_drop_css_property(ctx, rule->garbage);
131
fz_free(ctx, rule);
132
rule = next;
133
}
134
}
135
136
static void css_lex_next(struct lexbuf *buf)
137
{
138
buf->c = *(buf->s++);
139
if (buf->c == '\n')
140
++buf->line;
141
}
142
143
static void css_lex_init(fz_context *ctx, struct lexbuf *buf, const char *s, const char *file)
144
{
145
buf->ctx = ctx;
146
buf->s = s;
147
buf->c = 0;
148
buf->file = file;
149
buf->line = 1;
150
css_lex_next(buf);
151
152
buf->color = 0;
153
buf->string_len = 0;
154
}
155
156
static int iswhite(int c)
157
{
158
return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f';
159
}
160
161
static int isnmstart(int c)
162
{
163
return c == '\\' || c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
164
(c >= 128 && c <= 255);
165
}
166
167
static int isnmchar(int c)
168
{
169
return c == '\\' || c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
170
(c >= '0' && c <= '9') || c == '-' || (c >= 128 && c <= 255);
171
}
172
173
static void css_push_char(struct lexbuf *buf, int c)
174
{
175
if (buf->string_len + 1 >= nelem(buf->string))
176
fz_css_error(buf, "token too long");
177
buf->string[buf->string_len++] = c;
178
}
179
180
static int css_lex_accept(struct lexbuf *buf, int t)
181
{
182
if (buf->c == t)
183
{
184
css_lex_next(buf);
185
return 1;
186
}
187
return 0;
188
}
189
190
static void css_lex_expect(struct lexbuf *buf, int t)
191
{
192
if (!css_lex_accept(buf, t))
193
fz_css_error(buf, "unexpected character");
194
}
195
196
static int ishex(int c, int *v)
197
{
198
if (c >= '0' && c <= '9')
199
{
200
*v = c - '0';
201
return 1;
202
}
203
if (c >= 'A' && c <= 'F')
204
{
205
*v = c - 'A' + 0xA;
206
return 1;
207
}
208
if (c >= 'a' && c <= 'f')
209
{
210
*v = c - 'a' + 0xA;
211
return 1;
212
}
213
return 0;
214
}
215
216
static int css_lex_accept_hex(struct lexbuf *buf, int *v)
217
{
218
if (ishex(buf->c, v))
219
{
220
css_lex_next(buf);
221
return 1;
222
}
223
return 0;
224
}
225
226
static int css_lex_number(struct lexbuf *buf)
227
{
228
while (buf->c >= '0' && buf->c <= '9')
229
{
230
css_push_char(buf, buf->c);
231
css_lex_next(buf);
232
}
233
234
if (css_lex_accept(buf, '.'))
235
{
236
css_push_char(buf, '.');
237
while (buf->c >= '0' && buf->c <= '9')
238
{
239
css_push_char(buf, buf->c);
240
css_lex_next(buf);
241
}
242
}
243
244
if (css_lex_accept(buf, '%'))
245
{
246
css_push_char(buf, '%');
247
css_push_char(buf, 0);
248
return CSS_PERCENT;
249
}
250
251
if (isnmstart(buf->c))
252
{
253
css_push_char(buf, buf->c);
254
css_lex_next(buf);
255
while (isnmchar(buf->c))
256
{
257
css_push_char(buf, buf->c);
258
css_lex_next(buf);
259
}
260
css_push_char(buf, 0);
261
return CSS_LENGTH;
262
}
263
264
css_push_char(buf, 0);
265
return CSS_NUMBER;
266
}
267
268
static int css_lex_keyword(struct lexbuf *buf)
269
{
270
while (isnmchar(buf->c))
271
{
272
css_push_char(buf, buf->c);
273
css_lex_next(buf);
274
}
275
css_push_char(buf, 0);
276
return CSS_KEYWORD;
277
}
278
279
static int css_lex_string(struct lexbuf *buf, int q)
280
{
281
while (buf->c && buf->c != q)
282
{
283
if (css_lex_accept(buf, '\\'))
284
{
285
if (css_lex_accept(buf, 'n'))
286
css_push_char(buf, '\n');
287
else if (css_lex_accept(buf, 'r'))
288
css_push_char(buf, '\r');
289
else if (css_lex_accept(buf, 'f'))
290
css_push_char(buf, '\f');
291
else if (css_lex_accept(buf, '\f'))
292
/* line continuation */ ;
293
else if (css_lex_accept(buf, '\n'))
294
/* line continuation */ ;
295
else if (css_lex_accept(buf, '\r'))
296
css_lex_accept(buf, '\n');
297
else
298
{
299
css_push_char(buf, buf->c);
300
css_lex_next(buf);
301
}
302
}
303
else
304
{
305
css_push_char(buf, buf->c);
306
css_lex_next(buf);
307
}
308
}
309
css_lex_expect(buf, q);
310
css_push_char(buf, 0);
311
return CSS_STRING;
312
}
313
314
static void css_lex_uri(struct lexbuf *buf)
315
{
316
while (buf->c && buf->c != ')' && !iswhite(buf->c))
317
{
318
if (css_lex_accept(buf, '\\'))
319
{
320
if (css_lex_accept(buf, 'n'))
321
css_push_char(buf, '\n');
322
else if (css_lex_accept(buf, 'r'))
323
css_push_char(buf, '\r');
324
else if (css_lex_accept(buf, 'f'))
325
css_push_char(buf, '\f');
326
else
327
{
328
css_push_char(buf, buf->c);
329
css_lex_next(buf);
330
}
331
}
332
else if (buf->c == '!' || buf->c == '#' || buf->c == '$' || buf->c == '%' || buf->c == '&' ||
333
(buf->c >= '*' && buf->c <= '[') ||
334
(buf->c >= ']' && buf->c <= '~') ||
335
buf->c > 159)
336
{
337
css_push_char(buf, buf->c);
338
css_lex_next(buf);
339
}
340
else
341
fz_css_error(buf, "unexpected character in url");
342
}
343
css_push_char(buf, 0);
344
}
345
346
static int css_lex(struct lexbuf *buf)
347
{
348
int t;
349
350
// TODO: keyword escape sequences
351
352
buf->string_len = 0;
353
354
while (buf->c)
355
{
356
restart:
357
while (iswhite(buf->c))
358
css_lex_next(buf);
359
360
if (buf->c == 0)
361
break;
362
363
if (css_lex_accept(buf, '/'))
364
{
365
if (css_lex_accept(buf, '*'))
366
{
367
while (buf->c)
368
{
369
if (css_lex_accept(buf, '*'))
370
{
371
while (buf->c == '*')
372
css_lex_next(buf);
373
if (css_lex_accept(buf, '/'))
374
goto restart;
375
}
376
css_lex_next(buf);
377
}
378
fz_css_error(buf, "unterminated comment");
379
}
380
return '/';
381
}
382
383
if (css_lex_accept(buf, '<'))
384
{
385
if (css_lex_accept(buf, '!'))
386
{
387
css_lex_expect(buf, '-');
388
css_lex_expect(buf, '-');
389
continue; /* ignore CDO */
390
}
391
return '<';
392
}
393
394
if (css_lex_accept(buf, '-'))
395
{
396
if (css_lex_accept(buf, '-'))
397
{
398
css_lex_expect(buf, '>');
399
continue; /* ignore CDC */
400
}
401
if (buf->c >= '0' && buf->c <= '9')
402
{
403
css_push_char(buf, '-');
404
return css_lex_number(buf);
405
}
406
if (isnmstart(buf->c))
407
{
408
css_push_char(buf, '-');
409
css_push_char(buf, buf->c);
410
css_lex_next(buf);
411
return css_lex_keyword(buf);
412
}
413
return '-';
414
}
415
416
if (css_lex_accept(buf, '+'))
417
{
418
if (buf->c >= '0' && buf->c <= '9')
419
return css_lex_number(buf);
420
return '+';
421
}
422
423
if (css_lex_accept(buf, '.'))
424
{
425
if (buf->c >= '0' && buf->c <= '9')
426
{
427
css_push_char(buf, '.');
428
return css_lex_number(buf);
429
}
430
return '.';
431
}
432
433
if (css_lex_accept(buf, '#'))
434
{
435
int a, b, c, d, e, f;
436
if (!css_lex_accept_hex(buf, &a)) goto colorerror;
437
if (!css_lex_accept_hex(buf, &b)) goto colorerror;
438
if (!css_lex_accept_hex(buf, &c)) goto colorerror;
439
if (css_lex_accept_hex(buf, &d))
440
{
441
if (!css_lex_accept_hex(buf, &e)) goto colorerror;
442
if (!css_lex_accept_hex(buf, &f)) goto colorerror;
443
buf->color = (a << 20) | (b << 16) | (c << 12) | (d << 8) | (e << 4) | f;
444
}
445
else
446
{
447
buf->color = (a << 20) | (b << 12) | (c << 4);
448
}
449
sprintf(buf->string, "%06x", buf->color);
450
return CSS_COLOR;
451
colorerror:
452
fz_css_error(buf, "invalid color");
453
}
454
455
if (css_lex_accept(buf, '"'))
456
return css_lex_string(buf, '"');
457
if (css_lex_accept(buf, '\''))
458
return css_lex_string(buf, '\'');
459
460
if (buf->c >= '0' && buf->c <= '9')
461
return css_lex_number(buf);
462
463
if (css_lex_accept(buf, 'u'))
464
{
465
if (css_lex_accept(buf, 'r'))
466
{
467
if (css_lex_accept(buf, 'l'))
468
{
469
if (css_lex_accept(buf, '('))
470
{
471
while (iswhite(buf->c))
472
css_lex_next(buf);
473
if (css_lex_accept(buf, '"'))
474
css_lex_string(buf, '"');
475
else if (css_lex_accept(buf, '\''))
476
css_lex_string(buf, '\'');
477
else
478
css_lex_uri(buf);
479
while (iswhite(buf->c))
480
css_lex_next(buf);
481
css_lex_expect(buf, ')');
482
return CSS_URI;
483
}
484
css_push_char(buf, 'u');
485
css_push_char(buf, 'r');
486
css_push_char(buf, 'l');
487
return css_lex_keyword(buf);
488
}
489
css_push_char(buf, 'u');
490
css_push_char(buf, 'r');
491
return css_lex_keyword(buf);
492
}
493
css_push_char(buf, 'u');
494
return css_lex_keyword(buf);
495
}
496
497
if (isnmstart(buf->c))
498
{
499
css_push_char(buf, buf->c);
500
css_lex_next(buf);
501
return css_lex_keyword(buf);
502
}
503
504
t = buf->c;
505
css_lex_next(buf);
506
return t;
507
}
508
return EOF;
509
}
510
511
static void next(struct lexbuf *buf)
512
{
513
buf->lookahead = css_lex(buf);
514
}
515
516
static int accept(struct lexbuf *buf, int t)
517
{
518
if (buf->lookahead == t)
519
{
520
next(buf);
521
return 1;
522
}
523
return 0;
524
}
525
526
static void expect(struct lexbuf *buf, int t)
527
{
528
if (accept(buf, t))
529
return;
530
fz_css_error(buf, "unexpected token");
531
}
532
533
static int iscond(int t)
534
{
535
return t == ':' || t == '.' || t == '#' || t == '[';
536
}
537
538
static fz_css_value *parse_value_list(struct lexbuf *buf);
539
540
static fz_css_value *parse_value(struct lexbuf *buf)
541
{
542
fz_css_value *v;
543
544
if (buf->lookahead == CSS_KEYWORD)
545
{
546
v = fz_new_css_value(buf->ctx, CSS_KEYWORD, buf->string);
547
next(buf);
548
549
if (accept(buf, '('))
550
{
551
v->type = '(';
552
v->args = parse_value_list(buf);
553
expect(buf, ')');
554
}
555
556
return v;
557
}
558
559
switch (buf->lookahead)
560
{
561
case CSS_NUMBER:
562
case CSS_LENGTH:
563
case CSS_PERCENT:
564
case CSS_STRING:
565
case CSS_COLOR:
566
case CSS_URI:
567
v = fz_new_css_value(buf->ctx, buf->lookahead, buf->string);
568
next(buf);
569
return v;
570
}
571
572
if (accept(buf, ','))
573
return fz_new_css_value(buf->ctx, ',', ",");
574
if (accept(buf, '/'))
575
return fz_new_css_value(buf->ctx, '/', "/");
576
577
fz_css_error(buf, "expected value");
578
}
579
580
static fz_css_value *parse_value_list(struct lexbuf *buf)
581
{
582
fz_css_value *head, *tail;
583
584
head = tail = NULL;
585
586
while (buf->lookahead != '}' && buf->lookahead != ';' && buf->lookahead != '!' &&
587
buf->lookahead != ')' && buf->lookahead != EOF)
588
{
589
if (!head)
590
head = tail = parse_value(buf);
591
else
592
tail = tail->next = parse_value(buf);
593
}
594
595
return head;
596
}
597
598
static fz_css_property *parse_declaration(struct lexbuf *buf)
599
{
600
fz_css_property *p;
601
602
if (buf->lookahead != CSS_KEYWORD)
603
fz_css_error(buf, "expected keyword in property");
604
p = fz_new_css_property(buf->ctx, buf->string, NULL, 0);
605
next(buf);
606
607
expect(buf, ':');
608
609
p->value = parse_value_list(buf);
610
611
/* !important */
612
if (accept(buf, '!'))
613
expect(buf, CSS_KEYWORD);
614
615
return p;
616
}
617
618
static fz_css_property *parse_declaration_list(struct lexbuf *buf)
619
{
620
fz_css_property *head, *tail;
621
622
if (buf->lookahead == '}' || buf->lookahead == EOF)
623
return NULL;
624
625
head = tail = parse_declaration(buf);
626
627
while (accept(buf, ';'))
628
{
629
if (buf->lookahead != '}' && buf->lookahead != ';' && buf->lookahead != EOF)
630
{
631
tail = tail->next = parse_declaration(buf);
632
}
633
}
634
635
return head;
636
}
637
638
static char *parse_attrib_value(struct lexbuf *buf)
639
{
640
char *s;
641
642
if (buf->lookahead == CSS_KEYWORD || buf->lookahead == CSS_STRING)
643
{
644
s = fz_strdup(buf->ctx, buf->string);
645
next(buf);
646
return s;
647
}
648
649
fz_css_error(buf, "expected attribute value");
650
}
651
652
static fz_css_condition *parse_condition(struct lexbuf *buf)
653
{
654
fz_css_condition *c;
655
656
if (accept(buf, ':'))
657
{
658
accept(buf, ':'); /* swallow css3 :: syntax and pretend it's a normal pseudo-class */
659
if (buf->lookahead != CSS_KEYWORD)
660
fz_css_error(buf, "expected keyword after ':'");
661
c = fz_new_css_condition(buf->ctx, ':', "pseudo", buf->string);
662
next(buf);
663
return c;
664
}
665
666
if (accept(buf, '.'))
667
{
668
if (buf->lookahead != CSS_KEYWORD)
669
fz_css_error(buf, "expected keyword after '.'");
670
c = fz_new_css_condition(buf->ctx, '.', "class", buf->string);
671
next(buf);
672
return c;
673
}
674
675
if (accept(buf, '#'))
676
{
677
if (buf->lookahead != CSS_KEYWORD)
678
fz_css_error(buf, "expected keyword after '#'");
679
c = fz_new_css_condition(buf->ctx, '#', "id", buf->string);
680
next(buf);
681
return c;
682
}
683
684
if (accept(buf, '['))
685
{
686
if (buf->lookahead != CSS_KEYWORD)
687
fz_css_error(buf, "expected keyword after '['");
688
689
c = fz_new_css_condition(buf->ctx, '[', buf->string, NULL);
690
next(buf);
691
692
if (accept(buf, '='))
693
{
694
c->type = '=';
695
c->val = parse_attrib_value(buf);
696
}
697
else if (accept(buf, '|'))
698
{
699
expect(buf, '=');
700
c->type = '|';
701
c->val = parse_attrib_value(buf);
702
}
703
else if (accept(buf, '~'))
704
{
705
expect(buf, '=');
706
c->type = '~';
707
c->val = parse_attrib_value(buf);
708
}
709
710
expect(buf, ']');
711
712
return c;
713
}
714
715
fz_css_error(buf, "expected condition");
716
}
717
718
static fz_css_condition *parse_condition_list(struct lexbuf *buf)
719
{
720
fz_css_condition *head, *tail;
721
722
head = tail = parse_condition(buf);
723
while (iscond(buf->lookahead))
724
{
725
tail = tail->next = parse_condition(buf);
726
}
727
return head;
728
}
729
730
static fz_css_selector *parse_simple_selector(struct lexbuf *buf)
731
{
732
fz_css_selector *s;
733
734
if (accept(buf, '*'))
735
{
736
s = fz_new_css_selector(buf->ctx, NULL);
737
if (iscond(buf->lookahead))
738
s->cond = parse_condition_list(buf);
739
return s;
740
}
741
else if (buf->lookahead == CSS_KEYWORD)
742
{
743
s = fz_new_css_selector(buf->ctx, buf->string);
744
next(buf);
745
if (iscond(buf->lookahead))
746
s->cond = parse_condition_list(buf);
747
return s;
748
}
749
else if (iscond(buf->lookahead))
750
{
751
s = fz_new_css_selector(buf->ctx, NULL);
752
s->cond = parse_condition_list(buf);
753
return s;
754
}
755
756
fz_css_error(buf, "expected selector");
757
}
758
759
static fz_css_selector *parse_adjacent_selector(struct lexbuf *buf)
760
{
761
fz_css_selector *s, *a, *b;
762
763
a = parse_simple_selector(buf);
764
if (accept(buf, '+'))
765
{
766
b = parse_adjacent_selector(buf);
767
s = fz_new_css_selector(buf->ctx, NULL);
768
s->combine = '+';
769
s->left = a;
770
s->right = b;
771
return s;
772
}
773
return a;
774
}
775
776
static fz_css_selector *parse_child_selector(struct lexbuf *buf)
777
{
778
fz_css_selector *s, *a, *b;
779
780
a = parse_adjacent_selector(buf);
781
if (accept(buf, '>'))
782
{
783
b = parse_child_selector(buf);
784
s = fz_new_css_selector(buf->ctx, NULL);
785
s->combine = '>';
786
s->left = a;
787
s->right = b;
788
return s;
789
}
790
return a;
791
}
792
793
static fz_css_selector *parse_descendant_selector(struct lexbuf *buf)
794
{
795
fz_css_selector *s, *a, *b;
796
797
a = parse_child_selector(buf);
798
if (buf->lookahead != ',' && buf->lookahead != '{' && buf->lookahead != EOF)
799
{
800
b = parse_descendant_selector(buf);
801
s = fz_new_css_selector(buf->ctx, NULL);
802
s->combine = ' ';
803
s->left = a;
804
s->right = b;
805
return s;
806
}
807
return a;
808
}
809
810
static fz_css_selector *parse_selector_list(struct lexbuf *buf)
811
{
812
fz_css_selector *head, *tail;
813
814
head = tail = parse_descendant_selector(buf);
815
while (accept(buf, ','))
816
{
817
tail = tail->next = parse_descendant_selector(buf);
818
}
819
return head;
820
}
821
822
static fz_css_rule *parse_rule(struct lexbuf *buf)
823
{
824
fz_css_selector *s = NULL;
825
fz_css_property *p = NULL;
826
827
fz_try(buf->ctx)
828
{
829
s = parse_selector_list(buf);
830
expect(buf, '{');
831
p = parse_declaration_list(buf);
832
expect(buf, '}');
833
}
834
fz_catch(buf->ctx)
835
{
836
if (fz_caught(buf->ctx) != FZ_ERROR_SYNTAX)
837
fz_rethrow(buf->ctx);
838
while (buf->lookahead != EOF)
839
{
840
if (accept(buf, '}'))
841
break;
842
next(buf);
843
}
844
return NULL;
845
}
846
847
return fz_new_css_rule(buf->ctx, s, p);
848
}
849
850
static void parse_at_rule(struct lexbuf *buf)
851
{
852
expect(buf, CSS_KEYWORD);
853
854
/* skip until '{' or ';' */
855
while (buf->lookahead != EOF)
856
{
857
if (accept(buf, ';'))
858
return;
859
if (accept(buf, '{'))
860
{
861
int depth = 1;
862
while (buf->lookahead != EOF && depth > 0)
863
{
864
if (accept(buf, '{'))
865
++depth;
866
else if (accept(buf, '}'))
867
--depth;
868
else
869
next(buf);
870
}
871
return;
872
}
873
next(buf);
874
}
875
}
876
877
static fz_css_rule *parse_stylesheet(struct lexbuf *buf, fz_css_rule *chain)
878
{
879
fz_css_rule *rule, **nextp, *tail;
880
881
tail = chain;
882
if (tail)
883
{
884
while (tail->next)
885
tail = tail->next;
886
nextp = &tail->next;
887
}
888
else
889
{
890
nextp = &tail;
891
}
892
893
while (buf->lookahead != EOF)
894
{
895
if (accept(buf, '@'))
896
{
897
parse_at_rule(buf);
898
}
899
else
900
{
901
fz_css_rule *x = parse_rule(buf);
902
if (x)
903
{
904
rule = *nextp = x;
905
nextp = &rule->next;
906
}
907
}
908
}
909
910
return chain ? chain : tail;
911
}
912
913
fz_css_property *fz_parse_css_properties(fz_context *ctx, const char *source)
914
{
915
struct lexbuf buf;
916
css_lex_init(ctx, &buf, source, "<inline>");
917
next(&buf);
918
return parse_declaration_list(&buf);
919
}
920
921
fz_css_rule *fz_parse_css(fz_context *ctx, fz_css_rule *chain, const char *source, const char *file)
922
{
923
struct lexbuf buf;
924
css_lex_init(ctx, &buf, source, file);
925
next(&buf);
926
return parse_stylesheet(&buf, chain);
927
}
928
929