static cDict *unpack_dict(cBuf *buf, Long *buf_pos) { cDict *dict; cList *keys, *values; Int i; keys = unpack_list(buf, buf_pos); values = unpack_list(buf, buf_pos); if (keys->len <= 64) { dict = dict_new(keys, values); list_discard(keys); list_discard(values); return dict; } else { dict = EMALLOC(cDict, 1); dict->keys = keys; dict->values = values; dict->hashtab_size = read_long(buf, buf_pos); dict->links = EMALLOC(Int, dict->hashtab_size); dict->hashtab = EMALLOC(Int, dict->hashtab_size); for (i = 0; i < dict->hashtab_size; i++) { dict->links[i] = read_long(buf, buf_pos); dict->hashtab[i] = read_long(buf, buf_pos); } dict->refs = 1; return dict; } }
cDict *dict_from_slices(cList *slices) { cList *keys, *values; cDict *dict; cData *d; /* Make lists for keys and values. */ keys = list_new(list_length(slices)); values = list_new(list_length(slices)); for (d = list_first(slices); d; d = list_next(slices, d)) { if (d->type != LIST || list_length(d->u.list) != 2) { /* Invalid slice. Throw away what we had and return NULL. */ list_discard(keys); list_discard(values); return NULL; } keys = list_add(keys, list_elem(d->u.list, 0)); values = list_add(values, list_elem(d->u.list, 1)); } /* Slices were all valid; return new dict. */ dict = dict_new(keys, values); list_discard(keys); list_discard(values); return dict; }
void dict_discard(cDict *dict) { dict->refs--; if (!dict->refs) { list_discard(dict->keys); list_discard(dict->values); tfree(dict->links, sizeof(Int) * dict->hashtab_size); tfree(dict->hashtab, sizeof(Int) * dict->hashtab_size); tfree(dict, sizeof(cDict)); } }
cDict *dict_new_empty(void) { if (!generic_empty_dict) { cList *l1, *l2; l1 = list_new(0); l2 = list_new(0); generic_empty_dict = dict_new(l1, l2); list_discard(l1); list_discard(l2); } return dict_dup(generic_empty_dict); }
void hash_discard(Hash * hash) { hash->refs--; if (!hash->refs) { list_discard(hash->keys); efree(hash->links); efree(hash->hashtab); efree(hash); } }
Hash * hash_new(int size) { cList * keys; Hash * out; keys = list_new(size); out = hash_new_with(keys); list_discard(keys); return out; }
void func_dict_values(void) { cData * args; cList * values; if (!func_init_1(&args, DICT)) return; values = dict_values(DICT1); pop(1); push_list(values); list_discard(values); }
void func_dict_keys(void) { cData * args; cList * keys; if (!func_init_1(&args, DICT)) return; keys = dict_keys(DICT1); pop(1); push_list(keys); list_discard(keys); }
cList *list_prep(cList * list, Int start, Int len) { cList *cnew; Int i, resize, size; /* Figure out if we need to resize the list or move its contents. Moving * contents takes precedence. */ #if DISABLED resize = (len - start) * 4 < list->size; resize = resize && list->size > STARTING_SIZE; resize = resize || (list->size < len); #endif resize = list->size < len + start; /* Move the list contents into a new list. */ if ((list->refs > 1) || (resize && start > 0)) { cnew = list_new(len); cnew->len = len; len = (list->len < len) ? list->len : len; for (i = 0; i < len; i++) data_dup(&cnew->el[i], &list->el[start + i]); list_discard(list); return cnew; } /* Resize the list. We can assume that list->start == start == 0. */ else if (resize) { for (; list->len > len; list->len--) data_discard(&list->el[list->len - 1]); list->len = len; size = len; list = (cList *) erealloc(list, sizeof(cList) + (size * sizeof(cData))); list->size = size; return list; } else { for (; list->start < start; list->start++, list->len--) data_discard(&list->el[list->start]); for (; list->len > len; list->len--) data_discard(&list->el[list->start + list->len - 1]); list->start = start; list->len = len; return list; } }
cList *list_union(cList * list1, cList * list2) { cData *start, *end, *d; start = list2->el + list2->start; end = start + list2->len; if (list1->len + list2->len < 12) { for (d = start; d < end; d++) { if (list_search(list1, d) == -1) list1 = list_add(list1, d); } } else { Hash *tmp; tmp = hash_new_with(list1); list_discard(list1); for (d = start; d < end; d++) { tmp = hash_add(tmp, d); } list1 = list_dup(tmp->keys); hash_discard(tmp); } return list1; }
INTERNAL cList *add_op_arg(cList * out, Int type, Long op, Method * method) { Obj *obj = method->object; cData d; switch (type) { case INTEGER: d.type = INTEGER; d.u.val = op; break; case FLOAT: d.type = FLOAT; d.u.fval = *((Float *) (&op)); break; case T_ERROR: if (op == -1) { d.type = INTEGER; d.u.val = -1; } else { d.type = T_ERROR; d.u.error = object_get_ident(obj, op); } break; case IDENT: d.type = SYMBOL; d.u.symbol = object_get_ident(obj, op); break; case VAR: { Long id; d.type = SYMBOL; if (op < method->num_args) { op = method->num_args - op - 1; id = object_get_ident(obj, method->argnames[op]); d.u.symbol = id; break; } op -= method->num_args; if (method->rest != -1) { if (op == 0) { id = object_get_ident(obj, method->rest); d.u.symbol = id; break; } op--; } id = object_get_ident(obj, method->varnames[op]); d.u.symbol = id; break; } case STRING: d.type = STRING; d.u.str = object_get_string(obj, op); break; /* case JUMP: *//* ignore JUMP */ default: return out; #if DISABLED /* none of these are used as args in op_table */ case LIST: case FROB: case DICT: case BUFFER: #endif } out = list_add(out, &d); /* do not discard, we were not using duped data */ return out; } COLDC_FUNC(method_bytecode) { cData *args, d; Method *method; cList *list; register Int x; Long *ops; Op_info *info; Long opcode; /* Accept a list of lines of code and a symbol for the name. */ if (!func_init_1(&args, SYMBOL)) return; method = object_find_method(cur_frame->object->objnum, args[0].u.symbol, FROB_ANY); /* keep these for later reference, if its already around */ if (!method) THROW((methodnf_id, "Method %D not found.", &args[0])) list = list_new(method->num_opcodes); d.type = SYMBOL; ops = method->opcodes; x = 0; while (x < method->num_opcodes) { opcode = ops[x]; info = &op_table[opcode]; d.type = SYMBOL; d.u.symbol = info->symbol; list = list_add(list, &d); /* dont bother discarding, we didnt dup twice */ x++; if (info->arg1) { list = add_op_arg(list, info->arg1, ops[x], method); x++; } if (info->arg2) { list = add_op_arg(list, info->arg1, ops[x], method); x++; } } pop(1); push_list(list); list_discard(list); }
/* void catch_signal(int sig, int code, struct sigcontext *scp) { */ void catch_signal(int sig) { char *sptr; cStr *sigstr; cData arg1; Bool do_shutdown = NO; signal(sig, catch_signal); sptr = sig_name(sig); sigstr = string_from_chars(sptr, strlen(sptr)); write_err("Caught signal %d: %S", sig, sigstr); string_discard(sigstr); /* figure out what to do */ switch (sig) { #ifdef __UNIX__ case SIGHUP: atomic = NO; handle_connection_output(); flush_files(); #endif #ifndef __MSVC__ case SIGUSR2: /* let the db do what it wants from here */ break; case SIGUSR1: { cData *d; cList *l; /* First cancel all preempted and suspended tasks */ l = vm_list(); for (d = list_first(l); d; d = list_next(l, d)) { /* boggle */ if (d->type != INTEGER) continue; vm_cancel(d->u.val); } list_discard(l); /* now cancel the current task if it is valid */ if (vm_lookup(task_id) != NULL) { vm_cancel(task_id); } /* jump back to the main loop */ longjmp(main_jmp, 1); break; } #endif case SIGILL: /* lets panic and hopefully shutdown without frobbing the db */ panic(sig_name(sig)); break; case SIGTERM: if (running) { write_err("*** Attempting normal shutdown ***"); running = NO; /* jump back to the main loop, ignore any current tasks; *drip*, *drip*, leaky */ longjmp(main_jmp, 1); } else { panic(sig_name(sig)); } break; default: do_shutdown = YES; break; } /* only pass onto the db if we are 'executing' */ if (!running) return; /* send a message to the system object */ arg1.type = SYMBOL; arg1.u.symbol = ident_get(sptr); vm_task(SYSTEM_OBJNUM, signal_id, 1, &arg1); if (do_shutdown) running = NO; }