File Coverage

lib/Basic/Coercion/XS.xs
Criterion Covered Total %
statement 120 139 86.3
branch 54 86 62.7
condition n/a
subroutine n/a
pod n/a
total 174 225 77.3


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6 14           static SV * new_coerce (SV * type, CV * coerce) {
7             dTHX;
8 14           HV * hash = newHV();
9 14           hv_store(hash, "name", 4, type, 0);
10 14           hv_store(hash, "coerce", 6, (SV*)coerce, 0);
11 14           return sv_bless(newRV_noinc((SV*)hash), gv_stashsv(newSVpv("Basic::Coercion::XS", 19), 0));
12             }
13              
14 4           char *get_caller(void) {
15             dTHX;
16 4 50         char *callr = HvNAME((HV*)CopSTASH(PL_curcop));
    50          
    50          
    0          
    50          
    50          
17 4           return callr;
18             }
19              
20 14           AV* split_by_regex(char *input, SV **pattern_sv) {
21             dTHX;
22             REGEXP *rx;
23 14           AV *result = newAV();
24 26 100         if (!pattern_sv || !SvROK(*pattern_sv)) {
    100          
25 12 100         char *pattern = (pattern_sv && SvOK(*pattern_sv)) ? SvPV_nolen(*pattern_sv) : "\\s+";
    50          
26 12           STRLEN patlen = strlen(pattern);
27 12           SV *pat_sv = newSVpvn(pattern, patlen);
28 12           rx = pregcomp(pat_sv, 0);
29 12           SvREFCNT_dec(pat_sv);
30             } else {
31 2           SvREFCNT_inc(*pattern_sv);
32 2           rx = (REGEXP *)SvRV(*pattern_sv);
33             }
34              
35 14 50         if (!rx) {
36 0           return result;
37             }
38 14           STRLEN input_len = strlen(input);
39 14           STRLEN pos = 0;
40 14           STRLEN last = 0;
41 14           SV *input_sv = newSVpvn(input, input_len);
42 57 50         while (pos <= input_len) {
43             I32 nmatch;
44 57           nmatch = pregexec(rx, input + pos, input + input_len, input, 0, input_sv, 0);
45 57 100         if (nmatch > 0) {
46 43           STRLEN match_start = ((regexp *)SvANY(rx))->offs[0].start;
47 43           STRLEN match_end = ((regexp *)SvANY(rx))->offs[0].end;
48 43           SV *token = newSVpvn(input + last, match_start - last);
49 43           av_push(result, token);
50 43 50         if (match_end == match_start) {
51 0           pos = match_end + 1;
52             } else {
53 43           pos = match_end;
54             }
55 43           last = pos;
56             } else {
57 14           SV *token = newSVpvn(input + last, input_len - last);
58 14           av_push(result, token);
59 14           break;
60             }
61             }
62 14           SvREFCNT_dec(input_sv);
63 14           SvREFCNT_dec(rx);
64 14           return result;
65             }
66              
67             MODULE = Basic::Coercion::XS::Definition PACKAGE = Basic::Coercion::XS::Definition
68             PROTOTYPES: DISABLE
69              
70             SV *
71             _StrToArray(...)
72             CODE:
73 8           SV * self = CvXSUBANY(cv).any_ptr;
74 8 50         if (!self || !SvOK(self)) {
    50          
75 0           croak("StrToArray coerce constraint not initialized");
76             }
77 8           SV * param = ST(0);
78 8 50         if (SvTYPE(param) != SVt_PV) {
79 0           SvREFCNT_inc(param);
80 0           RETVAL = param;
81 0           XSRETURN(1);
82             }
83             STRLEN len;
84 8           char *input = SvPV(param, len);
85 8           SV **pattern_sv = hv_fetch((HV*)SvRV(self), "by", 2, 0);
86 8           AV *result = split_by_regex(input, pattern_sv);
87 8           RETVAL = newRV_noinc((SV*)result);
88             OUTPUT:
89             RETVAL
90              
91             SV *
92             StrToArray(...)
93             CODE:
94 9           CV *type = newXS(NULL, XS_Basic__Coercion__XS__Definition__StrToArray, __FILE__);
95 9           RETVAL = new_coerce(newSVpv("StrToArray", 10), type);
96 9           SvREFCNT_inc(type);
97 9           CvXSUBANY(type).any_ptr = (void *)RETVAL;
98 9           SvREFCNT_inc(RETVAL);
99 9           HV * self = (HV*)SvRV(RETVAL);
100 9           hv_store(self, "coerce", 6, newRV_noinc((SV*)type), 0);
101 9 50         if (items % 2 != 0) {
102 0           croak("StrToArray type constraint requires an even number of arguments");
103             }
104 9           int i = 0;
105 13 100         for (i = 0; i < items; i += 2) {
106 4           SV * key = ST(i);
107 4           SV * value = ST(i + 1);
108 4 50         if (!SvOK(key) || SvTYPE(key) != SVt_PV) {
    50          
109 0           croak("key must be a string");
110             }
111 4 50         if (!SvOK(value)) {
112 0           croak("value must be defined");
113             }
114             STRLEN keylen;
115 4           char * keystr = SvPV(key, keylen);
116 4           hv_store(self, keystr, keylen, newSVsv(value), 0);
117             }
118             OUTPUT:
119             RETVAL
120              
121             SV *
122             _StrToHash(...)
123             CODE:
124 6           SV * self = CvXSUBANY(cv).any_ptr;
125 6 50         if (!self || !SvOK(self)) {
    50          
126 0           croak("StrToHash coerce constraint not initialized");
127             }
128 6           SV * param = ST(0);
129 6 50         if (SvTYPE(param) != SVt_PV) {
130 0           SvREFCNT_inc(param);
131 0           RETVAL = param;
132 0           XSRETURN(1);
133             }
134 6           HV *hash = newHV();
135             STRLEN len;
136 6           char *input = SvPV(param, len);
137 6           SV **pattern_sv = hv_fetch((HV*)SvRV(self), "by", 2, 0);
138 6           AV *result = split_by_regex(input, pattern_sv);
139 6           int length = av_len(result);
140              
141 6 50         if (length && (length - 1) % 2 != 0) {
    100          
142 1           croak("StrToHash requires an even number of elements in hash assignment");
143             }
144              
145              
146 5           int i = 0;
147 19 100         for (i = 0; i < length; i += 2) {
148             STRLEN keylen;
149 14           char * key = SvPV(*av_fetch(result, i, 0), keylen);
150 14           SV * value = *av_fetch(result, i + 1, 0);
151 14           hv_store(hash, key, keylen, value, 0);
152             }
153              
154 5           RETVAL = newRV_noinc((SV*)hash);
155             OUTPUT:
156             RETVAL
157              
158             SV *
159             StrToHash(...)
160             CODE:
161 5           CV *type = newXS(NULL, XS_Basic__Coercion__XS__Definition__StrToHash, __FILE__);
162 5           RETVAL = new_coerce(newSVpv("StrToHash", 9), type);
163 5           SvREFCNT_inc(type);
164 5           CvXSUBANY(type).any_ptr = (void *)RETVAL;
165 5           SvREFCNT_inc(RETVAL);
166 5           HV * self = (HV*)SvRV(RETVAL);
167 5           hv_store(self, "coerce", 6, newRV_noinc((SV*)type), 0);
168 5 50         if (items % 2 != 0) {
169 0           croak("StrToHash type constraint requires an even number of arguments");
170             }
171 5           int i = 0;
172 7 100         for (i = 0; i < items; i += 2) {
173 2           SV * key = ST(i);
174 2           SV * value = ST(i + 1);
175 2 50         if (!SvOK(key) || SvTYPE(key) != SVt_PV) {
    50          
176 0           croak("key must be a string");
177             }
178 2 50         if (!SvOK(value)) {
179 0           croak("value must be defined");
180             }
181             STRLEN keylen;
182 2           char * keystr = SvPV(key, keylen);
183 2           hv_store(self, keystr, keylen, newSVsv(value), 0);
184             }
185             OUTPUT:
186             RETVAL
187              
188              
189             MODULE = Basic::Coercion::XS PACKAGE = Basic::Coercion::XS
190             PROTOTYPES: ENABLE
191             FALLBACK: TRUE
192              
193             SV *
194             by(self, pattern)
195             SV *self
196             SV *pattern
197             CODE:
198 3 50         if (!self || !SvROK(self)) {
    50          
199 0           croak("constraint not initialized");
200             }
201 3 100         if (SvTYPE(pattern) != SVt_PV && !SvROK(pattern)) {
    100          
202 1           croak("pattern must be a string or a regex object");
203             }
204 2           SvREFCNT_inc(self);
205 2           HV * self_hv = (HV*)SvRV(self);
206 2           hv_store(self_hv, "by", 2, newSVsv(pattern), 0);
207 2           RETVAL = self;
208             OUTPUT:
209             RETVAL
210              
211             CV *
212             coerce(...)
213             OVERLOAD: &{}
214             CODE:
215 14           SV * self = ST(0);
216 14 50         if (!SvROK(self) || SvTYPE(SvRV(self)) != SVt_PVHV) {
    50          
217 0           croak("first argument must be a Basic::Coercion::XS object");
218             }
219 14           SV * cb = *hv_fetch((HV*)SvRV(self), "coerce", 6, 0);
220 14           RETVAL = (CV*)SvRV(cb);
221             OUTPUT:
222             RETVAL
223              
224             void
225             import( ...)
226             CODE:
227 4           char *pkg = get_caller();
228             STRLEN retlen;
229 4           int i = 1;
230 7 100         for (i = 1; i < items; i++) {
231 3           char * ex = SvPV(ST(i), retlen);
232 3           int name_len = strlen(pkg) + retlen + 3;
233 3           char *name = (char *)malloc(name_len);
234 3 50         if (!name) croak("Out of memory");
235 3           snprintf(name, name_len, "%s::%s", pkg, ex);
236 3 100         if (strcmp(ex, "StrToArray") == 0) {
237 2           newXS(name, XS_Basic__Coercion__XS__Definition_StrToArray, __FILE__);
238 1 50         } else if (strcmp(ex, "StrToHash") == 0) {
239 1           newXS(name, XS_Basic__Coercion__XS__Definition_StrToHash, __FILE__);
240             } else {
241 0           croak("Unknown import: %s", ex);
242             }
243 3           safefree(name);
244             }