File Coverage

Safe.xs
Criterion Covered Total %
statement 152 182 83.5
branch 109 186 58.6
condition n/a
subroutine n/a
pod n/a
total 261 368 70.9


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             default:
179 0           croak ("Internal Error: Unhandled YAML::Safe::Load alias");
180             return;
181             }
182             /* restore old safemode */
183 188 100         if (old_safe) self->flags |= F_SAFEMODE;
184 181           else self->flags &= ~F_SAFEMODE;
185 188 50         if (!ret)
186 0           XSRETURN_UNDEF;
187             else
188 188           return;
189              
190             SV *
191             libyaml_version()
192             CODE:
193             {
194 1           const char *v = yaml_get_version_string();
195 1           RETVAL = newSVpv(v, strlen(v));
196             }
197             OUTPUT: RETVAL
198              
199             BOOT:
200             {
201             MY_CXT_INIT;
202 50           init_MY_CXT(aTHX_ &MY_CXT);
203             }
204              
205             #ifdef USE_ITHREADS
206              
207             void CLONE (...)
208             PPCODE:
209             MY_CXT_CLONE; /* possible declaration */
210             init_MY_CXT(aTHX_ &MY_CXT);
211             /* skip implicit PUTBACK, returning @_ to caller, more efficient*/
212             return;
213              
214             #endif
215              
216             #if 0
217              
218             void END(...)
219             PREINIT:
220             dMY_CXT;
221             SV * sv;
222             PPCODE:
223             sv = MY_CXT.yaml_str;
224             MY_CXT.yaml_str = NULL;
225             SvREFCNT_dec(sv);
226             /* skip implicit PUTBACK, returning @_ to caller, more efficient*/
227             return;
228              
229             #endif
230              
231             void DESTROY (YAML *self)
232             CODE:
233 23           yaml_destroy (self);
234              
235             SV* new (char *klass)
236             CODE:
237             dMY_CXT;
238 23           SV *pv = NEWSV (0, sizeof (YAML));
239 23           SvPOK_only (pv);
240 23           yaml_init ((YAML*)SvPVX (pv));
241 23           RETVAL = sv_bless (newRV (pv), gv_stashpv (klass, 1));
242             OUTPUT: RETVAL
243              
244             YAML*
245             unicode (YAML *self, int enable = 1)
246             ALIAS:
247             unicode = F_UNICODE
248             disableblessed = F_DISABLEBLESSED
249             nonstrict = F_NONSTRICT
250             loadcode = F_LOADCODE
251             dumpcode = F_DUMPCODE
252             quotenum = F_QUOTENUM
253             noindentmap = F_NOINDENTMAP
254             canonical = F_CANONICAL
255             openended = F_OPENENDED
256             enablecode = F_ENABLECODE
257             CODE:
258             (void)RETVAL;
259 35 100         if (enable)
260 24           self->flags |= ix;
261             else
262 11           self->flags &= ~ix;
263             OUTPUT: self
264              
265             SV*
266             get_unicode (YAML *self)
267             ALIAS:
268             get_unicode = F_UNICODE
269             get_disableblessed = F_DISABLEBLESSED
270             get_enablecode = F_ENABLECODE
271             get_nonstrict = F_NONSTRICT
272             get_loadcode = F_LOADCODE
273             get_dumpcode = F_DUMPCODE
274             get_quotenum = F_QUOTENUM
275             get_noindentmap = F_NOINDENTMAP
276             get_canonical = F_CANONICAL
277             get_openended = F_OPENENDED
278             get_safemode = F_SAFEMODE
279             CODE:
280 30 100         RETVAL = boolSV (self->flags & ix);
281             OUTPUT: RETVAL
282              
283             SV*
284             get_boolean (YAML *self)
285             CODE:
286 3 100         if (self->boolean == YAML_BOOLEAN_JSONPP)
287 1           RETVAL = newSVpvn("JSON::PP", sizeof("JSON::PP")-1);
288 2 100         else if (self->boolean == YAML_BOOLEAN_BOOLEAN)
289 1           RETVAL = newSVpvn("boolean", sizeof("boolean")-1);
290             else
291 1           RETVAL = &PL_sv_undef;
292             OUTPUT: RETVAL
293              
294             YAML*
295             boolean (YAML *self, SV *value)
296             CODE:
297             (void)RETVAL;
298 15 100         if (SvPOK(value)) {
299             #if (PERL_BCDVERSION >= 0x5008009)
300 12 100         if (strEQ(SvPVX(value), "JSON::PP")) {
301 4           self->boolean = YAML_BOOLEAN_JSONPP;
302             /* check JSON::PP::Boolean first, as it's implemented with
303             JSON, JSON::XS and many others also. In CORE since 5.13.9 */
304 4           better_load_module("JSON::PP::Boolean::", value);
305             }
306 8 100         else if (strEQ(SvPVX(value), "boolean")) {
307 2           self->boolean = YAML_BOOLEAN_BOOLEAN;
308 2           better_load_module("boolean::", value);
309             }
310             else
311             #endif
312 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          
313 3           self->boolean = YAML_BOOLEAN_NONE;
314             }
315             else {
316 12           croak("Invalid YAML::Safe->boolean value %s", SvPVX(value));
317             }
318 3 50         } else if (!SvTRUE(value)) {
    50          
    0          
    100          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    100          
    0          
319 2           self->boolean = YAML_BOOLEAN_NONE;
320             } else {
321 1           croak("Invalid YAML::Safe->boolean value");
322             }
323             OUTPUT: self
324              
325             char*
326             get_encoding (YAML *self)
327             CODE:
328 5           switch (self->encoding) {
329 2           case YAML_ANY_ENCODING: RETVAL = "any"; break;
330 1           case YAML_UTF8_ENCODING: RETVAL = "utf8"; break;
331 1           case YAML_UTF16LE_ENCODING: RETVAL = "utf16le"; break;
332 1           case YAML_UTF16BE_ENCODING: RETVAL = "utf16be"; break;
333 0           default: RETVAL = "utf8"; break;
334             }
335             OUTPUT: RETVAL
336              
337             # for parser and emitter
338             YAML*
339             encoding (YAML *self, char *value)
340             CODE:
341             (void)RETVAL;
342 5 100         if (strEQ(value, "any")) {
343 1           self->encoding = YAML_ANY_ENCODING;
344             }
345 4 100         else if (strEQ(value, "utf8")) {
346 1           self->encoding = YAML_UTF8_ENCODING;
347             }
348 3 100         else if (strEQ(value, "utf16le")) {
349 1           self->encoding = YAML_UTF16LE_ENCODING;
350             }
351 2 100         else if (strEQ(value, "utf16be")) {
352 1           self->encoding = YAML_UTF16BE_ENCODING;
353             }
354             else {
355 1           croak("Invalid YAML::Safe->encoding value %s", value);
356             }
357             OUTPUT: self
358              
359             char*
360             get_linebreak (YAML *self)
361             CODE:
362 5           switch (self->linebreak) {
363 2           case YAML_ANY_BREAK: RETVAL = "any"; break;
364 1           case YAML_CR_BREAK: RETVAL = "cr"; break;
365 1           case YAML_LN_BREAK: RETVAL = "ln"; break;
366 1           case YAML_CRLN_BREAK: RETVAL = "crln"; break;
367 0           default: RETVAL = "any"; break;
368             }
369             OUTPUT: RETVAL
370              
371             YAML*
372             linebreak (YAML *self, char *value)
373             CODE:
374             (void)RETVAL;
375 5 100         if (strEQ(value, "any")) {
376 1           self->linebreak = YAML_ANY_BREAK;
377             }
378 4 100         else if (strEQ(value, "cr")) {
379 1           self->linebreak = YAML_CR_BREAK;
380             }
381 3 100         else if (strEQ(value, "ln")) {
382 1           self->linebreak = YAML_LN_BREAK;
383             }
384 2 100         else if (strEQ(value, "crln")) {
385 1           self->linebreak = YAML_CRLN_BREAK;
386             }
387             else {
388 1           croak("Invalid YAML::Safe->linebreak value %s", value);
389             }
390             OUTPUT: self
391              
392             # both are for the emitter only
393             UV
394             get_indent (YAML *self)
395             ALIAS:
396             get_indent = 1
397             get_wrapwidth = 2
398             CODE:
399 4 100         RETVAL = ix == 1 ? self->indent
    50          
