/* Copyright (c) 1993 Stephen F. White */ #include <stdio.h> #ifdef SYSV #include <string.h> #else #include <strings.h> #endif #include "config.h" #include "cool.h" #include "proto.h" #include "sys_proto.h" #include "servers.h" #ifndef INLINE void var_free(Var v) { switch (v.type) { case NUM: case OBJ: case ERR: case PC: break; case LIST: list_free(v.v.list); break; case STR: string_free(v.v.str); break; } } Var var_dup(Var v) { switch (v.type) { case NUM: case OBJ: case ERR: case PC: break; case LIST: v.v.list = list_dup(v.v.list); break; case STR: v.v.str = string_dup(v.v.str); break; } return v; } #endif int var_compare(Var v1, Var v2) { switch(v1.type) { case NUM: return v1.v.num - v2.v.num; case STR: return cool_strcasecmp(v1.v.str->str, v2.v.str->str); case OBJ: case ERR: case LIST: case PC: return -1; /* cannot compare objid, error or list values */ } return -1; /* should never reach */ } int var_eq(Var v1, Var v2) { int i; if(v1.type != v2.type) { return 0; /* values of different types are unequal */ } switch(v1.type) { case NUM: case PC: return v1.v.num == v2.v.num; case OBJ: return v1.v.obj.id == v2.v.obj.id && v1.v.obj.server == v2.v.obj.server; case ERR: return v1.v.err == v2.v.err; case STR: return !cool_strcasecmp(v1.v.str->str, v2.v.str->str); case LIST: if (v1.v.list->len != v2.v.list->len) { return 0; } for (i = 0; i < v1.v.list->len; i++) { /* * recursively compare all elements of list */ if (!var_eq(v1.v.list->el[i], v2.v.list->el[i])) { return 0; } } return 1; } return 0; } Var var_init(int type) { Var v; switch(v.type = type) { case STR: v.v.str = string_new(1); break; case NUM: case PC: v.v.num = 0; break; case OBJ: v.v.obj.id = -1; v.v.obj.server = 0; break; case LIST: v.v.list = list_dup(empty_list); break; case ERR: v.v.err = E_NONE; break; } return v; } int var_add_local(Method *m, int name, int *varno) { Vardef *prev = 0, *v; for (v = m->vars, *varno = 0; v; v = v->next, (*varno)++) { prev = v; if (v->name == name) { return 1; } } v = MALLOC(Vardef, 1); v->name = name; v->value.type = NUM; v->value.v.num = 0; v->next = 0; if (prev) { prev->next = v; } else { m->vars = v; } return 0; } int var_add_global(Object *o, int name, Var init_value) { Vardef *v; int hval, dummy; if (!o->vars) { o->vars = hash_new(HASH_INIT_SIZE); } hval = hash(sym_get(o, name)->str) % o->vars->size; if (var_find(o->vars->table[hval], name, &dummy)) { return 1; } else { v = MALLOC(Vardef, 1); v->name = name; v->value = init_value; v->next = o->vars->table[hval]; o->vars->table[hval] = v; o->vars->num++; return 0; } } Error var_rm_global(Object *o, const char *name) { Vardef *v, *prev = 0; int hval; if (!o->vars) { return E_VARNF; } hval = hash(name) % o->vars->size; for (v = o->vars->table[hval]; v; prev = v, v = v->next) { if (!cool_strcasecmp(sym_get(o, v->name)->str, name)) { if (prev) { prev->next = v->next; } else { o->vars->table[hval] = v->next; } o->vars->num--; sym_free(o, v->name); var_free(v->value); FREE(v); return E_NONE; } } return E_VARNF; } Vardef * var_find(Vardef *top, int name, int *varno) { Vardef *v; for (v = top, *varno = 0; v; v = v->next, (*varno)++) { if (v->name == name) { return v; } } return 0; } Vardef * var_find_local_by_name(Object *o, Method *m, const char *name, int namelen, int *varno) { Vardef *v; const char *vname; for (v = m->vars, *varno = 0; v; v = v->next, (*varno)++) { vname = sym_get(o, v->name)->str; if (strlen(vname) == namelen && !cool_strncasecmp(vname, name, namelen)) { return v; } } return 0; } Vardef * var_find_local(Method *m, int varno) { Vardef *v; for (v = m->vars; v && varno; v = v->next, varno--) ; return v; } void var_assign_local(Var *vars, int varno, Var value) { var_free(vars[varno]); vars[varno] = value; } Error var_assign_global(Object *o, String *name, Var value) { Vardef *v; Var oldvalue; int hval; if (var_get_global(o, name->str, &oldvalue) == E_NONE) { if (value.type != oldvalue.type) { var_free(value); return E_TYPE; } } if (o->vars) { hval = hash(name->str) % o->vars->size; for (v = o->vars->table[hval]; v; v = v->next) { if (!cool_strcasecmp(sym_get(o, v->name)->str, name->str)) { var_free(v->value); v->value = value; cache_put(o, o->id.id); return E_NONE; } } } name->ref++; var_add_global(o, sym_add(o, name), value); cache_put(o, o->id.id); return E_NONE; } void var_get_local(Var *vars, int varno, Var *r) { *r = vars[varno]; } Error var_get_global(Object *o, const char *name, Var *r) { Vardef *v; Object *p; int i, hval; if (o->vars) { hval = hash(name) % o->vars->size; for (v = o->vars->table[hval]; v; v = v->next) { if (!cool_strcasecmp(name, sym_get(o, v->name)->str)) { *r = v->value; return E_NONE; } } } /* * couldn't find locally, search on parents, recursively */ for (i = 0; i < o->parents->len; i++) { if ((p = retrieve(o->parents->el[i].v.obj))) { if (var_get_global(p, name, r) == E_NONE) { return E_NONE; /* found it */ } } } /* * no match */ return E_VARNF; } String * var_tostring(String *st, Var v, int quotes) { switch (v.type) { case NUM: case PC: st = string_catnum(st, v.v.num); break; case OBJ: st = string_catobj(st, v.v.obj, v.v.obj.server); break; case STR: if (quotes) { st = string_catc(st, '"'); } st = string_backslash(st, v.v.str->str); if (quotes) { st = string_catc(st, '"'); } break; case LIST: st = list_tostring(st, v.v.list); break; case ERR: st = string_cat(st, err_id2desc(v.v.err)); break; } return st; } String * list_tostring(String *st, List *l) { int i; st = string_catc(st, '{'); for (i = 0; i < l->len; i++) { st = var_tostring(st, l->el[i], 1); if (i < l->len - 1) { st = string_cat(st, ", "); } } st = string_catc(st, '}'); return st; } int var_count_local(Method *m) { int c; Vardef *v; for (v = m->vars, c = 0; v; v = v->next, c++) ; return c; } void var_init_local(Object *on, Method *m, Var *vars) { int i; Vardef *v; for (v = m->vars, i = 0; v; v = v->next, i++) { vars[i] = var_dup(v->value); } } void var_copy_vars(Object *source, Object *dest) { Vardef *v; String *varname; int hval; if (!source->vars) { return; } for (hval = 0; hval < source->vars->size; hval++) { for (v = source->vars->table[hval]; v; v = v->next) { varname = sym_get(source, v->name); (void) var_assign_global(dest, varname, var_dup(v->value)); } } }