void single_hook_fill(pTHX_ const char *hook, const char *type, SingleHook *sth, SV *sub, U32 allowed_args) { if (!DEFINED(sub)) { sth->sub = NULL; sth->arg = NULL; } else if (SvROK(sub)) { SV *sv = SvRV(sub); switch (SvTYPE(sv)) { case SVt_PVCV: sth->sub = sv; sth->arg = NULL; break; case SVt_PVAV: { AV *in = (AV *) sv; I32 len = av_len(in); if (len < 0) Perl_croak(aTHX_ "Need at least a code reference in %s hook for " "type '%s'", hook, type); else { SV **pSV = av_fetch(in, 0, 0); if (pSV == NULL || !SvROK(*pSV) || SvTYPE(sv = SvRV(*pSV)) != SVt_PVCV) Perl_croak(aTHX_ "%s hook defined for '%s' is not " "a code reference", hook, type); else { I32 ix; AV *out; for (ix = 0; ix < len; ++ix) { pSV = av_fetch(in, ix+1, 0); if (pSV == NULL) fatal("NULL returned by av_fetch() in single_hook_fill()"); if (SvROK(*pSV) && sv_isa(*pSV, ARGTYPE_PACKAGE)) { HookArgType argtype = (HookArgType) SvIV(SvRV(*pSV)); #define CHECK_ARG_TYPE(type) \ case HOOK_ARG_ ## type: \ if ((allowed_args & SHF_ALLOW_ARG_ ## type) == 0) \ Perl_croak(aTHX_ #type " argument not allowed"); \ break switch (argtype) { CHECK_ARG_TYPE(SELF); CHECK_ARG_TYPE(TYPE); CHECK_ARG_TYPE(DATA); CHECK_ARG_TYPE(HOOK); } #undef CHECK_ARG_TYPE } } sth->sub = sv; out = newAV(); av_extend(out, len-1); for (ix = 0; ix < len; ++ix) { pSV = av_fetch(in, ix+1, 0); if (pSV == NULL) fatal("NULL returned by av_fetch() in single_hook_fill()"); SvREFCNT_inc(*pSV); if (av_store(out, ix, *pSV) == NULL) SvREFCNT_dec(*pSV); } sth->arg = (AV *) sv_2mortal((SV *) out); } } } break; default: goto not_code_or_array_ref; } } else { not_code_or_array_ref: Perl_croak(aTHX_ "%s hook defined for '%s' is not " "a code or array reference", hook, type); } }
// // rb_parse_args // - a rb_scan_args replacement, designed to assist in typecasting, since // use of RSTRING_* and RARRAY_* macros are so common in Shoes. // // returns 0 if no match. // returns 1 and up, the arg list matched. // (args.n is set to the arg count, args.a is the args) // static int rb_parse_args_p(unsigned char rais, int argc, const VALUE *argv, const char *fmt, rb_arg_list *args) { int i = 1, m = 0, n = 0, nmin = 0, x = 0; const char *p = fmt; args->n = 0; do { if (*p == ',') { if ((x && !m) || n < argc) { i++; x = 0; if (nmin == 0 || nmin > n) { nmin = n; } n = 0; } else break; } else if (*p == '|') { if (!x) m = i; } else if (*p == 's') { CHECK_ARG_COERCE(T_STRING, to_str) } else if (*p == 'S') { CHECK_ARG_COERCE(T_STRING, to_s) } else if (*p == 'i') { CHECK_ARG_COERCE(T_FIXNUM, to_int) } else if (*p == 'I') { CHECK_ARG_COERCE(T_FIXNUM, to_i) } else if (*p == 'f') { CHECK_ARG_TYPE(T_FLOAT, Qnil) } else if (*p == 'F') { CHECK_ARG_COERCE(T_FLOAT, to_f) } else if (*p == 'a') { CHECK_ARG_COERCE(T_ARRAY, to_ary) } else if (*p == 'A') { CHECK_ARG_COERCE(T_ARRAY, to_a) } else if (*p == 'k') { CHECK_ARG_TYPE(T_CLASS, Qnil) } else if (*p == 'h') { CHECK_ARG_TYPE(T_HASH, Qnil) } else if (*p == 'o') { CHECK_ARG_NOT_NIL() } else if (*p == '&') { if (rb_block_given_p()) SET_ARG(rb_block_proc()); else SET_ARG(Qnil); } // // shoes-specific structures // else if (*p == 'e') { CHECK_ARG_DATA(shoes_is_element) } else if (*p == 'E') { CHECK_ARG_DATA(shoes_is_any) } else break; } while (p++); if (!x && n >= argc) m = i; if (m) args->n = n; // printf("rb_parse_args(%s): %d %d (%d)\n", fmt, m, n, x); if (!m && rais) { if (argc < nmin) rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, nmin); else rb_raise(rb_eArgError, "bad arguments"); } return m; }