400 2           : ix == 2 ? self->wrapwidth
401             : 0;
402             OUTPUT: RETVAL
403              
404             YAML*
405             indent (YAML *self, IV iv)
406             ALIAS:
407             indent = 1
408             wrapwidth = 2
409             CODE:
410             (void)RETVAL;
411 6 50         if (!SvIOK(ST(1)))
412 0           croak("Invalid argument type");
413 6 100         if (ix == 1) {
414 4 100         if (iv < 1 || iv >= 10)
    50          
415 1           croak("Invalid YAML::Safe->indent value %" IVdf " (only 1-10)", iv);
416 3           self->indent = iv;
417             }
418 2 50         else if (ix == 2) {
419 2 100         if (iv < 1 || iv >= 0xffff)
    50          
420 1           croak("Invalid YAML::Safe->wrapwidth value %" IVdf " (only 1-0xffff)", iv);
421 1           self->wrapwidth = iv;
422             }
423             OUTPUT: self
424              
425             YAML*
426             SafeClass (YAML *self, ...)
427             PROTOTYPE: $;@
428             PREINIT:
429             int i;
430             CODE:
431             (void)RETVAL;
432 1           self->flags |= F_SAFEMODE;
433 1 50         if (!self->safeclasses)
434 1           self->safeclasses = newHV();
435 2 100         for (i=1; i
436 1           const char *s = SvPVX_const(ST(i));
437 1           (void)hv_store(self->safeclasses, s, strlen(s), newSViv(1), 0);
438             }
439             OUTPUT: self