File Coverage

lib/Const/XS.xs
Criterion Covered Total %
statement 118 127 92.9
branch 72 90 80.0
condition n/a
subroutine n/a
pod n/a
total 190 217 87.5


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT // we'll define thread context if necessary (faster)
2             #include "EXTERN.h" // globals/constant import locations
3             #include "perl.h" // Perl symbols, structures and constants definition
4             #include "XSUB.h" // xsubpp functions and macros
5              
6 27275           void _make_readonly (SV * val) {
7             dTHX;
8              
9 27275 100         if (SvOK(val) && SvROK(val)) {
    100          
10 1091 100         if (SvTYPE(SvRV(val)) == SVt_PVAV) {
11 21           AV * arr = (AV*)SvRV(val);
12 21 100         if (!SvREADONLY((SV*)arr)) {
13 20           _make_readonly((SV*)arr);
14 20           int i = 0;
15 20           int len = av_len(arr);
16 82 100         for (i = 0; i <= len; i++) {
17 62           SV * value = *av_fetch(arr, i, 0);
18 62           _make_readonly(value);
19             }
20             }
21 1070 100         } else if (SvTYPE(SvRV(val)) == SVt_PVHV) {
22 1056           HV * hash = (HV*)SvRV(val);
23 1056 100         if (!SvREADONLY((SV*)hash)) {
24 1052           _make_readonly((SV*)hash);
25             HE * entry;
26 1052           (void)hv_iterinit(hash);
27 27146 100         while ((entry = hv_iternext(hash))) {
28             STRLEN retlen;
29 26094           char * key = SvPV(hv_iterkeysv(entry), retlen);
30 26094           SV * value = *hv_fetch(hash, key, retlen, 0);
31 26094           _make_readonly(value);
32             }
33             }
34             }
35             }
36              
37 27275           SvREADONLY_on(val);
38 27275           }
39              
40 49           void _make_readwrite (SV * val) {
41             dTHX;
42              
43 49 100         if (SvOK(val) && SvROK(val)) {
    100          
44 15 100         if (SvTYPE(SvRV(val)) == SVt_PVAV) {
45 3           AV * arr = (AV*)SvRV(val);
46 3 50         if (SvREADONLY(arr)) {
47 3           int i = 0;
48 3           int len = av_len(arr);
49 3           _make_readwrite((SV*)arr);
50 14 100         for (i = 0; i <= len; i++) {
51 11           SV * value = *av_fetch(arr, i, 0);
52 11           _make_readwrite(value);
53             }
54             }
55 12 50         } else if (SvTYPE(SvRV(val)) == SVt_PVHV) {
56 12           HV * hash = (HV*)SvRV(val);
57 12 100         if (SvREADONLY(hash)) {
58             HE * entry;
59 10           (void)hv_iterinit(hash);
60 10           _make_readwrite((SV*)hash);
61 27 100         while ((entry = hv_iternext(hash))) {
62             STRLEN retlen;
63 17           char * key = SvPV(hv_iterkeysv(entry), retlen);
64 17           SV * value = *hv_fetch(hash, key, retlen, 0);
65 17           _make_readwrite(value);
66             }
67             }
68             }
69             }
70              
71 49           SvREADONLY_off(val);
72 49           }
73              
74 41           int _is_readonly (SV * val) {
75             dTHX;
76              
77 41 100         if (SvOK(val) && SvROK(val)) {
    100          
78 16 100         if (SvTYPE(SvRV(val)) == SVt_PVAV) {
79 5           AV * arr = (AV*)SvRV(val);
80 5 100         if (! _is_readonly((SV*)arr) ) {
81 3           return 0;
82             }
83 11 100         } else if (SvTYPE(SvRV(val)) == SVt_PVHV) {
84 9           HV * hash = (HV*)SvRV(val);
85 9 100         if (! _is_readonly((SV*)hash) ) {
86 2           return 0;
87             }
88             }
89             }
90              
91 36           return SvREADONLY(val) ? 1 : 0;
92             }
93              
94 8           void export (XSUBADDR_t cb, char * pkg, int pkg_len, char * method, int method_len) {
95             dTHX;
96 8           int name_len = pkg_len + method_len + 3;
97 8           char *name = (char *)malloc(name_len);
98 8           snprintf(name, name_len, "%s::%s", pkg, method);
99 8           newXS(name, cb, __FILE__);
100 8           free(name);
101 8           }
102              
103 33           void export_proto (XSUBADDR_t cb, char * pkg, int pkg_len, char * method, int method_len, char * proto) {
104             dTHX;
105 33           int name_len = pkg_len + method_len + 3;
106 33           char *name = (char *)malloc(name_len);
107 33           snprintf(name, name_len, "%s::%s", pkg, method);
108 33           newXSproto(name, cb, __FILE__, proto);
109 33           free(name);
110 33           }
111              
112              
113             MODULE = Const::XS PACKAGE = Const::XS
114             PROTOTYPES: ENABLE
115              
116             void
117             const(...)
118             PROTOTYPE: \[$@%]@
119             CODE:
120 31           int i = 1;
121              
122 31 100         if (items < 2) {
123 2           croak("No value for readonly variable");
124             }
125              
126 29 100         if (SvTYPE(SvRV(ST(0))) == SVt_PVAV) {
127 8           AV * ret = (AV*)SvRV(ST(0));
128 36 100         for (i = 1; i < items; i++) {
129 28           SV * val = newSVsv(ST(i));
130 28           av_push(ret, val);
131             }
132 8           _make_readonly(ST(0));
133 21 100         } else if ( SvTYPE(SvRV(ST(0))) == SVt_PVHV) {
134 8 100         if ((items - 1) % 2 != 0) {
135 1           croak("Odd number of elements in hash assignment");
136             }
137 7           HV * ret = (HV*)SvRV(ST(0));
138 26 100         for (i = 1; i < items; i += 2) {
139             STRLEN retlen;
140 19           char * key = SvPV(ST(i), retlen);
141 19           SV * value = newSVsv(ST(i + 1));
142 19           hv_store(ret, key, retlen, value, 0);
143             }
144 7           _make_readonly(ST(0));
145             } else {
146 13           SV * ret = SvRV(ST(0));
147 13           sv_setsv( ret, newSVsv(ST(1)) );
148 13           _make_readonly(ret);
149             }
150 28           XSRETURN(1);
151              
152             SV *
153             make_readonly_ref(...);
154             CODE:
155 1           _make_readonly(ST(0));
156 1           XSRETURN(1);
157              
158             SV *
159             make_readonly(...)
160             PROTOTYPE: \[$@%]@
161             CODE:
162 18           int type = SvTYPE(SvRV(ST(0)));
163 18 100         if (type == SVt_PVAV || type == SVt_PVHV) {
    100          
164 2           _make_readonly(ST(0));
165             } else {
166 16           _make_readonly(SvRV(ST(0)));
167             }
168 18           XSRETURN(1);
169              
170             SV *
171             unmake_readonly(...)
172             PROTOTYPE: \[$@%]@
173             CODE:
174 8           int type = SvTYPE(SvRV(ST(0)));
175 8 100         if (type == SVt_PVAV || type == SVt_PVHV) {
    100          
176 2           _make_readwrite(ST(0));
177             } else {
178 6           _make_readwrite(SvRV(ST(0)));
179             }
180 8           XSRETURN(1);
181              
182             SV *
183             is_readonly(...)
184             PROTOTYPE: \[$@%]@
185             CODE:
186 27           ST(0) = newSViv(_is_readonly(SvRV(ST(0))));
187 27           XSRETURN(1);
188              
189              
190             void
191             import(...)
192             CODE:
193 10 50         char *pkg = HvNAME((HV*)CopSTASH(PL_curcop));
    50          
    50          
    0          
    50          
    50          
