File Coverage

Safe.xs
Criterion Covered Total %
statement 152 181 83.9
branch 109 186 58.6
condition n/a
subroutine n/a
pod n/a
total 261 367 71.1


line stmt bran cond sub pod time code
1             #include "perl_libyaml.h"
2              
3             #define MY_CXT_KEY "YAML::Safe::_cxt"
4             typedef struct {
5             SV *yaml_str;
6             } my_cxt_t;
7              
8             START_MY_CXT
9              
10             static void
11 50           init_MY_CXT(pTHX_ my_cxt_t * cxt)
12             {
13 50           cxt->yaml_str = NULL;
14 50           }
15              
16             static NV
17 4           version_number(const char* name)
18             {
19 4           GV* gv = gv_fetchpv(name, 0, SVt_PV);
20 4 50         SV* version = gv ? GvSV(gv) : NULL;
21 4 50         if (!version)
22 0           return -1.0;
23 4 100         if (SvNOK(version))
24 1           return SvNVX(version);
25 3 50         if (SvIOK(version))
26 0           return (NV)SvIVX(version);
27 3 50         if (SvPOK(version)) {
28 3           return Atof(SvPVX(version));
29             }
30 0           return -1.0;
31             }
32              
33             static void
34 6           better_load_module(const char* stash, SV* name)
35             {
36 6           int badver = 0;
37             /* JSON::PP::Boolean:: or boolean:: */
38 6           GV* stashgv = gv_fetchpvn_flags(stash, strlen(stash), GV_NOADD_NOINIT, SVt_PVHV);
39 6 100         if (stashgv && strEQ(SvPVX(name), "JSON::PP")) {
    50          
40             /* Check for compat. versions. Which JSON::PP::Boolean is loaded? */
41             /* Cpanel::JSON::XS needs 3.0236, JSON::XS needs 3.0 */
42 4 50         char* file = GvFILE(stashgv);
43 4 50         if (file) {
44             /* we rely on C89 now */
45 8           if (strstr(file, "Cpanel/JSON/XS.pm") &&
46 4           version_number("Cpanel::JSON::XS::VERSION") < 3.0236)
47 0           badver = 1;
48 4           else if (strstr(file, "Types/Serialiser.pm") &&
49 0           version_number("Types::Serialiser::VERSION") < 1.0)
50 0           badver = 1;
51 4           else if (strstr(file, "JSON/backportPP/Boolean.pm") &&
52 0           version_number("JSON::backportPP::Boolean::VERSION") < 3.0)
53 0           badver = 1;
54             }
55             }
56 6 100         if (!stashgv || badver) {
    50          
57 2           char *copy = strdup(SvPVX(name));
58             /* On older perls (<5.20) this corrupted ax */
59 2           load_module(PERL_LOADMOD_NOIMPORT, SvREFCNT_inc_NN(name), NULL);
60             /* This overwrites value with the module path from %INC. Undo that */
61 2           SvREADONLY_off(name);
62             #ifdef SVf_PROTECT
63 2           SvFLAGS(name) &= ~SVf_PROTECT;
64             #endif
65 2           sv_force_normal_flags(name, 0);
66 2           sv_setpvn(name, copy, strlen(copy));
67 2           free(copy);
68             }
69 6           }
70              
71             MODULE = YAML::Safe PACKAGE = YAML::Safe
72              
73             PROTOTYPES: ENABLE
74              
75             void
76             Load (...)
77             PROTOTYPE: $;$@
78             ALIAS:
79             Load = 1
80             LoadFile = 2
81             Dump = 3
82             DumpFile = 4
83             SafeLoad = 9
84             SafeLoadFile = 10
85             SafeDump = 11
86             SafeDumpFile = 12
87             PREINIT:
88             YAML *self;
89             SV* yaml_arg;
90 196           int yaml_ix = 0;
91 196           int ret = 0;
92 196           int old_safe = 0;
93 196           int err = 0;
94             PPCODE:
95             /* check if called as method or function */
96 196 100         if (items >= 2 &&
    100          
97 46 100         SvROK(ST(0)) &&
98 46           sv_derived_from (ST(0), "YAML::Safe")) {
99 42           self = (YAML*)SvPVX(SvRV(ST(0)));
100             assert(self);
101 42           old_safe = self->flags & F_SAFEMODE;
102 42           yaml_ix = 1;
103 42           yaml_arg = ST(1);
104             }
105 154 100         else if ((items == 1 && ix < 8) || /* no self needed */
    50          
    50          
106 10 50         (ix >= 3 && ix <= 4)) { /* and Dump, DumpFile can have more args */
107             /* default options */
108 154           self = (YAML*)malloc(sizeof(YAML));
109 154           yaml_init (self);
110 154           yaml_arg = ST(0);
111             } else {
112 0           err = 1;
113             }
114 196           PL_markstack_ptr++;
115             /* set or unset safemode */
116 196           switch (ix) {
117 101 50         case 1: if (err)
118 0           croak ("Usage: Load([YAML::Safe,] str)");
119             else {
120 101           self->flags &= ~F_SAFEMODE;
121 101           ret = Load(self, yaml_arg);
122             }
123 93           break;
124 5 50         case 2: if (err)
125 0           croak ("Usage: LoadFile([YAML::Safe,] filename|io)");
126             else {
127 5           self->flags &= ~F_SAFEMODE;
128 5           ret = LoadFile(self, yaml_arg);
129             }
130 5           break;
131 80 50         case 3: if (err)
132 0           croak ("Usage: Dump([YAML::Safe,] ...)");
133             else {
134 80           self->flags &= ~F_SAFEMODE;
135 80           ret = Dump(self, yaml_ix);
136             }
137 80           break;
138 4 50         case 4: if (err)
139 0           croak ("Usage: DumpFile([YAML::Safe,] filename|io, ...)");
140             else {
141 4           self->flags &= ~F_SAFEMODE;
142 4           ret = DumpFile(self, yaml_arg, yaml_ix);
143             }
144 4           break;
145 3 50         case 9: if (err)
146 0           croak ("Usage: SafeLoad(YAML::Safe, str)");
147             else {
148 3           self->flags |= F_SAFEMODE;
149 3           ret = Load(self, yaml_arg);
150             }
151 3           break;
152 0 0         case 10: if (err)
153 0           croak ("Usage: SafeLoadFile(YAML::Safe, filename|io)");
154             else {
155 0           self->flags |= F_SAFEMODE;
156 0           ret = LoadFile(self, yaml_arg);
157             }
158 0           break;
159 3 50         case 11: if (err)
160 0           croak ("Usage: SafeDump(YAML::Safe, ...)");
161             else {
162 3           self->flags |= F_SAFEMODE;
163 3           ret = Dump(self, yaml_ix);
164             /*printf("# ret: %s %d 0x%x\n",
165             sv_peek(*PL_stack_sp),
166             SvREFCNT(*PL_stack_sp),
167             SvFLAGS(*PL_stack_sp)
168             );*/
169             }
170 3           break;
171 0 0         case 12: if (err)
172 0           croak ("Usage: SafeDumpFile(YAML::Safe*, filename|io, ...)");
173             else {
174 0           self->flags |= F_SAFEMODE;
175 0           ret = DumpFile(self, yaml_arg, yaml_ix);
176             }
177 0           break;
178             }
179             /* restore old safemode */
180 188 100         if (old_safe) self->flags |= F_SAFEMODE;
181 181           else self->flags &= ~F_SAFEMODE;
182 188 50         if (!ret)
183 0           XSRETURN_UNDEF;
184             else
185 188           return;
186              
187             SV *
188             libyaml_version()
189             CODE:
190             {
191 1           const char *v = yaml_get_version_string();
192 1           RETVAL = newSVpv(v, strlen(v));
193             }
194             OUTPUT: RETVAL
195              
196             BOOT:
197             {
198             MY_CXT_INIT;
199 50           init_MY_CXT(aTHX_ &MY_CXT);
200             }
201              
202             #ifdef USE_ITHREADS
203              
204             void CLONE (...)
205             PPCODE:
206             MY_CXT_CLONE; /* possible declaration */
207             init_MY_CXT(aTHX_ &MY_CXT);
208             /* skip implicit PUTBACK, returning @_ to caller, more efficient*/
209             return;
210              
211             #endif
212              
213             #if 0
214              
215             void END(...)
216             PREINIT:
217             dMY_CXT;
218             SV * sv;
219             PPCODE:
220             sv = MY_CXT.yaml_str;
221             MY_CXT.yaml_str = NULL;
222             SvREFCNT_dec(sv);
223             /* skip implicit PUTBACK, returning @_ to caller, more efficient*/
224             return;
225              
226             #endif
227              
228             void DESTROY (YAML *self)
229             CODE:
230 23           yaml_destroy (self);
231              
232             SV* new (char *klass)
233             CODE:
234             dMY_CXT;
235 23           SV *pv = NEWSV (0, sizeof (YAML));
236 23           SvPOK_only (pv);
237 23           yaml_init ((YAML*)SvPVX (pv));
238 23           RETVAL = sv_bless (newRV (pv), gv_stashpv (klass, 1));
239             OUTPUT: RETVAL
240              
241             YAML*
242             unicode (YAML *self, int enable = 1)
243             ALIAS:
244             unicode = F_UNICODE
245             disableblessed = F_DISABLEBLESSED
246             nonstrict = F_NONSTRICT
247             loadcode = F_LOADCODE
248             dumpcode = F_DUMPCODE
249             quotenum = F_QUOTENUM
250             noindentmap = F_NOINDENTMAP
251             canonical = F_CANONICAL
252             openended = F_OPENENDED
253             enablecode = F_ENABLECODE
254             CODE:
255             (void)RETVAL;
256 35 100         if (enable)
257 24           self->flags |= ix;
258             else
259 11           self->flags &= ~ix;
260             OUTPUT: self
261              
262             SV*
263             get_unicode (YAML *self)
264             ALIAS:
265             get_unicode = F_UNICODE
266             get_disableblessed = F_DISABLEBLESSED
267             get_enablecode = F_ENABLECODE
268             get_nonstrict = F_NONSTRICT
269             get_loadcode = F_LOADCODE
270             get_dumpcode = F_DUMPCODE
271             get_quotenum = F_QUOTENUM
272             get_noindentmap = F_NOINDENTMAP
273             get_canonical = F_CANONICAL
274             get_openended = F_OPENENDED
275             get_safemode = F_SAFEMODE
276             CODE:
277 30 100         RETVAL = boolSV (self->flags & ix);
278             OUTPUT: RETVAL
279              
280             SV*
281             get_boolean (YAML *self)
282             CODE:
283 3 100         if (self->boolean == YAML_BOOLEAN_JSONPP)
284 1           RETVAL = newSVpvn("JSON::PP", sizeof("JSON::PP")-1);
285 2 100         else if (self->boolean == YAML_BOOLEAN_BOOLEAN)
286 1           RETVAL = newSVpvn("boolean", sizeof("boolean")-1);
287             else
288 1           RETVAL = &PL_sv_undef;
289             OUTPUT: RETVAL
290              
291             YAML*
292             boolean (YAML *self, SV *value)
293             CODE:
294             (void)RETVAL;
295 15 100         if (SvPOK(value)) {
296             #if (PERL_BCDVERSION >= 0x5008009)
297 12 100         if (strEQ(SvPVX(value), "JSON::PP")) {
298 4           self->boolean = YAML_BOOLEAN_JSONPP;
299             /* check JSON::PP::Boolean first, as it's implemented with
300             JSON, JSON::XS and many others also. In CORE since 5.13.9 */
301 4           better_load_module("JSON::PP::Boolean::", value);
302             }
303 8 100         else if (strEQ(SvPVX(value), "boolean")) {
304 2           self->boolean = YAML_BOOLEAN_BOOLEAN;
305 2           better_load_module("boolean::", value);
306             }
307             else
308             #endif
309 6 100         if (strEQ(SvPVX(value), "false") || !SvTRUE(value)) {
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    100          
    100          
    100          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
310 3           self->boolean = YAML_BOOLEAN_NONE;
311             }
312             else {
313 12           croak("Invalid YAML::Safe->boolean value %s", SvPVX(value));
314             }
315 3 50         } else if (!SvTRUE(value)) {
    50          
    0          
    100          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    100          
    0          
316 2           self->boolean = YAML_BOOLEAN_NONE;
317             } else {
318 1           croak("Invalid YAML::Safe->boolean value");
319             }
320             OUTPUT: self
321              
322             char*
323             get_encoding (YAML *self)
324             CODE:
325 5           switch (self->encoding) {
326 2           case YAML_ANY_ENCODING: RETVAL = "any"; break;
327 1           case YAML_UTF8_ENCODING: RETVAL = "utf8"; break;
328 1           case YAML_UTF16LE_ENCODING: RETVAL = "utf16le"; break;
329 1           case YAML_UTF16BE_ENCODING: RETVAL = "utf16be"; break;
330 0           default: RETVAL = "utf8"; break;
331             }
332             OUTPUT: RETVAL
333              
334             # for parser and emitter
335             YAML*
336             encoding (YAML *self, char *value)
337             CODE:
338             (void)RETVAL;
339 5 100         if (strEQ(value, "any")) {
340 1           self->encoding = YAML_ANY_ENCODING;
341             }
342 4 100         else if (strEQ(value, "utf8")) {
343 1           self->encoding = YAML_UTF8_ENCODING;
344             }
345 3 100         else if (strEQ(value, "utf16le")) {
346 1           self->encoding = YAML_UTF16LE_ENCODING;
347             }
348 2 100         else if (strEQ(value, "utf16be")) {
349 1           self->encoding = YAML_UTF16BE_ENCODING;
350             }
351             else {
352 1           croak("Invalid YAML::Safe->encoding value %s", value);
353             }
354             OUTPUT: self
355              
356             char*
357             get_linebreak (YAML *self)
358             CODE:
359 5           switch (self->linebreak) {
360 2           case YAML_ANY_BREAK: RETVAL = "any"; break;
361 1           case YAML_CR_BREAK: RETVAL = "cr"; break;
362 1           case YAML_LN_BREAK: RETVAL = "ln"; break;
363 1           case YAML_CRLN_BREAK: RETVAL = "crln"; break;
364 0           default: RETVAL = "any"; break;
365             }
366             OUTPUT: RETVAL
367              
368             YAML*
369             linebreak (YAML *self, char *value)
370             CODE:
371             (void)RETVAL;
372 5 100         if (strEQ(value, "any")) {
373 1           self->linebreak = YAML_ANY_BREAK;
374             }
375 4 100         else if (strEQ(value, "cr")) {
376 1           self->linebreak = YAML_CR_BREAK;
377             }
378 3 100         else if (strEQ(value, "ln")) {
379 1           self->linebreak = YAML_LN_BREAK;
380             }
381 2 100         else if (strEQ(value, "crln")) {
382 1           self->linebreak = YAML_CRLN_BREAK;
383             }
384             else {
385 1           croak("Invalid YAML::Safe->linebreak value %s", value);
386             }
387             OUTPUT: self
388              
389             # both are for the emitter only
390             UV
391             get_indent (YAML *self)
392             ALIAS:
393             get_indent = 1
394             get_wrapwidth = 2
395             CODE:
396 4 100         RETVAL = ix == 1 ? self->indent
    50          
