File Coverage

util.c
Criterion Covered Total %
statement 140 147 95.2
branch 74 90 82.2
condition n/a
subroutine n/a
pod n/a
total 214 237 90.3


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 114           void set_value(pTHX_ HList* h, const char* ckey, SV* pval) {
18             SV *deref;
19             AV *array;
20              
21 114 100         if ( ! SvOK(pval) ) {
    50          
    50          
22             GLOG(("=X= deleting [%s]", ckey));
23 1           hlist_del( h, ckey );
24 1           return;
25             }
26              
27 113 100         if ( ! SvROK(pval) ) {
28 105           set_scalar(aTHX_ h, ckey, pval);
29 105           return;
30             }
31              
32 8           deref = SvRV(pval);
33 8 100         if (SvTYPE(deref) != SVt_PVAV) {
34 2           set_scalar(aTHX_ h, ckey, pval);
35 2           return;
36             }
37              
38 6           array = (AV*) deref;
39 6           set_array(aTHX_ h, ckey, array);
40             }
41              
42 107           void set_scalar(pTHX_ HList* h, const char* ckey, SV* pval) {
43 107           hlist_add(h, ckey, newSVsv(pval));
44             GLOG(("=X= set scalar [%s] => [%s]", ckey, SvPV_nolen(pval)));
45 107           }
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 100         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 50         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 30           char* format_all(pTHX_ HList* h, int sort, const char* endl, int* size) {
198 30           int le = strlen(endl);
199             int j;
200 30           *size = 64;
201              
202 30 100         if (sort) {
203 28           hlist_sort(h);
204             }
205              
206 150 100         for (j = 0; j < h->ulen; ++j) {
207 120           HNode* hn = &h->data[j];
208 120           const char* header = hn->header->name;
209 120           int lh = strlen(header);
210 120           PList* pl = hn->values;
211             int k;
212 249 100         for (k = 0; k < pl->ulen; ++k) {
213 129           PNode* pn = &pl->data[k];
214 129 100         const char* value = SvPV_nolen( (SV*) pn->ptr );
215 129           int lv = strlen(value);
216 129           *size += lh + 2 + lv + lv * le;
217             }
218             }
219              
220             {
221             char* rstr;
222 30           int rpos = 0;
223 30           GMEM_NEW(rstr, char*, *size);
224 150 100         for (j = 0; j < h->ulen; ++j) {
225 120           HNode* hn = &h->data[j];
226 120           const char* header = hn->header->name;
227 120           int lh = strlen(header);
228 120           PList* pl = hn->values;
229             int k;
230             PNode *pn;
231             const char *value;
232 249 100         for (k = 0; k < pl->ulen; ++k) {
233 129           memcpy(rstr + rpos, header, lh);
234 129           rpos += lh;
235 129           rstr[rpos++] = ':';
236 129           rstr[rpos++] = ' ';
237              
238 129           pn = &pl->data[k];
239 129 100         value = SvPV_nolen( (SV*) pn->ptr );
240 129           rpos += string_cleanup(value, rstr + rpos, *size - rpos, endl);
241             }
242             }
243              
244 30           rstr[rpos] = '\0';
245             GLOG(("=X= format_all (%d/%d) [%s]", rpos, *size, rstr));
246 30           return rstr;
247             }
248             }
249              
250 140           static int string_append(char* buf, int pos, const char* str) {
251             int k;
252 306 100         for (k = 0; str[k] != '\0'; ++k) {
253 166           buf[pos++] = str[k];
254             }
255 140           return pos;
256             }
257              
258 129           static int string_cleanup(const char* str, char* buf, int len, const char* newl) {
259 129           int pos = 0;
260 129           int last_nonblank = -1;
261 129           int saw_newline = 0;
262             int j;
263 911 100         for (j = 0; str[j] != '\0'; ++j) {
264 782 50         if (pos >= len) {
265 0           break;
266             }
267 782 100         if (isspace(str[j])) {
268 46 100         if (saw_newline) {
269             /* ignore */
270             } else {
271 30 100         if (str[j] == '\n') {
272 13           pos = string_append(buf, pos, newl);
273 13           saw_newline = 1;
274 13           last_nonblank = pos-1;
275             } else {
276 46           buf[pos++] = str[j];
277             }
278             }
279             } else {
280 736 100         if (saw_newline) {
281 11           buf[pos++] = ' ';
282             }
283 736           buf[pos++] = str[j];
284 736           last_nonblank = pos-1;
285 736           saw_newline = 0;
286             }
287             }
288              
289 129 100         if (! saw_newline) {
290 127           pos = string_append(buf, last_nonblank+1, newl);
291 127           last_nonblank = pos-1;
292             }
293 129           buf[++last_nonblank] = '\0';
294 129           return last_nonblank;
295              
296             /*
297             * This is the original code in Perl, for reference.
298              
299             sub _process_newline {
300             local $_ = shift;
301             my $endl = shift;
302             # must handle header values with embedded newlines with care
303             s/\s+$//; # trailing newlines and space must go
304             s/\n(\x0d?\n)+/\n/g; # no empty lines
305             s/\n([^\040\t])/\n $1/g; # intial space for continuation
306             s/\n/$endl/g; # substitute with requested line ending
307             $_;
308              
309             */
310             }