Example #1
0
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);
  }
}
Example #2
0
File: ruby.c Project: Shoes3/shoes3
//
// 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;
}