This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fix XS types in typemap in order to deal with references with get magics correctly
[perl5.git] / ext / XS-APItest / APItest.xs
1 #define PERL_IN_XS_APITEST
2 #include "EXTERN.h"
3 #include "perl.h"
4 #include "XSUB.h"
5
6 typedef SV *SVREF;
7 typedef PTR_TBL_t *XS__APItest__PtrTable;
8
9 #define croak_fail() croak("fail at " __FILE__ " line %d", __LINE__)
10 #define croak_fail_ne(h, w) croak("fail %p!=%p at " __FILE__ " line %d", (h), (w), __LINE__)
11
12 /* for my_cxt tests */
13
14 #define MY_CXT_KEY "XS::APItest::_guts" XS_VERSION
15
16 typedef struct {
17     int i;
18     SV *sv;
19     GV *cscgv;
20     AV *cscav;
21     AV *bhkav;
22     bool bhk_record;
23     peep_t orig_peep;
24     peep_t orig_rpeep;
25     int peep_recording;
26     AV *peep_recorder;
27     AV *rpeep_recorder;
28     AV *xop_record;
29 } my_cxt_t;
30
31 START_MY_CXT
32
33 MGVTBL vtbl_foo, vtbl_bar;
34
35 /* indirect functions to test the [pa]MY_CXT macros */
36
37 int
38 my_cxt_getint_p(pMY_CXT)
39 {
40     return MY_CXT.i;
41 }
42
43 void
44 my_cxt_setint_p(pMY_CXT_ int i)
45 {
46     MY_CXT.i = i;
47 }
48
49 SV*
50 my_cxt_getsv_interp_context(void)
51 {
52     dTHX;
53     dMY_CXT_INTERP(my_perl);
54     return MY_CXT.sv;
55 }
56
57 SV*
58 my_cxt_getsv_interp(void)
59 {
60     dMY_CXT;
61     return MY_CXT.sv;
62 }
63
64 void
65 my_cxt_setsv_p(SV* sv _pMY_CXT)
66 {
67     MY_CXT.sv = sv;
68 }
69
70
71 /* from exception.c */
72 int apitest_exception(int);
73
74 /* from core_or_not.inc */
75 bool sv_setsv_cow_hashkey_core(void);
76 bool sv_setsv_cow_hashkey_notcore(void);
77
78 /* A routine to test hv_delayfree_ent
79    (which itself is tested by testing on hv_free_ent  */
80
81 typedef void (freeent_function)(pTHX_ HV *, register HE *);
82
83 void
84 test_freeent(freeent_function *f) {
85     dTHX;
86     dSP;
87     HV *test_hash = newHV();
88     HE *victim;
89     SV *test_scalar;
90     U32 results[4];
91     int i;
92
93 #ifdef PURIFY
94     victim = (HE*)safemalloc(sizeof(HE));
95 #else
96     /* Storing then deleting something should ensure that a hash entry is
97        available.  */
98     hv_store(test_hash, "", 0, &PL_sv_yes, 0);
99     hv_delete(test_hash, "", 0, 0);
100
101     /* We need to "inline" new_he here as it's static, and the functions we
102        test expect to be able to call del_HE on the HE  */
103     if (!PL_body_roots[HE_SVSLOT])
104         croak("PL_he_root is 0");
105     victim = (HE*) PL_body_roots[HE_SVSLOT];
106     PL_body_roots[HE_SVSLOT] = HeNEXT(victim);
107 #endif
108
109     victim->hent_hek = Perl_share_hek(aTHX_ "", 0, 0);
110
111     test_scalar = newSV(0);
112     SvREFCNT_inc(test_scalar);
113     HeVAL(victim) = test_scalar;
114
115     /* Need this little game else we free the temps on the return stack.  */
116     results[0] = SvREFCNT(test_scalar);
117     SAVETMPS;
118     results[1] = SvREFCNT(test_scalar);
119     f(aTHX_ test_hash, victim);
120     results[2] = SvREFCNT(test_scalar);
121     FREETMPS;
122     results[3] = SvREFCNT(test_scalar);
123
124     i = 0;
125     do {
126         mPUSHu(results[i]);
127     } while (++i < sizeof(results)/sizeof(results[0]));
128
129     /* Goodbye to our extra reference.  */
130     SvREFCNT_dec(test_scalar);
131 }
132
133
134 static I32
135 bitflip_key(pTHX_ IV action, SV *field) {
136     MAGIC *mg = mg_find(field, PERL_MAGIC_uvar);
137     SV *keysv;
138     if (mg && (keysv = mg->mg_obj)) {
139         STRLEN len;
140         const char *p = SvPV(keysv, len);
141
142         if (len) {
143             SV *newkey = newSV(len);
144             char *new_p = SvPVX(newkey);
145
146             if (SvUTF8(keysv)) {
147                 const char *const end = p + len;
148                 while (p < end) {
149                     STRLEN len;
150                     UV chr = utf8_to_uvuni((U8 *)p, &len);
151                     new_p = (char *)uvuni_to_utf8((U8 *)new_p, chr ^ 32);
152                     p += len;
153                 }
154                 SvUTF8_on(newkey);
155             } else {
156                 while (len--)
157                     *new_p++ = *p++ ^ 32;
158             }
159             *new_p = '\0';
160             SvCUR_set(newkey, SvCUR(keysv));
161             SvPOK_on(newkey);
162
163             mg->mg_obj = newkey;
164         }
165     }
166     return 0;
167 }
168
169 static I32
170 rot13_key(pTHX_ IV action, SV *field) {
171     MAGIC *mg = mg_find(field, PERL_MAGIC_uvar);
172     SV *keysv;
173     if (mg && (keysv = mg->mg_obj)) {
174         STRLEN len;
175         const char *p = SvPV(keysv, len);
176
177         if (len) {
178             SV *newkey = newSV(len);
179             char *new_p = SvPVX(newkey);
180
181             /* There's a deliberate fencepost error here to loop len + 1 times
182                to copy the trailing \0  */
183             do {
184                 char new_c = *p++;
185                 /* Try doing this cleanly and clearly in EBCDIC another way: */
186                 switch (new_c) {
187                 case 'A': new_c = 'N'; break;
188                 case 'B': new_c = 'O'; break;
189                 case 'C': new_c = 'P'; break;
190                 case 'D': new_c = 'Q'; break;
191                 case 'E': new_c = 'R'; break;
192                 case 'F': new_c = 'S'; break;
193                 case 'G': new_c = 'T'; break;
194                 case 'H': new_c = 'U'; break;
195                 case 'I': new_c = 'V'; break;
196                 case 'J': new_c = 'W'; break;
197                 case 'K': new_c = 'X'; break;
198                 case 'L': new_c = 'Y'; break;
199                 case 'M': new_c = 'Z'; break;
200                 case 'N': new_c = 'A'; break;
201                 case 'O': new_c = 'B'; break;
202                 case 'P': new_c = 'C'; break;
203                 case 'Q': new_c = 'D'; break;
204                 case 'R': new_c = 'E'; break;
205                 case 'S': new_c = 'F'; break;
206                 case 'T': new_c = 'G'; break;
207                 case 'U': new_c = 'H'; break;
208                 case 'V': new_c = 'I'; break;
209                 case 'W': new_c = 'J'; break;
210                 case 'X': new_c = 'K'; break;
211                 case 'Y': new_c = 'L'; break;
212                 case 'Z': new_c = 'M'; break;
213                 case 'a': new_c = 'n'; break;
214                 case 'b': new_c = 'o'; break;
215                 case 'c': new_c = 'p'; break;
216                 case 'd': new_c = 'q'; break;
217                 case 'e': new_c = 'r'; break;
218                 case 'f': new_c = 's'; break;
219                 case 'g': new_c = 't'; break;
220                 case 'h': new_c = 'u'; break;
221                 case 'i': new_c = 'v'; break;
222                 case 'j': new_c = 'w'; break;
223                 case 'k': new_c = 'x'; break;
224                 case 'l': new_c = 'y'; break;
225                 case 'm': new_c = 'z'; break;
226                 case 'n': new_c = 'a'; break;
227                 case 'o': new_c = 'b'; break;
228                 case 'p': new_c = 'c'; break;
229                 case 'q': new_c = 'd'; break;
230                 case 'r': new_c = 'e'; break;
231                 case 's': new_c = 'f'; break;
232                 case 't': new_c = 'g'; break;
233                 case 'u': new_c = 'h'; break;
234                 case 'v': new_c = 'i'; break;
235                 case 'w': new_c = 'j'; break;
236                 case 'x': new_c = 'k'; break;
237                 case 'y': new_c = 'l'; break;
238                 case 'z': new_c = 'm'; break;
239                 }
240                 *new_p++ = new_c;
241             } while (len--);
242             SvCUR_set(newkey, SvCUR(keysv));
243             SvPOK_on(newkey);
244             if (SvUTF8(keysv))
245                 SvUTF8_on(newkey);
246
247             mg->mg_obj = newkey;
248         }
249     }
250     return 0;
251 }
252
253 STATIC I32
254 rmagical_a_dummy(pTHX_ IV idx, SV *sv) {
255     return 0;
256 }
257
258 STATIC MGVTBL rmagical_b = { 0 };
259
260 STATIC void
261 blockhook_csc_start(pTHX_ int full)
262 {
263     dMY_CXT;
264     AV *const cur = GvAV(MY_CXT.cscgv);
265
266     SAVEGENERICSV(GvAV(MY_CXT.cscgv));
267
268     if (cur) {
269         I32 i;
270         AV *const new_av = newAV();
271
272         for (i = 0; i <= av_len(cur); i++) {
273             av_store(new_av, i, newSVsv(*av_fetch(cur, i, 0)));
274         }
275
276         GvAV(MY_CXT.cscgv) = new_av;
277     }
278 }
279
280 STATIC void
281 blockhook_csc_pre_end(pTHX_ OP **o)
282 {
283     dMY_CXT;
284
285     /* if we hit the end of a scope we missed the start of, we need to
286      * unconditionally clear @CSC */
287     if (GvAV(MY_CXT.cscgv) == MY_CXT.cscav && MY_CXT.cscav) {
288         av_clear(MY_CXT.cscav);
289     }
290
291 }
292
293 STATIC void
294 blockhook_test_start(pTHX_ int full)
295 {
296     dMY_CXT;
297     AV *av;
298     
299     if (MY_CXT.bhk_record) {
300         av = newAV();
301         av_push(av, newSVpvs("start"));
302         av_push(av, newSViv(full));
303         av_push(MY_CXT.bhkav, newRV_noinc(MUTABLE_SV(av)));
304     }
305 }
306
307 STATIC void
308 blockhook_test_pre_end(pTHX_ OP **o)
309 {
310     dMY_CXT;
311
312     if (MY_CXT.bhk_record)
313         av_push(MY_CXT.bhkav, newSVpvs("pre_end"));
314 }
315
316 STATIC void
317 blockhook_test_post_end(pTHX_ OP **o)
318 {
319     dMY_CXT;
320
321     if (MY_CXT.bhk_record)
322         av_push(MY_CXT.bhkav, newSVpvs("post_end"));
323 }
324
325 STATIC void
326 blockhook_test_eval(pTHX_ OP *const o)
327 {
328     dMY_CXT;
329     AV *av;
330
331     if (MY_CXT.bhk_record) {
332         av = newAV();
333         av_push(av, newSVpvs("eval"));
334         av_push(av, newSVpv(OP_NAME(o), 0));
335         av_push(MY_CXT.bhkav, newRV_noinc(MUTABLE_SV(av)));
336     }
337 }
338
339 STATIC BHK bhk_csc, bhk_test;
340
341 STATIC void
342 my_peep (pTHX_ OP *o)
343 {
344     dMY_CXT;
345
346     if (!o)
347         return;
348
349     MY_CXT.orig_peep(aTHX_ o);
350
351     if (!MY_CXT.peep_recording)
352         return;
353
354     for (; o; o = o->op_next) {
355         if (o->op_type == OP_CONST && cSVOPx_sv(o) && SvPOK(cSVOPx_sv(o))) {
356             av_push(MY_CXT.peep_recorder, newSVsv(cSVOPx_sv(o)));
357         }
358     }
359 }
360
361 STATIC void
362 my_rpeep (pTHX_ OP *o)
363 {
364     dMY_CXT;
365
366     if (!o)
367         return;
368
369     MY_CXT.orig_rpeep(aTHX_ o);
370
371     if (!MY_CXT.peep_recording)
372         return;
373
374     for (; o; o = o->op_next) {
375         if (o->op_type == OP_CONST && cSVOPx_sv(o) && SvPOK(cSVOPx_sv(o))) {
376             av_push(MY_CXT.rpeep_recorder, newSVsv(cSVOPx_sv(o)));
377         }
378     }
379 }
380
381 STATIC OP *
382 THX_ck_entersub_args_lists(pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
383 {
384     return ck_entersub_args_list(entersubop);
385 }
386
387 STATIC OP *
388 THX_ck_entersub_args_scalars(pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
389 {
390     OP *aop = cUNOPx(entersubop)->op_first;
391     if (!aop->op_sibling)
392         aop = cUNOPx(aop)->op_first;
393     for (aop = aop->op_sibling; aop->op_sibling; aop = aop->op_sibling) {
394         op_contextualize(aop, G_SCALAR);
395     }
396     return entersubop;
397 }
398
399 STATIC OP *
400 THX_ck_entersub_multi_sum(pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
401 {
402     OP *sumop = NULL;
403     OP *pushop = cUNOPx(entersubop)->op_first;
404     if (!pushop->op_sibling)
405         pushop = cUNOPx(pushop)->op_first;
406     while (1) {
407         OP *aop = pushop->op_sibling;
408         if (!aop->op_sibling)
409             break;
410         pushop->op_sibling = aop->op_sibling;
411         aop->op_sibling = NULL;
412         op_contextualize(aop, G_SCALAR);
413         if (sumop) {
414             sumop = newBINOP(OP_ADD, 0, sumop, aop);
415         } else {
416             sumop = aop;
417         }
418     }
419     if (!sumop)
420         sumop = newSVOP(OP_CONST, 0, newSViv(0));
421     op_free(entersubop);
422     return sumop;
423 }
424
425 STATIC void test_op_list_describe_part(SV *res, OP *o);
426 STATIC void
427 test_op_list_describe_part(SV *res, OP *o)
428 {
429     sv_catpv(res, PL_op_name[o->op_type]);
430     switch (o->op_type) {
431         case OP_CONST: {
432             sv_catpvf(res, "(%d)", (int)SvIV(cSVOPx(o)->op_sv));
433         } break;
434     }
435     if (o->op_flags & OPf_KIDS) {
436         OP *k;
437         sv_catpvs(res, "[");
438         for (k = cUNOPx(o)->op_first; k; k = k->op_sibling)
439             test_op_list_describe_part(res, k);
440         sv_catpvs(res, "]");
441     } else {
442         sv_catpvs(res, ".");
443     }
444 }
445
446 STATIC char *
447 test_op_list_describe(OP *o)
448 {
449     SV *res = sv_2mortal(newSVpvs(""));
450     if (o)
451         test_op_list_describe_part(res, o);
452     return SvPVX(res);
453 }
454
455 /* the real new*OP functions have a tendancy to call fold_constants, and
456  * other such unhelpful things, so we need our own versions for testing */
457
458 #define mkUNOP(t, f) THX_mkUNOP(aTHX_ (t), (f))
459 static OP *
460 THX_mkUNOP(pTHX_ U32 type, OP *first)
461 {
462     UNOP *unop;
463     NewOp(1103, unop, 1, UNOP);
464     unop->op_type   = (OPCODE)type;
465     unop->op_first  = first;
466     unop->op_flags  = OPf_KIDS;
467     return (OP *)unop;
468 }
469
470 #define mkBINOP(t, f, l) THX_mkBINOP(aTHX_ (t), (f), (l))
471 static OP *
472 THX_mkBINOP(pTHX_ U32 type, OP *first, OP *last)
473 {
474     BINOP *binop;
475     NewOp(1103, binop, 1, BINOP);
476     binop->op_type      = (OPCODE)type;
477     binop->op_first     = first;
478     binop->op_flags     = OPf_KIDS;
479     binop->op_last      = last;
480     first->op_sibling   = last;
481     return (OP *)binop;
482 }
483
484 #define mkLISTOP(t, f, s, l) THX_mkLISTOP(aTHX_ (t), (f), (s), (l))
485 static OP *
486 THX_mkLISTOP(pTHX_ U32 type, OP *first, OP *sib, OP *last)
487 {
488     LISTOP *listop;
489     NewOp(1103, listop, 1, LISTOP);
490     listop->op_type     = (OPCODE)type;
491     listop->op_flags    = OPf_KIDS;
492     listop->op_first    = first;
493     first->op_sibling   = sib;
494     sib->op_sibling     = last;
495     listop->op_last     = last;
496     return (OP *)listop;
497 }
498
499 static char *
500 test_op_linklist_describe(OP *start)
501 {
502     SV *rv = sv_2mortal(newSVpvs(""));
503     OP *o;
504     o = start = LINKLIST(start);
505     do {
506         sv_catpvs(rv, ".");
507         sv_catpv(rv, OP_NAME(o));
508         if (o->op_type == OP_CONST)
509             sv_catsv(rv, cSVOPo->op_sv);
510         o = o->op_next;
511     } while (o && o != start);
512     return SvPVX(rv);
513 }
514
515 /** establish_cleanup operator, ripped off from Scope::Cleanup **/
516
517 STATIC void
518 THX_run_cleanup(pTHX_ void *cleanup_code_ref)
519 {
520     dSP;
521     ENTER;
522     SAVETMPS;
523     PUSHMARK(SP);
524     call_sv((SV*)cleanup_code_ref, G_VOID|G_DISCARD);
525     FREETMPS;
526     LEAVE;
527 }
528
529 STATIC OP *
530 THX_pp_establish_cleanup(pTHX)
531 {
532     dSP;
533     SV *cleanup_code_ref;
534     cleanup_code_ref = newSVsv(POPs);
535     SAVEFREESV(cleanup_code_ref);
536     SAVEDESTRUCTOR_X(THX_run_cleanup, cleanup_code_ref);
537     if(GIMME_V != G_VOID) PUSHs(&PL_sv_undef);
538     RETURN;
539 }
540
541 STATIC OP *
542 THX_ck_entersub_establish_cleanup(pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
543 {
544     OP *pushop, *argop, *estop;
545     ck_entersub_args_proto(entersubop, namegv, ckobj);
546     pushop = cUNOPx(entersubop)->op_first;
547     if(!pushop->op_sibling) pushop = cUNOPx(pushop)->op_first;
548     argop = pushop->op_sibling;
549     pushop->op_sibling = argop->op_sibling;
550     argop->op_sibling = NULL;
551     op_free(entersubop);
552     NewOpSz(0, estop, sizeof(UNOP));
553     estop->op_type = OP_RAND;
554     estop->op_ppaddr = THX_pp_establish_cleanup;
555     cUNOPx(estop)->op_flags = OPf_KIDS;
556     cUNOPx(estop)->op_first = argop;
557     PL_hints |= HINT_BLOCK_SCOPE;
558     return estop;
559 }
560
561 STATIC OP *
562 THX_ck_entersub_postinc(pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
563 {
564     OP *pushop, *argop, *estop;
565     ck_entersub_args_proto(entersubop, namegv, ckobj);
566     pushop = cUNOPx(entersubop)->op_first;
567     if(!pushop->op_sibling) pushop = cUNOPx(pushop)->op_first;
568     argop = pushop->op_sibling;
569     pushop->op_sibling = argop->op_sibling;
570     argop->op_sibling = NULL;
571     op_free(entersubop);
572     return newUNOP(OP_POSTINC, 0,
573         op_lvalue(op_contextualize(argop, G_SCALAR), OP_POSTINC));
574 }
575
576 /** RPN keyword parser **/
577
578 #define sv_is_glob(sv) (SvTYPE(sv) == SVt_PVGV)
579 #define sv_is_regexp(sv) (SvTYPE(sv) == SVt_REGEXP)
580 #define sv_is_string(sv) \
581     (!sv_is_glob(sv) && !sv_is_regexp(sv) && \
582      (SvFLAGS(sv) & (SVf_IOK|SVf_NOK|SVf_POK|SVp_IOK|SVp_NOK|SVp_POK)))
583
584 static SV *hintkey_rpn_sv, *hintkey_calcrpn_sv, *hintkey_stufftest_sv;
585 static SV *hintkey_swaptwostmts_sv, *hintkey_looprest_sv;
586 static SV *hintkey_scopelessblock_sv;
587 static SV *hintkey_stmtasexpr_sv, *hintkey_stmtsasexpr_sv;
588 static SV *hintkey_loopblock_sv, *hintkey_blockasexpr_sv;
589 static SV *hintkey_swaplabel_sv, *hintkey_labelconst_sv;
590 static int (*next_keyword_plugin)(pTHX_ char *, STRLEN, OP **);
591
592 /* low-level parser helpers */
593
594 #define PL_bufptr (PL_parser->bufptr)
595 #define PL_bufend (PL_parser->bufend)
596
597 /* RPN parser */
598
599 #define parse_var() THX_parse_var(aTHX)
600 static OP *THX_parse_var(pTHX)
601 {
602     char *s = PL_bufptr;
603     char *start = s;
604     PADOFFSET varpos;
605     OP *padop;
606     if(*s != '$') croak("RPN syntax error");
607     while(1) {
608         char c = *++s;
609         if(!isALNUM(c)) break;
610     }
611     if(s-start < 2) croak("RPN syntax error");
612     lex_read_to(s);
613     {
614         /* because pad_findmy() doesn't really use length yet */
615         SV *namesv = sv_2mortal(newSVpvn(start, s-start));
616         varpos = pad_findmy(SvPVX(namesv), s-start, 0);
617     }
618     if(varpos == NOT_IN_PAD || PAD_COMPNAME_FLAGS_isOUR(varpos))
619         croak("RPN only supports \"my\" variables");
620     padop = newOP(OP_PADSV, 0);
621     padop->op_targ = varpos;
622     return padop;
623 }
624
625 #define push_rpn_item(o) \
626     (tmpop = (o), tmpop->op_sibling = stack, stack = tmpop)
627 #define pop_rpn_item() \
628     (!stack ? (croak("RPN stack underflow"), (OP*)NULL) : \
629      (tmpop = stack, stack = stack->op_sibling, \
630       tmpop->op_sibling = NULL, tmpop))
631
632 #define parse_rpn_expr() THX_parse_rpn_expr(aTHX)
633 static OP *THX_parse_rpn_expr(pTHX)
634 {
635     OP *stack = NULL, *tmpop;
636     while(1) {
637         I32 c;
638         lex_read_space(0);
639         c = lex_peek_unichar(0);
640         switch(c) {
641             case /*(*/')': case /*{*/'}': {
642                 OP *result = pop_rpn_item();
643                 if(stack) croak("RPN expression must return a single value");
644                 return result;
645             } break;
646             case '0': case '1': case '2': case '3': case '4':
647             case '5': case '6': case '7': case '8': case '9': {
648                 UV val = 0;
649                 do {
650                     lex_read_unichar(0);
651                     val = 10*val + (c - '0');
652                     c = lex_peek_unichar(0);
653                 } while(c >= '0' && c <= '9');
654                 push_rpn_item(newSVOP(OP_CONST, 0, newSVuv(val)));
655             } break;
656             case '$': {
657                 push_rpn_item(parse_var());
658             } break;
659             case '+': {
660                 OP *b = pop_rpn_item();
661                 OP *a = pop_rpn_item();
662                 lex_read_unichar(0);
663                 push_rpn_item(newBINOP(OP_I_ADD, 0, a, b));
664             } break;
665             case '-': {
666                 OP *b = pop_rpn_item();
667                 OP *a = pop_rpn_item();
668                 lex_read_unichar(0);
669                 push_rpn_item(newBINOP(OP_I_SUBTRACT, 0, a, b));
670             } break;
671             case '*': {
672                 OP *b = pop_rpn_item();
673                 OP *a = pop_rpn_item();
674                 lex_read_unichar(0);
675                 push_rpn_item(newBINOP(OP_I_MULTIPLY, 0, a, b));
676             } break;
677             case '/': {
678                 OP *b = pop_rpn_item();
679                 OP *a = pop_rpn_item();
680                 lex_read_unichar(0);
681                 push_rpn_item(newBINOP(OP_I_DIVIDE, 0, a, b));
682             } break;
683             case '%': {
684                 OP *b = pop_rpn_item();
685                 OP *a = pop_rpn_item();
686                 lex_read_unichar(0);
687                 push_rpn_item(newBINOP(OP_I_MODULO, 0, a, b));
688             } break;
689             default: {
690                 croak("RPN syntax error");
691             } break;
692         }
693     }
694 }
695
696 #define parse_keyword_rpn() THX_parse_keyword_rpn(aTHX)
697 static OP *THX_parse_keyword_rpn(pTHX)
698 {
699     OP *op;
700     lex_read_space(0);
701     if(lex_peek_unichar(0) != '('/*)*/)
702         croak("RPN expression must be parenthesised");
703     lex_read_unichar(0);
704     op = parse_rpn_expr();
705     if(lex_peek_unichar(0) != /*(*/')')
706         croak("RPN expression must be parenthesised");
707     lex_read_unichar(0);
708     return op;
709 }
710
711 #define parse_keyword_calcrpn() THX_parse_keyword_calcrpn(aTHX)
712 static OP *THX_parse_keyword_calcrpn(pTHX)
713 {
714     OP *varop, *exprop;
715     lex_read_space(0);
716     varop = parse_var();
717     lex_read_space(0);
718     if(lex_peek_unichar(0) != '{'/*}*/)
719         croak("RPN expression must be braced");
720     lex_read_unichar(0);
721     exprop = parse_rpn_expr();
722     if(lex_peek_unichar(0) != /*{*/'}')
723         croak("RPN expression must be braced");
724     lex_read_unichar(0);
725     return newASSIGNOP(OPf_STACKED, varop, 0, exprop);
726 }
727
728 #define parse_keyword_stufftest() THX_parse_keyword_stufftest(aTHX)
729 static OP *THX_parse_keyword_stufftest(pTHX)
730 {
731     I32 c;
732     bool do_stuff;
733     lex_read_space(0);
734     do_stuff = lex_peek_unichar(0) == '+';
735     if(do_stuff) {
736         lex_read_unichar(0);
737         lex_read_space(0);
738     }
739     c = lex_peek_unichar(0);
740     if(c == ';') {
741         lex_read_unichar(0);
742     } else if(c != /*{*/'}') {
743         croak("syntax error");
744     }
745     if(do_stuff) lex_stuff_pvs(" ", 0);
746     return newOP(OP_NULL, 0);
747 }
748
749 #define parse_keyword_swaptwostmts() THX_parse_keyword_swaptwostmts(aTHX)
750 static OP *THX_parse_keyword_swaptwostmts(pTHX)
751 {
752     OP *a, *b;
753     a = parse_fullstmt(0);
754     b = parse_fullstmt(0);
755     if(a && b)
756         PL_hints |= HINT_BLOCK_SCOPE;
757     return op_append_list(OP_LINESEQ, b, a);
758 }
759
760 #define parse_keyword_looprest() THX_parse_keyword_looprest(aTHX)
761 static OP *THX_parse_keyword_looprest(pTHX)
762 {
763     return newWHILEOP(0, 1, NULL, newSVOP(OP_CONST, 0, &PL_sv_yes),
764                         parse_stmtseq(0), NULL, 1);
765 }
766
767 #define parse_keyword_scopelessblock() THX_parse_keyword_scopelessblock(aTHX)
768 static OP *THX_parse_keyword_scopelessblock(pTHX)
769 {
770     I32 c;
771     OP *body;
772     lex_read_space(0);
773     if(lex_peek_unichar(0) != '{'/*}*/) croak("syntax error");
774     lex_read_unichar(0);
775     body = parse_stmtseq(0);
776     c = lex_peek_unichar(0);
777     if(c != /*{*/'}' && c != /*[*/']' && c != /*(*/')') croak("syntax error");
778     lex_read_unichar(0);
779     return body;
780 }
781
782 #define parse_keyword_stmtasexpr() THX_parse_keyword_stmtasexpr(aTHX)
783 static OP *THX_parse_keyword_stmtasexpr(pTHX)
784 {
785     OP *o = parse_barestmt(0);
786     if (!o) o = newOP(OP_STUB, 0);
787     if (PL_hints & HINT_BLOCK_SCOPE) o->op_flags |= OPf_PARENS;
788     return op_scope(o);
789 }
790
791 #define parse_keyword_stmtsasexpr() THX_parse_keyword_stmtsasexpr(aTHX)
792 static OP *THX_parse_keyword_stmtsasexpr(pTHX)
793 {
794     OP *o;
795     lex_read_space(0);
796     if(lex_peek_unichar(0) != '{'/*}*/) croak("syntax error");
797     lex_read_unichar(0);
798     o = parse_stmtseq(0);
799     lex_read_space(0);
800     if(lex_peek_unichar(0) != /*{*/'}') croak("syntax error");
801     lex_read_unichar(0);
802     if (!o) o = newOP(OP_STUB, 0);
803     if (PL_hints & HINT_BLOCK_SCOPE) o->op_flags |= OPf_PARENS;
804     return op_scope(o);
805 }
806
807 #define parse_keyword_loopblock() THX_parse_keyword_loopblock(aTHX)
808 static OP *THX_parse_keyword_loopblock(pTHX)
809 {
810     return newWHILEOP(0, 1, NULL, newSVOP(OP_CONST, 0, &PL_sv_yes),
811                         parse_block(0), NULL, 1);
812 }
813
814 #define parse_keyword_blockasexpr() THX_parse_keyword_blockasexpr(aTHX)
815 static OP *THX_parse_keyword_blockasexpr(pTHX)
816 {
817     OP *o = parse_block(0);
818     if (!o) o = newOP(OP_STUB, 0);
819     if (PL_hints & HINT_BLOCK_SCOPE) o->op_flags |= OPf_PARENS;
820     return op_scope(o);
821 }
822
823 #define parse_keyword_swaplabel() THX_parse_keyword_swaplabel(aTHX)
824 static OP *THX_parse_keyword_swaplabel(pTHX)
825 {
826     OP *sop = parse_barestmt(0);
827     SV *label = parse_label(PARSE_OPTIONAL);
828     if (label) sv_2mortal(label);
829     return newSTATEOP(0, label ? savepv(SvPVX(label)) : NULL, sop);
830 }
831
832 #define parse_keyword_labelconst() THX_parse_keyword_labelconst(aTHX)
833 static OP *THX_parse_keyword_labelconst(pTHX)
834 {
835     return newSVOP(OP_CONST, 0, parse_label(0));
836 }
837
838 /* plugin glue */
839
840 #define keyword_active(hintkey_sv) THX_keyword_active(aTHX_ hintkey_sv)
841 static int THX_keyword_active(pTHX_ SV *hintkey_sv)
842 {
843     HE *he;
844     if(!GvHV(PL_hintgv)) return 0;
845     he = hv_fetch_ent(GvHV(PL_hintgv), hintkey_sv, 0,
846                 SvSHARED_HASH(hintkey_sv));
847     return he && SvTRUE(HeVAL(he));
848 }
849
850 static int my_keyword_plugin(pTHX_
851     char *keyword_ptr, STRLEN keyword_len, OP **op_ptr)
852 {
853     if(keyword_len == 3 && strnEQ(keyword_ptr, "rpn", 3) &&
854                     keyword_active(hintkey_rpn_sv)) {
855         *op_ptr = parse_keyword_rpn();
856         return KEYWORD_PLUGIN_EXPR;
857     } else if(keyword_len == 7 && strnEQ(keyword_ptr, "calcrpn", 7) &&
858                     keyword_active(hintkey_calcrpn_sv)) {
859         *op_ptr = parse_keyword_calcrpn();
860         return KEYWORD_PLUGIN_STMT;
861     } else if(keyword_len == 9 && strnEQ(keyword_ptr, "stufftest", 9) &&
862                     keyword_active(hintkey_stufftest_sv)) {
863         *op_ptr = parse_keyword_stufftest();
864         return KEYWORD_PLUGIN_STMT;
865     } else if(keyword_len == 12 &&
866                     strnEQ(keyword_ptr, "swaptwostmts", 12) &&
867                     keyword_active(hintkey_swaptwostmts_sv)) {
868         *op_ptr = parse_keyword_swaptwostmts();
869         return KEYWORD_PLUGIN_STMT;
870     } else if(keyword_len == 8 && strnEQ(keyword_ptr, "looprest", 8) &&
871                     keyword_active(hintkey_looprest_sv)) {
872         *op_ptr = parse_keyword_looprest();
873         return KEYWORD_PLUGIN_STMT;
874     } else if(keyword_len == 14 && strnEQ(keyword_ptr, "scopelessblock", 14) &&
875                     keyword_active(hintkey_scopelessblock_sv)) {
876         *op_ptr = parse_keyword_scopelessblock();
877         return KEYWORD_PLUGIN_STMT;
878     } else if(keyword_len == 10 && strnEQ(keyword_ptr, "stmtasexpr", 10) &&
879                     keyword_active(hintkey_stmtasexpr_sv)) {
880         *op_ptr = parse_keyword_stmtasexpr();
881         return KEYWORD_PLUGIN_EXPR;
882     } else if(keyword_len == 11 && strnEQ(keyword_ptr, "stmtsasexpr", 11) &&
883                     keyword_active(hintkey_stmtsasexpr_sv)) {
884         *op_ptr = parse_keyword_stmtsasexpr();
885         return KEYWORD_PLUGIN_EXPR;
886     } else if(keyword_len == 9 && strnEQ(keyword_ptr, "loopblock", 9) &&
887                     keyword_active(hintkey_loopblock_sv)) {
888         *op_ptr = parse_keyword_loopblock();
889         return KEYWORD_PLUGIN_STMT;
890     } else if(keyword_len == 11 && strnEQ(keyword_ptr, "blockasexpr", 11) &&
891                     keyword_active(hintkey_blockasexpr_sv)) {
892         *op_ptr = parse_keyword_blockasexpr();
893         return KEYWORD_PLUGIN_EXPR;
894     } else if(keyword_len == 9 && strnEQ(keyword_ptr, "swaplabel", 9) &&
895                     keyword_active(hintkey_swaplabel_sv)) {
896         *op_ptr = parse_keyword_swaplabel();
897         return KEYWORD_PLUGIN_STMT;
898     } else if(keyword_len == 10 && strnEQ(keyword_ptr, "labelconst", 10) &&
899                     keyword_active(hintkey_labelconst_sv)) {
900         *op_ptr = parse_keyword_labelconst();
901         return KEYWORD_PLUGIN_EXPR;
902     } else {
903         return next_keyword_plugin(aTHX_ keyword_ptr, keyword_len, op_ptr);
904     }
905 }
906
907 static XOP my_xop;
908
909 static OP *
910 pp_xop(pTHX)
911 {
912     return PL_op->op_next;
913 }
914
915 static void
916 peep_xop(pTHX_ OP *o, OP *oldop)
917 {
918     dMY_CXT;
919     av_push(MY_CXT.xop_record, newSVpvf("peep:%"UVxf, PTR2UV(o)));
920     av_push(MY_CXT.xop_record, newSVpvf("oldop:%"UVxf, PTR2UV(oldop)));
921 }
922
923 XS(XS_XS__APItest__XSUB_XS_VERSION_undef);
924 XS(XS_XS__APItest__XSUB_XS_VERSION_empty);
925 XS(XS_XS__APItest__XSUB_XS_APIVERSION_invalid);
926
927 #include "const-c.inc"
928
929 MODULE = XS::APItest            PACKAGE = XS::APItest
930
931 INCLUDE: const-xs.inc
932
933 INCLUDE: numeric.xs
934
935 MODULE = XS::APItest::utf8      PACKAGE = XS::APItest::utf8
936
937 int
938 bytes_cmp_utf8(bytes, utf8)
939         SV *bytes
940         SV *utf8
941     PREINIT:
942         const U8 *b;
943         STRLEN blen;
944         const U8 *u;
945         STRLEN ulen;
946     CODE:
947         b = (const U8 *)SvPVbyte(bytes, blen);
948         u = (const U8 *)SvPVbyte(utf8, ulen);
949         RETVAL = bytes_cmp_utf8(b, blen, u, ulen);
950     OUTPUT:
951         RETVAL
952
953 MODULE = XS::APItest:Overload   PACKAGE = XS::APItest::Overload
954
955 SV *
956 amagic_deref_call(sv, what)
957         SV *sv
958         int what
959     PPCODE:
960         /* The reference is owned by something else.  */
961         PUSHs(amagic_deref_call(sv, what));
962
963 # I'd certainly like to discourage the use of this macro, given that we now
964 # have amagic_deref_call
965
966 SV *
967 tryAMAGICunDEREF_var(sv, what)
968         SV *sv
969         int what
970     PPCODE:
971         {
972             SV **sp = &sv;
973             switch(what) {
974             case to_av_amg:
975                 tryAMAGICunDEREF(to_av);
976                 break;
977             case to_cv_amg:
978                 tryAMAGICunDEREF(to_cv);
979                 break;
980             case to_gv_amg:
981                 tryAMAGICunDEREF(to_gv);
982                 break;
983             case to_hv_amg:
984                 tryAMAGICunDEREF(to_hv);
985                 break;
986             case to_sv_amg:
987                 tryAMAGICunDEREF(to_sv);
988                 break;
989             default:
990                 croak("Invalid value %d passed to tryAMAGICunDEREF_var", what);
991             }
992         }
993         /* The reference is owned by something else.  */
994         PUSHs(sv);
995
996 MODULE = XS::APItest            PACKAGE = XS::APItest::XSUB
997
998 BOOT:
999     newXS("XS::APItest::XSUB::XS_VERSION_undef", XS_XS__APItest__XSUB_XS_VERSION_undef, __FILE__);
1000     newXS("XS::APItest::XSUB::XS_VERSION_empty", XS_XS__APItest__XSUB_XS_VERSION_empty, __FILE__);
1001     newXS("XS::APItest::XSUB::XS_APIVERSION_invalid", XS_XS__APItest__XSUB_XS_APIVERSION_invalid, __FILE__);
1002
1003 void
1004 XS_VERSION_defined(...)
1005     PPCODE:
1006         XS_VERSION_BOOTCHECK;
1007         XSRETURN_EMPTY;
1008
1009 void
1010 XS_APIVERSION_valid(...)
1011     PPCODE:
1012         XS_APIVERSION_BOOTCHECK;
1013         XSRETURN_EMPTY;
1014
1015 MODULE = XS::APItest:Hash               PACKAGE = XS::APItest::Hash
1016
1017 void
1018 rot13_hash(hash)
1019         HV *hash
1020         CODE:
1021         {
1022             struct ufuncs uf;
1023             uf.uf_val = rot13_key;
1024             uf.uf_set = 0;
1025             uf.uf_index = 0;
1026
1027             sv_magic((SV*)hash, NULL, PERL_MAGIC_uvar, (char*)&uf, sizeof(uf));
1028         }
1029
1030 void
1031 bitflip_hash(hash)
1032         HV *hash
1033         CODE:
1034         {
1035             struct ufuncs uf;
1036             uf.uf_val = bitflip_key;
1037             uf.uf_set = 0;
1038             uf.uf_index = 0;
1039
1040             sv_magic((SV*)hash, NULL, PERL_MAGIC_uvar, (char*)&uf, sizeof(uf));
1041         }
1042
1043 #define UTF8KLEN(sv, len)   (SvUTF8(sv) ? -(I32)len : (I32)len)
1044
1045 bool
1046 exists(hash, key_sv)
1047         PREINIT:
1048         STRLEN len;
1049         const char *key;
1050         INPUT:
1051         HV *hash
1052         SV *key_sv
1053         CODE:
1054         key = SvPV(key_sv, len);
1055         RETVAL = hv_exists(hash, key, UTF8KLEN(key_sv, len));
1056         OUTPUT:
1057         RETVAL
1058
1059 bool
1060 exists_ent(hash, key_sv)
1061         PREINIT:
1062         INPUT:
1063         HV *hash
1064         SV *key_sv
1065         CODE:
1066         RETVAL = hv_exists_ent(hash, key_sv, 0);
1067         OUTPUT:
1068         RETVAL
1069
1070 SV *
1071 delete(hash, key_sv, flags = 0)
1072         PREINIT:
1073         STRLEN len;
1074         const char *key;
1075         INPUT:
1076         HV *hash
1077         SV *key_sv
1078         I32 flags;
1079         CODE:
1080         key = SvPV(key_sv, len);
1081         /* It's already mortal, so need to increase reference count.  */
1082         RETVAL
1083             = SvREFCNT_inc(hv_delete(hash, key, UTF8KLEN(key_sv, len), flags));
1084         OUTPUT:
1085         RETVAL
1086
1087 SV *
1088 delete_ent(hash, key_sv, flags = 0)
1089         INPUT:
1090         HV *hash
1091         SV *key_sv
1092         I32 flags;
1093         CODE:
1094         /* It's already mortal, so need to increase reference count.  */
1095         RETVAL = SvREFCNT_inc(hv_delete_ent(hash, key_sv, flags, 0));
1096         OUTPUT:
1097         RETVAL
1098
1099 SV *
1100 store_ent(hash, key, value)
1101         PREINIT:
1102         SV *copy;
1103         HE *result;
1104         INPUT:
1105         HV *hash
1106         SV *key
1107         SV *value
1108         CODE:
1109         copy = newSV(0);
1110         result = hv_store_ent(hash, key, copy, 0);
1111         SvSetMagicSV(copy, value);
1112         if (!result) {
1113             SvREFCNT_dec(copy);
1114             XSRETURN_EMPTY;
1115         }
1116         /* It's about to become mortal, so need to increase reference count.
1117          */
1118         RETVAL = SvREFCNT_inc(HeVAL(result));
1119         OUTPUT:
1120         RETVAL
1121
1122 SV *
1123 store(hash, key_sv, value)
1124         PREINIT:
1125         STRLEN len;
1126         const char *key;
1127         SV *copy;
1128         SV **result;
1129         INPUT:
1130         HV *hash
1131         SV *key_sv
1132         SV *value
1133         CODE:
1134         key = SvPV(key_sv, len);
1135         copy = newSV(0);
1136         result = hv_store(hash, key, UTF8KLEN(key_sv, len), copy, 0);
1137         SvSetMagicSV(copy, value);
1138         if (!result) {
1139             SvREFCNT_dec(copy);
1140             XSRETURN_EMPTY;
1141         }
1142         /* It's about to become mortal, so need to increase reference count.
1143          */
1144         RETVAL = SvREFCNT_inc(*result);
1145         OUTPUT:
1146         RETVAL
1147
1148 SV *
1149 fetch_ent(hash, key_sv)
1150         PREINIT:
1151         HE *result;
1152         INPUT:
1153         HV *hash
1154         SV *key_sv
1155         CODE:
1156         result = hv_fetch_ent(hash, key_sv, 0, 0);
1157         if (!result) {
1158             XSRETURN_EMPTY;
1159         }
1160         /* Force mg_get  */
1161         RETVAL = newSVsv(HeVAL(result));
1162         OUTPUT:
1163         RETVAL
1164
1165 SV *
1166 fetch(hash, key_sv)
1167         PREINIT:
1168         STRLEN len;
1169         const char *key;
1170         SV **result;
1171         INPUT:
1172         HV *hash
1173         SV *key_sv
1174         CODE:
1175         key = SvPV(key_sv, len);
1176         result = hv_fetch(hash, key, UTF8KLEN(key_sv, len), 0);
1177         if (!result) {
1178             XSRETURN_EMPTY;
1179         }
1180         /* Force mg_get  */
1181         RETVAL = newSVsv(*result);
1182         OUTPUT:
1183         RETVAL
1184
1185 #if defined (hv_common)
1186
1187 SV *
1188 common(params)
1189         INPUT:
1190         HV *params
1191         PREINIT:
1192         HE *result;
1193         HV *hv = NULL;
1194         SV *keysv = NULL;
1195         const char *key = NULL;
1196         STRLEN klen = 0;
1197         int flags = 0;
1198         int action = 0;
1199         SV *val = NULL;
1200         U32 hash = 0;
1201         SV **svp;
1202         CODE:
1203         if ((svp = hv_fetchs(params, "hv", 0))) {
1204             SV *const rv = *svp;
1205             if (!SvROK(rv))
1206                 croak("common passed a non-reference for parameter hv");
1207             hv = (HV *)SvRV(rv);
1208         }
1209         if ((svp = hv_fetchs(params, "keysv", 0)))
1210             keysv = *svp;
1211         if ((svp = hv_fetchs(params, "keypv", 0))) {
1212             key = SvPV_const(*svp, klen);
1213             if (SvUTF8(*svp))
1214                 flags = HVhek_UTF8;
1215         }
1216         if ((svp = hv_fetchs(params, "action", 0)))
1217             action = SvIV(*svp);
1218         if ((svp = hv_fetchs(params, "val", 0)))
1219             val = newSVsv(*svp);
1220         if ((svp = hv_fetchs(params, "hash", 0)))
1221             hash = SvUV(*svp);
1222
1223         if ((svp = hv_fetchs(params, "hash_pv", 0))) {
1224             PERL_HASH(hash, key, klen);
1225         }
1226         if ((svp = hv_fetchs(params, "hash_sv", 0))) {
1227             STRLEN len;
1228             const char *const p = SvPV(keysv, len);
1229             PERL_HASH(hash, p, len);
1230         }
1231
1232         result = (HE *)hv_common(hv, keysv, key, klen, flags, action, val, hash);
1233         if (!result) {
1234             XSRETURN_EMPTY;
1235         }
1236         /* Force mg_get  */
1237         RETVAL = newSVsv(HeVAL(result));
1238         OUTPUT:
1239         RETVAL
1240
1241 #endif
1242
1243 void
1244 test_hv_free_ent()
1245         PPCODE:
1246         test_freeent(&Perl_hv_free_ent);
1247         XSRETURN(4);
1248
1249 void
1250 test_hv_delayfree_ent()
1251         PPCODE:
1252         test_freeent(&Perl_hv_delayfree_ent);
1253         XSRETURN(4);
1254
1255 SV *
1256 test_share_unshare_pvn(input)
1257         PREINIT:
1258         STRLEN len;
1259         U32 hash;
1260         char *pvx;
1261         char *p;
1262         INPUT:
1263         SV *input
1264         CODE:
1265         pvx = SvPV(input, len);
1266         PERL_HASH(hash, pvx, len);
1267         p = sharepvn(pvx, len, hash);
1268         RETVAL = newSVpvn(p, len);
1269         unsharepvn(p, len, hash);
1270         OUTPUT:
1271         RETVAL
1272
1273 #if PERL_VERSION >= 9
1274
1275 bool
1276 refcounted_he_exists(key, level=0)
1277         SV *key
1278         IV level
1279         CODE:
1280         if (level) {
1281             croak("level must be zero, not %"IVdf, level);
1282         }
1283         RETVAL = (cop_hints_fetch_sv(PL_curcop, key, 0, 0) != &PL_sv_placeholder);
1284         OUTPUT:
1285         RETVAL
1286
1287 SV *
1288 refcounted_he_fetch(key, level=0)
1289         SV *key
1290         IV level
1291         CODE:
1292         if (level) {
1293             croak("level must be zero, not %"IVdf, level);
1294         }
1295         RETVAL = cop_hints_fetch_sv(PL_curcop, key, 0, 0);
1296         SvREFCNT_inc(RETVAL);
1297         OUTPUT:
1298         RETVAL
1299
1300 #endif
1301
1302 =pod
1303
1304 sub TIEHASH  { bless {}, $_[0] }
1305 sub STORE    { $_[0]->{$_[1]} = $_[2] }
1306 sub FETCH    { $_[0]->{$_[1]} }
1307 sub FIRSTKEY { my $a = scalar keys %{$_[0]}; each %{$_[0]} }
1308 sub NEXTKEY  { each %{$_[0]} }
1309 sub EXISTS   { exists $_[0]->{$_[1]} }
1310 sub DELETE   { delete $_[0]->{$_[1]} }
1311 sub CLEAR    { %{$_[0]} = () }
1312
1313 =cut
1314
1315 MODULE = XS::APItest:TempLv             PACKAGE = XS::APItest::TempLv
1316
1317 void
1318 make_temp_mg_lv(sv)
1319 SV* sv
1320     PREINIT:
1321         SV * const lv = newSV_type(SVt_PVLV);
1322         STRLEN len;
1323     PPCODE:
1324         SvPV(sv, len);
1325
1326         sv_magic(lv, NULL, PERL_MAGIC_substr, NULL, 0);
1327         LvTYPE(lv) = 'x';
1328         LvTARG(lv) = SvREFCNT_inc_simple(sv);
1329         LvTARGOFF(lv) = len == 0 ? 0 : 1;
1330         LvTARGLEN(lv) = len < 2 ? 0 : len-2;
1331
1332         EXTEND(SP, 1);
1333         ST(0) = sv_2mortal(lv);
1334         XSRETURN(1);
1335
1336
1337 MODULE = XS::APItest::PtrTable  PACKAGE = XS::APItest::PtrTable PREFIX = ptr_table_
1338
1339 void
1340 ptr_table_new(classname)
1341 const char * classname
1342     PPCODE:
1343     PUSHs(sv_setref_pv(sv_newmortal(), classname, (void*)ptr_table_new()));
1344
1345 void
1346 DESTROY(table)
1347 XS::APItest::PtrTable table
1348     CODE:
1349     ptr_table_free(table);
1350
1351 void
1352 ptr_table_store(table, from, to)
1353 XS::APItest::PtrTable table
1354 SVREF from
1355 SVREF to
1356    CODE:
1357    ptr_table_store(table, from, to);
1358
1359 UV
1360 ptr_table_fetch(table, from)
1361 XS::APItest::PtrTable table
1362 SVREF from
1363    CODE:
1364    RETVAL = PTR2UV(ptr_table_fetch(table, from));
1365    OUTPUT:
1366    RETVAL
1367
1368 void
1369 ptr_table_split(table)
1370 XS::APItest::PtrTable table
1371
1372 void
1373 ptr_table_clear(table)
1374 XS::APItest::PtrTable table
1375
1376 MODULE = XS::APItest            PACKAGE = XS::APItest
1377
1378 PROTOTYPES: DISABLE
1379
1380 HV *
1381 xop_custom_ops ()
1382     CODE:
1383         RETVAL = PL_custom_ops;
1384     OUTPUT:
1385         RETVAL
1386
1387 HV *
1388 xop_custom_op_names ()
1389     CODE:
1390         PL_custom_op_names = newHV();
1391         RETVAL = PL_custom_op_names;
1392     OUTPUT:
1393         RETVAL
1394
1395 HV *
1396 xop_custom_op_descs ()
1397     CODE:
1398         PL_custom_op_descs = newHV();
1399         RETVAL = PL_custom_op_descs;
1400     OUTPUT:
1401         RETVAL
1402
1403 void
1404 xop_register ()
1405     CODE:
1406         XopENTRY_set(&my_xop, xop_name, "my_xop");
1407         XopENTRY_set(&my_xop, xop_desc, "XOP for testing");
1408         XopENTRY_set(&my_xop, xop_class, OA_UNOP);
1409         XopENTRY_set(&my_xop, xop_peep, peep_xop);
1410         Perl_custom_op_register(aTHX_ pp_xop, &my_xop);
1411
1412 void
1413 xop_clear ()
1414     CODE:
1415         XopDISABLE(&my_xop, xop_name);
1416         XopDISABLE(&my_xop, xop_desc);
1417         XopDISABLE(&my_xop, xop_class);
1418         XopDISABLE(&my_xop, xop_peep);
1419
1420 IV
1421 xop_my_xop ()
1422     CODE:
1423         RETVAL = PTR2IV(&my_xop);
1424     OUTPUT:
1425         RETVAL
1426
1427 IV
1428 xop_ppaddr ()
1429     CODE:
1430         RETVAL = PTR2IV(pp_xop);
1431     OUTPUT:
1432         RETVAL
1433
1434 IV
1435 xop_OA_UNOP ()
1436     CODE:
1437         RETVAL = OA_UNOP;
1438     OUTPUT:
1439         RETVAL
1440
1441 AV *
1442 xop_build_optree ()
1443     CODE:
1444         dMY_CXT;
1445         UNOP *unop;
1446         OP *kid;
1447
1448         MY_CXT.xop_record = newAV();
1449
1450         kid = newSVOP(OP_CONST, 0, newSViv(42));
1451         
1452         NewOp(1102, unop, 1, UNOP);
1453         unop->op_type       = OP_CUSTOM;
1454         unop->op_ppaddr     = pp_xop;
1455         unop->op_flags      = OPf_KIDS;
1456         unop->op_private    = 0;
1457         unop->op_first      = kid;
1458         unop->op_next       = NULL;
1459         kid->op_next        = (OP*)unop;
1460
1461         av_push(MY_CXT.xop_record, newSVpvf("unop:%"UVxf, PTR2UV(unop)));
1462         av_push(MY_CXT.xop_record, newSVpvf("kid:%"UVxf, PTR2UV(kid)));
1463
1464         av_push(MY_CXT.xop_record, newSVpvf("NAME:%s", OP_NAME((OP*)unop)));
1465         av_push(MY_CXT.xop_record, newSVpvf("DESC:%s", OP_DESC((OP*)unop)));
1466         av_push(MY_CXT.xop_record, newSVpvf("CLASS:%d", OP_CLASS((OP*)unop)));
1467
1468         PL_rpeepp(aTHX_ kid);
1469
1470         FreeOp(kid);
1471         FreeOp(unop);
1472
1473         RETVAL = MY_CXT.xop_record;
1474         MY_CXT.xop_record = NULL;
1475     OUTPUT:
1476         RETVAL
1477
1478 BOOT:
1479 {
1480     MY_CXT_INIT;
1481
1482     MY_CXT.i  = 99;
1483     MY_CXT.sv = newSVpv("initial",0);
1484
1485     MY_CXT.bhkav = get_av("XS::APItest::bhkav", GV_ADDMULTI);
1486     MY_CXT.bhk_record = 0;
1487
1488     BhkENTRY_set(&bhk_test, bhk_start, blockhook_test_start);
1489     BhkENTRY_set(&bhk_test, bhk_pre_end, blockhook_test_pre_end);
1490     BhkENTRY_set(&bhk_test, bhk_post_end, blockhook_test_post_end);
1491     BhkENTRY_set(&bhk_test, bhk_eval, blockhook_test_eval);
1492     Perl_blockhook_register(aTHX_ &bhk_test);
1493
1494     MY_CXT.cscgv = gv_fetchpvs("XS::APItest::COMPILE_SCOPE_CONTAINER",
1495         GV_ADDMULTI, SVt_PVAV);
1496     MY_CXT.cscav = GvAV(MY_CXT.cscgv);
1497
1498     BhkENTRY_set(&bhk_csc, bhk_start, blockhook_csc_start);
1499     BhkENTRY_set(&bhk_csc, bhk_pre_end, blockhook_csc_pre_end);
1500     Perl_blockhook_register(aTHX_ &bhk_csc);
1501
1502     MY_CXT.peep_recorder = newAV();
1503     MY_CXT.rpeep_recorder = newAV();
1504
1505     MY_CXT.orig_peep = PL_peepp;
1506     MY_CXT.orig_rpeep = PL_rpeepp;
1507     PL_peepp = my_peep;
1508     PL_rpeepp = my_rpeep;
1509 }
1510
1511 void
1512 CLONE(...)
1513     CODE:
1514     MY_CXT_CLONE;
1515     MY_CXT.sv = newSVpv("initial_clone",0);
1516     MY_CXT.cscgv = gv_fetchpvs("XS::APItest::COMPILE_SCOPE_CONTAINER",
1517         GV_ADDMULTI, SVt_PVAV);
1518     MY_CXT.cscav = NULL;
1519     MY_CXT.bhkav = get_av("XS::APItest::bhkav", GV_ADDMULTI);
1520     MY_CXT.bhk_record = 0;
1521     MY_CXT.peep_recorder = newAV();
1522     MY_CXT.rpeep_recorder = newAV();
1523
1524 void
1525 print_double(val)
1526         double val
1527         CODE:
1528         printf("%5.3f\n",val);
1529
1530 int
1531 have_long_double()
1532         CODE:
1533 #ifdef HAS_LONG_DOUBLE
1534         RETVAL = 1;
1535 #else
1536         RETVAL = 0;
1537 #endif
1538         OUTPUT:
1539         RETVAL
1540
1541 void
1542 print_long_double()
1543         CODE:
1544 #ifdef HAS_LONG_DOUBLE
1545 #   if defined(PERL_PRIfldbl) && (LONG_DOUBLESIZE > DOUBLESIZE)
1546         long double val = 7.0;
1547         printf("%5.3" PERL_PRIfldbl "\n",val);
1548 #   else
1549         double val = 7.0;
1550         printf("%5.3f\n",val);
1551 #   endif
1552 #endif
1553
1554 void
1555 print_int(val)
1556         int val
1557         CODE:
1558         printf("%d\n",val);
1559
1560 void
1561 print_long(val)
1562         long val
1563         CODE:
1564         printf("%ld\n",val);
1565
1566 void
1567 print_float(val)
1568         float val
1569         CODE:
1570         printf("%5.3f\n",val);
1571         
1572 void
1573 print_flush()
1574         CODE:
1575         fflush(stdout);
1576
1577 void
1578 mpushp()
1579         PPCODE:
1580         EXTEND(SP, 3);
1581         mPUSHp("one", 3);
1582         mPUSHp("two", 3);
1583         mPUSHp("three", 5);
1584         XSRETURN(3);
1585
1586 void
1587 mpushn()
1588         PPCODE:
1589         EXTEND(SP, 3);
1590         mPUSHn(0.5);
1591         mPUSHn(-0.25);
1592         mPUSHn(0.125);
1593         XSRETURN(3);
1594
1595 void
1596 mpushi()
1597         PPCODE:
1598         EXTEND(SP, 3);
1599         mPUSHi(-1);
1600         mPUSHi(2);
1601         mPUSHi(-3);
1602         XSRETURN(3);
1603
1604 void
1605 mpushu()
1606         PPCODE:
1607         EXTEND(SP, 3);
1608         mPUSHu(1);
1609         mPUSHu(2);
1610         mPUSHu(3);
1611         XSRETURN(3);
1612
1613 void
1614 mxpushp()
1615         PPCODE:
1616         mXPUSHp("one", 3);
1617         mXPUSHp("two", 3);
1618         mXPUSHp("three", 5);
1619         XSRETURN(3);
1620
1621 void
1622 mxpushn()
1623         PPCODE:
1624         mXPUSHn(0.5);
1625         mXPUSHn(-0.25);
1626         mXPUSHn(0.125);
1627         XSRETURN(3);
1628
1629 void
1630 mxpushi()
1631         PPCODE:
1632         mXPUSHi(-1);
1633         mXPUSHi(2);
1634         mXPUSHi(-3);
1635         XSRETURN(3);
1636
1637 void
1638 mxpushu()
1639         PPCODE:
1640         mXPUSHu(1);
1641         mXPUSHu(2);
1642         mXPUSHu(3);
1643         XSRETURN(3);
1644
1645
1646 void
1647 call_sv(sv, flags, ...)
1648     SV* sv
1649     I32 flags
1650     PREINIT:
1651         I32 i;
1652     PPCODE:
1653         for (i=0; i<items-2; i++)
1654             ST(i) = ST(i+2); /* pop first two args */
1655         PUSHMARK(SP);
1656         SP += items - 2;
1657         PUTBACK;
1658         i = call_sv(sv, flags);
1659         SPAGAIN;
1660         EXTEND(SP, 1);
1661         PUSHs(sv_2mortal(newSViv(i)));
1662
1663 void
1664 call_pv(subname, flags, ...)
1665     char* subname
1666     I32 flags
1667     PREINIT:
1668         I32 i;
1669     PPCODE:
1670         for (i=0; i<items-2; i++)
1671             ST(i) = ST(i+2); /* pop first two args */
1672         PUSHMARK(SP);
1673         SP += items - 2;
1674         PUTBACK;
1675         i = call_pv(subname, flags);
1676         SPAGAIN;
1677         EXTEND(SP, 1);
1678         PUSHs(sv_2mortal(newSViv(i)));
1679
1680 void
1681 call_method(methname, flags, ...)
1682     char* methname
1683     I32 flags
1684     PREINIT:
1685         I32 i;
1686     PPCODE:
1687         for (i=0; i<items-2; i++)
1688             ST(i) = ST(i+2); /* pop first two args */
1689         PUSHMARK(SP);
1690         SP += items - 2;
1691         PUTBACK;
1692         i = call_method(methname, flags);
1693         SPAGAIN;
1694         EXTEND(SP, 1);
1695         PUSHs(sv_2mortal(newSViv(i)));
1696
1697 void
1698 eval_sv(sv, flags)
1699     SV* sv
1700     I32 flags
1701     PREINIT:
1702         I32 i;
1703     PPCODE:
1704         PUTBACK;
1705         i = eval_sv(sv, flags);
1706         SPAGAIN;
1707         EXTEND(SP, 1);
1708         PUSHs(sv_2mortal(newSViv(i)));
1709
1710 void
1711 eval_pv(p, croak_on_error)
1712     const char* p
1713     I32 croak_on_error
1714     PPCODE:
1715         PUTBACK;
1716         EXTEND(SP, 1);
1717         PUSHs(eval_pv(p, croak_on_error));
1718
1719 void
1720 require_pv(pv)
1721     const char* pv
1722     PPCODE:
1723         PUTBACK;
1724         require_pv(pv);
1725
1726 int
1727 apitest_exception(throw_e)
1728     int throw_e
1729     OUTPUT:
1730         RETVAL
1731
1732 void
1733 mycroak(sv)
1734     SV* sv
1735     CODE:
1736     if (SvOK(sv)) {
1737         Perl_croak(aTHX_ "%s", SvPV_nolen(sv));
1738     }
1739     else {
1740         Perl_croak(aTHX_ NULL);
1741     }
1742
1743 SV*
1744 strtab()
1745    CODE:
1746    RETVAL = newRV_inc((SV*)PL_strtab);
1747    OUTPUT:
1748    RETVAL
1749
1750 int
1751 my_cxt_getint()
1752     CODE:
1753         dMY_CXT;
1754         RETVAL = my_cxt_getint_p(aMY_CXT);
1755     OUTPUT:
1756         RETVAL
1757
1758 void
1759 my_cxt_setint(i)
1760     int i;
1761     CODE:
1762         dMY_CXT;
1763         my_cxt_setint_p(aMY_CXT_ i);
1764
1765 void
1766 my_cxt_getsv(how)
1767     bool how;
1768     PPCODE:
1769         EXTEND(SP, 1);
1770         ST(0) = how ? my_cxt_getsv_interp_context() : my_cxt_getsv_interp();
1771         XSRETURN(1);
1772
1773 void
1774 my_cxt_setsv(sv)
1775     SV *sv;
1776     CODE:
1777         dMY_CXT;
1778         SvREFCNT_dec(MY_CXT.sv);
1779         my_cxt_setsv_p(sv _aMY_CXT);
1780         SvREFCNT_inc(sv);
1781
1782 bool
1783 sv_setsv_cow_hashkey_core()
1784
1785 bool
1786 sv_setsv_cow_hashkey_notcore()
1787
1788 void
1789 rmagical_cast(sv, type)
1790     SV *sv;
1791     SV *type;
1792     PREINIT:
1793         struct ufuncs uf;
1794     PPCODE:
1795         if (!SvOK(sv) || !SvROK(sv) || !SvOK(type)) { XSRETURN_UNDEF; }
1796         sv = SvRV(sv);
1797         if (SvTYPE(sv) != SVt_PVHV) { XSRETURN_UNDEF; }
1798         uf.uf_val = rmagical_a_dummy;
1799         uf.uf_set = NULL;
1800         uf.uf_index = 0;
1801         if (SvTRUE(type)) { /* b */
1802             sv_magicext(sv, NULL, PERL_MAGIC_ext, &rmagical_b, NULL, 0);
1803         } else { /* a */
1804             sv_magic(sv, NULL, PERL_MAGIC_uvar, (char *) &uf, sizeof(uf));
1805         }
1806         XSRETURN_YES;
1807
1808 void
1809 rmagical_flags(sv)
1810     SV *sv;
1811     PPCODE:
1812         if (!SvOK(sv) || !SvROK(sv)) { XSRETURN_UNDEF; }
1813         sv = SvRV(sv);
1814         EXTEND(SP, 3); 
1815         mXPUSHu(SvFLAGS(sv) & SVs_GMG);
1816         mXPUSHu(SvFLAGS(sv) & SVs_SMG);
1817         mXPUSHu(SvFLAGS(sv) & SVs_RMG);
1818         XSRETURN(3);
1819
1820 void
1821 my_caller(level)
1822         I32 level
1823     PREINIT:
1824         const PERL_CONTEXT *cx, *dbcx;
1825         const char *pv;
1826         const GV *gv;
1827         HV *hv;
1828     PPCODE:
1829         cx = caller_cx(level, &dbcx);
1830         EXTEND(SP, 8);
1831
1832         pv = CopSTASHPV(cx->blk_oldcop);
1833         ST(0) = pv ? sv_2mortal(newSVpv(pv, 0)) : &PL_sv_undef;
1834         gv = CvGV(cx->blk_sub.cv);
1835         ST(1) = isGV(gv) ? sv_2mortal(newSVpv(GvNAME(gv), 0)) : &PL_sv_undef;
1836
1837         pv = CopSTASHPV(dbcx->blk_oldcop);
1838         ST(2) = pv ? sv_2mortal(newSVpv(pv, 0)) : &PL_sv_undef;
1839         gv = CvGV(dbcx->blk_sub.cv);
1840         ST(3) = isGV(gv) ? sv_2mortal(newSVpv(GvNAME(gv), 0)) : &PL_sv_undef;
1841
1842         ST(4) = cop_hints_fetch_pvs(cx->blk_oldcop, "foo", 0);
1843         ST(5) = cop_hints_fetch_pvn(cx->blk_oldcop, "foo", 3, 0, 0);
1844         ST(6) = cop_hints_fetch_sv(cx->blk_oldcop, 
1845                 sv_2mortal(newSVpvn("foo", 3)), 0, 0);
1846
1847         hv = cop_hints_2hv(cx->blk_oldcop, 0);
1848         ST(7) = hv ? sv_2mortal(newRV_noinc((SV *)hv)) : &PL_sv_undef;
1849
1850         XSRETURN(8);
1851
1852 void
1853 DPeek (sv)
1854     SV   *sv
1855
1856   PPCODE:
1857     ST (0) = newSVpv (Perl_sv_peek (aTHX_ sv), 0);
1858     XSRETURN (1);
1859
1860 void
1861 BEGIN()
1862     CODE:
1863         sv_inc(get_sv("XS::APItest::BEGIN_called", GV_ADD|GV_ADDMULTI));
1864
1865 void
1866 CHECK()
1867     CODE:
1868         sv_inc(get_sv("XS::APItest::CHECK_called", GV_ADD|GV_ADDMULTI));
1869
1870 void
1871 UNITCHECK()
1872     CODE:
1873         sv_inc(get_sv("XS::APItest::UNITCHECK_called", GV_ADD|GV_ADDMULTI));
1874
1875 void
1876 INIT()
1877     CODE:
1878         sv_inc(get_sv("XS::APItest::INIT_called", GV_ADD|GV_ADDMULTI));
1879
1880 void
1881 END()
1882     CODE:
1883         sv_inc(get_sv("XS::APItest::END_called", GV_ADD|GV_ADDMULTI));
1884
1885 void
1886 utf16_to_utf8 (sv, ...)
1887     SV* sv
1888         ALIAS:
1889             utf16_to_utf8_reversed = 1
1890     PREINIT:
1891         STRLEN len;
1892         U8 *source;
1893         SV *dest;
1894         I32 got; /* Gah, badly thought out APIs */
1895     CODE:
1896         source = (U8 *)SvPVbyte(sv, len);
1897         /* Optionally only convert part of the buffer.  */      
1898         if (items > 1) {
1899             len = SvUV(ST(1));
1900         }
1901         /* Mortalise this right now, as we'll be testing croak()s  */
1902         dest = sv_2mortal(newSV(len * 3 / 2 + 1));
1903         if (ix) {
1904             utf16_to_utf8_reversed(source, (U8 *)SvPVX(dest), len, &got);
1905         } else {
1906             utf16_to_utf8(source, (U8 *)SvPVX(dest), len, &got);
1907         }
1908         SvCUR_set(dest, got);
1909         SvPVX(dest)[got] = '\0';
1910         SvPOK_on(dest);
1911         ST(0) = dest;
1912         XSRETURN(1);
1913
1914 void
1915 my_exit(int exitcode)
1916         PPCODE:
1917         my_exit(exitcode);
1918
1919 U8
1920 first_byte(sv)
1921         SV *sv
1922    CODE:
1923     char *s;
1924     STRLEN len;
1925         s = SvPVbyte(sv, len);
1926         RETVAL = s[0];
1927    OUTPUT:
1928     RETVAL
1929
1930 I32
1931 sv_count()
1932         CODE:
1933             RETVAL = PL_sv_count;
1934         OUTPUT:
1935             RETVAL
1936
1937 void
1938 bhk_record(bool on)
1939     CODE:
1940         dMY_CXT;
1941         MY_CXT.bhk_record = on;
1942         if (on)
1943             av_clear(MY_CXT.bhkav);
1944
1945 void
1946 test_magic_chain()
1947     PREINIT:
1948         SV *sv;
1949         MAGIC *callmg, *uvarmg;
1950     CODE:
1951         sv = sv_2mortal(newSV(0));
1952         if (SvTYPE(sv) >= SVt_PVMG) croak_fail();
1953         if (SvMAGICAL(sv)) croak_fail();
1954         sv_magic(sv, &PL_sv_yes, PERL_MAGIC_checkcall, (char*)&callmg, 0);
1955         if (SvTYPE(sv) < SVt_PVMG) croak_fail();
1956         if (!SvMAGICAL(sv)) croak_fail();
1957         if (mg_find(sv, PERL_MAGIC_uvar)) croak_fail();
1958         callmg = mg_find(sv, PERL_MAGIC_checkcall);
1959         if (!callmg) croak_fail();
1960         if (callmg->mg_obj != &PL_sv_yes || callmg->mg_ptr != (char*)&callmg)
1961             croak_fail();
1962         sv_magic(sv, &PL_sv_no, PERL_MAGIC_uvar, (char*)&uvarmg, 0);
1963         if (SvTYPE(sv) < SVt_PVMG) croak_fail();
1964         if (!SvMAGICAL(sv)) croak_fail();
1965         if (mg_find(sv, PERL_MAGIC_checkcall) != callmg) croak_fail();
1966         uvarmg = mg_find(sv, PERL_MAGIC_uvar);
1967         if (!uvarmg) croak_fail();
1968         if (callmg->mg_obj != &PL_sv_yes || callmg->mg_ptr != (char*)&callmg)
1969             croak_fail();
1970         if (uvarmg->mg_obj != &PL_sv_no || uvarmg->mg_ptr != (char*)&uvarmg)
1971             croak_fail();
1972         mg_free_type(sv, PERL_MAGIC_vec);
1973         if (SvTYPE(sv) < SVt_PVMG) croak_fail();
1974         if (!SvMAGICAL(sv)) croak_fail();
1975         if (mg_find(sv, PERL_MAGIC_checkcall) != callmg) croak_fail();
1976         if (mg_find(sv, PERL_MAGIC_uvar) != uvarmg) croak_fail();
1977         if (callmg->mg_obj != &PL_sv_yes || callmg->mg_ptr != (char*)&callmg)
1978             croak_fail();
1979         if (uvarmg->mg_obj != &PL_sv_no || uvarmg->mg_ptr != (char*)&uvarmg)
1980             croak_fail();
1981         mg_free_type(sv, PERL_MAGIC_uvar);
1982         if (SvTYPE(sv) < SVt_PVMG) croak_fail();
1983         if (!SvMAGICAL(sv)) croak_fail();
1984         if (mg_find(sv, PERL_MAGIC_checkcall) != callmg) croak_fail();
1985         if (mg_find(sv, PERL_MAGIC_uvar)) croak_fail();
1986         if (callmg->mg_obj != &PL_sv_yes || callmg->mg_ptr != (char*)&callmg)
1987             croak_fail();
1988         sv_magic(sv, &PL_sv_no, PERL_MAGIC_uvar, (char*)&uvarmg, 0);
1989         if (SvTYPE(sv) < SVt_PVMG) croak_fail();
1990         if (!SvMAGICAL(sv)) croak_fail();
1991         if (mg_find(sv, PERL_MAGIC_checkcall) != callmg) croak_fail();
1992         uvarmg = mg_find(sv, PERL_MAGIC_uvar);
1993         if (!uvarmg) croak_fail();
1994         if (callmg->mg_obj != &PL_sv_yes || callmg->mg_ptr != (char*)&callmg)
1995             croak_fail();
1996         if (uvarmg->mg_obj != &PL_sv_no || uvarmg->mg_ptr != (char*)&uvarmg)
1997             croak_fail();
1998         mg_free_type(sv, PERL_MAGIC_checkcall);
1999         if (SvTYPE(sv) < SVt_PVMG) croak_fail();
2000         if (!SvMAGICAL(sv)) croak_fail();
2001         if (mg_find(sv, PERL_MAGIC_uvar) != uvarmg) croak_fail();
2002         if (mg_find(sv, PERL_MAGIC_checkcall)) croak_fail();
2003         if (uvarmg->mg_obj != &PL_sv_no || uvarmg->mg_ptr != (char*)&uvarmg)
2004             croak_fail();
2005         mg_free_type(sv, PERL_MAGIC_uvar);
2006         if (SvMAGICAL(sv)) croak_fail();
2007         if (mg_find(sv, PERL_MAGIC_checkcall)) croak_fail();
2008         if (mg_find(sv, PERL_MAGIC_uvar)) croak_fail();
2009
2010 void
2011 test_op_contextualize()
2012     PREINIT:
2013         OP *o;
2014     CODE:
2015         o = newSVOP(OP_CONST, 0, newSViv(0));
2016         o->op_flags &= ~OPf_WANT;
2017         o = op_contextualize(o, G_SCALAR);
2018         if (o->op_type != OP_CONST ||
2019                 (o->op_flags & OPf_WANT) != OPf_WANT_SCALAR)
2020             croak_fail();
2021         op_free(o);
2022         o = newSVOP(OP_CONST, 0, newSViv(0));
2023         o->op_flags &= ~OPf_WANT;
2024         o = op_contextualize(o, G_ARRAY);
2025         if (o->op_type != OP_CONST ||
2026                 (o->op_flags & OPf_WANT) != OPf_WANT_LIST)
2027             croak_fail();
2028         op_free(o);
2029         o = newSVOP(OP_CONST, 0, newSViv(0));
2030         o->op_flags &= ~OPf_WANT;
2031         o = op_contextualize(o, G_VOID);
2032         if (o->op_type != OP_NULL) croak_fail();
2033         op_free(o);
2034
2035 void
2036 test_rv2cv_op_cv()
2037     PROTOTYPE:
2038     PREINIT:
2039         GV *troc_gv, *wibble_gv;
2040         CV *troc_cv;
2041         OP *o;
2042     CODE:
2043         troc_gv = gv_fetchpv("XS::APItest::test_rv2cv_op_cv", 0, SVt_PVGV);
2044         troc_cv = get_cv("XS::APItest::test_rv2cv_op_cv", 0);
2045         wibble_gv = gv_fetchpv("XS::APItest::wibble", 0, SVt_PVGV);
2046         o = newCVREF(0, newGVOP(OP_GV, 0, troc_gv));
2047         if (rv2cv_op_cv(o, 0) != troc_cv) croak_fail();
2048         if (rv2cv_op_cv(o, RV2CVOPCV_RETURN_NAME_GV) != (CV*)troc_gv)
2049             croak_fail();
2050         o->op_private |= OPpENTERSUB_AMPER;
2051         if (rv2cv_op_cv(o, 0)) croak_fail();
2052         if (rv2cv_op_cv(o, RV2CVOPCV_RETURN_NAME_GV)) croak_fail();
2053         o->op_private &= ~OPpENTERSUB_AMPER;
2054         if (cUNOPx(o)->op_first->op_private & OPpEARLY_CV) croak_fail();
2055         if (rv2cv_op_cv(o, RV2CVOPCV_MARK_EARLY) != troc_cv) croak_fail();
2056         if (cUNOPx(o)->op_first->op_private & OPpEARLY_CV) croak_fail();
2057         op_free(o);
2058         o = newSVOP(OP_CONST, 0, newSVpv("XS::APItest::test_rv2cv_op_cv", 0));
2059         o->op_private = OPpCONST_BARE;
2060         o = newCVREF(0, o);
2061         if (rv2cv_op_cv(o, 0) != troc_cv) croak_fail();
2062         if (rv2cv_op_cv(o, RV2CVOPCV_RETURN_NAME_GV) != (CV*)troc_gv)
2063             croak_fail();
2064         o->op_private |= OPpENTERSUB_AMPER;
2065         if (rv2cv_op_cv(o, 0)) croak_fail();
2066         if (rv2cv_op_cv(o, RV2CVOPCV_RETURN_NAME_GV)) croak_fail();
2067         op_free(o);
2068         o = newCVREF(0, newSVOP(OP_CONST, 0, newRV_inc((SV*)troc_cv)));
2069         if (rv2cv_op_cv(o, 0) != troc_cv) croak_fail();
2070         if (rv2cv_op_cv(o, RV2CVOPCV_RETURN_NAME_GV) != (CV*)troc_gv)
2071             croak_fail();
2072         o->op_private |= OPpENTERSUB_AMPER;
2073         if (rv2cv_op_cv(o, 0)) croak_fail();
2074         if (rv2cv_op_cv(o, RV2CVOPCV_RETURN_NAME_GV)) croak_fail();
2075         o->op_private &= ~OPpENTERSUB_AMPER;
2076         if (cUNOPx(o)->op_first->op_private & OPpEARLY_CV) croak_fail();
2077         if (rv2cv_op_cv(o, RV2CVOPCV_MARK_EARLY) != troc_cv) croak_fail();
2078         if (cUNOPx(o)->op_first->op_private & OPpEARLY_CV) croak_fail();
2079         op_free(o);
2080         o = newCVREF(0, newUNOP(OP_RAND, 0, newSVOP(OP_CONST, 0, newSViv(0))));
2081         if (rv2cv_op_cv(o, 0)) croak_fail();
2082         if (rv2cv_op_cv(o, RV2CVOPCV_RETURN_NAME_GV)) croak_fail();
2083         o->op_private |= OPpENTERSUB_AMPER;
2084         if (rv2cv_op_cv(o, 0)) croak_fail();
2085         if (rv2cv_op_cv(o, RV2CVOPCV_RETURN_NAME_GV)) croak_fail();
2086         o->op_private &= ~OPpENTERSUB_AMPER;
2087         if (cUNOPx(o)->op_first->op_private & OPpEARLY_CV) croak_fail();
2088         if (rv2cv_op_cv(o, RV2CVOPCV_MARK_EARLY)) croak_fail();
2089         if (cUNOPx(o)->op_first->op_private & OPpEARLY_CV) croak_fail();
2090         op_free(o);
2091         o = newUNOP(OP_RAND, 0, newSVOP(OP_CONST, 0, newSViv(0)));
2092         if (rv2cv_op_cv(o, 0)) croak_fail();
2093         if (rv2cv_op_cv(o, RV2CVOPCV_RETURN_NAME_GV)) croak_fail();
2094         op_free(o);
2095
2096 void
2097 test_cv_getset_call_checker()
2098     PREINIT:
2099         CV *troc_cv, *tsh_cv;
2100         Perl_call_checker ckfun;
2101         SV *ckobj;
2102     CODE:
2103 #define check_cc(cv, xckfun, xckobj) \
2104     do { \
2105         cv_get_call_checker((cv), &ckfun, &ckobj); \
2106         if (ckfun != (xckfun)) croak_fail_ne(FPTR2DPTR(void *, ckfun), xckfun); \
2107         if (ckobj != (xckobj)) croak_fail_ne(FPTR2DPTR(void *, ckobj), xckobj); \
2108     } while(0)
2109         troc_cv = get_cv("XS::APItest::test_rv2cv_op_cv", 0);
2110         tsh_cv = get_cv("XS::APItest::test_savehints", 0);
2111         check_cc(troc_cv, Perl_ck_entersub_args_proto_or_list, (SV*)troc_cv);
2112         check_cc(tsh_cv, Perl_ck_entersub_args_proto_or_list, (SV*)tsh_cv);
2113         cv_set_call_checker(tsh_cv, Perl_ck_entersub_args_proto_or_list,
2114                                     &PL_sv_yes);
2115         check_cc(troc_cv, Perl_ck_entersub_args_proto_or_list, (SV*)troc_cv);
2116         check_cc(tsh_cv, Perl_ck_entersub_args_proto_or_list, &PL_sv_yes);
2117         cv_set_call_checker(troc_cv, THX_ck_entersub_args_scalars, &PL_sv_no);
2118         check_cc(troc_cv, THX_ck_entersub_args_scalars, &PL_sv_no);
2119         check_cc(tsh_cv, Perl_ck_entersub_args_proto_or_list, &PL_sv_yes);
2120         cv_set_call_checker(tsh_cv, Perl_ck_entersub_args_proto_or_list,
2121                                     (SV*)tsh_cv);
2122         check_cc(troc_cv, THX_ck_entersub_args_scalars, &PL_sv_no);
2123         check_cc(tsh_cv, Perl_ck_entersub_args_proto_or_list, (SV*)tsh_cv);
2124         cv_set_call_checker(troc_cv, Perl_ck_entersub_args_proto_or_list,
2125                                     (SV*)troc_cv);
2126         check_cc(troc_cv, Perl_ck_entersub_args_proto_or_list, (SV*)troc_cv);
2127         check_cc(tsh_cv, Perl_ck_entersub_args_proto_or_list, (SV*)tsh_cv);
2128         if (SvMAGICAL((SV*)troc_cv) || SvMAGIC((SV*)troc_cv)) croak_fail();
2129         if (SvMAGICAL((SV*)tsh_cv) || SvMAGIC((SV*)tsh_cv)) croak_fail();
2130 #undef check_cc
2131
2132 void
2133 cv_set_call_checker_lists(CV *cv)
2134     CODE:
2135         cv_set_call_checker(cv, THX_ck_entersub_args_lists, &PL_sv_undef);
2136
2137 void
2138 cv_set_call_checker_scalars(CV *cv)
2139     CODE:
2140         cv_set_call_checker(cv, THX_ck_entersub_args_scalars, &PL_sv_undef);
2141
2142 void
2143 cv_set_call_checker_proto(CV *cv, SV *proto)
2144     CODE:
2145         if (SvROK(proto))
2146             proto = SvRV(proto);
2147         cv_set_call_checker(cv, Perl_ck_entersub_args_proto, proto);
2148
2149 void
2150 cv_set_call_checker_proto_or_list(CV *cv, SV *proto)
2151     CODE:
2152         if (SvROK(proto))
2153             proto = SvRV(proto);
2154         cv_set_call_checker(cv, Perl_ck_entersub_args_proto_or_list, proto);
2155
2156 void
2157 cv_set_call_checker_multi_sum(CV *cv)
2158     CODE:
2159         cv_set_call_checker(cv, THX_ck_entersub_multi_sum, &PL_sv_undef);
2160
2161 void
2162 test_cophh()
2163     PREINIT:
2164         COPHH *a, *b;
2165     CODE:
2166 #define check_ph(EXPR) \
2167             do { if((EXPR) != &PL_sv_placeholder) croak("fail"); } while(0)
2168 #define check_iv(EXPR, EXPECT) \
2169             do { if(SvIV(EXPR) != (EXPECT)) croak("fail"); } while(0)
2170 #define msvpvs(STR) sv_2mortal(newSVpvs(STR))
2171 #define msviv(VALUE) sv_2mortal(newSViv(VALUE))
2172         a = cophh_new_empty();
2173         check_ph(cophh_fetch_pvn(a, "foo_1", 5, 0, 0));
2174         check_ph(cophh_fetch_pvs(a, "foo_1", 0));
2175         check_ph(cophh_fetch_pv(a, "foo_1", 0, 0));
2176         check_ph(cophh_fetch_sv(a, msvpvs("foo_1"), 0, 0));
2177         a = cophh_store_pvn(a, "foo_1abc", 5, 0, msviv(111), 0);
2178         a = cophh_store_pvs(a, "foo_2", msviv(222), 0);
2179         a = cophh_store_pv(a, "foo_3", 0, msviv(333), 0);
2180         a = cophh_store_sv(a, msvpvs("foo_4"), 0, msviv(444), 0);
2181         check_iv(cophh_fetch_pvn(a, "foo_1xyz", 5, 0, 0), 111);
2182         check_iv(cophh_fetch_pvs(a, "foo_1", 0), 111);
2183         check_iv(cophh_fetch_pv(a, "foo_1", 0, 0), 111);
2184         check_iv(cophh_fetch_sv(a, msvpvs("foo_1"), 0, 0), 111);
2185         check_iv(cophh_fetch_pvs(a, "foo_2", 0), 222);
2186         check_iv(cophh_fetch_pvs(a, "foo_3", 0), 333);
2187         check_iv(cophh_fetch_pvs(a, "foo_4", 0), 444);
2188         check_ph(cophh_fetch_pvs(a, "foo_5", 0));
2189         b = cophh_copy(a);
2190         b = cophh_store_pvs(b, "foo_1", msviv(1111), 0);
2191         check_iv(cophh_fetch_pvs(a, "foo_1", 0), 111);
2192         check_iv(cophh_fetch_pvs(a, "foo_2", 0), 222);
2193         check_iv(cophh_fetch_pvs(a, "foo_3", 0), 333);
2194         check_iv(cophh_fetch_pvs(a, "foo_4", 0), 444);
2195         check_ph(cophh_fetch_pvs(a, "foo_5", 0));
2196         check_iv(cophh_fetch_pvs(b, "foo_1", 0), 1111);
2197         check_iv(cophh_fetch_pvs(b, "foo_2", 0), 222);
2198         check_iv(cophh_fetch_pvs(b, "foo_3", 0), 333);
2199         check_iv(cophh_fetch_pvs(b, "foo_4", 0), 444);
2200         check_ph(cophh_fetch_pvs(b, "foo_5", 0));
2201         a = cophh_delete_pvn(a, "foo_1abc", 5, 0, 0);
2202         a = cophh_delete_pvs(a, "foo_2", 0);
2203         b = cophh_delete_pv(b, "foo_3", 0, 0);
2204         b = cophh_delete_sv(b, msvpvs("foo_4"), 0, 0);
2205         check_ph(cophh_fetch_pvs(a, "foo_1", 0));
2206         check_ph(cophh_fetch_pvs(a, "foo_2", 0));
2207         check_iv(cophh_fetch_pvs(a, "foo_3", 0), 333);
2208         check_iv(cophh_fetch_pvs(a, "foo_4", 0), 444);
2209         check_ph(cophh_fetch_pvs(a, "foo_5", 0));
2210         check_iv(cophh_fetch_pvs(b, "foo_1", 0), 1111);
2211         check_iv(cophh_fetch_pvs(b, "foo_2", 0), 222);
2212         check_ph(cophh_fetch_pvs(b, "foo_3", 0));
2213         check_ph(cophh_fetch_pvs(b, "foo_4", 0));
2214         check_ph(cophh_fetch_pvs(b, "foo_5", 0));
2215         b = cophh_delete_pvs(b, "foo_3", 0);
2216         b = cophh_delete_pvs(b, "foo_5", 0);
2217         check_iv(cophh_fetch_pvs(b, "foo_1", 0), 1111);
2218         check_iv(cophh_fetch_pvs(b, "foo_2", 0), 222);
2219         check_ph(cophh_fetch_pvs(b, "foo_3", 0));
2220         check_ph(cophh_fetch_pvs(b, "foo_4", 0));
2221         check_ph(cophh_fetch_pvs(b, "foo_5", 0));
2222         cophh_free(b);
2223         check_ph(cophh_fetch_pvs(a, "foo_1", 0));
2224         check_ph(cophh_fetch_pvs(a, "foo_2", 0));
2225         check_iv(cophh_fetch_pvs(a, "foo_3", 0), 333);
2226         check_iv(cophh_fetch_pvs(a, "foo_4", 0), 444);
2227         check_ph(cophh_fetch_pvs(a, "foo_5", 0));
2228         a = cophh_store_pvs(a, "foo_1", msviv(11111), COPHH_KEY_UTF8);
2229         a = cophh_store_pvs(a, "foo_\xaa", msviv(123), 0);
2230         a = cophh_store_pvs(a, "foo_\xc2\xbb", msviv(456), COPHH_KEY_UTF8);
2231         a = cophh_store_pvs(a, "foo_\xc3\x8c", msviv(789), COPHH_KEY_UTF8);
2232         a = cophh_store_pvs(a, "foo_\xd9\xa6", msviv(666), COPHH_KEY_UTF8);
2233         check_iv(cophh_fetch_pvs(a, "foo_1", 0), 11111);
2234         check_iv(cophh_fetch_pvs(a, "foo_1", COPHH_KEY_UTF8), 11111);
2235         check_iv(cophh_fetch_pvs(a, "foo_\xaa", 0), 123);
2236         check_iv(cophh_fetch_pvs(a, "foo_\xc2\xaa", COPHH_KEY_UTF8), 123);
2237         check_ph(cophh_fetch_pvs(a, "foo_\xc2\xaa", 0));
2238         check_iv(cophh_fetch_pvs(a, "foo_\xbb", 0), 456);
2239         check_iv(cophh_fetch_pvs(a, "foo_\xc2\xbb", COPHH_KEY_UTF8), 456);
2240         check_ph(cophh_fetch_pvs(a, "foo_\xc2\xbb", 0));
2241         check_iv(cophh_fetch_pvs(a, "foo_\xcc", 0), 789);
2242         check_iv(cophh_fetch_pvs(a, "foo_\xc3\x8c", COPHH_KEY_UTF8), 789);
2243         check_ph(cophh_fetch_pvs(a, "foo_\xc2\x8c", 0));
2244         check_iv(cophh_fetch_pvs(a, "foo_\xd9\xa6", COPHH_KEY_UTF8), 666);
2245         check_ph(cophh_fetch_pvs(a, "foo_\xd9\xa6", 0));
2246         ENTER;
2247         SAVEFREECOPHH(a);
2248         LEAVE;
2249 #undef check_ph
2250 #undef check_iv
2251 #undef msvpvs
2252 #undef msviv
2253
2254 HV *
2255 example_cophh_2hv()
2256     PREINIT:
2257         COPHH *a;
2258     CODE:
2259 #define msviv(VALUE) sv_2mortal(newSViv(VALUE))
2260         a = cophh_new_empty();
2261         a = cophh_store_pvs(a, "foo_0", msviv(999), 0);
2262         a = cophh_store_pvs(a, "foo_1", msviv(111), 0);
2263         a = cophh_store_pvs(a, "foo_\xaa", msviv(123), 0);
2264         a = cophh_store_pvs(a, "foo_\xc2\xbb", msviv(456), COPHH_KEY_UTF8);
2265         a = cophh_store_pvs(a, "foo_\xc3\x8c", msviv(789), COPHH_KEY_UTF8);
2266         a = cophh_store_pvs(a, "foo_\xd9\xa6", msviv(666), COPHH_KEY_UTF8);
2267         a = cophh_delete_pvs(a, "foo_0", 0);
2268         a = cophh_delete_pvs(a, "foo_2", 0);
2269         RETVAL = cophh_2hv(a, 0);
2270         cophh_free(a);
2271 #undef msviv
2272     OUTPUT:
2273         RETVAL
2274
2275 void
2276 test_savehints()
2277     PREINIT:
2278         SV **svp, *sv;
2279     CODE:
2280 #define store_hint(KEY, VALUE) \
2281                 sv_setiv_mg(*hv_fetchs(GvHV(PL_hintgv), KEY, 1), (VALUE))
2282 #define hint_ok(KEY, EXPECT) \
2283                 ((svp = hv_fetchs(GvHV(PL_hintgv), KEY, 0)) && \
2284                     (sv = *svp) && SvIV(sv) == (EXPECT) && \
2285                     (sv = cop_hints_fetch_pvs(&PL_compiling, KEY, 0)) && \
2286                     SvIV(sv) == (EXPECT))
2287 #define check_hint(KEY, EXPECT) \
2288                 do { if (!hint_ok(KEY, EXPECT)) croak_fail(); } while(0)
2289         PL_hints |= HINT_LOCALIZE_HH;
2290         ENTER;
2291         SAVEHINTS();
2292         PL_hints &= HINT_INTEGER;
2293         store_hint("t0", 123);
2294         store_hint("t1", 456);
2295         if (PL_hints & HINT_INTEGER) croak_fail();
2296         check_hint("t0", 123); check_hint("t1", 456);
2297         ENTER;
2298         SAVEHINTS();
2299         if (PL_hints & HINT_INTEGER) croak_fail();
2300         check_hint("t0", 123); check_hint("t1", 456);
2301         PL_hints |= HINT_INTEGER;
2302         store_hint("t0", 321);
2303         if (!(PL_hints & HINT_INTEGER)) croak_fail();
2304         check_hint("t0", 321); check_hint("t1", 456);
2305         LEAVE;
2306         if (PL_hints & HINT_INTEGER) croak_fail();
2307         check_hint("t0", 123); check_hint("t1", 456);
2308         ENTER;
2309         SAVEHINTS();
2310         if (PL_hints & HINT_INTEGER) croak_fail();
2311         check_hint("t0", 123); check_hint("t1", 456);
2312         store_hint("t1", 654);
2313         if (PL_hints & HINT_INTEGER) croak_fail();
2314         check_hint("t0", 123); check_hint("t1", 654);
2315         LEAVE;
2316         if (PL_hints & HINT_INTEGER) croak_fail();
2317         check_hint("t0", 123); check_hint("t1", 456);
2318         LEAVE;
2319 #undef store_hint
2320 #undef hint_ok
2321 #undef check_hint
2322
2323 void
2324 test_copyhints()
2325     PREINIT:
2326         HV *a, *b;
2327     CODE:
2328         PL_hints |= HINT_LOCALIZE_HH;
2329         ENTER;
2330         SAVEHINTS();
2331         sv_setiv_mg(*hv_fetchs(GvHV(PL_hintgv), "t0", 1), 123);
2332         if (SvIV(cop_hints_fetch_pvs(&PL_compiling, "t0", 0)) != 123)
2333             croak_fail();
2334         a = newHVhv(GvHV(PL_hintgv));
2335         sv_2mortal((SV*)a);
2336         sv_setiv_mg(*hv_fetchs(a, "t0", 1), 456);
2337         if (SvIV(cop_hints_fetch_pvs(&PL_compiling, "t0", 0)) != 123)
2338             croak_fail();
2339         b = hv_copy_hints_hv(a);
2340         sv_2mortal((SV*)b);
2341         sv_setiv_mg(*hv_fetchs(b, "t0", 1), 789);
2342         if (SvIV(cop_hints_fetch_pvs(&PL_compiling, "t0", 0)) != 789)
2343             croak_fail();
2344         LEAVE;
2345
2346 void
2347 test_op_list()
2348     PREINIT:
2349         OP *a;
2350     CODE:
2351 #define iv_op(iv) newSVOP(OP_CONST, 0, newSViv(iv))
2352 #define check_op(o, expect) \
2353     do { \
2354         if (strcmp(test_op_list_describe(o), (expect))) \
2355             croak("fail %s %s", test_op_list_describe(o), (expect)); \
2356     } while(0)
2357         a = op_append_elem(OP_LIST, NULL, NULL);
2358         check_op(a, "");
2359         a = op_append_elem(OP_LIST, iv_op(1), a);
2360         check_op(a, "const(1).");
2361         a = op_append_elem(OP_LIST, NULL, a);
2362         check_op(a, "const(1).");
2363         a = op_append_elem(OP_LIST, a, iv_op(2));
2364         check_op(a, "list[pushmark.const(1).const(2).]");
2365         a = op_append_elem(OP_LIST, a, iv_op(3));
2366         check_op(a, "list[pushmark.const(1).const(2).const(3).]");
2367         a = op_append_elem(OP_LIST, a, NULL);
2368         check_op(a, "list[pushmark.const(1).const(2).const(3).]");
2369         a = op_append_elem(OP_LIST, NULL, a);
2370         check_op(a, "list[pushmark.const(1).const(2).const(3).]");
2371         a = op_append_elem(OP_LIST, iv_op(4), a);
2372         check_op(a, "list[pushmark.const(4)."
2373                 "list[pushmark.const(1).const(2).const(3).]]");
2374         a = op_append_elem(OP_LIST, a, iv_op(5));
2375         check_op(a, "list[pushmark.const(4)."
2376                 "list[pushmark.const(1).const(2).const(3).]const(5).]");
2377         a = op_append_elem(OP_LIST, a, 
2378                 op_append_elem(OP_LIST, iv_op(7), iv_op(6)));
2379         check_op(a, "list[pushmark.const(4)."
2380                 "list[pushmark.const(1).const(2).const(3).]const(5)."
2381                 "list[pushmark.const(7).const(6).]]");
2382         op_free(a);
2383         a = op_append_elem(OP_LINESEQ, iv_op(1), iv_op(2));
2384         check_op(a, "lineseq[const(1).const(2).]");
2385         a = op_append_elem(OP_LINESEQ, a, iv_op(3));
2386         check_op(a, "lineseq[const(1).const(2).const(3).]");
2387         op_free(a);
2388         a = op_append_elem(OP_LINESEQ,
2389                 op_append_elem(OP_LIST, iv_op(1), iv_op(2)),
2390                 iv_op(3));
2391         check_op(a, "lineseq[list[pushmark.const(1).const(2).]const(3).]");
2392         op_free(a);
2393         a = op_prepend_elem(OP_LIST, NULL, NULL);
2394         check_op(a, "");
2395         a = op_prepend_elem(OP_LIST, a, iv_op(1));
2396         check_op(a, "const(1).");
2397         a = op_prepend_elem(OP_LIST, a, NULL);
2398         check_op(a, "const(1).");
2399         a = op_prepend_elem(OP_LIST, iv_op(2), a);
2400         check_op(a, "list[pushmark.const(2).const(1).]");
2401         a = op_prepend_elem(OP_LIST, iv_op(3), a);
2402         check_op(a, "list[pushmark.const(3).const(2).const(1).]");
2403         a = op_prepend_elem(OP_LIST, NULL, a);
2404         check_op(a, "list[pushmark.const(3).const(2).const(1).]");
2405         a = op_prepend_elem(OP_LIST, a, NULL);
2406         check_op(a, "list[pushmark.const(3).const(2).const(1).]");
2407         a = op_prepend_elem(OP_LIST, a, iv_op(4));
2408         check_op(a, "list[pushmark."
2409                 "list[pushmark.const(3).const(2).const(1).]const(4).]");
2410         a = op_prepend_elem(OP_LIST, iv_op(5), a);
2411         check_op(a, "list[pushmark.const(5)."
2412                 "list[pushmark.const(3).const(2).const(1).]const(4).]");
2413         a = op_prepend_elem(OP_LIST,
2414                 op_prepend_elem(OP_LIST, iv_op(6), iv_op(7)), a);
2415         check_op(a, "list[pushmark.list[pushmark.const(6).const(7).]const(5)."
2416                 "list[pushmark.const(3).const(2).const(1).]const(4).]");
2417         op_free(a);
2418         a = op_prepend_elem(OP_LINESEQ, iv_op(2), iv_op(1));
2419         check_op(a, "lineseq[const(2).const(1).]");
2420         a = op_prepend_elem(OP_LINESEQ, iv_op(3), a);
2421         check_op(a, "lineseq[const(3).const(2).const(1).]");
2422         op_free(a);
2423         a = op_prepend_elem(OP_LINESEQ, iv_op(3),
2424                 op_prepend_elem(OP_LIST, iv_op(2), iv_op(1)));
2425         check_op(a, "lineseq[const(3).list[pushmark.const(2).const(1).]]");
2426         op_free(a);
2427         a = op_append_list(OP_LINESEQ, NULL, NULL);
2428         check_op(a, "");
2429         a = op_append_list(OP_LINESEQ, iv_op(1), a);
2430         check_op(a, "const(1).");
2431         a = op_append_list(OP_LINESEQ, NULL, a);
2432         check_op(a, "const(1).");
2433         a = op_append_list(OP_LINESEQ, a, iv_op(2));
2434         check_op(a, "lineseq[const(1).const(2).]");
2435         a = op_append_list(OP_LINESEQ, a, iv_op(3));
2436         check_op(a, "lineseq[const(1).const(2).const(3).]");
2437         a = op_append_list(OP_LINESEQ, iv_op(4), a);
2438         check_op(a, "lineseq[const(4).const(1).const(2).const(3).]");
2439         a = op_append_list(OP_LINESEQ, a, NULL);
2440         check_op(a, "lineseq[const(4).const(1).const(2).const(3).]");
2441         a = op_append_list(OP_LINESEQ, NULL, a);
2442         check_op(a, "lineseq[const(4).const(1).const(2).const(3).]");
2443         a = op_append_list(OP_LINESEQ, a,
2444                 op_append_list(OP_LINESEQ, iv_op(5), iv_op(6)));
2445         check_op(a, "lineseq[const(4).const(1).const(2).const(3)."
2446                 "const(5).const(6).]");
2447         op_free(a);
2448         a = op_append_list(OP_LINESEQ,
2449                 op_append_list(OP_LINESEQ, iv_op(1), iv_op(2)),
2450                 op_append_list(OP_LIST, iv_op(3), iv_op(4)));
2451         check_op(a, "lineseq[const(1).const(2)."
2452                 "list[pushmark.const(3).const(4).]]");
2453         op_free(a);
2454         a = op_append_list(OP_LINESEQ,
2455                 op_append_list(OP_LIST, iv_op(1), iv_op(2)),
2456                 op_append_list(OP_LINESEQ, iv_op(3), iv_op(4)));
2457         check_op(a, "lineseq[list[pushmark.const(1).const(2).]"
2458                 "const(3).const(4).]");
2459         op_free(a);
2460 #undef check_op
2461
2462 void
2463 test_op_linklist ()
2464     PREINIT:
2465         OP *o;
2466     CODE:
2467 #define check_ll(o, expect) \
2468     STMT_START { \
2469         if (strNE(test_op_linklist_describe(o), (expect))) \
2470             croak("fail %s %s", test_op_linklist_describe(o), (expect)); \
2471     } STMT_END
2472         o = iv_op(1);
2473         check_ll(o, ".const1");
2474         op_free(o);
2475
2476         o = mkUNOP(OP_NOT, iv_op(1));
2477         check_ll(o, ".const1.not");
2478         op_free(o);
2479
2480         o = mkUNOP(OP_NOT, mkUNOP(OP_NEGATE, iv_op(1)));
2481         check_ll(o, ".const1.negate.not");
2482         op_free(o);
2483
2484         o = mkBINOP(OP_ADD, iv_op(1), iv_op(2));
2485         check_ll(o, ".const1.const2.add");
2486         op_free(o);
2487
2488         o = mkBINOP(OP_ADD, mkUNOP(OP_NOT, iv_op(1)), iv_op(2));
2489         check_ll(o, ".const1.not.const2.add");
2490         op_free(o);
2491
2492         o = mkUNOP(OP_NOT, mkBINOP(OP_ADD, iv_op(1), iv_op(2)));
2493         check_ll(o, ".const1.const2.add.not");
2494         op_free(o);
2495
2496         o = mkLISTOP(OP_LINESEQ, iv_op(1), iv_op(2), iv_op(3));
2497         check_ll(o, ".const1.const2.const3.lineseq");
2498         op_free(o);
2499
2500         o = mkLISTOP(OP_LINESEQ,
2501                 mkBINOP(OP_ADD, iv_op(1), iv_op(2)),
2502                 mkUNOP(OP_NOT, iv_op(3)),
2503                 mkLISTOP(OP_SUBSTR, iv_op(4), iv_op(5), iv_op(6)));
2504         check_ll(o, ".const1.const2.add.const3.not"
2505                     ".const4.const5.const6.substr.lineseq");
2506         op_free(o);
2507
2508         o = mkBINOP(OP_ADD, iv_op(1), iv_op(2));
2509         LINKLIST(o);
2510         o = mkBINOP(OP_SUBTRACT, o, iv_op(3));
2511         check_ll(o, ".const1.const2.add.const3.subtract");
2512         op_free(o);
2513 #undef check_ll
2514 #undef iv_op
2515
2516 void
2517 peep_enable ()
2518     PREINIT:
2519         dMY_CXT;
2520     CODE:
2521         av_clear(MY_CXT.peep_recorder);
2522         av_clear(MY_CXT.rpeep_recorder);
2523         MY_CXT.peep_recording = 1;
2524
2525 void
2526 peep_disable ()
2527     PREINIT:
2528         dMY_CXT;
2529     CODE:
2530         MY_CXT.peep_recording = 0;
2531
2532 SV *
2533 peep_record ()
2534     PREINIT:
2535         dMY_CXT;
2536     CODE:
2537         RETVAL = newRV_inc((SV *)MY_CXT.peep_recorder);
2538     OUTPUT:
2539         RETVAL
2540
2541 SV *
2542 rpeep_record ()
2543     PREINIT:
2544         dMY_CXT;
2545     CODE:
2546         RETVAL = newRV_inc((SV *)MY_CXT.rpeep_recorder);
2547     OUTPUT:
2548         RETVAL
2549
2550 =pod
2551
2552 multicall_each: call a sub for each item in the list. Used to test MULTICALL
2553
2554 =cut
2555
2556 void
2557 multicall_each(block,...)
2558     SV * block
2559 PROTOTYPE: &@
2560 CODE:
2561 {
2562     dMULTICALL;
2563     int index;
2564     GV *gv;
2565     HV *stash;
2566     I32 gimme = G_SCALAR;
2567     SV **args = &PL_stack_base[ax];
2568     CV *cv;
2569
2570     if(items <= 1) {
2571         XSRETURN_UNDEF;
2572     }
2573     cv = sv_2cv(block, &stash, &gv, 0);
2574     if (cv == Nullcv) {
2575        croak("multicall_each: not a subroutine reference");
2576     }
2577     PUSH_MULTICALL(cv);
2578     SAVESPTR(GvSV(PL_defgv));
2579
2580     for(index = 1 ; index < items ; index++) {
2581         GvSV(PL_defgv) = args[index];
2582         MULTICALL;
2583     }
2584     POP_MULTICALL;
2585     XSRETURN_UNDEF;
2586 }
2587
2588
2589 SV*
2590 take_svref(SVREF sv)
2591 CODE:
2592     RETVAL = newRV_inc(sv);
2593 OUTPUT:
2594     RETVAL
2595
2596 SV*
2597 take_avref(AV* av)
2598 CODE:
2599     RETVAL = newRV_inc((SV*)av);
2600 OUTPUT:
2601     RETVAL
2602
2603 SV*
2604 take_hvref(HV* hv)
2605 CODE:
2606     RETVAL = newRV_inc((SV*)hv);
2607 OUTPUT:
2608     RETVAL
2609
2610
2611 SV*
2612 take_cvref(CV* cv)
2613 CODE:
2614     RETVAL = newRV_inc((SV*)cv);
2615 OUTPUT:
2616     RETVAL
2617
2618
2619 BOOT:
2620         {
2621         HV* stash;
2622         SV** meth = NULL;
2623         CV* cv;
2624         stash = gv_stashpv("XS::APItest::TempLv", 0);
2625         if (stash)
2626             meth = hv_fetchs(stash, "make_temp_mg_lv", 0);
2627         if (!meth)
2628             croak("lost method 'make_temp_mg_lv'");
2629         cv = GvCV(*meth);
2630         CvLVALUE_on(cv);
2631         }
2632
2633 BOOT:
2634 {
2635     hintkey_rpn_sv = newSVpvs_share("XS::APItest/rpn");
2636     hintkey_calcrpn_sv = newSVpvs_share("XS::APItest/calcrpn");
2637     hintkey_stufftest_sv = newSVpvs_share("XS::APItest/stufftest");
2638     hintkey_swaptwostmts_sv = newSVpvs_share("XS::APItest/swaptwostmts");
2639     hintkey_looprest_sv = newSVpvs_share("XS::APItest/looprest");
2640     hintkey_scopelessblock_sv = newSVpvs_share("XS::APItest/scopelessblock");
2641     hintkey_stmtasexpr_sv = newSVpvs_share("XS::APItest/stmtasexpr");
2642     hintkey_stmtsasexpr_sv = newSVpvs_share("XS::APItest/stmtsasexpr");
2643     hintkey_loopblock_sv = newSVpvs_share("XS::APItest/loopblock");
2644     hintkey_blockasexpr_sv = newSVpvs_share("XS::APItest/blockasexpr");
2645     hintkey_swaplabel_sv = newSVpvs_share("XS::APItest/swaplabel");
2646     hintkey_labelconst_sv = newSVpvs_share("XS::APItest/labelconst");
2647     next_keyword_plugin = PL_keyword_plugin;
2648     PL_keyword_plugin = my_keyword_plugin;
2649 }
2650
2651 void
2652 establish_cleanup(...)
2653 PROTOTYPE: $
2654 CODE:
2655     croak("establish_cleanup called as a function");
2656
2657 BOOT:
2658 {
2659     CV *estcv = get_cv("XS::APItest::establish_cleanup", 0);
2660     cv_set_call_checker(estcv, THX_ck_entersub_establish_cleanup, (SV*)estcv);
2661 }
2662
2663 void
2664 postinc(...)
2665 PROTOTYPE: $
2666 CODE:
2667     croak("postinc called as a function");
2668
2669 BOOT:
2670 {
2671     CV *asscv = get_cv("XS::APItest::postinc", 0);
2672     cv_set_call_checker(asscv, THX_ck_entersub_postinc, (SV*)asscv);
2673 }
2674
2675 MODULE = XS::APItest            PACKAGE = XS::APItest::Magic
2676
2677 PROTOTYPES: DISABLE
2678
2679 void
2680 sv_magic_foo(SV *sv, SV *thingy)
2681 ALIAS:
2682     sv_magic_bar = 1
2683 CODE:
2684     sv_magicext(SvRV(sv), NULL, PERL_MAGIC_ext, ix ? &vtbl_bar : &vtbl_foo, (const char *)thingy, 0);
2685
2686 SV *
2687 mg_find_foo(SV *sv)
2688 ALIAS:
2689     mg_find_bar = 1
2690 CODE:
2691     MAGIC *mg = mg_findext(SvRV(sv), PERL_MAGIC_ext, ix ? &vtbl_bar : &vtbl_foo);
2692     RETVAL = mg ? SvREFCNT_inc((SV *)mg->mg_ptr) : &PL_sv_undef;
2693 OUTPUT:
2694     RETVAL
2695
2696 void
2697 sv_unmagic_foo(SV *sv)
2698 ALIAS:
2699     sv_unmagic_bar = 1
2700 CODE:
2701     sv_unmagicext(SvRV(sv), PERL_MAGIC_ext, ix ? &vtbl_bar : &vtbl_foo);