File Coverage

util.c
Criterion Covered Total %
statement 162 167 97.0
branch 131 142 92.2
condition n/a
subroutine n/a
pod n/a
total 293 309 94.8


line stmt bran cond sub pod time code
1             /*
2             * Copyright 1999-2009, Gisle Aas.
3             *
4             * This library is free software; you can redistribute it and/or
5             * modify it under the same terms as Perl itself.
6             */
7              
8             #ifndef EXTERN
9             #define EXTERN extern
10             #endif
11              
12              
13             EXTERN SV*
14 35913           sv_lower(pTHX_ SV* sv)
15             {
16             STRLEN len;
17 35913           char *s = SvPV_force(sv, len);
18 911689 100         for (; len--; s++)
19 875776 100         *s = toLOWER(*s);
20 35913           return sv;
21             }
22              
23             EXTERN int
24 270           strnEQx(const char* s1, const char* s2, STRLEN n, int ignore_case)
25             {
26 2149 100         while (n--) {
27 1880 100         if (ignore_case) {
28 1874 100         if (toLOWER(*s1) != toLOWER(*s2))
    50          
    100          
29 1           return 0;
30             }
31             else {
32 6 50         if (*s1 != *s2)
33 0           return 0;
34             }
35 1879           s1++;
36 1879           s2++;
37             }
38 269           return 1;
39             }
40              
41             static void
42 27           grow_gap(pTHX_ SV* sv, STRLEN grow, char** t, char** s, char** e)
43             {
44             /*
45             SvPVX ---> AAAAAA...BBBBBB
46             ^ ^ ^
47             t s e
48             */
49 27           STRLEN t_offset = *t - SvPVX(sv);
50 27           STRLEN s_offset = *s - SvPVX(sv);
51 27           STRLEN e_offset = *e - SvPVX(sv);
52              
53 27 50         SvGROW(sv, e_offset + grow + 1);
    100          
54              
55 27           *t = SvPVX(sv) + t_offset;
56 27           *s = SvPVX(sv) + s_offset;
57 27           *e = SvPVX(sv) + e_offset;
58              
59 27           Move(*s, *s+grow, *e - *s, char);
60 27           *s += grow;
61 27           *e += grow;
62 27           }
63              
64             EXTERN SV*
65 3877           decode_entities(pTHX_ SV* sv, HV* entity2char, bool expand_prefix)
66             {
67             STRLEN len;
68 3877           char *s = SvPV_force(sv, len);
69 3877           char *t = s;
70 3877           char *end = s + len;
71             char *ent_start;
72              
73             char *repl;
74             STRLEN repl_len;
75 3877           char *repl_allocated = 0;
76             char buf[UTF8_MAXLEN];
77             int repl_utf8;
78 3877           int high_surrogate = 0;
79              
80             #if defined(__GNUC__)
81             /* gcc -Wall reports this variable as possibly used uninitialized */
82 3877           repl_utf8 = 0;
83             #endif
84              
85 77514 100         while (s < end) {
86             assert(t <= s);
87              
88 73637 100         if ((*t++ = *s++) != '&')
89 72947           continue;
90              
91 690           ent_start = s;
92 690           repl = 0;
93 690           repl_allocated = 0;
94              
95 799 100         if (s < end && *s == '#') {
    100          
96 109           UV num = 0;
97 109           int ok = 0;
98 109           s++;
99 109 50         if (s < end && (*s == 'x' || *s == 'X')) {
    100          
    100          
100 41           s++;
101 174 100         while (s < end) {
102 162           char *tmp = strchr(PL_hexdigit, *s);
103 162 100         if (!tmp)
104 25           break;
105 137           num = num << 4 | ((tmp - PL_hexdigit) & 15);
106 137 100         if (num > 0x10FFFF) {
107             /* overflow */
108 4           ok = 0;
109 4           break;
110             }
111 133           s++;
112 133           ok = 1;
113             }
114             }
115             else {
116 280 100         while (s < end && isDIGIT(*s)) {
    100          
117 214           num = num * 10 + (*s - '0');
118 214 100         if (num > 0x10FFFF) {
119             /* overflow */
120 2           ok = 0;
121 2           break;
122             }
123 212           s++;
124 212           ok = 1;
125             }
126             }
127 109 100         if (num && ok) {
    100          
128 96 100         if (!SvUTF8(sv) && num <= 255) {
    100          
129 41           buf[0] = (char) num;
130 41           repl = buf;
131 41           repl_len = 1;
132 41           repl_utf8 = 0;
133             }
134 55 50         else if (num == 0xFFFE || num == 0xFFFF) {
    100          
135             /* illegal */
136             }
137             else {
138             char *tmp;
139 54 100         if ((num & 0xFFFFFC00) == 0xDC00) { /* low-surrogate */
140 1 50         if (high_surrogate != 0) {
141 1           t -= 3; /* Back up past 0xFFFD */
142 1           num = ((high_surrogate - 0xD800) << 10) +
143             (num - 0xDC00) + 0x10000;
144 1           high_surrogate = 0;
145             } else {
146 0           num = 0xFFFD;
147             }
148             }
149 53 100         else if ((num & 0xFFFFFC00) == 0xD800) { /* high-surrogate */
150 2           high_surrogate = num;
151 2           num = 0xFFFD;
152             }
153             else {
154 51           high_surrogate = 0;
155             /* otherwise invalid? */
156 51 100         if ((num >= 0xFDD0 && num <= 0xFDEF) ||
    100          
157 47 100         ((num & 0xFFFE) == 0xFFFE) ||
    50          
158             num > 0x10FFFF)
159             {
160 5           num = 0xFFFD;
161             }
162             }
163              
164 54           tmp = (char*)uvchr_to_utf8((U8*)buf, num);
165 54           repl = buf;
166 54           repl_len = tmp - buf;
167 54           repl_utf8 = 1;
168             }
169             }
170             }
171             else {
172 581           char *ent_name = s;
173 2120 100         while (s < end && isALNUM(*s))
    100          
174 1539           s++;
175 581 100         if (ent_name != s && entity2char) {
    100          
176             SV** svp;
177 364 100         if ( (svp = hv_fetch(entity2char, ent_name, s - ent_name, 0)) ||
178 83 100         (*s == ';' && (svp = hv_fetch(entity2char, ent_name, s - ent_name + 1, 0)))
    100          
179             )
180 294           {
181 294           char *src = SvPV(*svp, repl_len);
182 294           repl_utf8 = SvUTF8(*svp);
183 294 100         if ((SV*)*svp == sv) {
184             /* Self-aliased: hash entry SV == input SV.
185             * grow_gap() may realloc sv's PV later; copy
186             * the entity value into an owned buffer first.
187             * Freed by the repl_allocated cleanup below. */
188 1 50         Newx(repl_allocated, repl_len ? repl_len : 1, char);
189 1           Copy(src, repl_allocated, repl_len, char);
190 1           repl = repl_allocated;
191             } else {
192 293           repl = src;
193             }
194             }
195 70 100         else if (expand_prefix) {
196 4           char *ss = s - 1;
197 16 100         while (ss > ent_name) {
198 14           svp = hv_fetch(entity2char, ent_name, ss - ent_name, 0);
199 14 100         if (svp) {
200 2           char *src = SvPV(*svp, repl_len);
201 2           repl_utf8 = SvUTF8(*svp);
202 2 50         if ((SV*)*svp == sv) {
203 0 0         Newx(repl_allocated, repl_len ? repl_len : 1, char);
204 0           Copy(src, repl_allocated, repl_len, char);
205 0           repl = repl_allocated;
206             } else {
207 2           repl = src;
208             }
209 2           s = ss;
210 2           break;
211             }
212 12           ss--;
213             }
214             }
215             }
216 581           high_surrogate = 0;
217             }
218              
219 690 100         if (repl) {
220             /* repl_allocated is now function-scoped; set by the
221             * named-entity self-alias path above or by the UTF8 mismatch
222             * branch below. Same cleanup in either case. */
223 391 100         if (s < end && *s == ';')
    100          
224 246           s++;
225 391           t--; /* '&' already copied, undo it */
226              
227 391 100         if (*s != '&') {
228 102           high_surrogate = 0;
229             }
230              
231 391 100         if (!SvUTF8(sv) && repl_utf8) {
    100          
232             /* need to upgrade sv before we continue */
233 18           STRLEN before_gap_len = t - SvPVX(sv);
234 18           char *before_gap = (char*)bytes_to_utf8((U8*)SvPVX(sv), &before_gap_len);
235 18           STRLEN after_gap_len = end - s;
236 18           char *after_gap = (char*)bytes_to_utf8((U8*)s, &after_gap_len);
237              
238 18           sv_setpvn(sv, before_gap, before_gap_len);
239 18           sv_catpvn(sv, after_gap, after_gap_len);
240 18           SvUTF8_on(sv);
241              
242 18           Safefree(before_gap);
243 18           Safefree(after_gap);
244              
245 18           s = t = SvPVX(sv) + before_gap_len;
246 18           end = SvPVX(sv) + before_gap_len + after_gap_len;
247             }
248 373 100         else if (SvUTF8(sv) && !repl_utf8) {
    100          
249 212           repl = (char*)bytes_to_utf8((U8*)repl, &repl_len);
250 212           repl_allocated = repl;
251             }
252              
253 391 100         if (t + repl_len > s) {
254             /* need to grow the string */
255 27           grow_gap(aTHX_ sv, repl_len - (s - t), &t, &s, &end);
256             }
257              
258             /* copy replacement string into string */
259 9371 100         while (repl_len--)
260 8980           *t++ = *repl++;
261              
262 391 100         if (repl_allocated)
263 213           Safefree(repl_allocated);
264             }
265             else {
266 484 100         while (ent_start < s)
267 185           *t++ = *ent_start++;
268             }
269             }
270              
271 3877           *t = '\0';
272 3877           SvCUR_set(sv, t - SvPVX(sv));
273              
274 3877           return sv;
275             }
276              
277             static bool
278 13           has_hibit(char *s, char *e)
279             {
280 29 100         while (s < e) {
281 25           U8 ch = *s++;
282 25 100         if (!UTF8_IS_INVARIANT(ch)) {
283 9           return 1;
284             }
285             }
286 4           return 0;
287             }
288              
289              
290             EXTERN bool
291 13           probably_utf8_chunk(pTHX_ char *s, STRLEN len)
292             {
293 13           char *e = s + len;
294             STRLEN clen;
295              
296             /* ignore partial utf8 char at end of buffer */
297 18 100         while (s < e && UTF8_IS_CONTINUATION((U8)*(e - 1)))
    100          
298 5           e--;
299 13 100         if (s < e && UTF8_IS_START((U8)*(e - 1)))
    100          
300 6           e--;
301 13           clen = len - (e - s);
302 13 100         if (clen && UTF8SKIP(e) == clen) {
    100          
303             /* all promised continuation bytes are present */
304 2           e = s + len;
305             }
306              
307 13 100         if (!has_hibit(s, e))
308 4           return 0;
309              
310 9           return is_utf8_string((U8*)s, e - s);
311             }