194 10           int pkg_len = strlen(pkg);
195             STRLEN retlen;
196 10           int i = 1;
197 19 100         for (i = 1; i < items; i++) {
198 9           char * ex = SvPV(ST(i), retlen);
199 9 100         if (strcmp(ex, "all") == 0) {
200 8           export_proto(XS_Const__XS_const, pkg, pkg_len, "const", 5, "\\[$@%]@");
201 8           export_proto(XS_Const__XS_make_readonly, pkg, pkg_len, "make_readonly", 13, "\\[$@%]@");
202 8           export(XS_Const__XS_make_readonly_ref, pkg, pkg_len, "make_readonly_ref", 17);
203 8           export_proto(XS_Const__XS_unmake_readonly, pkg, pkg_len, "unmake_readonly", 15, "\\[$@%]@");
204 8           export_proto(XS_Const__XS_is_readonly, pkg, pkg_len, "is_readonly", 11, "\\[$@%]@");
205 1 50         } else if (strcmp(ex, "const") == 0) {
206 1           export_proto(XS_Const__XS_const, pkg, pkg_len, "const", 5, "\\[$@%]@");
207 0 0         } else if (strcmp(ex, "make_readonly") == 0) {
208 0           export_proto(XS_Const__XS_make_readonly, pkg, pkg_len, "make_readonly", 13, "\\[$@%]@");
209 0 0         } else if (strcmp(ex, "make_readonly_ref") == 0) {
210 0           export(XS_Const__XS_make_readonly_ref, pkg, pkg_len, "make_readonly_ref", 17);
211 0 0         } else if (strcmp(ex, "unmake_readonly") == 0) {
212 0           export_proto(XS_Const__XS_unmake_readonly, pkg, pkg_len, "unmake_readonly", 15, "\\[$@%]@");
213 0 0         } else if (strcmp(ex, "is_readonly") == 0) {
214 0           export_proto(XS_Const__XS_is_readonly, pkg, pkg_len, "is_readonly", 11, "\\[$@%]@");
215             } else {
216 0           croak("Unknown import: %s", ex);
217             }
218             }
219