File Coverage

util.c
Criterion Covered Total %
statement 154 155 99.3
branch 131 142 92.2
condition n/a
subroutine n/a
pod n/a
total 285 297 95.9


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 45029           sv_lower(pTHX_ SV* sv)
15             {
16             STRLEN len;
17 45029 50         char *s = SvPV_force(sv, len);
18 1203901 100         for (; len--; s++)
19 1158872 100         *s = toLOWER(*s);
20 45029           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 26           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 26           STRLEN t_offset = *t - SvPVX(sv);
50 26           STRLEN s_offset = *s - SvPVX(sv);
51 26           STRLEN e_offset = *e - SvPVX(sv);
52              
53 26 50         SvGROW(sv, e_offset + grow + 1);
    100          
54              
55 26           *t = SvPVX(sv) + t_offset;
56 26           *s = SvPVX(sv) + s_offset;
57 26           *e = SvPVX(sv) + e_offset;
58              
59 26           Move(*s, *s+grow, *e - *s, char);
60 26           *s += grow;
61 26           *e += grow;
62 26           }
63              
64             EXTERN SV*
65 4414           decode_entities(pTHX_ SV* sv, HV* entity2char, bool expand_prefix)
66             {
67             STRLEN len;
68 4414 50         char *s = SvPV_force(sv, len);
69 4414           char *t = s;
70 4414           char *end = s + len;
71             char *ent_start;
72              
73             char *repl;
74             STRLEN repl_len;
75             char buf[UTF8_MAXLEN];
76             int repl_utf8;
77 4414           int high_surrogate = 0;
78              
79             #if defined(__GNUC__)
80             /* gcc -Wall reports this variable as possibly used uninitialized */
81 4414           repl_utf8 = 0;
82             #endif
83              
84 87488 100         while (s < end) {
85             assert(t <= s);
86              
87 83074 100         if ((*t++ = *s++) != '&')
88 82258           continue;
89              
90 816           ent_start = s;
91 816           repl = 0;
92              
93 925 100         if (s < end && *s == '#') {
    100          
94 109           UV num = 0;
95 109           int ok = 0;
96 109           s++;
97 150 50         if (s < end && (*s == 'x' || *s == 'X')) {
    100          
    100          
98 41           s++;
99 174 100         while (s < end) {
100 162           char *tmp = strchr(PL_hexdigit, *s);
101 162 100         if (!tmp)
102 25           break;
103 137           num = num << 4 | ((tmp - PL_hexdigit) & 15);
104 137 100         if (num > 0x10FFFF) {
105             /* overflow */
106 4           ok = 0;
107 4           break;
108             }
109 133           s++;
110 133           ok = 1;
111             }
112             }
113             else {
114 280 100         while (s < end && isDIGIT(*s)) {
    100          
115 214           num = num * 10 + (*s - '0');
116 214 100         if (num > 0x10FFFF) {
117             /* overflow */
118 2           ok = 0;
119 2           break;
120             }
121 212           s++;
122 212           ok = 1;
123             }
124             }
125 109 100         if (num && ok) {
    100          
126 96 100         if (!SvUTF8(sv) && num <= 255) {
    100          
127 41           buf[0] = (char) num;
128 41           repl = buf;
129 41           repl_len = 1;
130 41           repl_utf8 = 0;
131             }
132 55 50         else if (num == 0xFFFE || num == 0xFFFF) {
    100          
133             /* illegal */
134             }
135             else {
136             char *tmp;
137 54 100         if ((num & 0xFFFFFC00) == 0xDC00) { /* low-surrogate */
138 1 50         if (high_surrogate != 0) {
139 1           t -= 3; /* Back up past 0xFFFD */
140 1           num = ((high_surrogate - 0xD800) << 10) +
141             (num - 0xDC00) + 0x10000;
142 1           high_surrogate = 0;
143             } else {
144 1           num = 0xFFFD;
145             }
146             }
147 53 100         else if ((num & 0xFFFFFC00) == 0xD800) { /* high-surrogate */
148 2           high_surrogate = num;
149 2           num = 0xFFFD;
150             }
151             else {
152 51           high_surrogate = 0;
153             /* otherwise invalid? */
154 51 100         if ((num >= 0xFDD0 && num <= 0xFDEF) ||
    100          
    100          
155 46 50         ((num & 0xFFFE) == 0xFFFE) ||
156             num > 0x10FFFF)
157             {
158 5           num = 0xFFFD;
159             }
160             }
161              
162 54           tmp = (char*)uvuni_to_utf8((U8*)buf, num);
163 54           repl = buf;
164 54           repl_len = tmp - buf;
165 54           repl_utf8 = 1;
166             }
167             }
168             }
169             else {
170 707           char *ent_name = s;
171 2284 100         while (s < end && isALNUM(*s))
    100          
172 1577           s++;
173 707 100         if (ent_name != s && entity2char) {
    100          
174             SV** svp;
175 394 100         if ( (svp = hv_fetch(entity2char, ent_name, s - ent_name, 0)) ||
    100          
176 16 100         (*s == ';' && (svp = hv_fetch(entity2char, ent_name, s - ent_name + 1, 0)))
177             )
178             {
179 293 50         repl = SvPV(*svp, repl_len);
180 293           repl_utf8 = SvUTF8(*svp);
181             }
182 101 100         else if (expand_prefix) {
183 4           char *ss = s - 1;
184 16 100         while (ss > ent_name) {
185 14           svp = hv_fetch(entity2char, ent_name, ss - ent_name, 0);
186 14 100         if (svp) {
187 2 50         repl = SvPV(*svp, repl_len);
188 2           repl_utf8 = SvUTF8(*svp);
189 2           s = ss;
190 2           break;
191             }
192 12           ss--;
193             }
194             }
195             }
196 707           high_surrogate = 0;
197             }
198              
199 816 100         if (repl) {
200 390           char *repl_allocated = 0;
201 390 100         if (s < end && *s == ';')
    100          
202 245           s++;
203 390           t--; /* '&' already copied, undo it */
204              
205 390 100         if (*s != '&') {
206 101           high_surrogate = 0;
207             }
208              
209 408 100         if (!SvUTF8(sv) && repl_utf8) {
    100          
210             /* need to upgrade sv before we continue */
211 18           STRLEN before_gap_len = t - SvPVX(sv);
212 18           char *before_gap = (char*)bytes_to_utf8((U8*)SvPVX(sv), &before_gap_len);
213 18           STRLEN after_gap_len = end - s;
214 18           char *after_gap = (char*)bytes_to_utf8((U8*)s, &after_gap_len);
215              
216 18           sv_setpvn(sv, before_gap, before_gap_len);
217 18           sv_catpvn(sv, after_gap, after_gap_len);
218 18           SvUTF8_on(sv);
219              
220 18           Safefree(before_gap);
221 18           Safefree(after_gap);
222              
223 18           s = t = SvPVX(sv) + before_gap_len;
224 18           end = SvPVX(sv) + before_gap_len + after_gap_len;
225             }
226 372 100         else if (SvUTF8(sv) && !repl_utf8) {
    100          
227 212           repl = (char*)bytes_to_utf8((U8*)repl, &repl_len);
228 212           repl_allocated = repl;
229             }
230              
231 390 100         if (t + repl_len > s) {
232             /* need to grow the string */
233 26           grow_gap(aTHX_ sv, repl_len - (s - t), &t, &s, &end);
234             }
235              
236             /* copy replacement string into string */
237 1141 100         while (repl_len--)
238 751           *t++ = *repl++;
239              
240 390 100         if (repl_allocated)
241 390           Safefree(repl_allocated);
242             }
243             else {
244 652 100         while (ent_start < s)
245 226           *t++ = *ent_start++;
246             }
247             }
248              
249 4414           *t = '\0';
250 4414           SvCUR_set(sv, t - SvPVX(sv));
251              
252 4414           return sv;
253             }
254              
255             static bool
256 13           has_hibit(char *s, char *e)
257             {
258 29 100         while (s < e) {
259 25           U8 ch = *s++;
260 25 100         if (!UTF8_IS_INVARIANT(ch)) {
261 9           return 1;
262             }
263             }
264 4           return 0;
265             }
266              
267              
268             EXTERN bool
269 13           probably_utf8_chunk(pTHX_ char *s, STRLEN len)
270             {
271 13           char *e = s + len;
272             STRLEN clen;
273              
274             /* ignore partial utf8 char at end of buffer */
275 18 100         while (s < e && UTF8_IS_CONTINUATION((U8)*(e - 1)))
    100          
276 5           e--;
277 13 100         if (s < e && UTF8_IS_START((U8)*(e - 1)))
    100          
278 6           e--;
279 13           clen = len - (e - s);
280 13 100         if (clen && UTF8SKIP(e) == clen) {
    100          
281             /* all promised continuation bytes are present */
282 2           e = s + len;
283             }
284              
285 13 100         if (!has_hibit(s, e))
286 4           return 0;
287              
288 9           return is_utf8_string((U8*)s, e - s);
289             }