+void
+context_info(...)
+PROTOTYPE: ;$
+PREINIT:
+ I32 cxix;
+ const PERL_CONTEXT *cx, *dbcx;
+ COP *cop;
+PPCODE:
+ SU_GET_CONTEXT(0, 0, su_context_skip_db(cxstack_ix));
+ cxix = su_context_normalize_up(cxix);
+ cx = cxstack + cxix;
+ dbcx = cx;
+ if (PL_DBsub && cxix && (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT)) {
+ I32 i = su_context_skip_db(cxix - 1) + 1;
+ if (i < cxix && CxTYPE(cxstack + i) == CXt_SUB)
+ cx = cxstack + i;
+ }
+ cop = cx->blk_oldcop;
+ EXTEND(SP, SU_INFO_COUNT);
+ /* stash (0) */
+ {
+ HV *stash = CopSTASH(cop);
+ if (stash)
+ PUSHs(su_newmortal_pvn(HvNAME(stash), HvNAMELEN(stash)));
+ else
+ PUSHs(&PL_sv_undef);
+ }
+ /* file (1) */
+ PUSHs(su_newmortal_pvn(OutCopFILE(cop), OutCopFILE_len(cop)));
+ /* line (2) */
+ mPUSHi(CopLINE(cop));
+ /* subroutine (3) and has_args (4) */
+ switch (CxTYPE(cx)) {
+ case CXt_SUB:
+ case CXt_FORMAT: {
+ GV *cvgv = CvGV(dbcx->blk_sub.cv);
+ if (cvgv && isGV(cvgv)) {
+ SV *sv = sv_newmortal();
+ gv_efullname3(sv, cvgv, NULL);
+ PUSHs(sv);
+ } else {
+ PUSHs(su_newmortal_pvs("(unknown)"));
+ }
+ if (CxHASARGS(cx))
+ PUSHs(&PL_sv_yes);
+ else
+ PUSHs(&PL_sv_no);
+ break;
+ }
+ case CXt_EVAL:
+ PUSHs(su_newmortal_pvs("(eval)"));
+ mPUSHi(0);
+ break;
+ default:
+ PUSHs(&PL_sv_undef);
+ PUSHs(&PL_sv_undef);
+ }
+ /* gimme (5) */
+ switch (su_context_gimme(cxix)) {
+ case G_ARRAY:
+ PUSHs(&PL_sv_yes);
+ break;
+ case G_SCALAR:
+ PUSHs(&PL_sv_no);
+ break;
+ default: /* G_VOID */
+ PUSHs(&PL_sv_undef);
+ break;
+ }
+ /* eval text (6) and is_require (7) */
+ switch (CxTYPE(cx)) {
+ case CXt_EVAL:
+ if (CxOLD_OP_TYPE(cx) == OP_ENTEREVAL) {
+ /* eval STRING */
+#if XSH_HAS_PERL(5, 17, 4)
+ PUSHs(newSVpvn_flags(SvPVX(cx->blk_eval.cur_text),
+ SvCUR(cx->blk_eval.cur_text)-2,
+ SvUTF8(cx->blk_eval.cur_text)|SVs_TEMP));
+#else
+ PUSHs(cx->blk_eval.cur_text);
+#endif
+ PUSHs(&PL_sv_no);
+ break;
+ } else if (cx->blk_eval.old_namesv) {
+ /* require */
+ PUSHs(sv_mortalcopy(cx->blk_eval.old_namesv));
+ PUSHs(&PL_sv_yes);
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ /* Anything else including eval BLOCK */
+ PUSHs(&PL_sv_undef);
+ PUSHs(&PL_sv_undef);
+ break;
+ }
+ /* hints (8) */
+ mPUSHi(CopHINTS_get(cop));
+ /* warnings (9) */
+ {
+ SV *mask = NULL;
+#if XSH_HAS_PERL(5, 9, 4)
+ STRLEN *old_warnings = cop->cop_warnings;
+#else
+ SV *old_warnings = cop->cop_warnings;
+#endif
+ if (old_warnings == pWARN_STD) {
+ if (PL_dowarn & G_WARN_ON)
+ goto context_info_warnings_on;
+ else
+#if XSH_HAS_PERL(5, 17, 4)
+ mask = &PL_sv_undef;
+#else
+ goto context_info_warnings_off;
+#endif
+ } else if (old_warnings == pWARN_NONE) {
+#if !XSH_HAS_PERL(5, 17, 4)
+context_info_warnings_off:
+#endif
+ mask = su_newmortal_pvn(WARN_NONEstring, WARNsize);
+ } else if (old_warnings == pWARN_ALL) {
+ HV *bits;
+context_info_warnings_on:
+#if XSH_HAS_PERL(5, 8, 7)
+ bits = get_hv("warnings::Bits", 0);
+ if (bits) {
+ SV **bits_all = hv_fetchs(bits, "all", FALSE);
+ if (bits_all)
+ mask = sv_mortalcopy(*bits_all);
+ }
+#endif
+ if (!mask)
+ mask = su_newmortal_pvn(WARN_ALLstring, WARNsize);
+ } else {
+#if XSH_HAS_PERL(5, 9, 4)
+ mask = su_newmortal_pvn((char *) (old_warnings + 1), old_warnings[0]);
+#else
+ mask = sv_mortalcopy(old_warnings);
+#endif
+ }
+ PUSHs(mask);
+ }
+#if XSH_HAS_PERL(5, 10, 0)
+ /* hints hash (10) */
+ {
+ COPHH *hints_hash = CopHINTHASH_get(cop);
+ if (hints_hash) {
+ SV *rhv = sv_2mortal(newRV_noinc((SV *) cophh_2hv(hints_hash, 0)));
+ PUSHs(rhv);
+ } else {
+ PUSHs(&PL_sv_undef);
+ }
+ }
+#endif
+ XSRETURN(SU_INFO_COUNT);
+