/* * NAME: del_lhs() * DESCRIPTION: delete the left-hand side in an assignment */ static void del_lhs(dataspace *data, value *lhs) { string *str; array *arr; switch (lhs->type) { case T_STRING: str = lhs->u.string; if (str->primary != (strref *) NULL && str->primary->data == data) { /* in this object */ if (--(str->primary->ref) == 0) { str->primary->str = (string *) NULL; str->primary = (strref *) NULL; str_del(str); data->plane->schange++; /* last reference removed */ } data->plane->flags |= MOD_STRINGREF; } else { /* not in this object: deref imported string */ data->plane->schange--; } break; case T_ARRAY: case T_MAPPING: case T_LWOBJECT: arr = lhs->u.array; if (arr->primary->data == data) { /* in this object */ if (arr->primary->arr != (array *) NULL) { /* swapped in */ data->plane->flags |= MOD_ARRAYREF; if ((--(arr->primary->ref) & ~ARR_MOD) == 0) { d_get_elts(arr); arr->primary->arr = (array *) NULL; arr->primary = &arr->primary->plane->alocal; arr_del(arr); data->plane->achange++; } } else { /* deref new array */ data->plane->achange--; } } else { /* not in this object: deref imported array */ data->plane->imports--; data->plane->achange--; } break; } }
/* * NAME: arrchunk->clean() * DESCRIPTION: remove array chunks, and arrays, from memory */ static void ac_clean(arrchunk *c) { arrchunk *f; int i; while (c != (arrchunk *) NULL) { for (i = c->chunksz; --i >= 0; ) { arr_del(c->arr[i]); } f = c; c = c->next; FREE(f); } }
/* * NAME: path->include() * DESCRIPTION: resolve an include path */ char *path_include(char *buf, char *from, char *file, string ***strs, int *nstr) { frame *f; int i; value *v; string **str; *strs = NULL; *nstr = 0; if (c_autodriver()) { return path_from(buf, from, file); } f = cframe; PUSH_STRVAL(f, str_new(from, strlen(from))); PUSH_STRVAL(f, str_new(file, (long) strlen(file))); if (!call_driver_object(f, "include_file", 2)) { f->sp++; return path_from(buf, from, file); } if (f->sp->type == T_STRING) { /* simple path */ path_resolve(buf, f->sp->u.string->text); str_del((f->sp++)->u.string); return buf; } else if (f->sp->type == T_ARRAY) { /* * Array of strings. Check that the array does indeed contain only * strings, then return it. */ i = f->sp->u.array->size; if (i != 0) { v = d_get_elts(f->sp->u.array); while ((v++)->type == T_STRING) { if (--i == 0) { *nstr = i = f->sp->u.array->size; str = ALLOC(string*, i); do { str_ref(*str++ = (--v)->u.string); } while (--i != 0); *strs = str; arr_del((f->sp++)->u.array); /* return the untranslated path, as well */ return path_from(buf, from, file); } }
/* * NAME: data->discard_plane() * DESCRIPTION: discard the current data plane without committing it */ void d_discard_plane(Int level) { dataplane *p; dataspace *data; value *v; Uint i; for (p = plist; p != (dataplane *) NULL && p->level == level; p = p->plist) { /* * discard changes except for callout mods */ p->prev->flags |= p->flags & (MOD_CALLOUT | MOD_NEWCALLOUT); data = p->alocal.data; if (p->original != (value *) NULL) { /* restore original variable values */ for (v = data->variables, i = data->nvariables; i != 0; --i, v++) { i_del_value(v); } memcpy(data->variables, p->original, data->nvariables * sizeof(value)); FREE(p->original); } if (p->coptab != (coptable *) NULL) { /* undo callout changes */ discard_callouts(p); if (p->prev == &data->base) { cop_clean(p); } else { p->prev->coptab = p->coptab; } } arr_discard(&p->achunk); if (p->arrays != (arrref *) NULL) { arrref *a; /* delete new array refs */ for (a = p->arrays, i = data->narrays; i != 0; a++, --i) { if (a->arr != (array *) NULL) { arr_del(a->arr); } } FREE(p->arrays); /* fix old ones */ for (a = p->prev->arrays, i = data->narrays; i != 0; a++, --i) { if (a->arr != (array *) NULL) { a->arr->primary = a; } } } if (p->strings != (strref *) NULL) { strref *s; /* delete new string refs */ for (s = p->strings, i = data->nstrings; i != 0; s++, --i) { if (s->str != (string *) NULL) { str_del(s->str); } } FREE(p->strings); /* fix old ones */ for (s = p->prev->strings, i = data->nstrings; i != 0; s++, --i) { if (s->str != (string *) NULL) { s->str->primary = s; } } } data->plane = p->prev; plist = p->plist; FREE(p); } }
/* * NAME: data->commit_plane() * DESCRIPTION: commit the current data plane */ void d_commit_plane(Int level, value *retval) { dataplane *p, *commit, **r, **cr; dataspace *data; value *v; Uint i; dataplane *clist; /* * pass 1: construct commit planes */ clist = (dataplane *) NULL; cr = &clist; for (r = &plist, p = *r; p != (dataplane *) NULL && p->level == level; r = &p->plist, p = *r) { if (p->prev->level != level - 1) { /* insert commit plane */ commit = ALLOC(dataplane, 1); commit->level = level - 1; commit->original = (value *) NULL; commit->alocal.arr = (array *) NULL; commit->alocal.plane = commit; commit->alocal.data = p->alocal.data; commit->alocal.state = AR_CHANGED; commit->arrays = p->arrays; commit->achunk = p->achunk; commit->strings = p->strings; commit->coptab = p->coptab; commit->prev = p->prev; *cr = commit; cr = &commit->plist; p->prev = commit; } else { p->flags |= PLANE_MERGE; } } if (clist != (dataplane *) NULL) { /* insert commit planes in plane list */ *cr = p; *r = clist; } clist = *r; /* sentinel */ /* * pass 2: commit */ for (p = plist; p != clist; p = p->plist) { /* * commit changes to previous plane */ data = p->alocal.data; if (p->original != (value *) NULL) { if (p->level == 1 || p->prev->original != (value *) NULL) { /* free backed-up variable values */ for (v = p->original, i = data->nvariables; i != 0; v++, --i) { i_del_value(v); } FREE(p->original); } else { /* move originals to previous plane */ p->prev->original = p->original; } commit_values(data->variables, data->nvariables, level - 1); } if (p->coptab != (coptable *) NULL) { /* commit callout changes */ commit_callouts(p, p->flags & PLANE_MERGE); if (p->level == 1) { cop_clean(p); } else { p->prev->coptab = p->coptab; } } arr_commit(&p->achunk, p->prev, p->flags & PLANE_MERGE); if (p->flags & PLANE_MERGE) { if (p->arrays != (arrref *) NULL) { arrref *a; /* remove old array refs */ for (a = p->prev->arrays, i = data->narrays; i != 0; a++, --i) { if (a->arr != (array *) NULL) { if (a->arr->primary == &p->alocal) { a->arr->primary = &p->prev->alocal; } arr_del(a->arr); } } FREE(p->prev->arrays); p->prev->arrays = p->arrays; } if (p->strings != (strref *) NULL) { strref *s; /* remove old string refs */ for (s = p->prev->strings, i = data->nstrings; i != 0; s++, --i) { if (s->str != (string *) NULL) { str_del(s->str); } } FREE(p->prev->strings); p->prev->strings = p->strings; } } } commit_values(retval, 1, level - 1); /* * pass 3: deallocate */ for (p = plist; p != clist; p = plist) { p->prev->flags = (p->flags & MOD_ALL) | MOD_SAVE; p->prev->schange = p->schange; p->prev->achange = p->achange; p->prev->imports = p->imports; p->alocal.data->plane = p->prev; plist = p->plist; FREE(p); } }
/* * NAME: data->get_call_out() * DESCRIPTION: get a callout */ string *d_get_call_out(dataspace *data, unsigned int handle, frame *f, int *nargs) { string *str; dcallout *co; value *v, *o; uindex n; if (data->callouts == (dcallout *) NULL) { d_get_callouts(data); } co = &data->callouts[handle - 1]; v = co->val; del_lhs(data, &v[0]); str = v[0].u.string; i_grow_stack(f, (*nargs = co->nargs) + 1); *--f->sp = v[0]; switch (co->nargs) { case 3: del_lhs(data, &v[3]); *--f->sp = v[3]; case 2: del_lhs(data, &v[2]); *--f->sp = v[2]; case 1: del_lhs(data, &v[1]); *--f->sp = v[1]; case 0: break; default: n = co->nargs - 2; f->sp -= n; memcpy(f->sp, d_get_elts(v[3].u.array), n * sizeof(value)); del_lhs(data, &v[3]); FREE(v[3].u.array->elts); v[3].u.array->elts = (value *) NULL; arr_del(v[3].u.array); del_lhs(data, &v[2]); *--f->sp = v[2]; del_lhs(data, &v[1]); *--f->sp = v[1]; break; } /* wipe out destructed objects */ for (n = co->nargs, v = f->sp; n > 0; --n, v++) { switch (v->type) { case T_OBJECT: if (DESTRUCTED(v)) { *v = nil_value; } break; case T_LWOBJECT: o = d_get_elts(v->u.array); if (o->type == T_OBJECT && DESTRUCTED(o)) { arr_del(v->u.array); *v = nil_value; } break; } } co->val[0] = nil_value; n = data->fcallouts; if (n != 0) { data->callouts[n - 1].co_prev = handle; } co->co_next = n; data->fcallouts = handle; data->plane->flags |= MOD_CALLOUT; return str; }