static VALUE
rb_mod_const_get(int argc, VALUE *argv, VALUE mod)
{
VALUE name, recur;
rb_encoding *enc;
const char *pbeg, *p, *path, *pend;
ID id;
rb_check_arity(argc, 1, 2);
name = argv[0];
recur = (argc == 1) ? Qtrue : argv[1];
if (SYMBOL_P(name)) {
if (!rb_is_const_sym(name)) goto wrong_name;
id = rb_check_id(&name);
if (!id) return rb_const_missing(mod, name);
return RTEST(recur) ? rb_const_get(mod, id) : rb_const_get_at(mod, id);
}
path = StringValuePtr(name);
enc = rb_enc_get(name);
if (!rb_enc_asciicompat(enc)) {
rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
}
pbeg = p = path;
pend = path + RSTRING_LEN(name);
if (p >= pend || !*p) {
wrong_name:
rb_name_error_str(name, "wrong constant name % "PRIsVALUE, name);
}
if (p + 2 < pend && p[0] == ':' && p[1] == ':') {
mod = rb_cObject;
p += 2;
pbeg = p;
}
while (p < pend) {
VALUE part;
long len, beglen;
while (p < pend && *p != ':') p++;
if (pbeg == p) goto wrong_name;
id = rb_check_id_cstr(pbeg, len = p-pbeg, enc);
beglen = pbeg-path;
if (p < pend && p[0] == ':') {
if (p + 2 >= pend || p[1] != ':') goto wrong_name;
p += 2;
pbeg = p;
}
if (!RB_TYPE_P(mod, T_MODULE) && !RB_TYPE_P(mod, T_CLASS)) {
rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
QUOTE(name));
}
if (!id) {
part = rb_str_subseq(name, beglen, len);
OBJ_FREEZE(part);
if (!ISUPPER(*pbeg) || !rb_is_const_name(part)) {
rb_name_error_str(part, "wrong constant name %"PRIsVALUE,
QUOTE(part));
}
else if (!rb_method_basic_definition_p(CLASS_OF(mod), id_const_missing)) {
part = rb_str_intern(part);
mod = rb_const_missing(mod, part);
continue;
}
else {
rb_name_error_str(part, "uninitialized constant %"PRIsVALUE"% "PRIsVALUE,
rb_str_subseq(name, 0, beglen),
part);
}
}
if (!rb_is_const_id(id)) {
rb_name_error(id, "wrong constant name %"PRIsVALUE,
QUOTE_ID(id));
}
mod = RTEST(recur) ? rb_const_get(mod, id) : rb_const_get_at(mod, id);
}
return mod;
}