static VALUE
cbsubst_def_attr_aliases(self, tbl)
VALUE self;
VALUE tbl;
{
struct cbsubst_info *inf;
if (TYPE(tbl) != T_HASH) {
rb_raise(rb_eArgError, "expected a Hash");
}
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
rb_hash_foreach(tbl, each_attr_def, self);
return rb_funcall(inf->aliases, rb_intern("update"), 1, tbl);
}
static VALUE
cbsubst_get_all_subst_keys(self)
VALUE self;
{
struct cbsubst_info *inf;
char *buf, *ptr;
int i, len;
volatile VALUE ret;
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
len = strlen(inf->key);
buf = ALLOC_N(char, 3*len + 1);
ptr = buf;
for(i = 0; i < len; i++) {
*(ptr++) = '%';
*(ptr++) = *(inf->key + i);
*(ptr++) = ' ';
}
*(buf + 3*len) = '\0';
ret = rb_ary_new3(2, rb_str_new2(inf->key), rb_str_new2(buf));
free(buf);
return ret;
}
static VALUE
cbsubst_get_extra_args_tbl(self)
VALUE self;
{
return rb_ary_new();
}
static VALUE
cbsubst_get_subst_key(self, str)
VALUE self;
VALUE str;
{
volatile VALUE list;
volatile VALUE ret;
int i, len;
char *buf, *ptr;
list = rb_funcall(cTclTkLib, ID_split_tklist, 1, str);
len = RARRAY(list)->len;
buf = ALLOC_N(char, len + 1);
for(i = 0; i < len; i++) {
ptr = RSTRING(RARRAY(list)->ptr[i])->ptr;
if (*ptr == '%' && *(ptr + 2) == '\0') {
*(buf + i) = *(ptr + 1);
} else {
*(buf + i) = ' ';
}
}
*(buf + len) = '\0';
ret = rb_str_new2(buf);
free(buf);
return ret;
}
static VALUE
cbsubst_table_setup(self, key_inf, proc_inf)
VALUE self;
VALUE key_inf;
VALUE proc_inf;
{
struct cbsubst_info *subst_inf;
int idx;
int len = RARRAY(key_inf)->len;
int real_len = 0;
char *key = ALLOC_N(char, len + 1);
char *type = ALLOC_N(char, len + 1);
ID *ivar = ALLOC_N(ID, len + 1);
volatile VALUE proc = rb_hash_new();
volatile VALUE aliases = rb_hash_new();
volatile VALUE inf;
/* init */
subst_inf = ALLOC(struct cbsubst_info);
/* subst_inf->size = len; */
subst_inf->key = key;
subst_inf->type = type;
subst_inf->ivar = ivar;
subst_inf->proc = proc;
subst_inf->aliases = aliases;
/*
* keys : array of [subst, type, ivar]
* subst ==> char code
* type ==> char code
* ivar ==> symbol
*/
for(idx = 0; idx < len; idx++) {
inf = RARRAY(key_inf)->ptr[idx];
if (TYPE(inf) != T_ARRAY) continue;
*(key + real_len) = (char)NUM2INT(RARRAY(inf)->ptr[0]);
*(type + real_len) = (char)NUM2INT(RARRAY(inf)->ptr[1]);
*(ivar + real_len)
= rb_intern(
RSTRING(
rb_str_cat2(rb_str_new2("@"),
rb_id2name(SYM2ID(RARRAY(inf)->ptr[2])))
)->ptr
);
rb_attr(self, SYM2ID(RARRAY(inf)->ptr[2]), 1, 0, Qtrue);
real_len++;
}
*(key + real_len) = '\0';
*(type + real_len) = '\0';
subst_inf->size = real_len;
/*
* procs : array of [type, proc]
* type ==> char code
* proc ==> proc/method/obj (must respond to 'call')
*/
len = RARRAY(proc_inf)->len;
for(idx = 0; idx < len; idx++) {
inf = RARRAY(proc_inf)->ptr[idx];
if (TYPE(inf) != T_ARRAY) continue;
rb_hash_aset(proc, RARRAY(inf)->ptr[0], RARRAY(inf)->ptr[1]);
}
rb_const_set(self, ID_SUBST_INFO,
Data_Wrap_Struct(cSUBST_INFO, subst_mark,
subst_free, subst_inf));
return self;
}
static VALUE
cbsubst_inspect(self)
VALUE self;
{
return rb_str_new2("CallbackSubst");
}
static VALUE
cbsubst_initialize(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
{
struct cbsubst_info *inf;
int idx;
Data_Get_Struct(rb_const_get(rb_obj_class(self), ID_SUBST_INFO),
struct cbsubst_info, inf);
for(idx = 0; idx < argc; idx++) {
rb_ivar_set(self, inf->ivar[idx], argv[idx]);
}
return self;
}
static VALUE
cbsubst_ret_val(self, val)
VALUE self;
VALUE val;
{
return val;
}
static VALUE
cbsubst_scan_args(self, arg_key, val_ary)
VALUE self;
VALUE arg_key;
VALUE val_ary;
{
struct cbsubst_info *inf;
int idx;
int len = RARRAY(val_ary)->len;
char c;
char *ptr;
volatile VALUE dst = rb_ary_new2(len);
volatile VALUE proc;
int thr_crit_bup;
VALUE old_gc;
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
old_gc = rb_gc_disable();
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
RARRAY(dst)->len = 0;
for(idx = 0; idx < len; idx++) {
if (idx >= RSTRING(arg_key)->len) {
proc = Qnil;
} else if (*(RSTRING(arg_key)->ptr + idx) == ' ') {
proc = Qnil;
} else {
ptr = strchr(inf->key, *(RSTRING(arg_key)->ptr + idx));
if (ptr == (char*)NULL) {
proc = Qnil;
} else {
c = *(inf->type + (ptr - inf->key));
proc = rb_hash_aref(inf->proc, INT2FIX(c));
}
}
if (NIL_P(proc)) {
RARRAY(dst)->ptr[RARRAY(dst)->len++] = RARRAY(val_ary)->ptr[idx];
} else {
RARRAY(dst)->ptr[RARRAY(dst)->len++]
= rb_funcall(proc, ID_call, 1, RARRAY(val_ary)->ptr[idx]);
}
}
if (old_gc == Qfalse) rb_gc_enable();
rb_thread_critical = thr_crit_bup;
return dst;
}
static VALUE
cbsubst_get_subst_arg(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
{
struct cbsubst_info *inf;
char *str, *buf, *ptr;
int i, j, len;
ID id;
volatile VALUE arg_sym, ret;
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
buf = ALLOC_N(char, 3*argc + 1);
ptr = buf;
len = strlen(inf->key);
for(i = 0; i < argc; i++) {
switch(TYPE(argv[i])) {
case T_STRING:
str = RSTRING(argv[i])->ptr;
arg_sym = ID2SYM(rb_intern(str));
break;
case T_SYMBOL:
arg_sym = argv[i];
str = rb_id2name(SYM2ID(arg_sym));
break;
default:
rb_raise(rb_eArgError, "arg #%d is not a String or a Symbol", i);
}
if (!NIL_P(ret = rb_hash_aref(inf->aliases, arg_sym))) {
str = rb_id2name(SYM2ID(ret));
}
id = rb_intern(RSTRING(rb_str_cat2(rb_str_new2("@"), str))->ptr);
for(j = 0; j < len; j++) {
if (inf->ivar[j] == id) break;
}
if (j >= len) {
rb_raise(rb_eArgError, "cannot find attribute :%s", str);
}
*(ptr++) = '%';
*(ptr++) = *(inf->key + j);
*(ptr++) = ' ';
}
*ptr = '\0';
ret = rb_str_new2(buf);
free(buf);
return ret;
}