line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/* |
2
|
|
|
|
|
|
|
* Copyright 1999-2016, Gisle Aas |
3
|
|
|
|
|
|
|
* Copyright 1999-2000, Michael A. Chase |
4
|
|
|
|
|
|
|
* |
5
|
|
|
|
|
|
|
* This library is free software; you can redistribute it and/or |
6
|
|
|
|
|
|
|
* modify it under the same terms as Perl itself. |
7
|
|
|
|
|
|
|
*/ |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#ifndef EXTERN |
10
|
|
|
|
|
|
|
#define EXTERN extern |
11
|
|
|
|
|
|
|
#endif |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
#include "hctype.h" /* isH...() macros */ |
14
|
|
|
|
|
|
|
#include "tokenpos.h" /* dTOKEN; PUSH_TOKEN() */ |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
const static |
18
|
|
|
|
|
|
|
struct literal_tag { |
19
|
|
|
|
|
|
|
int len; |
20
|
|
|
|
|
|
|
char* str; |
21
|
|
|
|
|
|
|
int is_cdata; |
22
|
|
|
|
|
|
|
} |
23
|
|
|
|
|
|
|
literal_mode_elem[] = |
24
|
|
|
|
|
|
|
{ |
25
|
|
|
|
|
|
|
{6, "script", 1}, |
26
|
|
|
|
|
|
|
{5, "style", 1}, |
27
|
|
|
|
|
|
|
{3, "xmp", 1}, |
28
|
|
|
|
|
|
|
{6, "iframe", 1}, |
29
|
|
|
|
|
|
|
{9, "plaintext", 1}, |
30
|
|
|
|
|
|
|
{5, "title", 0}, |
31
|
|
|
|
|
|
|
{8, "textarea", 0}, |
32
|
|
|
|
|
|
|
{0, 0, 0} |
33
|
|
|
|
|
|
|
}; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
enum argcode { |
36
|
|
|
|
|
|
|
ARG_SELF = 1, /* need to avoid '\0' in argspec string */ |
37
|
|
|
|
|
|
|
ARG_TOKENS, |
38
|
|
|
|
|
|
|
ARG_TOKENPOS, |
39
|
|
|
|
|
|
|
ARG_TOKEN0, |
40
|
|
|
|
|
|
|
ARG_TAGNAME, |
41
|
|
|
|
|
|
|
ARG_TAG, |
42
|
|
|
|
|
|
|
ARG_ATTR, |
43
|
|
|
|
|
|
|
ARG_ATTRARR, |
44
|
|
|
|
|
|
|
ARG_ATTRSEQ, |
45
|
|
|
|
|
|
|
ARG_TEXT, |
46
|
|
|
|
|
|
|
ARG_DTEXT, |
47
|
|
|
|
|
|
|
ARG_IS_CDATA, |
48
|
|
|
|
|
|
|
ARG_SKIPPED_TEXT, |
49
|
|
|
|
|
|
|
ARG_OFFSET, |
50
|
|
|
|
|
|
|
ARG_OFFSET_END, |
51
|
|
|
|
|
|
|
ARG_LENGTH, |
52
|
|
|
|
|
|
|
ARG_LINE, |
53
|
|
|
|
|
|
|
ARG_COLUMN, |
54
|
|
|
|
|
|
|
ARG_EVENT, |
55
|
|
|
|
|
|
|
ARG_UNDEF, |
56
|
|
|
|
|
|
|
ARG_LITERAL, /* Always keep last */ |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
/* extra flags always encoded first */ |
59
|
|
|
|
|
|
|
ARG_FLAG_FLAT_ARRAY |
60
|
|
|
|
|
|
|
}; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
static const char * const argname[] = { |
63
|
|
|
|
|
|
|
/* Must be in the same order as enum argcode */ |
64
|
|
|
|
|
|
|
"self", /* ARG_SELF */ |
65
|
|
|
|
|
|
|
"tokens", /* ARG_TOKENS */ |
66
|
|
|
|
|
|
|
"tokenpos", /* ARG_TOKENPOS */ |
67
|
|
|
|
|
|
|
"token0", /* ARG_TOKEN0 */ |
68
|
|
|
|
|
|
|
"tagname", /* ARG_TAGNAME */ |
69
|
|
|
|
|
|
|
"tag", /* ARG_TAG */ |
70
|
|
|
|
|
|
|
"attr", /* ARG_ATTR */ |
71
|
|
|
|
|
|
|
"@attr", /* ARG_ATTRARR */ |
72
|
|
|
|
|
|
|
"attrseq", /* ARG_ATTRSEQ */ |
73
|
|
|
|
|
|
|
"text", /* ARG_TEXT */ |
74
|
|
|
|
|
|
|
"dtext", /* ARG_DTEXT */ |
75
|
|
|
|
|
|
|
"is_cdata", /* ARG_IS_CDATA */ |
76
|
|
|
|
|
|
|
"skipped_text", /* ARG_SKIPPED_TEXT */ |
77
|
|
|
|
|
|
|
"offset", /* ARG_OFFSET */ |
78
|
|
|
|
|
|
|
"offset_end", /* ARG_OFFSET_END */ |
79
|
|
|
|
|
|
|
"length", /* ARG_LENGTH */ |
80
|
|
|
|
|
|
|
"line", /* ARG_LINE */ |
81
|
|
|
|
|
|
|
"column", /* ARG_COLUMN */ |
82
|
|
|
|
|
|
|
"event", /* ARG_EVENT */ |
83
|
|
|
|
|
|
|
"undef", /* ARG_UNDEF */ |
84
|
|
|
|
|
|
|
/* ARG_LITERAL (not compared) */ |
85
|
|
|
|
|
|
|
/* ARG_FLAG_FLAT_ARRAY */ |
86
|
|
|
|
|
|
|
}; |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
#define CASE_SENSITIVE(p_state) \ |
89
|
|
|
|
|
|
|
((p_state)->xml_mode || (p_state)->case_sensitive) |
90
|
|
|
|
|
|
|
#define STRICT_NAMES(p_state) \ |
91
|
|
|
|
|
|
|
((p_state)->xml_mode || (p_state)->strict_names) |
92
|
|
|
|
|
|
|
#define ALLOW_EMPTY_TAG(p_state) \ |
93
|
|
|
|
|
|
|
((p_state)->xml_mode || (p_state)->empty_element_tags) |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
static void flush_pending_text(PSTATE* p_state, SV* self); |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
/* |
98
|
|
|
|
|
|
|
* Parser functions. |
99
|
|
|
|
|
|
|
* |
100
|
|
|
|
|
|
|
* parse() - top level entry point. |
101
|
|
|
|
|
|
|
* deals with text and calls one of its |
102
|
|
|
|
|
|
|
* subordinate parse_*() routines after |
103
|
|
|
|
|
|
|
* looking at the first char after "<" |
104
|
|
|
|
|
|
|
* parse_decl() - deals with declarations |
105
|
|
|
|
|
|
|
* parse_comment() - deals with |
106
|
|
|
|
|
|
|
* parse_marked_section - deals with |
107
|
|
|
|
|
|
|
* parse_end() - deals with end tags |
108
|
|
|
|
|
|
|
* parse_start() - deals with start tags |
109
|
|
|
|
|
|
|
* parse_process() - deals with process instructions ...> |
110
|
|
|
|
|
|
|
* parse_null() - deals with anything else <....> |
111
|
|
|
|
|
|
|
* |
112
|
|
|
|
|
|
|
* report_event() - called whenever any of the parse*() routines |
113
|
|
|
|
|
|
|
* has recongnized something. |
114
|
|
|
|
|
|
|
*/ |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
static void |
117
|
43765
|
|
|
|
|
|
report_event(PSTATE* p_state, |
118
|
|
|
|
|
|
|
event_id_t event, |
119
|
|
|
|
|
|
|
char *beg, char *end, U32 utf8, |
120
|
|
|
|
|
|
|
token_pos_t *tokens, int num_tokens, |
121
|
|
|
|
|
|
|
SV* self |
122
|
|
|
|
|
|
|
) |
123
|
|
|
|
|
|
|
{ |
124
|
|
|
|
|
|
|
struct p_handler *h; |
125
|
|
|
|
|
|
|
dTHX; |
126
|
43765
|
|
|
|
|
|
dSP; |
127
|
|
|
|
|
|
|
AV *array; |
128
|
|
|
|
|
|
|
STRLEN my_na; |
129
|
|
|
|
|
|
|
char *argspec; |
130
|
|
|
|
|
|
|
char *s; |
131
|
|
|
|
|
|
|
STRLEN offset; |
132
|
|
|
|
|
|
|
STRLEN line; |
133
|
|
|
|
|
|
|
STRLEN column; |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
#define CHR_DIST(a,b) (utf8 ? utf8_distance((U8*)(a),(U8*)(b)) : (a) - (b)) |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
/* some events might still fire after a handler has signaled eof |
138
|
|
|
|
|
|
|
* so suppress them here. |
139
|
|
|
|
|
|
|
*/ |
140
|
43765
|
100
|
|
|
|
|
if (p_state->eof) |
141
|
4
|
|
|
|
|
|
return; |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
/* capture offsets */ |
144
|
43761
|
|
|
|
|
|
offset = p_state->offset; |
145
|
43761
|
|
|
|
|
|
line = p_state->line; |
146
|
43761
|
|
|
|
|
|
column = p_state->column; |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
#if 0 |
149
|
|
|
|
|
|
|
{ /* used for debugging at some point */ |
150
|
|
|
|
|
|
|
char *s = beg; |
151
|
|
|
|
|
|
|
int i; |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
/* print debug output */ |
154
|
|
|
|
|
|
|
switch(event) { |
155
|
|
|
|
|
|
|
case E_DECLARATION: printf("DECLARATION"); break; |
156
|
|
|
|
|
|
|
case E_COMMENT: printf("COMMENT"); break; |
157
|
|
|
|
|
|
|
case E_START: printf("START"); break; |
158
|
|
|
|
|
|
|
case E_END: printf("END"); break; |
159
|
|
|
|
|
|
|
case E_TEXT: printf("TEXT"); break; |
160
|
|
|
|
|
|
|
case E_PROCESS: printf("PROCESS"); break; |
161
|
|
|
|
|
|
|
case E_NONE: printf("NONE"); break; |
162
|
|
|
|
|
|
|
default: printf("EVENT #%d", event); break; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
printf(" ["); |
166
|
|
|
|
|
|
|
while (s < end) { |
167
|
|
|
|
|
|
|
if (*s == '\n') { |
168
|
|
|
|
|
|
|
putchar('\\'); putchar('n'); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
else |
171
|
|
|
|
|
|
|
putchar(*s); |
172
|
|
|
|
|
|
|
s++; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
printf("] %d\n", end - beg); |
175
|
|
|
|
|
|
|
for (i = 0; i < num_tokens; i++) { |
176
|
|
|
|
|
|
|
printf(" token %d: %d %d\n", |
177
|
|
|
|
|
|
|
i, |
178
|
|
|
|
|
|
|
tokens[i].beg - beg, |
179
|
|
|
|
|
|
|
tokens[i].end - tokens[i].beg); |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
#endif |
183
|
|
|
|
|
|
|
|
184
|
43761
|
50
|
|
|
|
|
if (p_state->pending_end_tag && event != E_TEXT && event != E_COMMENT) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
185
|
|
|
|
|
|
|
token_pos_t t; |
186
|
|
|
|
|
|
|
char dummy; |
187
|
0
|
|
|
|
|
|
t.beg = p_state->pending_end_tag; |
188
|
0
|
|
|
|
|
|
t.end = p_state->pending_end_tag + strlen(p_state->pending_end_tag); |
189
|
0
|
|
|
|
|
|
p_state->pending_end_tag = 0; |
190
|
0
|
|
|
|
|
|
report_event(p_state, E_END, &dummy, &dummy, 0, &t, 1, self); |
191
|
0
|
|
|
|
|
|
SPAGAIN; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
/* update offsets */ |
195
|
43761
|
100
|
|
|
|
|
p_state->offset += CHR_DIST(end, beg); |
196
|
43761
|
100
|
|
|
|
|
if (line) { |
197
|
122
|
|
|
|
|
|
char *s = beg; |
198
|
122
|
|
|
|
|
|
char *nl = NULL; |
199
|
840
|
100
|
|
|
|
|
while (s < end) { |
200
|
718
|
100
|
|
|
|
|
if (*s == '\n') { |
201
|
31
|
|
|
|
|
|
p_state->line++; |
202
|
31
|
|
|
|
|
|
nl = s; |
203
|
|
|
|
|
|
|
} |
204
|
718
|
|
|
|
|
|
s++; |
205
|
|
|
|
|
|
|
} |
206
|
122
|
100
|
|
|
|
|
if (nl) |
207
|
27
|
100
|
|
|
|
|
p_state->column = CHR_DIST(end, nl) - 1; |
208
|
|
|
|
|
|
|
else |
209
|
95
|
100
|
|
|
|
|
p_state->column += CHR_DIST(end, beg); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
43761
|
100
|
|
|
|
|
if (event == E_NONE) |
213
|
32
|
|
|
|
|
|
goto IGNORE_EVENT; |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
#ifdef MARKED_SECTION |
216
|
43729
|
100
|
|
|
|
|
if (p_state->ms == MS_IGNORE) |
217
|
4
|
|
|
|
|
|
goto IGNORE_EVENT; |
218
|
|
|
|
|
|
|
#endif |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
/* tag filters */ |
221
|
43725
|
100
|
|
|
|
|
if (p_state->ignore_tags || p_state->report_tags || p_state->ignore_elements) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
222
|
|
|
|
|
|
|
|
223
|
533
|
100
|
|
|
|
|
if (event == E_START || event == E_END) { |
|
|
100
|
|
|
|
|
|
224
|
167
|
|
|
|
|
|
SV* tagname = p_state->tmp; |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
assert(num_tokens >= 1); |
227
|
167
|
|
|
|
|
|
sv_setpvn(tagname, tokens[0].beg, tokens[0].end - tokens[0].beg); |
228
|
167
|
100
|
|
|
|
|
if (utf8) |
229
|
38
|
|
|
|
|
|
SvUTF8_on(tagname); |
230
|
|
|
|
|
|
|
else |
231
|
129
|
|
|
|
|
|
SvUTF8_off(tagname); |
232
|
167
|
100
|
|
|
|
|
if (!CASE_SENSITIVE(p_state)) |
|
|
100
|
|
|
|
|
|
233
|
155
|
|
|
|
|
|
sv_lower(aTHX_ tagname); |
234
|
|
|
|
|
|
|
|
235
|
167
|
100
|
|
|
|
|
if (p_state->ignoring_element) { |
236
|
7
|
50
|
|
|
|
|
if (sv_eq(p_state->ignoring_element, tagname)) { |
237
|
7
|
50
|
|
|
|
|
if (event == E_START) |
238
|
0
|
|
|
|
|
|
p_state->ignore_depth++; |
239
|
7
|
50
|
|
|
|
|
else if (--p_state->ignore_depth == 0) { |
240
|
7
|
|
|
|
|
|
SvREFCNT_dec(p_state->ignoring_element); |
241
|
7
|
|
|
|
|
|
p_state->ignoring_element = 0; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
} |
244
|
7
|
|
|
|
|
|
goto IGNORE_EVENT; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
244
|
|
|
|
|
|
if (p_state->ignore_elements && |
248
|
84
|
|
|
|
|
|
hv_fetch_ent(p_state->ignore_elements, tagname, 0, 0)) |
249
|
|
|
|
|
|
|
{ |
250
|
8
|
100
|
|
|
|
|
if (event == E_START) { |
251
|
7
|
|
|
|
|
|
p_state->ignoring_element = newSVsv(tagname); |
252
|
7
|
|
|
|
|
|
p_state->ignore_depth = 1; |
253
|
|
|
|
|
|
|
} |
254
|
8
|
|
|
|
|
|
goto IGNORE_EVENT; |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
205
|
|
|
|
|
|
if (p_state->ignore_tags && |
258
|
53
|
|
|
|
|
|
hv_fetch_ent(p_state->ignore_tags, tagname, 0, 0)) |
259
|
|
|
|
|
|
|
{ |
260
|
20
|
|
|
|
|
|
goto IGNORE_EVENT; |
261
|
|
|
|
|
|
|
} |
262
|
174
|
|
|
|
|
|
if (p_state->report_tags && |
263
|
42
|
|
|
|
|
|
!hv_fetch_ent(p_state->report_tags, tagname, 0, 0)) |
264
|
|
|
|
|
|
|
{ |
265
|
12
|
|
|
|
|
|
goto IGNORE_EVENT; |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
} |
268
|
246
|
100
|
|
|
|
|
else if (p_state->ignoring_element) { |
269
|
7
|
|
|
|
|
|
goto IGNORE_EVENT; |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
43671
|
|
|
|
|
|
h = &p_state->handlers[event]; |
274
|
43671
|
100
|
|
|
|
|
if (!h->cb) { |
275
|
|
|
|
|
|
|
/* event = E_DEFAULT; */ |
276
|
3286
|
|
|
|
|
|
h = &p_state->handlers[E_DEFAULT]; |
277
|
3286
|
100
|
|
|
|
|
if (!h->cb) |
278
|
2178
|
|
|
|
|
|
goto IGNORE_EVENT; |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
41493
|
100
|
|
|
|
|
if (SvTYPE(h->cb) != SVt_PVAV && !SvTRUE(h->cb)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
282
|
|
|
|
|
|
|
/* FALSE scalar ('' or 0) means IGNORE this event */ |
283
|
7
|
|
|
|
|
|
return; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
41486
|
100
|
|
|
|
|
if (p_state->unbroken_text && event == E_TEXT) { |
|
|
100
|
|
|
|
|
|
287
|
|
|
|
|
|
|
/* should buffer text */ |
288
|
4510
|
100
|
|
|
|
|
if (!p_state->pend_text) |
289
|
16
|
|
|
|
|
|
p_state->pend_text = newSV(256); |
290
|
4510
|
100
|
|
|
|
|
if (SvOK(p_state->pend_text)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
291
|
154
|
100
|
|
|
|
|
if (p_state->is_cdata != p_state->pend_text_is_cdata) { |
292
|
2
|
|
|
|
|
|
flush_pending_text(p_state, self); |
293
|
2
|
|
|
|
|
|
SPAGAIN; |
294
|
2
|
|
|
|
|
|
goto INIT_PEND_TEXT; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
else { |
298
|
|
|
|
|
|
|
INIT_PEND_TEXT: |
299
|
4358
|
|
|
|
|
|
p_state->pend_text_offset = offset; |
300
|
4358
|
|
|
|
|
|
p_state->pend_text_line = line; |
301
|
4358
|
|
|
|
|
|
p_state->pend_text_column = column; |
302
|
4358
|
|
|
|
|
|
p_state->pend_text_is_cdata = p_state->is_cdata; |
303
|
4358
|
|
|
|
|
|
sv_setpvs(p_state->pend_text, ""); |
304
|
4358
|
50
|
|
|
|
|
if (!utf8) |
305
|
4358
|
|
|
|
|
|
SvUTF8_off(p_state->pend_text); |
306
|
|
|
|
|
|
|
} |
307
|
4510
|
50
|
|
|
|
|
if (utf8 && !SvUTF8(p_state->pend_text)) |
|
|
0
|
|
|
|
|
|
308
|
0
|
|
|
|
|
|
sv_utf8_upgrade(p_state->pend_text); |
309
|
4510
|
50
|
|
|
|
|
if (utf8 || !SvUTF8(p_state->pend_text)) { |
|
|
50
|
|
|
|
|
|
310
|
4510
|
|
|
|
|
|
sv_catpvn(p_state->pend_text, beg, end - beg); |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
else { |
313
|
0
|
|
|
|
|
|
SV *tmp = newSVpvn(beg, end - beg); |
314
|
0
|
|
|
|
|
|
sv_utf8_upgrade(tmp); |
315
|
0
|
|
|
|
|
|
sv_catsv(p_state->pend_text, tmp); |
316
|
0
|
|
|
|
|
|
SvREFCNT_dec(tmp); |
317
|
|
|
|
|
|
|
} |
318
|
4510
|
|
|
|
|
|
return; |
319
|
|
|
|
|
|
|
} |
320
|
36976
|
100
|
|
|
|
|
else if (p_state->pend_text && SvOK(p_state->pend_text)) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
321
|
4294
|
|
|
|
|
|
flush_pending_text(p_state, self); |
322
|
4294
|
|
|
|
|
|
SPAGAIN; |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
/* At this point we have decided to generate an event callback */ |
326
|
|
|
|
|
|
|
|
327
|
36976
|
100
|
|
|
|
|
argspec = h->argspec ? SvPV(h->argspec, my_na) : ""; |
|
|
50
|
|
|
|
|
|
328
|
|
|
|
|
|
|
|
329
|
36976
|
100
|
|
|
|
|
if (SvTYPE(h->cb) == SVt_PVAV) { |
330
|
|
|
|
|
|
|
|
331
|
8945
|
100
|
|
|
|
|
if (*argspec == ARG_FLAG_FLAT_ARRAY) { |
332
|
502
|
|
|
|
|
|
argspec++; |
333
|
502
|
|
|
|
|
|
array = (AV*)h->cb; |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
else { |
336
|
|
|
|
|
|
|
/* start sub-array for accumulator array */ |
337
|
8945
|
|
|
|
|
|
array = newAV(); |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
else { |
341
|
28031
|
|
|
|
|
|
array = 0; |
342
|
28031
|
50
|
|
|
|
|
if (*argspec == ARG_FLAG_FLAT_ARRAY) |
343
|
0
|
|
|
|
|
|
argspec++; |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
/* start argument stack for callback */ |
346
|
28031
|
|
|
|
|
|
ENTER; |
347
|
28031
|
|
|
|
|
|
SAVETMPS; |
348
|
28031
|
50
|
|
|
|
|
PUSHMARK(SP); |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
158996
|
100
|
|
|
|
|
for (s = argspec; *s; s++) { |
352
|
122020
|
|
|
|
|
|
SV* arg = 0; |
353
|
122020
|
|
|
|
|
|
int push_arg = 1; |
354
|
122020
|
|
|
|
|
|
enum argcode argcode = (enum argcode)*s; |
355
|
|
|
|
|
|
|
|
356
|
122020
|
|
|
|
|
|
switch( argcode ) { |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
case ARG_SELF: |
359
|
27664
|
|
|
|
|
|
arg = sv_mortalcopy(self); |
360
|
27664
|
|
|
|
|
|
break; |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
case ARG_TOKENS: |
363
|
114
|
100
|
|
|
|
|
if (num_tokens >= 1) { |
364
|
97
|
|
|
|
|
|
AV* av = newAV(); |
365
|
97
|
|
|
|
|
|
SV* prev_token = &PL_sv_undef; |
366
|
|
|
|
|
|
|
int i; |
367
|
97
|
|
|
|
|
|
av_extend(av, num_tokens); |
368
|
531
|
100
|
|
|
|
|
for (i = 0; i < num_tokens; i++) { |
369
|
434
|
50
|
|
|
|
|
if (tokens[i].beg) { |
370
|
434
|
|
|
|
|
|
prev_token = newSVpvn(tokens[i].beg, tokens[i].end-tokens[i].beg); |
371
|
434
|
50
|
|
|
|
|
if (utf8) |
372
|
0
|
|
|
|
|
|
SvUTF8_on(prev_token); |
373
|
434
|
|
|
|
|
|
av_push(av, prev_token); |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
else { /* boolean */ |
376
|
0
|
0
|
|
|
|
|
av_push(av, p_state->bool_attr_val |
377
|
|
|
|
|
|
|
? newSVsv(p_state->bool_attr_val) |
378
|
|
|
|
|
|
|
: newSVsv(prev_token)); |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
} |
381
|
97
|
|
|
|
|
|
arg = sv_2mortal(newRV_noinc((SV*)av)); |
382
|
|
|
|
|
|
|
} |
383
|
114
|
|
|
|
|
|
break; |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
case ARG_TOKENPOS: |
386
|
84
|
100
|
|
|
|
|
if (num_tokens >= 1 && tokens[0].beg >= beg) { |
|
|
100
|
|
|
|
|
|
387
|
32
|
|
|
|
|
|
AV* av = newAV(); |
388
|
|
|
|
|
|
|
int i; |
389
|
32
|
|
|
|
|
|
av_extend(av, num_tokens*2); |
390
|
401
|
100
|
|
|
|
|
for (i = 0; i < num_tokens; i++) { |
391
|
369
|
100
|
|
|
|
|
if (tokens[i].beg) { |
392
|
367
|
100
|
|
|
|
|
av_push(av, newSViv(CHR_DIST(tokens[i].beg, beg))); |
393
|
367
|
100
|
|
|
|
|
av_push(av, newSViv(CHR_DIST(tokens[i].end, tokens[i].beg))); |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
else { /* boolean tag value */ |
396
|
2
|
|
|
|
|
|
av_push(av, newSViv(0)); |
397
|
2
|
|
|
|
|
|
av_push(av, newSViv(0)); |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
} |
400
|
32
|
|
|
|
|
|
arg = sv_2mortal(newRV_noinc((SV*)av)); |
401
|
|
|
|
|
|
|
} |
402
|
84
|
|
|
|
|
|
break; |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
case ARG_TOKEN0: |
405
|
|
|
|
|
|
|
case ARG_TAGNAME: |
406
|
|
|
|
|
|
|
/* fall through */ |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
case ARG_TAG: |
409
|
8339
|
100
|
|
|
|
|
if (num_tokens >= 1) { |
410
|
8271
|
|
|
|
|
|
arg = sv_2mortal(newSVpvn(tokens[0].beg, |
411
|
|
|
|
|
|
|
tokens[0].end - tokens[0].beg)); |
412
|
8271
|
100
|
|
|
|
|
if (utf8) |
413
|
29
|
|
|
|
|
|
SvUTF8_on(arg); |
414
|
8271
|
100
|
|
|
|
|
if (!CASE_SENSITIVE(p_state) && argcode != ARG_TOKEN0) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
415
|
8104
|
|
|
|
|
|
sv_lower(aTHX_ arg); |
416
|
8271
|
100
|
|
|
|
|
if (argcode == ARG_TAG && event != E_START) { |
|
|
100
|
|
|
|
|
|
417
|
10
|
|
|
|
|
|
char *e_type = "!##/#?#"; |
418
|
10
|
|
|
|
|
|
sv_insert(arg, 0, 0, &e_type[event], 1); |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
} |
421
|
8339
|
|
|
|
|
|
break; |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
case ARG_ATTR: |
424
|
|
|
|
|
|
|
case ARG_ATTRARR: |
425
|
5984
|
100
|
|
|
|
|
if (event == E_START) { |
426
|
|
|
|
|
|
|
HV* hv; |
427
|
|
|
|
|
|
|
int i; |
428
|
5892
|
100
|
|
|
|
|
if (argcode == ARG_ATTR) { |
429
|
5883
|
|
|
|
|
|
hv = newHV(); |
430
|
5883
|
|
|
|
|
|
arg = sv_2mortal(newRV_noinc((SV*)hv)); |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
else { |
433
|
|
|
|
|
|
|
#ifdef __GNUC__ |
434
|
|
|
|
|
|
|
/* gcc -Wall reports this variable as possibly used uninitialized */ |
435
|
9
|
|
|
|
|
|
hv = 0; |
436
|
|
|
|
|
|
|
#endif |
437
|
9
|
|
|
|
|
|
push_arg = 0; /* deal with argument pushing here */ |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
|
440
|
25449
|
100
|
|
|
|
|
for (i = 1; i < num_tokens; i += 2) { |
441
|
19557
|
|
|
|
|
|
SV* attrname = newSVpvn(tokens[i].beg, |
442
|
|
|
|
|
|
|
tokens[i].end-tokens[i].beg); |
443
|
|
|
|
|
|
|
SV* attrval; |
444
|
|
|
|
|
|
|
|
445
|
19557
|
100
|
|
|
|
|
if (utf8) |
446
|
37
|
|
|
|
|
|
SvUTF8_on(attrname); |
447
|
19557
|
100
|
|
|
|
|
if (tokens[i+1].beg) { |
448
|
4432
|
|
|
|
|
|
char *beg = tokens[i+1].beg; |
449
|
4432
|
|
|
|
|
|
STRLEN len = tokens[i+1].end - beg; |
450
|
4432
|
100
|
|
|
|
|
if (*beg == '"' || *beg == '\'' || (*beg == '`' && p_state->backquote)) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
451
|
|
|
|
|
|
|
assert(len >= 2 && *beg == beg[len-1]); |
452
|
2217
|
|
|
|
|
|
beg++; len -= 2; |
453
|
|
|
|
|
|
|
} |
454
|
4432
|
|
|
|
|
|
attrval = newSVpvn(beg, len); |
455
|
4432
|
100
|
|
|
|
|
if (utf8) |
456
|
34
|
|
|
|
|
|
SvUTF8_on(attrval); |
457
|
4432
|
100
|
|
|
|
|
if (!p_state->attr_encoded) { |
458
|
4430
|
100
|
|
|
|
|
if (p_state->utf8_mode) { |
459
|
20
|
|
|
|
|
|
sv_utf8_decode(attrval); |
460
|
20
|
|
|
|
|
|
sv_utf8_upgrade(attrval); |
461
|
|
|
|
|
|
|
} |
462
|
4430
|
|
|
|
|
|
decode_entities(aTHX_ attrval, p_state->entity2char, 0); |
463
|
4430
|
100
|
|
|
|
|
if (p_state->utf8_mode) |
464
|
4432
|
|
|
|
|
|
SvUTF8_off(attrval); |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
else { /* boolean */ |
468
|
15125
|
50
|
|
|
|
|
if (p_state->bool_attr_val) |
469
|
0
|
|
|
|
|
|
attrval = newSVsv(p_state->bool_attr_val); |
470
|
|
|
|
|
|
|
else |
471
|
15125
|
|
|
|
|
|
attrval = newSVsv(attrname); |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
19557
|
100
|
|
|
|
|
if (!CASE_SENSITIVE(p_state)) |
|
|
100
|
|
|
|
|
|
475
|
19540
|
|
|
|
|
|
sv_lower(aTHX_ attrname); |
476
|
|
|
|
|
|
|
|
477
|
19557
|
100
|
|
|
|
|
if (argcode == ARG_ATTR) { |
478
|
39095
|
|
|
|
|
|
if (hv_exists_ent(hv, attrname, 0) || |
479
|
19546
|
|
|
|
|
|
!hv_store_ent(hv, attrname, attrval, 0)) { |
480
|
3
|
|
|
|
|
|
SvREFCNT_dec(attrval); |
481
|
|
|
|
|
|
|
} |
482
|
19549
|
|
|
|
|
|
SvREFCNT_dec(attrname); |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
else { /* ARG_ATTRARR */ |
485
|
8
|
100
|
|
|
|
|
if (array) { |
486
|
4
|
|
|
|
|
|
av_push(array, attrname); |
487
|
4
|
|
|
|
|
|
av_push(array, attrval); |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
else { |
490
|
4
|
50
|
|
|
|
|
mXPUSHs(attrname); |
491
|
4
|
50
|
|
|
|
|
mXPUSHs(attrval); |
492
|
|
|
|
|
|
|
} |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
} |
495
|
|
|
|
|
|
|
} |
496
|
92
|
100
|
|
|
|
|
else if (argcode == ARG_ATTRARR) { |
497
|
18
|
|
|
|
|
|
push_arg = 0; |
498
|
|
|
|
|
|
|
} |
499
|
5984
|
|
|
|
|
|
break; |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
case ARG_ATTRSEQ: /* (v2 compatibility stuff) */ |
502
|
5807
|
100
|
|
|
|
|
if (event == E_START) { |
503
|
5782
|
|
|
|
|
|
AV* av = newAV(); |
504
|
|
|
|
|
|
|
int i; |
505
|
25223
|
100
|
|
|
|
|
for (i = 1; i < num_tokens; i += 2) { |
506
|
19441
|
|
|
|
|
|
SV* attrname = newSVpvn(tokens[i].beg, |
507
|
|
|
|
|
|
|
tokens[i].end-tokens[i].beg); |
508
|
19441
|
50
|
|
|
|
|
if (utf8) |
509
|
0
|
|
|
|
|
|
SvUTF8_on(attrname); |
510
|
19441
|
100
|
|
|
|
|
if (!CASE_SENSITIVE(p_state)) |
|
|
100
|
|
|
|
|
|
511
|
19427
|
|
|
|
|
|
sv_lower(aTHX_ attrname); |
512
|
19441
|
|
|
|
|
|
av_push(av, attrname); |
513
|
|
|
|
|
|
|
} |
514
|
5782
|
|
|
|
|
|
arg = sv_2mortal(newRV_noinc((SV*)av)); |
515
|
|
|
|
|
|
|
} |
516
|
5807
|
|
|
|
|
|
break; |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
case ARG_TEXT: |
519
|
36654
|
|
|
|
|
|
arg = sv_2mortal(newSVpvn(beg, end - beg)); |
520
|
36654
|
100
|
|
|
|
|
if (utf8) |
521
|
115
|
|
|
|
|
|
SvUTF8_on(arg); |
522
|
36654
|
|
|
|
|
|
break; |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
case ARG_DTEXT: |
525
|
156
|
100
|
|
|
|
|
if (event == E_TEXT) { |
526
|
79
|
|
|
|
|
|
arg = sv_2mortal(newSVpvn(beg, end - beg)); |
527
|
79
|
100
|
|
|
|
|
if (utf8) |
528
|
23
|
|
|
|
|
|
SvUTF8_on(arg); |
529
|
79
|
100
|
|
|
|
|
if (!p_state->is_cdata) { |
530
|
71
|
100
|
|
|
|
|
if (p_state->utf8_mode) { |
531
|
8
|
|
|
|
|
|
sv_utf8_decode(arg); |
532
|
8
|
|
|
|
|
|
sv_utf8_upgrade(arg); |
533
|
|
|
|
|
|
|
} |
534
|
71
|
|
|
|
|
|
decode_entities(aTHX_ arg, p_state->entity2char, 1); |
535
|
71
|
100
|
|
|
|
|
if (p_state->utf8_mode) |
536
|
8
|
|
|
|
|
|
SvUTF8_off(arg); |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
} |
539
|
156
|
|
|
|
|
|
break; |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
case ARG_IS_CDATA: |
542
|
27746
|
100
|
|
|
|
|
if (event == E_TEXT) { |
543
|
27693
|
100
|
|
|
|
|
arg = boolSV(p_state->is_cdata); |
544
|
|
|
|
|
|
|
} |
545
|
27746
|
|
|
|
|
|
break; |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
case ARG_SKIPPED_TEXT: |
548
|
14
|
|
|
|
|
|
arg = sv_2mortal(p_state->skipped_text); |
549
|
14
|
|
|
|
|
|
p_state->skipped_text = newSVpvs(""); |
550
|
14
|
|
|
|
|
|
break; |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
case ARG_OFFSET: |
553
|
122
|
|
|
|
|
|
arg = sv_2mortal(newSViv(offset)); |
554
|
122
|
|
|
|
|
|
break; |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
case ARG_OFFSET_END: |
557
|
74
|
100
|
|
|
|
|
arg = sv_2mortal(newSViv(offset + CHR_DIST(end, beg))); |
558
|
74
|
|
|
|
|
|
break; |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
case ARG_LENGTH: |
561
|
101
|
100
|
|
|
|
|
arg = sv_2mortal(newSViv(CHR_DIST(end, beg))); |
562
|
101
|
|
|
|
|
|
break; |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
case ARG_LINE: |
565
|
39
|
|
|
|
|
|
arg = sv_2mortal(newSViv(line)); |
566
|
39
|
|
|
|
|
|
break; |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
case ARG_COLUMN: |
569
|
95
|
|
|
|
|
|
arg = sv_2mortal(newSViv(column)); |
570
|
95
|
|
|
|
|
|
break; |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
case ARG_EVENT: |
573
|
|
|
|
|
|
|
assert(event >= 0 && event < EVENT_COUNT); |
574
|
708
|
|
|
|
|
|
arg = sv_2mortal(newSVpv(event_id_str[event], 0)); |
575
|
708
|
|
|
|
|
|
break; |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
case ARG_LITERAL: |
578
|
|
|
|
|
|
|
{ |
579
|
8319
|
|
|
|
|
|
int len = (unsigned char)s[1]; |
580
|
8319
|
|
|
|
|
|
arg = sv_2mortal(newSVpvn(s+2, len)); |
581
|
8319
|
50
|
|
|
|
|
if (SvUTF8(h->argspec)) |
582
|
0
|
|
|
|
|
|
SvUTF8_on(arg); |
583
|
8319
|
|
|
|
|
|
s += len + 1; |
584
|
|
|
|
|
|
|
} |
585
|
8319
|
|
|
|
|
|
break; |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
case ARG_UNDEF: |
588
|
0
|
|
|
|
|
|
arg = sv_mortalcopy(&PL_sv_undef); |
589
|
0
|
|
|
|
|
|
break; |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
default: |
592
|
0
|
|
|
|
|
|
arg = sv_2mortal(newSVpvf("Bad argspec %d", *s)); |
593
|
0
|
|
|
|
|
|
break; |
594
|
|
|
|
|
|
|
} |
595
|
|
|
|
|
|
|
|
596
|
122020
|
100
|
|
|
|
|
if (push_arg) { |
597
|
121993
|
100
|
|
|
|
|
if (!arg) |
598
|
366
|
|
|
|
|
|
arg = sv_mortalcopy(&PL_sv_undef); |
599
|
|
|
|
|
|
|
|
600
|
121993
|
100
|
|
|
|
|
if (array) { |
601
|
|
|
|
|
|
|
/* have to fix mortality here or add mortality to |
602
|
|
|
|
|
|
|
* XPUSHs after removing it from the switch cases. |
603
|
|
|
|
|
|
|
*/ |
604
|
31113
|
|
|
|
|
|
av_push(array, SvREFCNT_inc(arg)); |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
else { |
607
|
90880
|
50
|
|
|
|
|
XPUSHs(arg); |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
} |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
|
612
|
36976
|
100
|
|
|
|
|
if (array) { |
613
|
8945
|
100
|
|
|
|
|
if (array != (AV*)h->cb) |
614
|
8945
|
|
|
|
|
|
av_push((AV*)h->cb, newRV_noinc((SV*)array)); |
615
|
|
|
|
|
|
|
} |
616
|
|
|
|
|
|
|
else { |
617
|
28031
|
|
|
|
|
|
PUTBACK; |
618
|
|
|
|
|
|
|
|
619
|
55566
|
100
|
|
|
|
|
if ((enum argcode)*argspec == ARG_SELF && !SvROK(h->cb)) { |
|
|
100
|
|
|
|
|
|
620
|
27535
|
50
|
|
|
|
|
char *method = SvPV(h->cb, my_na); |
621
|
27535
|
|
|
|
|
|
call_method(method, G_DISCARD | G_EVAL | G_VOID); |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
else { |
624
|
496
|
|
|
|
|
|
call_sv(h->cb, G_DISCARD | G_EVAL | G_VOID); |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
|
627
|
28031
|
50
|
|
|
|
|
if (SvTRUE(ERRSV)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
628
|
1
|
|
|
|
|
|
RETHROW; |
629
|
|
|
|
|
|
|
} |
630
|
|
|
|
|
|
|
|
631
|
28030
|
100
|
|
|
|
|
FREETMPS; |
632
|
28030
|
|
|
|
|
|
LEAVE; |
633
|
|
|
|
|
|
|
} |
634
|
36975
|
100
|
|
|
|
|
if (p_state->skipped_text) |
635
|
14
|
|
|
|
|
|
SvCUR_set(p_state->skipped_text, 0); |
636
|
36975
|
|
|
|
|
|
return; |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
IGNORE_EVENT: |
639
|
2268
|
100
|
|
|
|
|
if (p_state->skipped_text) { |
640
|
38
|
100
|
|
|
|
|
if (event != E_TEXT && p_state->pend_text && SvOK(p_state->pend_text)) |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
641
|
2
|
|
|
|
|
|
flush_pending_text(p_state, self); |
642
|
38
|
100
|
|
|
|
|
if (utf8 && !SvUTF8(p_state->skipped_text)) |
|
|
100
|
|
|
|
|
|
643
|
1
|
|
|
|
|
|
sv_utf8_upgrade(p_state->skipped_text); |
644
|
38
|
100
|
|
|
|
|
if (utf8 || !SvUTF8(p_state->skipped_text)) { |
|
|
100
|
|
|
|
|
|
645
|
37
|
|
|
|
|
|
sv_catpvn(p_state->skipped_text, beg, end - beg); |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
else { |
648
|
1
|
|
|
|
|
|
SV *tmp = newSVpvn(beg, end - beg); |
649
|
1
|
|
|
|
|
|
sv_utf8_upgrade(tmp); |
650
|
1
|
|
|
|
|
|
sv_catsv(p_state->skipped_text, tmp); |
651
|
1
|
|
|
|
|
|
SvREFCNT_dec(tmp); |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
} |
654
|
|
|
|
|
|
|
#undef CHR_DIST |
655
|
43764
|
|
|
|
|
|
return; |
656
|
|
|
|
|
|
|
} |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
EXTERN SV* |
660
|
463
|
|
|
|
|
|
argspec_compile(SV* src, PSTATE* p_state) |
661
|
|
|
|
|
|
|
{ |
662
|
|
|
|
|
|
|
dTHX; |
663
|
463
|
|
|
|
|
|
SV* argspec = newSVpvs(""); |
664
|
|
|
|
|
|
|
STRLEN len; |
665
|
463
|
50
|
|
|
|
|
char *s = SvPV(src, len); |
666
|
463
|
|
|
|
|
|
char *end = s + len; |
667
|
|
|
|
|
|
|
|
668
|
463
|
50
|
|
|
|
|
if (SvUTF8(src)) |
669
|
0
|
|
|
|
|
|
SvUTF8_on(argspec); |
670
|
|
|
|
|
|
|
|
671
|
463
|
50
|
|
|
|
|
while (isHSPACE(*s)) |
672
|
0
|
|
|
|
|
|
s++; |
673
|
|
|
|
|
|
|
|
674
|
463
|
100
|
|
|
|
|
if (*s == '@') { |
675
|
|
|
|
|
|
|
/* try to deal with '@{ ... }' wrapping */ |
676
|
7
|
|
|
|
|
|
char *tmp = s + 1; |
677
|
7
|
50
|
|
|
|
|
while (isHSPACE(*tmp)) |
678
|
0
|
|
|
|
|
|
tmp++; |
679
|
7
|
50
|
|
|
|
|
if (*tmp == '{') { |
680
|
7
|
|
|
|
|
|
char c = ARG_FLAG_FLAT_ARRAY; |
681
|
7
|
|
|
|
|
|
sv_catpvn(argspec, &c, 1); |
682
|
7
|
|
|
|
|
|
tmp++; |
683
|
7
|
50
|
|
|
|
|
while (isHSPACE(*tmp)) |
684
|
0
|
|
|
|
|
|
tmp++; |
685
|
7
|
|
|
|
|
|
s = tmp; |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
} |
688
|
1271
|
100
|
|
|
|
|
while (s < end) { |
689
|
2465
|
100
|
|
|
|
|
if (isHNAME_FIRST(*s) || *s == '@') { |
|
|
100
|
|
|
|
|
|
690
|
1200
|
|
|
|
|
|
char *name = s; |
691
|
1200
|
|
|
|
|
|
int a = ARG_SELF; |
692
|
|
|
|
|
|
|
const char * const *arg_name; |
693
|
|
|
|
|
|
|
|
694
|
1200
|
|
|
|
|
|
s++; |
695
|
6076
|
100
|
|
|
|
|
while (isHNAME_CHAR(*s)) |
696
|
4876
|
|
|
|
|
|
s++; |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
/* check identifier */ |
699
|
7622
|
100
|
|
|
|
|
for ( arg_name = argname; a < ARG_LITERAL ; ++a, ++arg_name ) { |
700
|
7620
|
100
|
|
|
|
|
if (strnEQ(*arg_name, name, s - name) && |
|
|
100
|
|
|
|
|
|
701
|
1202
|
|
|
|
|
|
(*arg_name)[s - name] == '\0') |
702
|
1198
|
|
|
|
|
|
break; |
703
|
|
|
|
|
|
|
} |
704
|
1200
|
100
|
|
|
|
|
if (a < ARG_LITERAL) { |
705
|
1198
|
|
|
|
|
|
char c = (unsigned char) a; |
706
|
1198
|
|
|
|
|
|
sv_catpvn(argspec, &c, 1); |
707
|
|
|
|
|
|
|
|
708
|
1198
|
100
|
|
|
|
|
if (a == ARG_LINE || a == ARG_COLUMN) { |
|
|
100
|
|
|
|
|
|
709
|
9
|
100
|
|
|
|
|
if (!p_state->line) |
710
|
5
|
|
|
|
|
|
p_state->line = 1; /* enable tracing of line/column */ |
711
|
|
|
|
|
|
|
} |
712
|
1198
|
100
|
|
|
|
|
if (a == ARG_SKIPPED_TEXT) { |
713
|
7
|
100
|
|
|
|
|
if (!p_state->skipped_text) { |
714
|
5
|
|
|
|
|
|
p_state->skipped_text = newSVpvs(""); |
715
|
|
|
|
|
|
|
} |
716
|
|
|
|
|
|
|
} |
717
|
1198
|
100
|
|
|
|
|
if (a == ARG_ATTR || a == ARG_ATTRARR) { |
|
|
100
|
|
|
|
|
|
718
|
162
|
100
|
|
|
|
|
if (p_state->argspec_entity_decode != ARG_DTEXT) |
719
|
80
|
|
|
|
|
|
p_state->argspec_entity_decode = ARG_ATTR; |
720
|
|
|
|
|
|
|
} |
721
|
1116
|
100
|
|
|
|
|
else if (a == ARG_DTEXT) { |
722
|
1198
|
|
|
|
|
|
p_state->argspec_entity_decode = ARG_DTEXT; |
723
|
|
|
|
|
|
|
} |
724
|
|
|
|
|
|
|
} |
725
|
|
|
|
|
|
|
else { |
726
|
2
|
|
|
|
|
|
croak("Unrecognized identifier %.*s in argspec", (int) (s - name), name); |
727
|
|
|
|
|
|
|
} |
728
|
|
|
|
|
|
|
} |
729
|
131
|
100
|
|
|
|
|
else if (*s == '"' || *s == '\'') { |
|
|
50
|
|
|
|
|
|
730
|
67
|
|
|
|
|
|
char *string_beg = s; |
731
|
67
|
|
|
|
|
|
s++; |
732
|
656
|
100
|
|
|
|
|
while (s < end && *s != *string_beg && *s != '\\') |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
733
|
589
|
|
|
|
|
|
s++; |
734
|
67
|
100
|
|
|
|
|
if (*s == *string_beg) { |
735
|
|
|
|
|
|
|
/* literal */ |
736
|
65
|
|
|
|
|
|
int len = s - string_beg - 1; |
737
|
|
|
|
|
|
|
unsigned char buf[2]; |
738
|
65
|
100
|
|
|
|
|
if (len > 255) |
739
|
1
|
|
|
|
|
|
croak("Literal string is longer than 255 chars in argspec"); |
740
|
64
|
|
|
|
|
|
buf[0] = ARG_LITERAL; |
741
|
64
|
|
|
|
|
|
buf[1] = len; |
742
|
64
|
|
|
|
|
|
sv_catpvn(argspec, (char*)buf, 2); |
743
|
64
|
|
|
|
|
|
sv_catpvn(argspec, string_beg+1, len); |
744
|
64
|
|
|
|
|
|
s++; |
745
|
|
|
|
|
|
|
} |
746
|
2
|
100
|
|
|
|
|
else if (*s == '\\') { |
747
|
1
|
|
|
|
|
|
croak("Backslash reserved for literal string in argspec"); |
748
|
|
|
|
|
|
|
} |
749
|
|
|
|
|
|
|
else { |
750
|
1
|
|
|
|
|
|
croak("Unterminated literal string in argspec"); |
751
|
|
|
|
|
|
|
} |
752
|
|
|
|
|
|
|
} |
753
|
|
|
|
|
|
|
else { |
754
|
0
|
|
|
|
|
|
croak("Bad argspec (%s)", s); |
755
|
|
|
|
|
|
|
} |
756
|
|
|
|
|
|
|
|
757
|
1263
|
100
|
|
|
|
|
while (isHSPACE(*s)) |
758
|
1
|
|
|
|
|
|
s++; |
759
|
|
|
|
|
|
|
|
760
|
1262
|
100
|
|
|
|
|
if (*s == '}' && SvPVX(argspec)[0] == ARG_FLAG_FLAT_ARRAY) { |
|
|
50
|
|
|
|
|
|
761
|
|
|
|
|
|
|
/* end of '@{ ... }' */ |
762
|
7
|
|
|
|
|
|
s++; |
763
|
7
|
50
|
|
|
|
|
while (isHSPACE(*s)) |
764
|
0
|
|
|
|
|
|
s++; |
765
|
7
|
50
|
|
|
|
|
if (s < end) |
766
|
0
|
|
|
|
|
|
croak("Bad argspec: stuff after @{...} (%s)", s); |
767
|
|
|
|
|
|
|
} |
768
|
|
|
|
|
|
|
|
769
|
1262
|
100
|
|
|
|
|
if (s == end) |
770
|
453
|
|
|
|
|
|
break; |
771
|
809
|
100
|
|
|
|
|
if (*s != ',') { |
772
|
1
|
|
|
|
|
|
croak("Missing comma separator in argspec"); |
773
|
|
|
|
|
|
|
} |
774
|
808
|
|
|
|
|
|
s++; |
775
|
840
|
100
|
|
|
|
|
while (isHSPACE(*s)) |
776
|
32
|
|
|
|
|
|
s++; |
777
|
|
|
|
|
|
|
} |
778
|
457
|
|
|
|
|
|
return argspec; |
779
|
|
|
|
|
|
|
} |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
static void |
783
|
4358
|
|
|
|
|
|
flush_pending_text(PSTATE* p_state, SV* self) |
784
|
|
|
|
|
|
|
{ |
785
|
|
|
|
|
|
|
dTHX; |
786
|
4358
|
|
|
|
|
|
bool old_unbroken_text = p_state->unbroken_text; |
787
|
4358
|
|
|
|
|
|
SV* old_pend_text = p_state->pend_text; |
788
|
4358
|
|
|
|
|
|
bool old_is_cdata = p_state->is_cdata; |
789
|
4358
|
|
|
|
|
|
STRLEN old_offset = p_state->offset; |
790
|
4358
|
|
|
|
|
|
STRLEN old_line = p_state->line; |
791
|
4358
|
|
|
|
|
|
STRLEN old_column = p_state->column; |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
assert(p_state->pend_text && SvOK(p_state->pend_text)); |
794
|
|
|
|
|
|
|
|
795
|
4358
|
|
|
|
|
|
p_state->unbroken_text = 0; |
796
|
4358
|
|
|
|
|
|
p_state->pend_text = 0; |
797
|
4358
|
|
|
|
|
|
p_state->is_cdata = p_state->pend_text_is_cdata; |
798
|
4358
|
|
|
|
|
|
p_state->offset = p_state->pend_text_offset; |
799
|
4358
|
|
|
|
|
|
p_state->line = p_state->pend_text_line; |
800
|
4358
|
|
|
|
|
|
p_state->column = p_state->pend_text_column; |
801
|
|
|
|
|
|
|
|
802
|
4358
|
|
|
|
|
|
report_event(p_state, E_TEXT, |
803
|
4358
|
|
|
|
|
|
SvPVX(old_pend_text), SvEND(old_pend_text), |
804
|
4358
|
|
|
|
|
|
SvUTF8(old_pend_text), 0, 0, self); |
805
|
4358
|
50
|
|
|
|
|
SvOK_off(old_pend_text); |
806
|
|
|
|
|
|
|
|
807
|
4358
|
|
|
|
|
|
p_state->unbroken_text = old_unbroken_text; |
808
|
4358
|
|
|
|
|
|
p_state->pend_text = old_pend_text; |
809
|
4358
|
|
|
|
|
|
p_state->is_cdata = old_is_cdata; |
810
|
4358
|
|
|
|
|
|
p_state->offset = old_offset; |
811
|
4358
|
|
|
|
|
|
p_state->line = old_line; |
812
|
4358
|
|
|
|
|
|
p_state->column = old_column; |
813
|
4358
|
|
|
|
|
|
} |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
static char* |
816
|
2995
|
|
|
|
|
|
skip_until_gt(char *beg, char *end) |
817
|
|
|
|
|
|
|
{ |
818
|
|
|
|
|
|
|
/* tries to emulate quote skipping behaviour observed in MSIE */ |
819
|
2995
|
|
|
|
|
|
char *s = beg; |
820
|
2995
|
|
|
|
|
|
char quote = '\0'; |
821
|
2995
|
|
|
|
|
|
char prev = ' '; |
822
|
20904
|
100
|
|
|
|
|
while (s < end) { |
823
|
20832
|
100
|
|
|
|
|
if (!quote && *s == '>') |
|
|
100
|
|
|
|
|
|
824
|
2923
|
|
|
|
|
|
return s; |
825
|
17909
|
100
|
|
|
|
|
if (*s == '"' || *s == '\'') { |
|
|
100
|
|
|
|
|
|
826
|
152
|
100
|
|
|
|
|
if (*s == quote) { |
827
|
6
|
|
|
|
|
|
quote = '\0'; /* end of quoted string */ |
828
|
|
|
|
|
|
|
} |
829
|
146
|
50
|
|
|
|
|
else if (!quote && (prev == ' ' || prev == '=')) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
830
|
6
|
|
|
|
|
|
quote = *s; |
831
|
|
|
|
|
|
|
} |
832
|
|
|
|
|
|
|
} |
833
|
17909
|
|
|
|
|
|
prev = *s++; |
834
|
|
|
|
|
|
|
} |
835
|
72
|
|
|
|
|
|
return end; |
836
|
|
|
|
|
|
|
} |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
static char* |
839
|
177
|
|
|
|
|
|
parse_comment(PSTATE* p_state, char *beg, char *end, U32 utf8, SV* self) |
840
|
|
|
|
|
|
|
{ |
841
|
177
|
|
|
|
|
|
char *s = beg; |
842
|
|
|
|
|
|
|
|
843
|
177
|
100
|
|
|
|
|
if (p_state->strict_comment) { |
844
|
6
|
|
|
|
|
|
dTOKENS(4); |
845
|
6
|
|
|
|
|
|
char *start_com = s; /* also used to signal inside/outside */ |
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
while (1) { |
848
|
|
|
|
|
|
|
/* try to locate "--" */ |
849
|
|
|
|
|
|
|
FIND_DASH_DASH: |
850
|
|
|
|
|
|
|
/* printf("find_dash_dash: [%s]\n", s); */ |
851
|
125
|
50
|
|
|
|
|
while (s < end && *s != '-' && *s != '>') |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
852
|
104
|
|
|
|
|
|
s++; |
853
|
|
|
|
|
|
|
|
854
|
21
|
50
|
|
|
|
|
if (s == end) { |
855
|
0
|
0
|
|
|
|
|
FREE_TOKENS; |
856
|
0
|
|
|
|
|
|
return beg; |
857
|
|
|
|
|
|
|
} |
858
|
|
|
|
|
|
|
|
859
|
21
|
100
|
|
|
|
|
if (*s == '>') { |
860
|
8
|
|
|
|
|
|
s++; |
861
|
8
|
100
|
|
|
|
|
if (start_com) |
862
|
2
|
|
|
|
|
|
goto FIND_DASH_DASH; |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
/* we are done recognizing all comments, make callbacks */ |
865
|
6
|
|
|
|
|
|
report_event(p_state, E_COMMENT, |
866
|
|
|
|
|
|
|
beg - 4, s, utf8, |
867
|
|
|
|
|
|
|
tokens, num_tokens, |
868
|
|
|
|
|
|
|
self); |
869
|
6
|
50
|
|
|
|
|
FREE_TOKENS; |
870
|
|
|
|
|
|
|
|
871
|
6
|
|
|
|
|
|
return s; |
872
|
|
|
|
|
|
|
} |
873
|
|
|
|
|
|
|
|
874
|
13
|
|
|
|
|
|
s++; |
875
|
13
|
50
|
|
|
|
|
if (s == end) { |
876
|
0
|
0
|
|
|
|
|
FREE_TOKENS; |
877
|
0
|
|
|
|
|
|
return beg; |
878
|
|
|
|
|
|
|
} |
879
|
|
|
|
|
|
|
|
880
|
13
|
100
|
|
|
|
|
if (*s == '-') { |
881
|
|
|
|
|
|
|
/* two dashes in a row seen */ |
882
|
12
|
|
|
|
|
|
s++; |
883
|
|
|
|
|
|
|
/* do something */ |
884
|
12
|
100
|
|
|
|
|
if (start_com) { |
885
|
9
|
50
|
|
|
|
|
PUSH_TOKEN(start_com, s-2); |
886
|
9
|
|
|
|
|
|
start_com = 0; |
887
|
|
|
|
|
|
|
} |
888
|
|
|
|
|
|
|
else { |
889
|
3
|
|
|
|
|
|
start_com = s; |
890
|
|
|
|
|
|
|
} |
891
|
|
|
|
|
|
|
} |
892
|
19
|
|
|
|
|
|
} |
893
|
|
|
|
|
|
|
} |
894
|
171
|
100
|
|
|
|
|
else if (p_state->no_dash_dash_comment_end) { |
895
|
|
|
|
|
|
|
token_pos_t token; |
896
|
2
|
|
|
|
|
|
token.beg = beg; |
897
|
|
|
|
|
|
|
/* a lone '>' signals end-of-comment */ |
898
|
16
|
50
|
|
|
|
|
while (s < end && *s != '>') |
|
|
100
|
|
|
|
|
|
899
|
14
|
|
|
|
|
|
s++; |
900
|
2
|
|
|
|
|
|
token.end = s; |
901
|
2
|
50
|
|
|
|
|
if (s < end) { |
902
|
2
|
|
|
|
|
|
s++; |
903
|
2
|
|
|
|
|
|
report_event(p_state, E_COMMENT, beg-4, s, utf8, &token, 1, self); |
904
|
2
|
|
|
|
|
|
return s; |
905
|
|
|
|
|
|
|
} |
906
|
|
|
|
|
|
|
else { |
907
|
2
|
|
|
|
|
|
return beg; |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
} |
910
|
|
|
|
|
|
|
else { /* non-strict comment */ |
911
|
|
|
|
|
|
|
token_pos_t token; |
912
|
169
|
|
|
|
|
|
token.beg = beg; |
913
|
|
|
|
|
|
|
/* try to locate /--\s*>/ which signals end-of-comment */ |
914
|
|
|
|
|
|
|
LOCATE_END: |
915
|
2330
|
100
|
|
|
|
|
while (s < end && *s != '-') |
|
|
100
|
|
|
|
|
|
916
|
2131
|
|
|
|
|
|
s++; |
917
|
199
|
|
|
|
|
|
token.end = s; |
918
|
199
|
100
|
|
|
|
|
if (s < end) { |
919
|
95
|
|
|
|
|
|
s++; |
920
|
95
|
100
|
|
|
|
|
if (*s == '-') { |
921
|
78
|
|
|
|
|
|
s++; |
922
|
93
|
100
|
|
|
|
|
while (isHSPACE(*s)) |
923
|
15
|
|
|
|
|
|
s++; |
924
|
78
|
100
|
|
|
|
|
if (*s == '>') { |
925
|
48
|
|
|
|
|
|
s++; |
926
|
|
|
|
|
|
|
/* yup */ |
927
|
48
|
|
|
|
|
|
report_event(p_state, E_COMMENT, beg-4, s, utf8, &token, 1, self); |
928
|
169
|
|
|
|
|
|
return s; |
929
|
|
|
|
|
|
|
} |
930
|
|
|
|
|
|
|
} |
931
|
47
|
100
|
|
|
|
|
if (s < end) { |
932
|
30
|
|
|
|
|
|
s = token.end + 1; |
933
|
30
|
|
|
|
|
|
goto LOCATE_END; |
934
|
|
|
|
|
|
|
} |
935
|
|
|
|
|
|
|
} |
936
|
|
|
|
|
|
|
|
937
|
121
|
50
|
|
|
|
|
if (s == end) |
938
|
121
|
|
|
|
|
|
return beg; |
939
|
|
|
|
|
|
|
} |
940
|
|
|
|
|
|
|
|
941
|
0
|
|
|
|
|
|
return 0; |
942
|
|
|
|
|
|
|
} |
943
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
#ifdef MARKED_SECTION |
946
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
static void |
948
|
32
|
|
|
|
|
|
marked_section_update(PSTATE* p_state) |
949
|
|
|
|
|
|
|
{ |
950
|
|
|
|
|
|
|
dTHX; |
951
|
|
|
|
|
|
|
/* we look at p_state->ms_stack to determine p_state->ms */ |
952
|
32
|
|
|
|
|
|
AV* ms_stack = p_state->ms_stack; |
953
|
32
|
|
|
|
|
|
p_state->ms = MS_NONE; |
954
|
|
|
|
|
|
|
|
955
|
32
|
50
|
|
|
|
|
if (ms_stack) { |
956
|
32
|
|
|
|
|
|
int stack_len = av_len(ms_stack); |
957
|
|
|
|
|
|
|
int stack_idx; |
958
|
50
|
100
|
|
|
|
|
for (stack_idx = 0; stack_idx <= stack_len; stack_idx++) { |
959
|
18
|
|
|
|
|
|
SV** svp = av_fetch(ms_stack, stack_idx, 0); |
960
|
18
|
50
|
|
|
|
|
if (svp) { |
961
|
18
|
|
|
|
|
|
AV* tokens = (AV*)SvRV(*svp); |
962
|
18
|
|
|
|
|
|
int tokens_len = av_len(tokens); |
963
|
|
|
|
|
|
|
int i; |
964
|
|
|
|
|
|
|
assert(SvTYPE(tokens) == SVt_PVAV); |
965
|
43
|
100
|
|
|
|
|
for (i = 0; i <= tokens_len; i++) { |
966
|
25
|
|
|
|
|
|
SV** svp = av_fetch(tokens, i, 0); |
967
|
25
|
50
|
|
|
|
|
if (svp) { |
968
|
|
|
|
|
|
|
STRLEN len; |
969
|
25
|
50
|
|
|
|
|
char *token_str = SvPV(*svp, len); |
970
|
|
|
|
|
|
|
enum marked_section_t token; |
971
|
25
|
100
|
|
|
|
|
if (strEQ(token_str, "include")) |
972
|
11
|
|
|
|
|
|
token = MS_INCLUDE; |
973
|
14
|
100
|
|
|
|
|
else if (strEQ(token_str, "rcdata")) |
974
|
4
|
|
|
|
|
|
token = MS_RCDATA; |
975
|
10
|
100
|
|
|
|
|
else if (strEQ(token_str, "cdata")) |
976
|
7
|
|
|
|
|
|
token = MS_CDATA; |
977
|
3
|
100
|
|
|
|
|
else if (strEQ(token_str, "ignore")) |
978
|
2
|
|
|
|
|
|
token = MS_IGNORE; |
979
|
|
|
|
|
|
|
else |
980
|
1
|
|
|
|
|
|
token = MS_NONE; |
981
|
25
|
100
|
|
|
|
|
if (p_state->ms < token) |
982
|
25
|
|
|
|
|
|
p_state->ms = token; |
983
|
|
|
|
|
|
|
} |
984
|
|
|
|
|
|
|
} |
985
|
|
|
|
|
|
|
} |
986
|
|
|
|
|
|
|
} |
987
|
|
|
|
|
|
|
} |
988
|
|
|
|
|
|
|
/* printf("MS %d\n", p_state->ms); */ |
989
|
32
|
|
|
|
|
|
p_state->is_cdata = (p_state->ms == MS_CDATA); |
990
|
32
|
|
|
|
|
|
return; |
991
|
|
|
|
|
|
|
} |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
static char* |
995
|
16
|
|
|
|
|
|
parse_marked_section(PSTATE* p_state, char *beg, char *end, U32 utf8, SV* self) |
996
|
|
|
|
|
|
|
{ |
997
|
|
|
|
|
|
|
dTHX; |
998
|
|
|
|
|
|
|
char *s; |
999
|
16
|
|
|
|
|
|
AV* tokens = 0; |
1000
|
|
|
|
|
|
|
|
1001
|
16
|
50
|
|
|
|
|
if (!p_state->marked_sections) |
1002
|
0
|
|
|
|
|
|
return 0; |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
assert(beg[0] == '<'); |
1005
|
|
|
|
|
|
|
assert(beg[1] == '!'); |
1006
|
|
|
|
|
|
|
assert(beg[2] == '['); |
1007
|
16
|
|
|
|
|
|
s = beg + 3; |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
FIND_NAMES: |
1010
|
22
|
100
|
|
|
|
|
while (isHSPACE(*s)) |
1011
|
5
|
|
|
|
|
|
s++; |
1012
|
37
|
100
|
|
|
|
|
while (isHNAME_FIRST(*s)) { |
1013
|
20
|
|
|
|
|
|
char *name_start = s; |
1014
|
|
|
|
|
|
|
char *name_end; |
1015
|
|
|
|
|
|
|
SV *name; |
1016
|
20
|
|
|
|
|
|
s++; |
1017
|
117
|
100
|
|
|
|
|
while (isHNAME_CHAR(*s)) |
1018
|
97
|
|
|
|
|
|
s++; |
1019
|
20
|
|
|
|
|
|
name_end = s; |
1020
|
39
|
100
|
|
|
|
|
while (isHSPACE(*s)) |
1021
|
19
|
|
|
|
|
|
s++; |
1022
|
20
|
50
|
|
|
|
|
if (s == end) |
1023
|
0
|
|
|
|
|
|
goto PREMATURE; |
1024
|
|
|
|
|
|
|
|
1025
|
20
|
100
|
|
|
|
|
if (!tokens) |
1026
|
13
|
|
|
|
|
|
tokens = newAV(); |
1027
|
20
|
|
|
|
|
|
name = newSVpvn(name_start, name_end - name_start); |
1028
|
20
|
100
|
|
|
|
|
if (utf8) |
1029
|
1
|
|
|
|
|
|
SvUTF8_on(name); |
1030
|
20
|
|
|
|
|
|
av_push(tokens, sv_lower(aTHX_ name)); |
1031
|
|
|
|
|
|
|
} |
1032
|
17
|
100
|
|
|
|
|
if (*s == '-') { |
1033
|
1
|
|
|
|
|
|
s++; |
1034
|
1
|
50
|
|
|
|
|
if (*s == '-') { |
1035
|
|
|
|
|
|
|
/* comment */ |
1036
|
1
|
|
|
|
|
|
s++; |
1037
|
|
|
|
|
|
|
while (1) { |
1038
|
9
|
50
|
|
|
|
|
while (s < end && *s != '-') |
|
|
100
|
|
|
|
|
|
1039
|
8
|
|
|
|
|
|
s++; |
1040
|
1
|
50
|
|
|
|
|
if (s == end) |
1041
|
0
|
|
|
|
|
|
goto PREMATURE; |
1042
|
|
|
|
|
|
|
|
1043
|
1
|
|
|
|
|
|
s++; /* skip first '-' */ |
1044
|
1
|
50
|
|
|
|
|
if (*s == '-') { |
1045
|
1
|
|
|
|
|
|
s++; |
1046
|
|
|
|
|
|
|
/* comment finished */ |
1047
|
1
|
|
|
|
|
|
goto FIND_NAMES; |
1048
|
|
|
|
|
|
|
} |
1049
|
0
|
|
|
|
|
|
} |
1050
|
|
|
|
|
|
|
} |
1051
|
|
|
|
|
|
|
else |
1052
|
0
|
|
|
|
|
|
goto FAIL; |
1053
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
} |
1055
|
16
|
50
|
|
|
|
|
if (*s == '[') { |
1056
|
16
|
|
|
|
|
|
s++; |
1057
|
|
|
|
|
|
|
/* yup */ |
1058
|
|
|
|
|
|
|
|
1059
|
16
|
100
|
|
|
|
|
if (!tokens) { |
1060
|
3
|
|
|
|
|
|
tokens = newAV(); |
1061
|
3
|
|
|
|
|
|
av_push(tokens, newSVpvs("include")); |
1062
|
|
|
|
|
|
|
} |
1063
|
|
|
|
|
|
|
|
1064
|
16
|
100
|
|
|
|
|
if (!p_state->ms_stack) |
1065
|
4
|
|
|
|
|
|
p_state->ms_stack = newAV(); |
1066
|
16
|
|
|
|
|
|
av_push(p_state->ms_stack, newRV_noinc((SV*)tokens)); |
1067
|
16
|
|
|
|
|
|
marked_section_update(p_state); |
1068
|
16
|
|
|
|
|
|
report_event(p_state, E_NONE, beg, s, utf8, 0, 0, self); |
1069
|
16
|
|
|
|
|
|
return s; |
1070
|
|
|
|
|
|
|
} |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
FAIL: |
1073
|
0
|
|
|
|
|
|
SvREFCNT_dec(tokens); |
1074
|
0
|
|
|
|
|
|
return 0; /* not yet implemented */ |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
PREMATURE: |
1077
|
0
|
|
|
|
|
|
SvREFCNT_dec(tokens); |
1078
|
0
|
|
|
|
|
|
return beg; |
1079
|
|
|
|
|
|
|
} |
1080
|
|
|
|
|
|
|
#endif |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
static char* |
1084
|
579
|
|
|
|
|
|
parse_decl(PSTATE* p_state, char *beg, char *end, U32 utf8, SV* self) |
1085
|
|
|
|
|
|
|
{ |
1086
|
579
|
|
|
|
|
|
char *s = beg + 2; |
1087
|
|
|
|
|
|
|
|
1088
|
579
|
100
|
|
|
|
|
if (*s == '-') { |
1089
|
|
|
|
|
|
|
/* comment? */ |
1090
|
|
|
|
|
|
|
|
1091
|
|
|
|
|
|
|
char *tmp; |
1092
|
185
|
|
|
|
|
|
s++; |
1093
|
185
|
100
|
|
|
|
|
if (s == end) |
1094
|
6
|
|
|
|
|
|
return beg; |
1095
|
|
|
|
|
|
|
|
1096
|
179
|
100
|
|
|
|
|
if (*s != '-') |
1097
|
2
|
|
|
|
|
|
goto DECL_FAIL; /* nope, illegal */ |
1098
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
/* yes, two dashes seen */ |
1100
|
177
|
|
|
|
|
|
s++; |
1101
|
|
|
|
|
|
|
|
1102
|
177
|
|
|
|
|
|
tmp = parse_comment(p_state, s, end, utf8, self); |
1103
|
177
|
100
|
|
|
|
|
return (tmp == s) ? beg : tmp; |
1104
|
|
|
|
|
|
|
} |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
#ifdef MARKED_SECTION |
1107
|
394
|
100
|
|
|
|
|
if (*s == '[') { |
1108
|
|
|
|
|
|
|
/* marked section */ |
1109
|
|
|
|
|
|
|
char *tmp; |
1110
|
16
|
|
|
|
|
|
tmp = parse_marked_section(p_state, beg, end, utf8, self); |
1111
|
16
|
50
|
|
|
|
|
if (!tmp) |
1112
|
0
|
|
|
|
|
|
goto DECL_FAIL; |
1113
|
16
|
|
|
|
|
|
return tmp; |
1114
|
|
|
|
|
|
|
} |
1115
|
|
|
|
|
|
|
#endif |
1116
|
|
|
|
|
|
|
|
1117
|
378
|
100
|
|
|
|
|
if (*s == '>') { |
1118
|
|
|
|
|
|
|
/* make into empty comment */ |
1119
|
|
|
|
|
|
|
token_pos_t token; |
1120
|
1
|
|
|
|
|
|
token.beg = s; |
1121
|
1
|
|
|
|
|
|
token.end = s; |
1122
|
1
|
|
|
|
|
|
s++; |
1123
|
1
|
|
|
|
|
|
report_event(p_state, E_COMMENT, beg, s, utf8, &token, 1, self); |
1124
|
1
|
|
|
|
|
|
return s; |
1125
|
|
|
|
|
|
|
} |
1126
|
|
|
|
|
|
|
|
1127
|
377
|
100
|
|
|
|
|
if (isALPHA(*s)) { |
1128
|
308
|
|
|
|
|
|
dTOKENS(8); |
1129
|
308
|
|
|
|
|
|
char *decl_id = s; |
1130
|
|
|
|
|
|
|
STRLEN decl_id_len; |
1131
|
|
|
|
|
|
|
|
1132
|
308
|
|
|
|
|
|
s++; |
1133
|
|
|
|
|
|
|
/* declaration */ |
1134
|
1986
|
100
|
|
|
|
|
while (s < end && isHNAME_CHAR(*s)) |
|
|
100
|
|
|
|
|
|
1135
|
1678
|
|
|
|
|
|
s++; |
1136
|
308
|
|
|
|
|
|
decl_id_len = s - decl_id; |
1137
|
308
|
100
|
|
|
|
|
if (s == end) |
1138
|
16
|
|
|
|
|
|
goto PREMATURE; |
1139
|
|
|
|
|
|
|
|
1140
|
|
|
|
|
|
|
/* just hardcode a few names as the recognized declarations */ |
1141
|
558
|
100
|
|
|
|
|
if (!((decl_id_len == 7 && |
1142
|
266
|
50
|
|
|
|
|
strnEQx(decl_id, "DOCTYPE", 7, !CASE_SENSITIVE(p_state))) || |
|
|
50
|
|
|
|
|
|
1143
|
4
|
50
|
|
|
|
|
(decl_id_len == 6 && |
1144
|
4
|
100
|
|
|
|
|
strnEQx(decl_id, "ENTITY", 6, !CASE_SENSITIVE(p_state))) |
|
|
50
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
) |
1146
|
|
|
|
|
|
|
) |
1147
|
|
|
|
|
|
|
{ |
1148
|
|
|
|
|
|
|
goto FAIL; |
1149
|
|
|
|
|
|
|
} |
1150
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
/* first word available */ |
1152
|
269
|
50
|
|
|
|
|
PUSH_TOKEN(decl_id, s); |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
while (1) { |
1155
|
50732
|
100
|
|
|
|
|
while (s < end && isHSPACE(*s)) |
|
|
100
|
|
|
|
|
|
1156
|
25413
|
|
|
|
|
|
s++; |
1157
|
|
|
|
|
|
|
|
1158
|
25319
|
100
|
|
|
|
|
if (s == end) |
1159
|
165
|
|
|
|
|
|
goto PREMATURE; |
1160
|
|
|
|
|
|
|
|
1161
|
25218
|
100
|
|
|
|
|
if (*s == '"' || *s == '\'' || (*s == '`' && p_state->backquote)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1162
|
129
|
|
|
|
|
|
char *str_beg = s; |
1163
|
129
|
|
|
|
|
|
s++; |
1164
|
2914
|
100
|
|
|
|
|
while (s < end && *s != *str_beg) |
|
|
100
|
|
|
|
|
|
1165
|
2785
|
|
|
|
|
|
s++; |
1166
|
129
|
100
|
|
|
|
|
if (s == end) |
1167
|
65
|
|
|
|
|
|
goto PREMATURE; |
1168
|
64
|
|
|
|
|
|
s++; |
1169
|
64
|
50
|
|
|
|
|
PUSH_TOKEN(str_beg, s); |
1170
|
|
|
|
|
|
|
} |
1171
|
25025
|
100
|
|
|
|
|
else if (*s == '-') { |
1172
|
|
|
|
|
|
|
/* comment */ |
1173
|
12405
|
|
|
|
|
|
char *com_beg = s; |
1174
|
12405
|
|
|
|
|
|
s++; |
1175
|
12405
|
50
|
|
|
|
|
if (s == end) |
1176
|
0
|
|
|
|
|
|
goto PREMATURE; |
1177
|
12405
|
50
|
|
|
|
|
if (*s != '-') |
1178
|
0
|
|
|
|
|
|
goto FAIL; |
1179
|
12405
|
|
|
|
|
|
s++; |
1180
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
while (1) { |
1182
|
62054
|
50
|
|
|
|
|
while (s < end && *s != '-') |
|
|
100
|
|
|
|
|
|
1183
|
49647
|
|
|
|
|
|
s++; |
1184
|
12407
|
50
|
|
|
|
|
if (s == end) |
1185
|
0
|
|
|
|
|
|
goto PREMATURE; |
1186
|
12407
|
|
|
|
|
|
s++; |
1187
|
12407
|
50
|
|
|
|
|
if (s == end) |
1188
|
0
|
|
|
|
|
|
goto PREMATURE; |
1189
|
12407
|
100
|
|
|
|
|
if (*s == '-') { |
1190
|
12405
|
|
|
|
|
|
s++; |
1191
|
12405
|
50
|
|
|
|
|
PUSH_TOKEN(com_beg, s); |
1192
|
12405
|
|
|
|
|
|
break; |
1193
|
|
|
|
|
|
|
} |
1194
|
12407
|
|
|
|
|
|
} |
1195
|
|
|
|
|
|
|
} |
1196
|
12620
|
100
|
|
|
|
|
else if (*s != '>') { |
1197
|
|
|
|
|
|
|
/* plain word */ |
1198
|
12598
|
|
|
|
|
|
char *word_beg = s; |
1199
|
12598
|
|
|
|
|
|
s++; |
1200
|
25722
|
100
|
|
|
|
|
while (s < end && isHNOT_SPACE_GT(*s)) |
|
|
100
|
|
|
|
|
|
1201
|
13124
|
|
|
|
|
|
s++; |
1202
|
12598
|
100
|
|
|
|
|
if (s == end) |
1203
|
17
|
|
|
|
|
|
goto PREMATURE; |
1204
|
12581
|
100
|
|
|
|
|
PUSH_TOKEN(word_beg, s); |
1205
|
|
|
|
|
|
|
} |
1206
|
|
|
|
|
|
|
else { |
1207
|
22
|
|
|
|
|
|
break; |
1208
|
|
|
|
|
|
|
} |
1209
|
25050
|
|
|
|
|
|
} |
1210
|
|
|
|
|
|
|
|
1211
|
22
|
50
|
|
|
|
|
if (s == end) |
1212
|
0
|
|
|
|
|
|
goto PREMATURE; |
1213
|
22
|
50
|
|
|
|
|
if (*s == '>') { |
1214
|
22
|
|
|
|
|
|
s++; |
1215
|
22
|
|
|
|
|
|
report_event(p_state, E_DECLARATION, beg, s, utf8, tokens, num_tokens, self); |
1216
|
22
|
100
|
|
|
|
|
FREE_TOKENS; |
1217
|
285
|
|
|
|
|
|
return s; |
1218
|
|
|
|
|
|
|
} |
1219
|
|
|
|
|
|
|
|
1220
|
|
|
|
|
|
|
FAIL: |
1221
|
23
|
50
|
|
|
|
|
FREE_TOKENS; |
1222
|
23
|
|
|
|
|
|
goto DECL_FAIL; |
1223
|
|
|
|
|
|
|
|
1224
|
|
|
|
|
|
|
PREMATURE: |
1225
|
263
|
100
|
|
|
|
|
FREE_TOKENS; |
1226
|
263
|
|
|
|
|
|
return beg; |
1227
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
} |
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
DECL_FAIL: |
1231
|
94
|
50
|
|
|
|
|
if (p_state->strict_comment) |
1232
|
0
|
|
|
|
|
|
return 0; |
1233
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
/* consider everything up to the first '>' a comment */ |
1235
|
15815
|
100
|
|
|
|
|
while (s < end && *s != '>') |
|
|
100
|
|
|
|
|
|
1236
|
15721
|
|
|
|
|
|
s++; |
1237
|
94
|
100
|
|
|
|
|
if (s < end) { |
1238
|
|
|
|
|
|
|
token_pos_t token; |
1239
|
67
|
|
|
|
|
|
token.beg = beg + 2; |
1240
|
67
|
|
|
|
|
|
token.end = s; |
1241
|
67
|
|
|
|
|
|
s++; |
1242
|
67
|
|
|
|
|
|
report_event(p_state, E_COMMENT, beg, s, utf8, &token, 1, self); |
1243
|
67
|
|
|
|
|
|
return s; |
1244
|
|
|
|
|
|
|
} |
1245
|
|
|
|
|
|
|
else { |
1246
|
27
|
|
|
|
|
|
return beg; |
1247
|
|
|
|
|
|
|
} |
1248
|
|
|
|
|
|
|
} |
1249
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
|
1251
|
|
|
|
|
|
|
static char* |
1252
|
8982
|
|
|
|
|
|
parse_start(PSTATE* p_state, char *beg, char *end, U32 utf8, SV* self) |
1253
|
|
|
|
|
|
|
{ |
1254
|
8982
|
|
|
|
|
|
char *s = beg; |
1255
|
8982
|
|
|
|
|
|
int empty_tag = 0; |
1256
|
8982
|
|
|
|
|
|
dTOKENS(16); |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
hctype_t tag_name_char; |
1259
|
|
|
|
|
|
|
hctype_t attr_name_first, attr_name_char; |
1260
|
|
|
|
|
|
|
|
1261
|
8982
|
100
|
|
|
|
|
if (STRICT_NAMES(p_state)) { |
|
|
50
|
|
|
|
|
|
1262
|
20
|
|
|
|
|
|
attr_name_first = HCTYPE_NAME_FIRST; |
1263
|
20
|
|
|
|
|
|
tag_name_char = attr_name_char = HCTYPE_NAME_CHAR; |
1264
|
|
|
|
|
|
|
} |
1265
|
|
|
|
|
|
|
else { |
1266
|
8962
|
|
|
|
|
|
tag_name_char = HCTYPE_NOT_SPACE_GT; |
1267
|
8962
|
|
|
|
|
|
attr_name_first = HCTYPE_NOT_SPACE_GT; |
1268
|
8962
|
|
|
|
|
|
attr_name_char = HCTYPE_NOT_SPACE_EQ_GT; |
1269
|
|
|
|
|
|
|
} |
1270
|
|
|
|
|
|
|
|
1271
|
8982
|
|
|
|
|
|
s += 2; |
1272
|
|
|
|
|
|
|
|
1273
|
190506
|
100
|
|
|
|
|
while (s < end && isHCTYPE(*s, tag_name_char)) { |
|
|
100
|
|
|
|
|
|
1274
|
181524
|
100
|
|
|
|
|
if (*s == '/' && ALLOW_EMPTY_TAG(p_state)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1275
|
0
|
0
|
|
|
|
|
if ((s + 1) == end) |
1276
|
0
|
|
|
|
|
|
goto PREMATURE; |
1277
|
0
|
0
|
|
|
|
|
if (*(s + 1) == '>') |
1278
|
0
|
|
|
|
|
|
break; |
1279
|
|
|
|
|
|
|
} |
1280
|
181524
|
|
|
|
|
|
s++; |
1281
|
|
|
|
|
|
|
} |
1282
|
8982
|
50
|
|
|
|
|
PUSH_TOKEN(beg+1, s); /* tagname */ |
1283
|
|
|
|
|
|
|
|
1284
|
16514
|
100
|
|
|
|
|
while (isHSPACE(*s)) |
1285
|
7532
|
|
|
|
|
|
s++; |
1286
|
8982
|
100
|
|
|
|
|
if (s == end) |
1287
|
337
|
|
|
|
|
|
goto PREMATURE; |
1288
|
|
|
|
|
|
|
|
1289
|
47051
|
100
|
|
|
|
|
while (isHCTYPE(*s, attr_name_first)) { |
1290
|
|
|
|
|
|
|
/* attribute */ |
1291
|
40368
|
|
|
|
|
|
char *attr_name_beg = s; |
1292
|
|
|
|
|
|
|
char *attr_name_end; |
1293
|
40368
|
100
|
|
|
|
|
if (*s == '/' && ALLOW_EMPTY_TAG(p_state)) { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1294
|
4
|
50
|
|
|
|
|
if ((s + 1) == end) |
1295
|
0
|
|
|
|
|
|
goto PREMATURE; |
1296
|
4
|
50
|
|
|
|
|
if (*(s + 1) == '>') |
1297
|
4
|
|
|
|
|
|
break; |
1298
|
|
|
|
|
|
|
} |
1299
|
40364
|
|
|
|
|
|
s++; |
1300
|
812099
|
100
|
|
|
|
|
while (s < end && isHCTYPE(*s, attr_name_char)) { |
|
|
100
|
|
|
|
|
|
1301
|
771735
|
100
|
|
|
|
|
if (*s == '/' && ALLOW_EMPTY_TAG(p_state)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1302
|
0
|
0
|
|
|
|
|
if ((s + 1) == end) |
1303
|
0
|
|
|
|
|
|
goto PREMATURE; |
1304
|
0
|
0
|
|
|
|
|
if (*(s + 1) == '>') |
1305
|
0
|
|
|
|
|
|
break; |
1306
|
|
|
|
|
|
|
} |
1307
|
771735
|
|
|
|
|
|
s++; |
1308
|
|
|
|
|
|
|
} |
1309
|
40364
|
100
|
|
|
|
|
if (s == end) |
1310
|
1232
|
|
|
|
|
|
goto PREMATURE; |
1311
|
|
|
|
|
|
|
|
1312
|
39132
|
|
|
|
|
|
attr_name_end = s; |
1313
|
39132
|
100
|
|
|
|
|
PUSH_TOKEN(attr_name_beg, attr_name_end); /* attr name */ |
1314
|
|
|
|
|
|
|
|
1315
|
57595
|
100
|
|
|
|
|
while (isHSPACE(*s)) |
1316
|
18463
|
|
|
|
|
|
s++; |
1317
|
39132
|
100
|
|
|
|
|
if (s == end) |
1318
|
34
|
|
|
|
|
|
goto PREMATURE; |
1319
|
|
|
|
|
|
|
|
1320
|
39098
|
100
|
|
|
|
|
if (*s == '=') { |
1321
|
|
|
|
|
|
|
/* with a value */ |
1322
|
18620
|
|
|
|
|
|
s++; |
1323
|
18693
|
100
|
|
|
|
|
while (isHSPACE(*s)) |
1324
|
73
|
|
|
|
|
|
s++; |
1325
|
18620
|
100
|
|
|
|
|
if (s == end) |
1326
|
35
|
|
|
|
|
|
goto PREMATURE; |
1327
|
18585
|
100
|
|
|
|
|
if (*s == '>') { |
1328
|
|
|
|
|
|
|
/* parse it similar to ="" */ |
1329
|
18
|
50
|
|
|
|
|
PUSH_TOKEN(s, s); |
1330
|
18
|
|
|
|
|
|
break; |
1331
|
|
|
|
|
|
|
} |
1332
|
21291
|
100
|
|
|
|
|
if (*s == '"' || *s == '\'' || (*s == '`' && p_state->backquote)) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1333
|
3009
|
|
|
|
|
|
char *str_beg = s; |
1334
|
3009
|
|
|
|
|
|
s++; |
1335
|
37442
|
100
|
|
|
|
|
while (s < end && *s != *str_beg) |
|
|
100
|
|
|
|
|
|
1336
|
34433
|
|
|
|
|
|
s++; |
1337
|
3009
|
100
|
|
|
|
|
if (s == end) |
1338
|
285
|
|
|
|
|
|
goto PREMATURE; |
1339
|
2724
|
|
|
|
|
|
s++; |
1340
|
2724
|
50
|
|
|
|
|
PUSH_TOKEN(str_beg, s); |
1341
|
|
|
|
|
|
|
} |
1342
|
|
|
|
|
|
|
else { |
1343
|
15558
|
|
|
|
|
|
char *word_start = s; |
1344
|
141087
|
100
|
|
|
|
|
while (s < end && isHNOT_SPACE_GT(*s)) { |
|
|
100
|
|
|
|
|
|
1345
|
125531
|
100
|
|
|
|
|
if (*s == '/' && ALLOW_EMPTY_TAG(p_state)) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1346
|
2
|
50
|
|
|
|
|
if ((s + 1) == end) |
1347
|
0
|
|
|
|
|
|
goto PREMATURE; |
1348
|
2
|
50
|
|
|
|
|
if (*(s + 1) == '>') |
1349
|
2
|
|
|
|
|
|
break; |
1350
|
|
|
|
|
|
|
} |
1351
|
125529
|
|
|
|
|
|
s++; |
1352
|
|
|
|
|
|
|
} |
1353
|
15558
|
100
|
|
|
|
|
if (s == end) |
1354
|
158
|
|
|
|
|
|
goto PREMATURE; |
1355
|
15400
|
50
|
|
|
|
|
PUSH_TOKEN(word_start, s); |
1356
|
|
|
|
|
|
|
} |
1357
|
33411
|
100
|
|
|
|
|
while (isHSPACE(*s)) |
1358
|
15287
|
|
|
|
|
|
s++; |
1359
|
18124
|
100
|
|
|
|
|
if (s == end) |
1360
|
196
|
|
|
|
|
|
goto PREMATURE; |
1361
|
|
|
|
|
|
|
} |
1362
|
|
|
|
|
|
|
else { |
1363
|
20478
|
50
|
|
|
|
|
PUSH_TOKEN(0, 0); /* boolean attr value */ |
1364
|
|
|
|
|
|
|
} |
1365
|
|
|
|
|
|
|
} |
1366
|
|
|
|
|
|
|
|
1367
|
6705
|
100
|
|
|
|
|
if (ALLOW_EMPTY_TAG(p_state) && *s == '/') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1368
|
7
|
|
|
|
|
|
s++; |
1369
|
7
|
50
|
|
|
|
|
if (s == end) |
1370
|
0
|
|
|
|
|
|
goto PREMATURE; |
1371
|
7
|
|
|
|
|
|
empty_tag = 1; |
1372
|
|
|
|
|
|
|
} |
1373
|
|
|
|
|
|
|
|
1374
|
6705
|
50
|
|
|
|
|
if (*s == '>') { |
1375
|
6705
|
|
|
|
|
|
s++; |
1376
|
|
|
|
|
|
|
/* done */ |
1377
|
6705
|
|
|
|
|
|
report_event(p_state, E_START, beg, s, utf8, tokens, num_tokens, self); |
1378
|
6705
|
100
|
|
|
|
|
if (empty_tag) { |
1379
|
7
|
|
|
|
|
|
report_event(p_state, E_END, s, s, utf8, tokens, 1, self); |
1380
|
|
|
|
|
|
|
} |
1381
|
6698
|
100
|
|
|
|
|
else if (!p_state->xml_mode) { |
1382
|
|
|
|
|
|
|
/* find out if this start tag should put us into literal_mode |
1383
|
|
|
|
|
|
|
*/ |
1384
|
|
|
|
|
|
|
int i; |
1385
|
6681
|
|
|
|
|
|
int tag_len = tokens[0].end - tokens[0].beg; |
1386
|
|
|
|
|
|
|
|
1387
|
53160
|
100
|
|
|
|
|
for (i = 0; literal_mode_elem[i].len; i++) { |
1388
|
46584
|
100
|
|
|
|
|
if (tag_len == literal_mode_elem[i].len) { |
1389
|
|
|
|
|
|
|
/* try to match it */ |
1390
|
852
|
|
|
|
|
|
char *s = beg + 1; |
1391
|
852
|
|
|
|
|
|
char *t = literal_mode_elem[i].str; |
1392
|
852
|
|
|
|
|
|
int len = tag_len; |
1393
|
1320
|
50
|
|
|
|
|
while (len) { |
1394
|
1320
|
100
|
|
|
|
|
if (toLOWER(*s) != *t) |
|
|
100
|
|
|
|
|
|
1395
|
747
|
|
|
|
|
|
break; |
1396
|
573
|
|
|
|
|
|
s++; |
1397
|
573
|
|
|
|
|
|
t++; |
1398
|
573
|
100
|
|
|
|
|
if (!--len) { |
1399
|
|
|
|
|
|
|
/* found it */ |
1400
|
105
|
|
|
|
|
|
p_state->literal_mode = literal_mode_elem[i].str; |
1401
|
105
|
|
|
|
|
|
p_state->is_cdata = literal_mode_elem[i].is_cdata; |
1402
|
|
|
|
|
|
|
/* printf("Found %s\n", p_state->literal_mode); */ |
1403
|
105
|
|
|
|
|
|
goto END_OF_LITERAL_SEARCH; |
1404
|
|
|
|
|
|
|
} |
1405
|
|
|
|
|
|
|
} |
1406
|
|
|
|
|
|
|
} |
1407
|
|
|
|
|
|
|
} |
1408
|
|
|
|
|
|
|
END_OF_LITERAL_SEARCH: |
1409
|
|
|
|
|
|
|
; |
1410
|
|
|
|
|
|
|
} |
1411
|
|
|
|
|
|
|
|
1412
|
6705
|
100
|
|
|
|
|
FREE_TOKENS; |
1413
|
6705
|
|
|
|
|
|
return s; |
1414
|
|
|
|
|
|
|
} |
1415
|
|
|
|
|
|
|
|
1416
|
0
|
0
|
|
|
|
|
FREE_TOKENS; |
1417
|
0
|
|
|
|
|
|
return 0; |
1418
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
PREMATURE: |
1420
|
2277
|
100
|
|
|
|
|
FREE_TOKENS; |
1421
|
8982
|
|
|
|
|
|
return beg; |
1422
|
|
|
|
|
|
|
} |
1423
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
|
1425
|
|
|
|
|
|
|
static char* |
1426
|
2995
|
|
|
|
|
|
parse_end(PSTATE* p_state, char *beg, char *end, U32 utf8, SV* self) |
1427
|
|
|
|
|
|
|
{ |
1428
|
2995
|
|
|
|
|
|
char *s = beg+2; |
1429
|
|
|
|
|
|
|
hctype_t name_first, name_char; |
1430
|
|
|
|
|
|
|
|
1431
|
2995
|
100
|
|
|
|
|
if (STRICT_NAMES(p_state)) { |
|
|
50
|
|
|
|
|
|
1432
|
17
|
|
|
|
|
|
name_first = HCTYPE_NAME_FIRST; |
1433
|
17
|
|
|
|
|
|
name_char = HCTYPE_NAME_CHAR; |
1434
|
|
|
|
|
|
|
} |
1435
|
|
|
|
|
|
|
else { |
1436
|
2978
|
|
|
|
|
|
name_first = name_char = HCTYPE_NOT_SPACE_GT; |
1437
|
|
|
|
|
|
|
} |
1438
|
|
|
|
|
|
|
|
1439
|
2995
|
100
|
|
|
|
|
if (isHCTYPE(*s, name_first)) { |
1440
|
|
|
|
|
|
|
token_pos_t tagname; |
1441
|
2992
|
|
|
|
|
|
tagname.beg = s; |
1442
|
2992
|
|
|
|
|
|
s++; |
1443
|
7272
|
100
|
|
|
|
|
while (s < end && isHCTYPE(*s, name_char)) |
|
|
100
|
|
|
|
|
|
1444
|
4280
|
|
|
|
|
|
s++; |
1445
|
2992
|
|
|
|
|
|
tagname.end = s; |
1446
|
|
|
|
|
|
|
|
1447
|
2992
|
50
|
|
|
|
|
if (p_state->strict_end) { |
1448
|
0
|
0
|
|
|
|
|
while (isHSPACE(*s)) |
1449
|
0
|
|
|
|
|
|
s++; |
1450
|
|
|
|
|
|
|
} |
1451
|
|
|
|
|
|
|
else { |
1452
|
2992
|
|
|
|
|
|
s = skip_until_gt(s, end); |
1453
|
|
|
|
|
|
|
} |
1454
|
2992
|
100
|
|
|
|
|
if (s < end) { |
1455
|
2920
|
50
|
|
|
|
|
if (*s == '>') { |
1456
|
2920
|
|
|
|
|
|
s++; |
1457
|
|
|
|
|
|
|
/* a complete end tag has been recognized */ |
1458
|
2920
|
|
|
|
|
|
report_event(p_state, E_END, beg, s, utf8, &tagname, 1, self); |
1459
|
2991
|
|
|
|
|
|
return s; |
1460
|
|
|
|
|
|
|
} |
1461
|
|
|
|
|
|
|
} |
1462
|
|
|
|
|
|
|
else { |
1463
|
72
|
|
|
|
|
|
return beg; |
1464
|
|
|
|
|
|
|
} |
1465
|
|
|
|
|
|
|
} |
1466
|
3
|
50
|
|
|
|
|
else if (!p_state->strict_comment) { |
1467
|
3
|
|
|
|
|
|
s = skip_until_gt(s, end); |
1468
|
3
|
50
|
|
|
|
|
if (s < end) { |
1469
|
|
|
|
|
|
|
token_pos_t token; |
1470
|
3
|
|
|
|
|
|
token.beg = beg + 2; |
1471
|
3
|
|
|
|
|
|
token.end = s; |
1472
|
3
|
|
|
|
|
|
s++; |
1473
|
3
|
|
|
|
|
|
report_event(p_state, E_COMMENT, beg, s, utf8, &token, 1, self); |
1474
|
3
|
|
|
|
|
|
return s; |
1475
|
|
|
|
|
|
|
} |
1476
|
|
|
|
|
|
|
else { |
1477
|
0
|
|
|
|
|
|
return beg; |
1478
|
|
|
|
|
|
|
} |
1479
|
|
|
|
|
|
|
} |
1480
|
0
|
|
|
|
|
|
return 0; |
1481
|
|
|
|
|
|
|
} |
1482
|
|
|
|
|
|
|
|
1483
|
|
|
|
|
|
|
|
1484
|
|
|
|
|
|
|
static char* |
1485
|
140
|
|
|
|
|
|
parse_process(PSTATE* p_state, char *beg, char *end, U32 utf8, SV* self) |
1486
|
|
|
|
|
|
|
{ |
1487
|
140
|
|
|
|
|
|
char *s = beg + 2; /* skip '' */ |
1488
|
|
|
|
|
|
|
/* processing instruction */ |
1489
|
|
|
|
|
|
|
token_pos_t token_pos; |
1490
|
140
|
|
|
|
|
|
token_pos.beg = s; |
1491
|
|
|
|
|
|
|
|
1492
|
23804
|
100
|
|
|
|
|
while (s < end) { |
1493
|
23761
|
100
|
|
|
|
|
if (*s == '>') { |
1494
|
99
|
|
|
|
|
|
token_pos.end = s; |
1495
|
99
|
|
|
|
|
|
s++; |
1496
|
|
|
|
|
|
|
|
1497
|
99
|
100
|
|
|
|
|
if (p_state->xml_mode || p_state->xml_pic) { |
|
|
100
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
/* XML processing instructions are ended by "?>" */ |
1499
|
8
|
50
|
|
|
|
|
if (s - beg < 4 || s[-2] != '?') |
|
|
100
|
|
|
|
|
|
1500
|
2
|
|
|
|
|
|
continue; |
1501
|
6
|
|
|
|
|
|
token_pos.end = s - 2; |
1502
|
|
|
|
|
|
|
} |
1503
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
/* a complete processing instruction seen */ |
1505
|
97
|
|
|
|
|
|
report_event(p_state, E_PROCESS, beg, s, utf8, |
1506
|
|
|
|
|
|
|
&token_pos, 1, self); |
1507
|
97
|
|
|
|
|
|
return s; |
1508
|
|
|
|
|
|
|
} |
1509
|
23662
|
|
|
|
|
|
s++; |
1510
|
|
|
|
|
|
|
} |
1511
|
140
|
|
|
|
|
|
return beg; /* could not find end */ |
1512
|
|
|
|
|
|
|
} |
1513
|
|
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
#ifdef USE_PFUNC |
1516
|
|
|
|
|
|
|
static char* |
1517
|
|
|
|
|
|
|
parse_null(PSTATE* p_state, char *beg, char *end, U32 utf8, SV* self) |
1518
|
|
|
|
|
|
|
{ |
1519
|
|
|
|
|
|
|
return 0; |
1520
|
|
|
|
|
|
|
} |
1521
|
|
|
|
|
|
|
|
1522
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
|
1524
|
|
|
|
|
|
|
#include "pfunc.h" /* declares the parsefunc[] */ |
1525
|
|
|
|
|
|
|
#endif /* USE_PFUNC */ |
1526
|
|
|
|
|
|
|
|
1527
|
|
|
|
|
|
|
static char* |
1528
|
11123
|
|
|
|
|
|
parse_buf(pTHX_ PSTATE* p_state, char *beg, char *end, U32 utf8, SV* self) |
1529
|
|
|
|
|
|
|
{ |
1530
|
11123
|
|
|
|
|
|
char *s = beg; |
1531
|
11123
|
|
|
|
|
|
char *t = beg; |
1532
|
|
|
|
|
|
|
char *new_pos; |
1533
|
|
|
|
|
|
|
|
1534
|
35545
|
100
|
|
|
|
|
while (!p_state->eof) { |
1535
|
|
|
|
|
|
|
/* |
1536
|
|
|
|
|
|
|
* At the start of this loop we will always be ready for eating text |
1537
|
|
|
|
|
|
|
* or a new tag. We will never be inside some tag. The 't' points |
1538
|
|
|
|
|
|
|
* to where we started and the 's' is advanced as we go. |
1539
|
|
|
|
|
|
|
*/ |
1540
|
|
|
|
|
|
|
|
1541
|
35707
|
100
|
|
|
|
|
while (p_state->literal_mode) { |
1542
|
287
|
|
|
|
|
|
char *l = p_state->literal_mode; |
1543
|
|
|
|
|
|
|
char *end_text; |
1544
|
|
|
|
|
|
|
|
1545
|
2704
|
100
|
|
|
|
|
while (s < end && *s != '<') { |
|
|
100
|
|
|
|
|
|
1546
|
2417
|
|
|
|
|
|
s++; |
1547
|
|
|
|
|
|
|
} |
1548
|
|
|
|
|
|
|
|
1549
|
287
|
100
|
|
|
|
|
if (s == end) { |
1550
|
119
|
|
|
|
|
|
s = t; |
1551
|
119
|
|
|
|
|
|
goto DONE; |
1552
|
|
|
|
|
|
|
} |
1553
|
|
|
|
|
|
|
|
1554
|
168
|
|
|
|
|
|
end_text = s; |
1555
|
168
|
|
|
|
|
|
s++; |
1556
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
/* here we rely on '\0' termination of perl svpv buffers */ |
1558
|
168
|
100
|
|
|
|
|
if (*s == '/') { |
1559
|
147
|
|
|
|
|
|
s++; |
1560
|
777
|
100
|
|
|
|
|
while (*l && toLOWER(*s) == *l) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1561
|
630
|
|
|
|
|
|
s++; |
1562
|
630
|
|
|
|
|
|
l++; |
1563
|
|
|
|
|
|
|
} |
1564
|
|
|
|
|
|
|
|
1565
|
147
|
100
|
|
|
|
|
if (!*l && (strNE(p_state->literal_mode, "plaintext") || p_state->closing_plaintext)) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
/* matched it all */ |
1567
|
|
|
|
|
|
|
token_pos_t end_token; |
1568
|
110
|
|
|
|
|
|
end_token.beg = end_text + 2; |
1569
|
110
|
|
|
|
|
|
end_token.end = s; |
1570
|
|
|
|
|
|
|
|
1571
|
110
|
50
|
|
|
|
|
while (isHSPACE(*s)) |
1572
|
0
|
|
|
|
|
|
s++; |
1573
|
110
|
100
|
|
|
|
|
if (*s == '>') { |
1574
|
101
|
|
|
|
|
|
s++; |
1575
|
101
|
50
|
|
|
|
|
if (t != end_text) |
1576
|
101
|
|
|
|
|
|
report_event(p_state, E_TEXT, t, end_text, utf8, |
1577
|
|
|
|
|
|
|
0, 0, self); |
1578
|
101
|
|
|
|
|
|
report_event(p_state, E_END, end_text, s, utf8, |
1579
|
|
|
|
|
|
|
&end_token, 1, self); |
1580
|
101
|
|
|
|
|
|
p_state->literal_mode = 0; |
1581
|
101
|
|
|
|
|
|
p_state->is_cdata = 0; |
1582
|
110
|
|
|
|
|
|
t = s; |
1583
|
|
|
|
|
|
|
} |
1584
|
|
|
|
|
|
|
} |
1585
|
|
|
|
|
|
|
} |
1586
|
|
|
|
|
|
|
} |
1587
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
#ifdef MARKED_SECTION |
1589
|
35429
|
100
|
|
|
|
|
while (p_state->ms == MS_CDATA || p_state->ms == MS_RCDATA) { |
|
|
100
|
|
|
|
|
|
1590
|
116
|
100
|
|
|
|
|
while (s < end && *s != ']') |
|
|
100
|
|
|
|
|
|
1591
|
106
|
|
|
|
|
|
s++; |
1592
|
10
|
100
|
|
|
|
|
if (*s == ']') { |
1593
|
9
|
|
|
|
|
|
char *end_text = s; |
1594
|
9
|
|
|
|
|
|
s++; |
1595
|
9
|
50
|
|
|
|
|
if (*s == ']' && *(s + 1) == '>') { |
|
|
100
|
|
|
|
|
|
1596
|
8
|
|
|
|
|
|
s += 2; |
1597
|
|
|
|
|
|
|
/* marked section end */ |
1598
|
8
|
50
|
|
|
|
|
if (t != end_text) |
1599
|
8
|
|
|
|
|
|
report_event(p_state, E_TEXT, t, end_text, utf8, |
1600
|
|
|
|
|
|
|
0, 0, self); |
1601
|
8
|
|
|
|
|
|
report_event(p_state, E_NONE, end_text, s, utf8, 0, 0, self); |
1602
|
8
|
|
|
|
|
|
t = s; |
1603
|
8
|
|
|
|
|
|
SvREFCNT_dec(av_pop(p_state->ms_stack)); |
1604
|
8
|
|
|
|
|
|
marked_section_update(p_state); |
1605
|
8
|
|
|
|
|
|
continue; |
1606
|
|
|
|
|
|
|
} |
1607
|
|
|
|
|
|
|
} |
1608
|
2
|
100
|
|
|
|
|
if (s == end) { |
1609
|
1
|
|
|
|
|
|
s = t; |
1610
|
1
|
|
|
|
|
|
goto DONE; |
1611
|
|
|
|
|
|
|
} |
1612
|
|
|
|
|
|
|
} |
1613
|
|
|
|
|
|
|
#endif |
1614
|
|
|
|
|
|
|
|
1615
|
|
|
|
|
|
|
/* first we try to match as much text as possible */ |
1616
|
3945046
|
100
|
|
|
|
|
while (s < end && *s != '<') { |
|
|
100
|
|
|
|
|
|
1617
|
|
|
|
|
|
|
#ifdef MARKED_SECTION |
1618
|
3909627
|
100
|
|
|
|
|
if (p_state->ms && *s == ']') { |
|
|
100
|
|
|
|
|
|
1619
|
8
|
|
|
|
|
|
char *end_text = s; |
1620
|
8
|
|
|
|
|
|
s++; |
1621
|
8
|
50
|
|
|
|
|
if (*s == ']') { |
1622
|
8
|
|
|
|
|
|
s++; |
1623
|
8
|
50
|
|
|
|
|
if (*s == '>') { |
1624
|
8
|
|
|
|
|
|
s++; |
1625
|
8
|
|
|
|
|
|
report_event(p_state, E_TEXT, t, end_text, utf8, |
1626
|
|
|
|
|
|
|
0, 0, self); |
1627
|
8
|
|
|
|
|
|
report_event(p_state, E_NONE, end_text, s, utf8, |
1628
|
|
|
|
|
|
|
0, 0, self); |
1629
|
8
|
|
|
|
|
|
t = s; |
1630
|
8
|
|
|
|
|
|
SvREFCNT_dec(av_pop(p_state->ms_stack)); |
1631
|
8
|
|
|
|
|
|
marked_section_update(p_state); |
1632
|
8
|
|
|
|
|
|
continue; |
1633
|
|
|
|
|
|
|
} |
1634
|
|
|
|
|
|
|
} |
1635
|
|
|
|
|
|
|
} |
1636
|
|
|
|
|
|
|
#endif |
1637
|
3909619
|
|
|
|
|
|
s++; |
1638
|
|
|
|
|
|
|
} |
1639
|
35419
|
100
|
|
|
|
|
if (s != t) { |
1640
|
30349
|
100
|
|
|
|
|
if (*s == '<') { |
1641
|
22562
|
|
|
|
|
|
report_event(p_state, E_TEXT, t, s, utf8, 0, 0, self); |
1642
|
22562
|
|
|
|
|
|
t = s; |
1643
|
|
|
|
|
|
|
} |
1644
|
|
|
|
|
|
|
else { |
1645
|
7787
|
|
|
|
|
|
s--; |
1646
|
7787
|
100
|
|
|
|
|
if (isHSPACE(*s)) { |
1647
|
|
|
|
|
|
|
/* wait with white space at end */ |
1648
|
943
|
100
|
|
|
|
|
while (s >= t && isHSPACE(*s)) |
|
|
100
|
|
|
|
|
|
1649
|
503
|
|
|
|
|
|
s--; |
1650
|
|
|
|
|
|
|
} |
1651
|
|
|
|
|
|
|
else { |
1652
|
|
|
|
|
|
|
/* might be a chopped up entities/words */ |
1653
|
249861
|
100
|
|
|
|
|
while (s >= t && !isHSPACE(*s)) |
|
|
100
|
|
|
|
|
|
1654
|
242514
|
|
|
|
|
|
s--; |
1655
|
13610
|
100
|
|
|
|
|
while (s >= t && isHSPACE(*s)) |
|
|
100
|
|
|
|
|
|
1656
|
6263
|
|
|
|
|
|
s--; |
1657
|
|
|
|
|
|
|
} |
1658
|
7787
|
|
|
|
|
|
s++; |
1659
|
7787
|
100
|
|
|
|
|
if (s != t) |
1660
|
6160
|
|
|
|
|
|
report_event(p_state, E_TEXT, t, s, utf8, 0, 0, self); |
1661
|
7787
|
|
|
|
|
|
break; |
1662
|
|
|
|
|
|
|
} |
1663
|
|
|
|
|
|
|
} |
1664
|
|
|
|
|
|
|
|
1665
|
27632
|
100
|
|
|
|
|
if (end - s < 3) |
1666
|
400
|
|
|
|
|
|
break; |
1667
|
|
|
|
|
|
|
|
1668
|
|
|
|
|
|
|
/* next char is known to be '<' and pointed to by 't' as well as 's' */ |
1669
|
27232
|
|
|
|
|
|
s++; |
1670
|
|
|
|
|
|
|
|
1671
|
|
|
|
|
|
|
#ifdef USE_PFUNC |
1672
|
|
|
|
|
|
|
new_pos = parsefunc[(unsigned char)*s](p_state, t, end, utf8, self); |
1673
|
|
|
|
|
|
|
#else |
1674
|
27232
|
100
|
|
|
|
|
if (isHNAME_FIRST(*s)) |
1675
|
8982
|
|
|
|
|
|
new_pos = parse_start(p_state, t, end, utf8, self); |
1676
|
18250
|
100
|
|
|
|
|
else if (*s == '/') |
1677
|
2995
|
|
|
|
|
|
new_pos = parse_end(p_state, t, end, utf8, self); |
1678
|
15255
|
100
|
|
|
|
|
else if (*s == '!') |
1679
|
579
|
|
|
|
|
|
new_pos = parse_decl(p_state, t, end, utf8, self); |
1680
|
14676
|
100
|
|
|
|
|
else if (*s == '?') |
1681
|
140
|
|
|
|
|
|
new_pos = parse_process(p_state, t, end, utf8, self); |
1682
|
|
|
|
|
|
|
else |
1683
|
14536
|
|
|
|
|
|
new_pos = 0; |
1684
|
|
|
|
|
|
|
#endif /* USE_PFUNC */ |
1685
|
|
|
|
|
|
|
|
1686
|
27231
|
100
|
|
|
|
|
if (new_pos) { |
1687
|
12695
|
100
|
|
|
|
|
if (new_pos == t) { |
1688
|
|
|
|
|
|
|
/* no progress, need more data to know what it is */ |
1689
|
2809
|
|
|
|
|
|
s = t; |
1690
|
2809
|
|
|
|
|
|
break; |
1691
|
|
|
|
|
|
|
} |
1692
|
9886
|
|
|
|
|
|
t = s = new_pos; |
1693
|
|
|
|
|
|
|
} |
1694
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
/* if we get out here then this was not a conforming tag, so |
1696
|
|
|
|
|
|
|
* treat it is plain text at the top of the loop again (we |
1697
|
|
|
|
|
|
|
* have already skipped past the "<"). |
1698
|
|
|
|
|
|
|
*/ |
1699
|
|
|
|
|
|
|
} |
1700
|
|
|
|
|
|
|
|
1701
|
|
|
|
|
|
|
DONE: |
1702
|
11122
|
|
|
|
|
|
return s; |
1703
|
|
|
|
|
|
|
|
1704
|
|
|
|
|
|
|
} |
1705
|
|
|
|
|
|
|
|
1706
|
|
|
|
|
|
|
EXTERN void |
1707
|
11321
|
|
|
|
|
|
parse(pTHX_ |
1708
|
|
|
|
|
|
|
PSTATE* p_state, |
1709
|
|
|
|
|
|
|
SV* chunk, |
1710
|
|
|
|
|
|
|
SV* self) |
1711
|
|
|
|
|
|
|
{ |
1712
|
|
|
|
|
|
|
char *s, *beg, *end; |
1713
|
11321
|
|
|
|
|
|
U32 utf8 = 0; |
1714
|
|
|
|
|
|
|
STRLEN len; |
1715
|
|
|
|
|
|
|
|
1716
|
11321
|
100
|
|
|
|
|
if (!p_state->start_document) { |
1717
|
|
|
|
|
|
|
char dummy[1]; |
1718
|
211
|
|
|
|
|
|
report_event(p_state, E_START_DOCUMENT, dummy, dummy, 0, 0, 0, self); |
1719
|
211
|
|
|
|
|
|
p_state->start_document = 1; |
1720
|
|
|
|
|
|
|
} |
1721
|
|
|
|
|
|
|
|
1722
|
11321
|
100
|
|
|
|
|
if (!chunk) { |
1723
|
|
|
|
|
|
|
/* eof */ |
1724
|
|
|
|
|
|
|
char empty[1]; |
1725
|
197
|
100
|
|
|
|
|
if (p_state->buf && SvOK(p_state->buf)) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1726
|
|
|
|
|
|
|
/* flush it */ |
1727
|
149
|
50
|
|
|
|
|
s = SvPV(p_state->buf, len); |
1728
|
149
|
|
|
|
|
|
end = s + len; |
1729
|
149
|
|
|
|
|
|
utf8 = SvUTF8(p_state->buf); |
1730
|
|
|
|
|
|
|
assert(len); |
1731
|
|
|
|
|
|
|
|
1732
|
152
|
50
|
|
|
|
|
while (s < end) { |
1733
|
152
|
100
|
|
|
|
|
if (p_state->literal_mode) { |
1734
|
2
|
50
|
|
|
|
|
if (strEQ(p_state->literal_mode, "plaintext") || |
|
|
0
|
|
|
|
|
|
1735
|
0
|
0
|
|
|
|
|
strEQ(p_state->literal_mode, "xmp") || |
1736
|
0
|
0
|
|
|
|
|
strEQ(p_state->literal_mode, "iframe") || |
1737
|
0
|
|
|
|
|
|
strEQ(p_state->literal_mode, "textarea")) |
1738
|
|
|
|
|
|
|
{ |
1739
|
|
|
|
|
|
|
/* rest is considered text */ |
1740
|
|
|
|
|
|
|
break; |
1741
|
|
|
|
|
|
|
} |
1742
|
0
|
0
|
|
|
|
|
if (strEQ(p_state->literal_mode, "script") || |
|
|
0
|
|
|
|
|
|
1743
|
0
|
|
|
|
|
|
strEQ(p_state->literal_mode, "style")) |
1744
|
0
|
|
|
|
|
|
{ |
1745
|
|
|
|
|
|
|
/* effectively make it an empty element */ |
1746
|
|
|
|
|
|
|
token_pos_t t; |
1747
|
|
|
|
|
|
|
char dummy; |
1748
|
0
|
|
|
|
|
|
t.beg = p_state->literal_mode; |
1749
|
0
|
|
|
|
|
|
t.end = p_state->literal_mode + strlen(p_state->literal_mode); |
1750
|
0
|
|
|
|
|
|
report_event(p_state, E_END, &dummy, &dummy, 0, &t, 1, self); |
1751
|
|
|
|
|
|
|
} |
1752
|
|
|
|
|
|
|
else { |
1753
|
0
|
|
|
|
|
|
p_state->pending_end_tag = p_state->literal_mode; |
1754
|
|
|
|
|
|
|
} |
1755
|
0
|
|
|
|
|
|
p_state->literal_mode = 0; |
1756
|
0
|
|
|
|
|
|
s = parse_buf(aTHX_ p_state, s, end, utf8, self); |
1757
|
0
|
|
|
|
|
|
continue; |
1758
|
|
|
|
|
|
|
} |
1759
|
|
|
|
|
|
|
|
1760
|
150
|
100
|
|
|
|
|
if (!p_state->strict_comment && !p_state->no_dash_dash_comment_end && *s == '<') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1761
|
3
|
|
|
|
|
|
p_state->no_dash_dash_comment_end = 1; |
1762
|
3
|
|
|
|
|
|
s = parse_buf(aTHX_ p_state, s, end, utf8, self); |
1763
|
3
|
|
|
|
|
|
continue; |
1764
|
|
|
|
|
|
|
} |
1765
|
|
|
|
|
|
|
|
1766
|
147
|
100
|
|
|
|
|
if (!p_state->strict_comment && *s == '<') { |
|
|
100
|
|
|
|
|
|
1767
|
3
|
|
|
|
|
|
char *s1 = s + 1; |
1768
|
3
|
100
|
|
|
|
|
if (s1 == end || isHNAME_FIRST(*s1) || *s1 == '/' || *s1 == '!' || *s1 == '?') { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1769
|
|
|
|
|
|
|
/* some kind of unterminated markup. Report rest as as comment */ |
1770
|
|
|
|
|
|
|
token_pos_t token; |
1771
|
2
|
|
|
|
|
|
token.beg = s + 1; |
1772
|
2
|
|
|
|
|
|
token.end = end; |
1773
|
2
|
|
|
|
|
|
report_event(p_state, E_COMMENT, s, end, utf8, &token, 1, self); |
1774
|
2
|
|
|
|
|
|
s = end; |
1775
|
|
|
|
|
|
|
} |
1776
|
|
|
|
|
|
|
} |
1777
|
|
|
|
|
|
|
|
1778
|
147
|
|
|
|
|
|
break; |
1779
|
|
|
|
|
|
|
} |
1780
|
|
|
|
|
|
|
|
1781
|
149
|
100
|
|
|
|
|
if (s < end) { |
1782
|
|
|
|
|
|
|
/* report rest as text */ |
1783
|
147
|
|
|
|
|
|
report_event(p_state, E_TEXT, s, end, utf8, 0, 0, self); |
1784
|
|
|
|
|
|
|
} |
1785
|
|
|
|
|
|
|
|
1786
|
149
|
|
|
|
|
|
SvREFCNT_dec(p_state->buf); |
1787
|
149
|
|
|
|
|
|
p_state->buf = 0; |
1788
|
|
|
|
|
|
|
} |
1789
|
197
|
100
|
|
|
|
|
if (p_state->pend_text && SvOK(p_state->pend_text)) |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1790
|
60
|
|
|
|
|
|
flush_pending_text(p_state, self); |
1791
|
|
|
|
|
|
|
|
1792
|
197
|
50
|
|
|
|
|
if (p_state->ignoring_element) { |
1793
|
|
|
|
|
|
|
/* document not balanced */ |
1794
|
0
|
|
|
|
|
|
SvREFCNT_dec(p_state->ignoring_element); |
1795
|
0
|
|
|
|
|
|
p_state->ignoring_element = 0; |
1796
|
|
|
|
|
|
|
} |
1797
|
197
|
|
|
|
|
|
report_event(p_state, E_END_DOCUMENT, empty, empty, 0, 0, 0, self); |
1798
|
|
|
|
|
|
|
|
1799
|
|
|
|
|
|
|
/* reset state */ |
1800
|
197
|
|
|
|
|
|
p_state->offset = 0; |
1801
|
197
|
100
|
|
|
|
|
if (p_state->line) |
1802
|
10
|
|
|
|
|
|
p_state->line = 1; |
1803
|
197
|
|
|
|
|
|
p_state->column = 0; |
1804
|
197
|
|
|
|
|
|
p_state->start_document = 0; |
1805
|
197
|
|
|
|
|
|
p_state->literal_mode = 0; |
1806
|
197
|
|
|
|
|
|
p_state->is_cdata = 0; |
1807
|
197
|
|
|
|
|
|
return; |
1808
|
|
|
|
|
|
|
} |
1809
|
|
|
|
|
|
|
|
1810
|
11124
|
100
|
|
|
|
|
if (p_state->utf8_mode) |
1811
|
5
|
|
|
|
|
|
sv_utf8_downgrade(chunk, 0); |
1812
|
|
|
|
|
|
|
|
1813
|
11124
|
100
|
|
|
|
|
if (p_state->buf && SvOK(p_state->buf)) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1814
|
10789
|
|
|
|
|
|
sv_catsv(p_state->buf, chunk); |
1815
|
10789
|
50
|
|
|
|
|
beg = SvPV(p_state->buf, len); |
1816
|
10789
|
|
|
|
|
|
utf8 = SvUTF8(p_state->buf); |
1817
|
|
|
|
|
|
|
} |
1818
|
|
|
|
|
|
|
else { |
1819
|
335
|
100
|
|
|
|
|
beg = SvPV(chunk, len); |
1820
|
335
|
|
|
|
|
|
utf8 = SvUTF8(chunk); |
1821
|
335
|
100
|
|
|
|
|
if (p_state->offset == 0 && DOWARN) { |
|
|
100
|
|
|
|
|
|
1822
|
|
|
|
|
|
|
/* Print warnings if we find unexpected Unicode BOM forms */ |
1823
|
15
|
100
|
|
|
|
|
if (p_state->argspec_entity_decode && |
|
|
100
|
|
|
|
|
|
1824
|
14
|
50
|
|
|
|
|
!(p_state->attr_encoded && p_state->argspec_entity_decode == ARG_ATTR) && |
|
|
100
|
|
|
|
|
|
1825
|
10
|
100
|
|
|
|
|
!p_state->utf8_mode && ( |
1826
|
10
|
50
|
|
|
|
|
(!utf8 && len >= 3 && strnEQ(beg, "\xEF\xBB\xBF", 3)) || |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1827
|
8
|
50
|
|
|
|
|
(utf8 && len >= 6 && strnEQ(beg, "\xC3\xAF\xC2\xBB\xC2\xBF", 6)) || |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1828
|
5
|
100
|
|
|
|
|
(!utf8 && probably_utf8_chunk(aTHX_ beg, len)) |
1829
|
|
|
|
|
|
|
) |
1830
|
|
|
|
|
|
|
) |
1831
|
|
|
|
|
|
|
{ |
1832
|
4
|
|
|
|
|
|
warn("Parsing of undecoded UTF-8 will give garbage when decoding entities"); |
1833
|
|
|
|
|
|
|
} |
1834
|
15
|
100
|
|
|
|
|
if (utf8 && len >= 2 && strnEQ(beg, "\xFF\xFE", 2)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1835
|
0
|
|
|
|
|
|
warn("Parsing string decoded with wrong endianness"); |
1836
|
|
|
|
|
|
|
} |
1837
|
15
|
100
|
|
|
|
|
if (!utf8 && len >= 4 && |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1838
|
11
|
100
|
|
|
|
|
(strnEQ(beg, "\x00\x00\xFE\xFF", 4) || |
1839
|
11
|
|
|
|
|
|
strnEQ(beg, "\xFE\xFF\x00\x00", 4)) |
1840
|
|
|
|
|
|
|
) |
1841
|
|
|
|
|
|
|
{ |
1842
|
2
|
|
|
|
|
|
warn("Parsing of undecoded UTF-32"); |
1843
|
|
|
|
|
|
|
} |
1844
|
13
|
100
|
|
|
|
|
else if (!utf8 && len >= 2 && |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1845
|
9
|
100
|
|
|
|
|
(strnEQ(beg, "\xFE\xFF", 2) || strnEQ(beg, "\xFF\xFE", 2)) |
1846
|
|
|
|
|
|
|
) |
1847
|
|
|
|
|
|
|
{ |
1848
|
2
|
|
|
|
|
|
warn("Parsing of undecoded UTF-16"); |
1849
|
|
|
|
|
|
|
} |
1850
|
|
|
|
|
|
|
} |
1851
|
|
|
|
|
|
|
} |
1852
|
|
|
|
|
|
|
|
1853
|
11124
|
100
|
|
|
|
|
if (!len) |
1854
|
4
|
|
|
|
|
|
return; /* nothing to do */ |
1855
|
|
|
|
|
|
|
|
1856
|
11120
|
|
|
|
|
|
end = beg + len; |
1857
|
11120
|
|
|
|
|
|
s = parse_buf(aTHX_ p_state, beg, end, utf8, self); |
1858
|
|
|
|
|
|
|
|
1859
|
11119
|
100
|
|
|
|
|
if (s == end || p_state->eof) { |
|
|
100
|
|
|
|
|
|
1860
|
288
|
100
|
|
|
|
|
if (p_state->buf) { |
1861
|
109
|
100
|
|
|
|
|
SvOK_off(p_state->buf); |
1862
|
|
|
|
|
|
|
} |
1863
|
|
|
|
|
|
|
} |
1864
|
|
|
|
|
|
|
else { |
1865
|
|
|
|
|
|
|
/* need to keep rest in buffer */ |
1866
|
10940
|
100
|
|
|
|
|
if (p_state->buf) { |
1867
|
|
|
|
|
|
|
/* chop off some chars at the beginning */ |
1868
|
10784
|
100
|
|
|
|
|
if (SvOK(p_state->buf)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1869
|
10694
|
|
|
|
|
|
sv_chop(p_state->buf, s); |
1870
|
|
|
|
|
|
|
} |
1871
|
|
|
|
|
|
|
else { |
1872
|
90
|
|
|
|
|
|
sv_setpvn(p_state->buf, s, end - s); |
1873
|
90
|
100
|
|
|
|
|
if (utf8) |
1874
|
16
|
|
|
|
|
|
SvUTF8_on(p_state->buf); |
1875
|
|
|
|
|
|
|
else |
1876
|
10784
|
|
|
|
|
|
SvUTF8_off(p_state->buf); |
1877
|
|
|
|
|
|
|
} |
1878
|
|
|
|
|
|
|
} |
1879
|
|
|
|
|
|
|
else { |
1880
|
156
|
|
|
|
|
|
p_state->buf = newSVpv(s, end - s); |
1881
|
156
|
100
|
|
|
|
|
if (utf8) |
1882
|
8
|
|
|
|
|
|
SvUTF8_on(p_state->buf); |
1883
|
|
|
|
|
|
|
} |
1884
|
|
|
|
|
|
|
} |
1885
|
11320
|
|
|
|
|
|
return; |
1886
|
|
|
|
|
|
|
} |