File Coverage

Decoder.xs
Criterion Covered Total %
statement 172 209 82.3
branch 86 154 55.8
condition n/a
subroutine n/a
pod n/a
total 258 363 71.0


line stmt bran cond sub pod time code
1             /* Must be defined before including Perl header files or we slow down by 2x! */
2             #define PERL_NO_GET_CONTEXT
3              
4             #define NEED_newSV_type
5             #include "EXTERN.h"
6             #include "perl.h"
7             #include "XSUB.h"
8              
9             #include "ppport.h"
10              
11             #include "srl_common.h"
12             #include "srl_decoder.h"
13             #include "srl_protocol.h"
14              
15             #ifndef GvCV_set
16             # define GvCV_set(gv, cv) (GvCV(gv) = (cv))
17             #endif
18              
19             #ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
20             #define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)
21              
22             /* prototype to pass -Wmissing-prototypes */
23             STATIC void
24             S_croak_xs_usage(pTHX_ const CV *const cv, const char *const params);
25              
26             STATIC void
27             S_croak_xs_usage(pTHX_ const CV *const cv, const char *const params)
28             {
29             const GV *const gv = CvGV(cv);
30              
31             PERL_ARGS_ASSERT_CROAK_XS_USAGE;
32              
33             if (gv) {
34             const char *const gvname = GvNAME(gv);
35             const HV *const stash = GvSTASH(gv);
36             const char *const hvname = stash ? HvNAME(stash) : NULL;
37              
38             if (hvname)
39             Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
40             else
41             Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
42             } else {
43             /* Pants. I don't think that it should be possible to get here. */
44             Perl_croak_nocontext("Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
45             }
46             }
47              
48             #ifdef PERL_IMPLICIT_CONTEXT
49             #define croak_xs_usage(a,b) S_croak_xs_usage(aTHX_ a,b)
50             #else
51             #define croak_xs_usage S_croak_xs_usage
52             #endif
53              
54             #endif
55              
56              
57             #if defined(cv_set_call_checker) && defined(XopENTRY_set)
58             # define USE_CUSTOM_OPS 1
59             #else
60             # define USE_CUSTOM_OPS 0
61             #endif
62              
63             #define OPOPT_DO_BODY (1<<0)
64             #define OPOPT_DO_HEADER (1<<1)
65             #define OPOPT_OFFSET (1<<2)
66             #define OPOPT_OUTARG_BODY (1<<3)
67             #define OPOPT_OUTARG_HEADER (1<<4)
68             #define OPOPT_LOOKS_LIKE (1<<5)
69              
70             #define pp1_sereal_decode(opopt) THX_pp1_sereal_decode(aTHX_ opopt)
71             static void
72 685796           THX_pp1_sereal_decode(pTHX_ U8 opopt)
73             {
74 685796 100         bool need_retvalue = GIMME_V != G_VOID;
75             SV *decoder_ref_sv, *decoder_sv, *src_sv;
76             UV offset;
77             SV *body_into, *header_into;
78             srl_decoder_t *decoder;
79             char *stash_name;
80 685796           dSP;
81              
82 1371592           header_into = expect_false(opopt & OPOPT_OUTARG_HEADER)
83 0           ? POPs
84 685796 50         : expect_false(opopt & OPOPT_DO_HEADER) ? sv_newmortal() : NULL;
    100          
85 1371592           body_into = expect_false(opopt & OPOPT_OUTARG_BODY)
86 69           ? POPs
87 685796 100         : expect_true(opopt & OPOPT_DO_BODY) ? sv_newmortal() : NULL;
    100          
88              
89 685796 100         offset = expect_false(opopt & OPOPT_OFFSET) ? SvUVx(POPs) : 0;
    50          
90 685796           src_sv = POPs;
91 685796           decoder_ref_sv = POPs;
92 685796           PUTBACK;
93              
94 685796 50         if (!expect_true(
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
95             decoder_ref_sv &&
96             SvROK(decoder_ref_sv) &&
97             (decoder_sv = SvRV(decoder_ref_sv)) &&
98             SvOBJECT(decoder_sv) &&
99             (stash_name = HvNAME(SvSTASH(decoder_sv))) &&
100             !strcmp(stash_name, "Sereal::Decoder")
101             ))
102             {
103 0           croak("handle is not a Sereal::Decoder handle");
104             }
105              
106 685796 50         decoder = (srl_decoder_t *)SvIV(decoder_sv);
107 685796 100         if (expect_true(opopt & OPOPT_DO_BODY)) {
108 523316 50         if (opopt & OPOPT_DO_HEADER) {
109 0           srl_decode_all_into(aTHX_ decoder, src_sv, header_into,
110             body_into, offset);
111             } else {
112 523316           srl_decode_into(aTHX_ decoder, src_sv, body_into, offset);
113             }
114             } else {
115 162480           srl_decode_header_into(aTHX_ decoder, src_sv, header_into, offset);
116             }
117              
118 685786 100         if (expect_true(need_retvalue)) {
119             SV *retvalue;
120 685766 100         if (expect_true(opopt & OPOPT_DO_BODY)) {
121 523286 50         if (opopt & OPOPT_DO_HEADER) {
122 0           AV *retav = newAV();
123 0           retvalue = newRV_noinc((SV*)retav);
124 0           sv_2mortal(retvalue);
125 0           av_extend(retav, 1);
126 0           av_store(retav, 0, SvREFCNT_inc(header_into));
127 0           av_store(retav, 1, SvREFCNT_inc(body_into));
128             } else {
129 523286           retvalue = body_into;
130             }
131             } else {
132 162480           retvalue = header_into;
133             }
134 685766           SPAGAIN;
135 685766 50         XPUSHs(retvalue);
136 685766           PUTBACK;
137             }
138 685786           }
139              
140             #define pp1_looks_like_sereal() THX_pp1_looks_like_sereal(aTHX)
141             static void
142 10121           THX_pp1_looks_like_sereal(pTHX)
143             {
144 10121           dSP;
145 10121           SV *data= TOPs;
146             /* Should this be SvPOK()? Or better yet, check if it's *really* a string pointer: SvPOKp(data). After all
147             the serialization format is a string and anything otherwise would not look sereal. */
148 20237 100         if ( SvOK(data) ) {
    50          
    50          
149             STRLEN len;
150 10116 100         char *strdata= SvPV(data, len);
151 10116           IV ret= srl_validate_header_version_pv_len(aTHX_ strdata, len);
152 10116 100         if ( ret < 0 ) {
153 85           SETs(&PL_sv_no);
154             } else {
155 10031           SETs(sv_2mortal(newSViv(ret & SRL_PROTOCOL_VERSION_MASK)));
156             }
157             } else {
158 5           SETs(&PL_sv_no);
159             }
160 10121           }
161              
162             #if USE_CUSTOM_OPS
163              
164             static OP *
165 178729           THX_pp_sereal_decode(pTHX)
166             {
167 178729           pp1_sereal_decode(PL_op->op_private);
168 178729           return NORMAL;
169             }
170              
171             static OP *
172 23           THX_pp_looks_like_sereal(pTHX)
173             {
174 23           pp1_looks_like_sereal();
175 23           return NORMAL;
176             }
177              
178             static OP *
179 73           THX_ck_entersub_args_sereal_decoder(pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
180             {
181              
182             /* pull apart a standard entersub op tree */
183              
184 73           CV *cv = (CV*)ckobj;
185 73           I32 cv_private = CvXSUBANY(cv).any_i32;
186 73           U8 opopt = cv_private & 0xff;
187 73           U8 min_arity = (cv_private >> 8) & 0xff;
188 73           U8 max_arity = (cv_private >> 16) & 0xff;
189             OP *pushop, *firstargop, *cvop, *lastargop, *argop, *newop;
190             int arity;
191              
192             /* Walk the OP structure under the "entersub" to validate that we
193             * can use the custom OP implementation. */
194              
195 73           entersubop = ck_entersub_args_proto(entersubop, namegv, (SV*)cv);
196 73           pushop = cUNOPx(entersubop)->op_first;
197 73 50         if ( ! OpHAS_SIBLING(pushop) )
198 73           pushop = cUNOPx(pushop)->op_first;
199 73 50         firstargop = OpSIBLING(pushop);
200              
201 217 50         for (cvop = firstargop; OpHAS_SIBLING(cvop); cvop = OpSIBLING(cvop)) ;
    100          
202              
203 73           lastargop = pushop;
204 217 100         for (
205 73           arity = 0, lastargop = pushop, argop = firstargop;
206             argop != cvop;
207 144 50         lastargop = argop, argop = OpSIBLING(argop)
208             ){
209 144           arity++;
210             }
211              
212 73 50         if (expect_false(arity < min_arity || arity > max_arity))
    50          
    50          
213 0           return entersubop;
214              
215             /* If we get here, we can replace the entersub with a suitable
216             * custom OP. */
217              
218 73 50         if (arity > min_arity && (opopt & OPOPT_DO_BODY)) {
    0          
219 0           opopt |= OPOPT_OUTARG_BODY;
220 0           min_arity++;
221             }
222              
223 73 50         if (arity > min_arity)
224 0           opopt |= OPOPT_OUTARG_HEADER;
225              
226             #ifdef op_sibling_splice
227             /* op_sibling_splice is new in 5.31 and we have to do things differenly */
228              
229             /* cut out all ops between the pushmark and the RV2CV */
230 73           op_sibling_splice(NULL, pushop, arity, NULL);
231             /* then throw everything else out */
232 73           op_free(entersubop);
233 73           newop = newUNOP(OP_NULL, 0, NULL);
234              
235             #else
236              
237             OpMORESIB_set(pushop, cvop);
238             OpLASTSIB_set(lastargop, op_parent(lastargop));
239             op_free(entersubop);
240             newop = newUNOP(OP_NULL, 0, firstargop);
241              
242             #endif
243              
244 73           newop->op_type = OP_CUSTOM;
245 73           newop->op_private = opopt;
246 73 100         newop->op_ppaddr = opopt & OPOPT_LOOKS_LIKE ? THX_pp_looks_like_sereal : THX_pp_sereal_decode;
247              
248             #ifdef op_sibling_splice
249              
250             /* attach the spliced-out args as children of the custom op, while
251             * deleting the stub op created by newUNOP() */
252 73           op_sibling_splice(newop, NULL, 1, firstargop);
253              
254             #endif
255              
256 73           return newop;
257             }
258              
259             #endif /* USE_CUSTOM_OPS */
260              
261             static void
262 507067           THX_xsfunc_sereal_decode(pTHX_ CV *cv)
263             {
264 507067           dMARK;
265 507067           dSP;
266 507067           SSize_t arity = SP - MARK;
267 507067           I32 cv_private = CvXSUBANY(cv).any_i32;
268 507067           U8 opopt = cv_private & 0xff;
269 507067           U8 min_arity = (cv_private >> 8) & 0xff;
270 507067           U8 max_arity = (cv_private >> 16) & 0xff;
271              
272 507067 50         if (arity < min_arity || arity > max_arity)
    50          
273 0           croak("bad Sereal decoder usage");
274 507067 100         if (arity > min_arity && (opopt & OPOPT_DO_BODY)) {
    50          
275 69           opopt |= OPOPT_OUTARG_BODY;
276 69           min_arity++;
277             }
278 507067 50         if (arity > min_arity)
279 0           opopt |= OPOPT_OUTARG_HEADER;
280              
281 507067           pp1_sereal_decode(opopt);
282 507057           }
283              
284             static void
285 10098           THX_xsfunc_looks_like_sereal(pTHX_ CV *cv)
286             {
287 10098           dMARK;
288 10098           dSP;
289 10098           SSize_t arity = SP - MARK;
290 10098           I32 cv_private = CvXSUBANY(cv).any_i32;
291 10098           U8 max_arity = (cv_private >> 16) & 0xff;
292              
293 10098 50         if (arity < 1 || arity > max_arity)
    50          
294 0 0         croak_xs_usage(cv, max_arity == 1 ? "data" : "[invocant,] data");
295 10098 100         if(arity == 2) {
296 44           SV *data = POPs;
297 44           SETs(data);
298 44           PUTBACK;
299             }
300 10098           pp1_looks_like_sereal();
301 10098           }
302              
303             #define MY_CXT_KEY "Sereal::Decoder::_stash" XS_VERSION
304              
305             typedef struct {
306             sv_with_hash options[SRL_DEC_OPT_COUNT];
307             } my_cxt_t;
308              
309             START_MY_CXT
310              
311              
312             MODULE = Sereal::Decoder PACKAGE = Sereal::Decoder
313             PROTOTYPES: DISABLE
314              
315             BOOT:
316             {
317             struct {
318             char const *name_suffix;
319             U8 opopt;
320 73           } const funcs_to_install[] = {
321             { "", OPOPT_DO_BODY },
322             { "_only_header", OPOPT_DO_HEADER },
323             { "_with_header", (OPOPT_DO_BODY|OPOPT_DO_HEADER) },
324             { "_with_offset", (OPOPT_DO_BODY|OPOPT_OFFSET) },
325             { "_only_header_with_offset", (OPOPT_DO_HEADER|OPOPT_OFFSET) },
326             { "_with_header_and_offset", (OPOPT_DO_BODY|OPOPT_DO_HEADER|OPOPT_OFFSET) },
327             /*012345678901234567890123*/
328             }, *fti;
329             int i;
330             {
331             MY_CXT_INIT;
332 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_ALIAS_SMALLINT, SRL_DEC_OPT_STR_ALIAS_SMALLINT );
333 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_ALIAS_VARINT_UNDER, SRL_DEC_OPT_STR_ALIAS_VARINT_UNDER );
334 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_DESTRUCTIVE_INCREMENTAL, SRL_DEC_OPT_STR_DESTRUCTIVE_INCREMENTAL );
335 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_MAX_NUM_HASH_ENTRIES, SRL_DEC_OPT_STR_MAX_NUM_HASH_ENTRIES );
336 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_MAX_RECURSION_DEPTH, SRL_DEC_OPT_STR_MAX_RECURSION_DEPTH );
337 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_NO_BLESS_OBJECTS, SRL_DEC_OPT_STR_NO_BLESS_OBJECTS );
338 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_REFUSE_OBJECTS, SRL_DEC_OPT_STR_REFUSE_OBJECTS );
339 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_REFUSE_SNAPPY, SRL_DEC_OPT_STR_REFUSE_SNAPPY );
340 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_REFUSE_ZLIB, SRL_DEC_OPT_STR_REFUSE_ZLIB );
341 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_SET_READONLY, SRL_DEC_OPT_STR_SET_READONLY );
342 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_SET_READONLY_SCALARS, SRL_DEC_OPT_STR_SET_READONLY_SCALARS );
343 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_USE_UNDEF, SRL_DEC_OPT_STR_USE_UNDEF );
344 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_VALIDATE_UTF8, SRL_DEC_OPT_STR_VALIDATE_UTF8 );
345 73           SRL_INIT_OPTION( SRL_DEC_OPT_IDX_REFUSE_ZSTD, SRL_DEC_OPT_STR_REFUSE_ZSTD );
346             }
347             #if USE_CUSTOM_OPS
348             {
349             XOP *xop;
350 73           Newxz(xop, 1, XOP);
351 73           XopENTRY_set(xop, xop_name, "sereal_decode_with_object");
352 73           XopENTRY_set(xop, xop_desc, "sereal_decode_with_object");
353 73           XopENTRY_set(xop, xop_class, OA_UNOP);
354 73           Perl_custom_op_register(aTHX_ THX_pp_sereal_decode, xop);
355             }
356             #endif /* USE_CUSTOM_OPS */
357 511 100         for (i = sizeof(funcs_to_install)/sizeof(*fti); i--; ) {
358             # define LONG_CLASS_FMT "Sereal::Decoder::sereal_decode%s_with_object"
359             char name[sizeof(LONG_CLASS_FMT)+24];
360 438           char proto[7], *p = proto;
361             U8 opopt;
362             I32 cv_private;
363             GV *gv;
364             CV *cv;
365              
366 438           fti = &funcs_to_install[i];
367 438           opopt = fti->opopt;
368             /*
369             * The cv_private value incorporates flags describing the operation to be
370             * performed by the sub and precomputed arity limits. 0x020200 corresponds
371             * to min_arity=2 and max_arity=2. The various additions to cv_private
372             * increment one or both of these sub-values.
373              
374             * The six subs created there share a single C body function, and are
375             * differentiated only by the option flags in cv_private. The custom ops
376             * likewise share one op_ppaddr function, and the operations they perform
377             * are differentiated by the same flags, stored in op_private.
378             */
379 438           cv_private = opopt | 0x020200;
380              
381             /* Yes, the subs have prototypes. The protoypes have no effect when the
382             * subs are used as methods, so there's no break of compatibility for those
383             * using the documented API. There is a change that could be detected by
384             * code such as "Sereal::Decoder::decode($dec, @v)", that uses the methods
385             * directly in an undocumented way.
386             *
387             * The prototype, specifically the putting of argument expressions into
388             * scalar context, is required in order to be able to resolve arity at
389             * compile time. If this wasn't done, there would have to be a pushmark
390             * op preceding the argument ops, and pp_sereal_decode() would need the
391             * same code as xsfunc_sereal_decode() to check arity and resolve the
392             * optional-parameter flags.
393             */
394 438           *p++ = '$';
395 438           *p++ = '$';
396              
397 438 100         if (opopt & OPOPT_OFFSET) {
398 219           *p++ = '$';
399 219           cv_private += 0x010100;
400             }
401 438           *p++ = ';';
402 438 100         if (opopt & OPOPT_DO_BODY) {
403 292           *p++ = '$';
404 292           cv_private += 0x010000;
405             }
406 438 100         if (opopt & OPOPT_DO_HEADER) {
407 292           *p++ = '$';
408 292           cv_private += 0x010000;
409             }
410 438           *p = 0;
411             /* setup the name of the sub */
412 438           sprintf(name, LONG_CLASS_FMT, fti->name_suffix);
413 438           cv = newXSproto_portable(name, THX_xsfunc_sereal_decode, __FILE__,
414             proto);
415 438           CvXSUBANY(cv).any_i32 = cv_private;
416             #if USE_CUSTOM_OPS
417 438           cv_set_call_checker(cv, THX_ck_entersub_args_sereal_decoder, (SV*)cv);
418             #endif /* USE_CUSTOM_OPS */
419 438           sprintf(name, "Sereal::Decoder::decode%s", fti->name_suffix);
420 438           gv = gv_fetchpv(name, GV_ADDMULTI, SVt_PVCV);
421 438           GvCV_set(gv, cv);
422             }
423             }
424              
425             BOOT:
426             {
427             #if USE_CUSTOM_OPS
428             {
429             XOP *xop;
430 73           Newxz(xop, 1, XOP);
431 73           XopENTRY_set(xop, xop_name, "scalar_looks_like_sereal");
432 73           XopENTRY_set(xop, xop_desc, "scalar_looks_like_sereal");
433 73           XopENTRY_set(xop, xop_class, OA_UNOP);
434 73           Perl_custom_op_register(aTHX_ THX_pp_looks_like_sereal, xop);
435             }
436             #endif /* USE_CUSTOM_OPS */
437             {
438             CV *cv;
439 73           cv = newXSproto_portable("Sereal::Decoder::scalar_looks_like_sereal", THX_xsfunc_looks_like_sereal, __FILE__, "$");
440 73           CvXSUBANY(cv).any_i32 = 0x010100 | OPOPT_LOOKS_LIKE;
441             #if USE_CUSTOM_OPS
442 73           cv_set_call_checker(cv, THX_ck_entersub_args_sereal_decoder, (SV*)cv);
443             #endif /* USE_CUSTOM_OPS */
444 73           cv = newXS("Sereal::Decoder::looks_like_sereal", THX_xsfunc_looks_like_sereal, __FILE__);
445 73           CvXSUBANY(cv).any_i32 = 0x020100 | OPOPT_LOOKS_LIKE;
446             }
447             }
448              
449             srl_decoder_t *
450             new(CLASS, opt = NULL)
451             char *CLASS;
452             HV *opt;
453             PREINIT:
454             dMY_CXT;
455             CODE:
456 163           RETVAL = srl_build_decoder_struct(aTHX_ opt, MY_CXT.options);
457 163           RETVAL->flags |= SRL_F_DECODER_REUSE;
458             OUTPUT: RETVAL
459              
460             void
461             DESTROY(dec)
462             srl_decoder_t *dec;
463             CODE:
464 163           srl_destroy_decoder(aTHX_ dec);
465              
466             void
467             decode_sereal(src, opt = NULL, into = NULL)
468             SV *src;
469             SV *opt;
470             SV *into;
471             PREINIT:
472             dMY_CXT;
473 179348           srl_decoder_t *dec= NULL;
474             PPCODE:
475 179348 100         if (SvROK(src))
476 4           croak("We can't decode a reference as Sereal!");
477             /* Support no opt at all, undef, hashref */
478 179344 100         if (opt != NULL) {
479 179296 50         SvGETMAGIC(opt);
    0          
480 179296 100         if (!SvOK(opt))
    50          
    50          
481 44           opt = NULL;
482 179252 50         else if (SvROK(opt) && SvTYPE(SvRV(opt)) == SVt_PVHV)
    50          
483 179252           opt = (SV *)SvRV(opt);
484             else
485 0           croak("Options are neither undef nor hash reference");
486             }
487 179344           dec = srl_build_decoder_struct(aTHX_ (HV *)opt, MY_CXT.options);
488 179344           ST(0)= srl_decode_into(aTHX_ dec, src, into, 0);
489 179331           XSRETURN(1);
490              
491             AV *
492             decode_sereal_with_header_data(src, opt = NULL, body_into = NULL, header_into = NULL)
493             SV *src;
494             SV *opt;
495             SV *body_into;
496             SV *header_into;
497             PREINIT:
498             dMY_CXT;
499 0           srl_decoder_t *dec= NULL;
500             CODE:
501             /* Support no opt at all, undef, hashref */
502 0 0         if (opt != NULL) {
503 0 0         SvGETMAGIC(opt);
    0          
504 0 0         if (!SvOK(opt))
    0          
    0          
505 0           opt = NULL;
506 0 0         else if (SvROK(opt) && SvTYPE(SvRV(opt)) == SVt_PVHV)
    0          
507 0           opt = (SV *)SvRV(opt);
508             else
509 0           croak("Options are neither undef nor hash reference");
510             }
511 0           dec = srl_build_decoder_struct(aTHX_ (HV *)opt, MY_CXT.options);
512 0 0         if (body_into == NULL)
513 0           body_into = sv_newmortal();
514 0 0         if (header_into == NULL)
515 0           header_into = sv_newmortal();
516 0           srl_decode_all_into(aTHX_ dec, src, header_into, body_into, 0);
517 0           RETVAL = newAV();
518 0           sv_2mortal((SV *)RETVAL);
519 0           av_extend(RETVAL, 1);
520 0           av_store(RETVAL, 0, SvREFCNT_inc(header_into));
521 0           av_store(RETVAL, 1, SvREFCNT_inc(body_into));
522             OUTPUT: RETVAL
523              
524             UV
525             bytes_consumed(dec)
526             srl_decoder_t *dec;
527             CODE:
528 185           RETVAL = dec->bytes_consumed;
529             OUTPUT: RETVAL
530              
531             U32
532             flags(dec)
533             srl_decoder_t *dec;
534             CODE:
535 0           RETVAL = dec->flags;
536             OUTPUT: RETVAL
537              
538             SV*
539             regexp_internals_type()
540             CODE:
541 1           RETVAL = newSVpvs(REGEXP_TYPE);
542             OUTPUT: RETVAL