File Coverage

util.c
Criterion Covered Total %
statement 149 156 95.5
branch 73 88 82.9
condition n/a
subroutine n/a
pod n/a
total 222 244 90.9


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT /* we want efficiency */
2             #include "EXTERN.h"
3             #include "perl.h"
4              
5             #include "glog.h"
6             #include "gmem.h"
7             #include "header.h"
8             #include "util.h"
9              
10             /* Append string str at pos in buf. */
11             static int string_append(char* buf, int pos, const char* str);
12              
13             /* Cleanup string str (as used in as_string), leaving cleaned up result in */
14             /* buf, with maximum length len; use newl as new line terminator. */
15             static int string_cleanup(const char* str, char* buf, int len, const char* newl);
16              
17 127           void set_value(pTHX_ HList* h, const char* ckey, SV* pval) {
18             SV *deref;
19             AV *array;
20              
21 127 100         if ( ! SvOK(pval) ) {
22             GLOG(("=X= deleting [%s]", ckey));
23 3           hlist_del( h, ckey );
24 3           return;
25             }
26              
27 124 100         if ( ! SvROK(pval) ) {
28 115           set_scalar(aTHX_ h, ckey, pval);
29 115           return;
30             }
31              
32 9           deref = SvRV(pval);
33 9 100         if (SvTYPE(deref) != SVt_PVAV) {
34 3           set_scalar(aTHX_ h, ckey, pval);
35 3           return;
36             }
37              
38 6           array = (AV*) deref;
39 6           set_array(aTHX_ h, ckey, array);
40             }
41              
42 118           void set_scalar(pTHX_ HList* h, const char* ckey, SV* pval) {
43 118           hlist_add(h, ckey, newSVsv(pval));
44             GLOG(("=X= set scalar [%s] => [%s]", ckey, SvPV_nolen(pval)));
45 118           }
46              
47 6           void set_array(pTHX_ HList* h, const char* ckey, AV* pval) {
48 6           int count = av_len(pval) + 1;
49             int j;
50 19 100         for (j = 0; j < count; ++j) {
51 13           SV** svp = av_fetch(pval, j, 0);
52             GLOG(("=X= set array %2d [%s]", j, ckey));
53 13           set_value(aTHX_ h, ckey, *svp);
54             }
55 6           }
56              
57 9           void return_hlist(pTHX_ HList* list, const char* func, int want) {
58 9           dSP;
59             int count;
60              
61 9 50         if (want == G_VOID) {
62             GLOG(("=X= %s: no return expected, nothing will be returned", func));
63 0           return;
64             }
65              
66 9           count = hlist_size(list);
67              
68 9 100         if (want == G_SCALAR) {
69             GLOG(("=X= %s: returning number of elements", func));
70 3 50         EXTEND(SP, 1);
71 3           PUSHs(sv_2mortal(newSViv(count)));
72 3           PUTBACK;
73             }
74              
75 9 100         if (count <= 0) {
76             GLOG(("=X= %s: hlist is empty, returning nothing", func));
77 2           return;
78             }
79              
80 7 100         if (want == G_ARRAY) {
81 5           int num = 0;
82             int j;
83              
84             GLOG(("=X= %s: returning as %d elements", func, count));
85 5 50         EXTEND(SP, count);
    50          
86              
87 18 100         for (j = 0; j < list->ulen; ++j) {
88 13           HNode* node = &list->data[j];
89 13           const char* s = node->header->name;
90 13           ++num;
91              
92             GLOG(("=X= %s: returning %2d - str [%s]", func, num, s));
93 13           PUSHs(sv_2mortal(newSVpv(s, 0)));
94             }
95 5           PUTBACK;
96             }
97             }
98              
99 89           void return_plist(pTHX_ PList* list, const char* func, int want) {
100             int count;
101 89           dSP;
102              
103 89 100         if (want == G_VOID) {
104             GLOG(("=X= %s: no return expected, nothing will be returned", func));
105 6           return;
106             }
107              
108 83           count = plist_size(list);
109              
110 83 50         if (count <= 0) {
111 0 0         if (want == G_ARRAY) {
112             GLOG(("=X= %s: plist is empty, wantarray => 0", func));
113 0 0         EXTEND(SP, 1);
114 0           PUSHs(sv_2mortal(newSViv(0)));
115 0           PUTBACK;
116             } else {
117             GLOG(("=X= %s: plist is empty, returning nothing", func));
118             }
119 0           return;
120             }
121              
122             GLOG(("=X= %s: returning %d values", func, count));
123              
124 83 100         if (want == G_SCALAR) {
125             GLOG(("=X= %s: returning as single string", func));
126 38 50         EXTEND( SP, 1 );
127              
128 38 100         if ( count == 1 ) {
129             /*
130             * handle returning one value, useful when storing an object
131             */
132 34           PNode* node = &list->data[0];
133 34           PUSHs( (SV*)node->ptr );
134              
135             } else {
136              
137             /*
138             * concatenate values, useful for full header strings
139             */
140              
141 4           int size = 16;
142             int j;
143 15 100         for (j = 0; j < list->ulen; ++j) {
144 11           PNode* node = &list->data[j];
145             STRLEN len;
146 11           SvPV( (SV*)node->ptr, len ); /* We just need the length */
147 11           size += len + 2;
148             }
149              
150             {
151             char* rstr;
152 4           int rpos = 0;
153 4           int num = 0;
154             int j;
155 4           GMEM_NEW(rstr, char*, size);
156 15 100         for (j = 0; j < list->ulen; ++j) {
157 11           PNode* node = &list->data[j];
158 11           ++num;
159              
160             STRLEN len;
161 11           char* str = SvPV( (SV*)node->ptr, len );
162             GLOG(("=X= %s: returning %2d - str [%s]", func, num, str));
163 11 100         if (rpos > 0) {
164 7           rstr[rpos++] = ',';
165 7           rstr[rpos++] = ' ';
166             }
167              
168 11           memcpy(rstr + rpos, str, len);
169 11           rpos += len;
170             }
171              
172 4           rstr[rpos] = '\0';
173 4           PUSHs(sv_2mortal(newSVpv(rstr, rpos)));
174 4           GMEM_DEL(rstr, char*, size);
175             }
176             }
177              
178 38           PUTBACK;
179             }
180              
181 83 100         if (want == G_ARRAY) {
182 45           int num = 0;
183             int j;
184             GLOG(("=X= %s: returning as %d elements", func, count));
185 45 50         EXTEND(SP, count);
    50          
186 103 100         for (j = 0; j < list->ulen; ++j) {
187 58           PNode* node = &list->data[j];
188 58           ++num;
189              
190 58           PUSHs( (SV*)node->ptr );
191             }
192              
193 45           PUTBACK;
194             }
195             }
196              
197 32           char* format_all(pTHX_ HList* h, int sort, const char* endl, int* size) {
198 32           int le = strlen(endl);
199             int j;
200 32           *size = 64;
201              
202 32 100         if (sort) {
203 30           hlist_sort(h);
204             }
205              
206 154 100         for (j = 0; j < h->ulen; ++j) {
207 122           HNode* hn = &h->data[j];
208 122           const char* header = hn->header->name;
209 122           int lh = strlen(header);
210 122           PList* pl = hn->values;
211             int k;
212 253 100         for (k = 0; k < pl->ulen; ++k) {
213 131           PNode* pn = &pl->data[k];
214 131           const char* value = SvPV_nolen( (SV*) pn->ptr );
215 131           int lv = strlen(value);
216 131           *size += lh + 2 + lv + lv * le;
217             }
218             }
219              
220             {
221             char* rstr;
222 32           int rpos = 0;
223 32           GMEM_NEW(rstr, char*, *size);
224 154 100         for (j = 0; j < h->ulen; ++j) {
225 122           HNode* hn = &h->data[j];
226 122           const char* header = hn->header->name;
227 122           int lh = strlen(header);
228 122           PList* pl = hn->values;
229             int k;
230             PNode *pn;
231             const char *value;
232 253 100         for (k = 0; k < pl->ulen; ++k) {
233 131           memcpy(rstr + rpos, header, lh);
234 131           rpos += lh;
235 131           rstr[rpos++] = ':';
236 131           rstr[rpos++] = ' ';
237              
238 131           pn = &pl->data[k];
239 131           value = SvPV_nolen( (SV*) pn->ptr );
240 131           rpos += string_cleanup(value, rstr + rpos, *size - rpos, endl);
241             }
242             }
243              
244 32           rstr[rpos] = '\0';
245             GLOG(("=X= format_all (%d/%d) [%s]", rpos, *size, rstr));
246 32           return rstr;
247             }
248             }
249              
250 144           static int string_append(char* buf, int pos, const char* str) {
251             int k;
252 316 100         for (k = 0; str[k] != '\0'; ++k) {
253 172           buf[pos++] = str[k];
254             }
255 144           return pos;
256             }
257              
258 131           static int string_cleanup(const char* str, char* buf, int len, const char* newl) {
259 131           int pos = 0;
260 131           int last_nonblank = -1;
261 131           int saw_newline = 0;
262             int j;
263 923 100         for (j = 0; str[j] != '\0'; ++j) {
264 792           char c = str[j];
265 792           int emit_cr = 0;
266 792 100         if (c == '\r' && str[j + 1] == '\n') {
    50          
267 10 100         if (strchr(newl, '\r') == NULL) {
268 8           emit_cr = 1;
269             }
270 10           ++j;
271 10           c = '\n';
272             }
273 792 50         if (pos >= len) {
274 0           break;
275             }
276 792 100         if (isspace((unsigned char)c)) {
277 44 100         if (saw_newline) {
278             /* ignore */
279             } else {
280 29 100         if (c == '\n') {
281 15 100         if (emit_cr && pos < len) {
    50          
282 4           buf[pos++] = '\r';
283             }
284 15           pos = string_append(buf, pos, newl);
285 15           saw_newline = 1;
286 15           last_nonblank = pos-1;
287             } else {
288 14           buf[pos++] = c;
289             }
290             }
291             } else {
292 748 100         if (saw_newline) {
293 13           buf[pos++] = ' ';
294             }
295 748           buf[pos++] = c;
296 748           last_nonblank = pos-1;
297 748           saw_newline = 0;
298             }
299             }
300              
301 131 100         if (! saw_newline) {
302 129           pos = string_append(buf, last_nonblank+1, newl);
303 129           last_nonblank = pos-1;
304             }
305 131           buf[++last_nonblank] = '\0';
306 131           return last_nonblank;
307              
308             /*
309             * This is the original code in Perl, for reference.
310              
311             sub _process_newline {
312             local $_ = shift;
313             my $endl = shift;
314             # must handle header values with embedded newlines with care
315             s/\s+$//; # trailing newlines and space must go
316             s/\n(\x0d?\n)+/\n/g; # no empty lines
317             s/\n([^\040\t])/\n $1/g; # intial space for continuation
318             s/\n/$endl/g; # substitute with requested line ending
319             $_;
320              
321             */
322             }