397 2           : ix == 2 ? self->wrapwidth
398             : 0;
399             OUTPUT: RETVAL
400              
401             YAML*
402             indent (YAML *self, IV iv)
403             ALIAS:
404             indent = 1
405             wrapwidth = 2
406             CODE:
407             (void)RETVAL;
408 6 50         if (!SvIOK(ST(1)))
409 0           croak("Invalid argument type");
410 6 100         if (ix == 1) {
411 4 100         if (iv < 1 || iv >= 10)
    50          
412 1           croak("Invalid YAML::Safe->indent value %" IVdf " (only 1-10)", iv);
413 3           self->indent = iv;
414             }
415 2 50         else if (ix == 2) {
416 2 100         if (iv < 1 || iv >= 0xffff)
    50          
417 1           croak("Invalid YAML::Safe->wrapwidth value %" IVdf " (only 1-0xffff)", iv);
418 1           self->wrapwidth = iv;
419             }
420             OUTPUT: self
421              
422             YAML*
423             SafeClass (YAML *self, ...)
424             PROTOTYPE: $;@
425             PREINIT:
426             int i;
427             CODE:
428             (void)RETVAL;
429 1           self->flags |= F_SAFEMODE;
430 1 50         if (!self->safeclasses)
431 1           self->safeclasses = newHV();
432 2 100         for (i=1; i
433 1           const char *s = SvPVX_const(ST(i));
434 1           (void)hv_store(self->safeclasses, s, strlen(s), newSViv(1), 0);
435             }
436             OUTPUT: self