/* discard the free list. iterate through tables, if element is unmarked and not zero-sized, free it. return reclaimed size */ static unsigned int _xpost_garbage_sweep(Xpost_Memory_File *mem) { Xpost_Memory_Table *tab; int ntab; unsigned int zero = 0; unsigned int z; unsigned int i; unsigned int sz = 0; int ret; ret = xpost_memory_table_get_addr(mem, XPOST_MEMORY_TABLE_SPECIAL_FREE, &z); /* address of the free list head */ if (!ret) { XPOST_LOG_ERR("cannot load free list head"); return 0; } memcpy(mem->base+z, &zero, sizeof(unsigned int)); /* discard list */ /* *(unsigned int *)(mem->base+z) = 0; */ /* scan first table */ tab = (void *)(mem->base); ntab = 0; for (i = mem->start; i < tab->nextent; i++) { if ( (tab->tab[i].mark & XPOST_MEMORY_TABLE_MARK_DATA_MARK_MASK) == 0 && tab->tab[i].sz != 0) { ret = xpost_free_memory_ent(mem, i); if (ret < 0) { XPOST_LOG_ERR("cannot free ent"); return sz; } sz += (unsigned int)ret; } } /* scan linked tables */ while (i < XPOST_MEMORY_TABLE_SIZE && tab->nexttab != 0) { tab = (void *)(mem->base + tab->nexttab); ++ntab; for (i = mem->start; i < tab->nextent; i++) { if ( (tab->tab[i].mark & XPOST_MEMORY_TABLE_MARK_DATA_MARK_MASK) == 0 && tab->tab[i].sz != 0) { ret = xpost_free_memory_ent(mem, i + ntab*XPOST_MEMORY_TABLE_SIZE); if (ret < 0) { XPOST_LOG_ERR("cannot free ent"); return sz; } sz += (unsigned int)ret; } } } return sz; }
/* check basic pointers and addresses for sanity */ static int validate_context(Xpost_Context *ctx) { /*assert(ctx); */ /*assert(ctx->lo); */ /*assert(ctx->lo->base); */ /*assert(ctx->gl); */ /*assert(ctx->gl->base); */ if (!ctx) { XPOST_LOG_ERR("ctx invalid"); return 0; } if (!ctx->lo) { XPOST_LOG_ERR("ctx->lo invalid"); return 0; } if (!ctx->lo->base) { XPOST_LOG_ERR("ctx->lo->base invalid"); return 0; } if (!ctx->gl) { XPOST_LOG_ERR("ctx->gl invalid"); return 0; } if (!ctx->gl->base) { XPOST_LOG_ERR("ctx->gl->base invalid"); return 0; } return 1; }
/* initialize the C-level data and define in the device instance */ static int _create_cont (Xpost_Context *ctx, Xpost_Object w, Xpost_Object h, Xpost_Object devdic) { Xpost_Object privatestr; PrivateData private; xcb_screen_iterator_t iter; xcb_get_geometry_reply_t *geom; integer width = w.int_.val; integer height = h.int_.val; int scrno; unsigned char depth; /* create a string to contain device data structure */ privatestr = xpost_string_cons(ctx, sizeof(PrivateData), NULL); if (xpost_object_get_type(privatestr) == invalidtype) { XPOST_LOG_ERR("cannot allocat private data structure"); return unregistered; } xpost_dict_put(ctx, devdic, namePrivate, privatestr); private.width = width;
/* add the name to the name stack, return index */ static unsigned int addname(Xpost_Context *ctx, const char *s) { Xpost_Memory_File *mem = ctx->vmmode==GLOBAL?ctx->gl:ctx->lo; unsigned int names; unsigned int u; Xpost_Object str; xpost_memory_table_get_addr(mem, XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK, &names); u = xpost_stack_count(mem, names); //xpost_memory_file_dump(ctx->gl); //dumpmtab(ctx->gl, 0); //unsigned int vmmode = ctx->vmmode; //ctx->vmmode = GLOBAL; str = xpost_string_cons(ctx, strlen(s), s); if (xpost_object_get_type(str) == nulltype) { XPOST_LOG_ERR("cannot allocate name string"); return 0; } xpost_stack_push(mem, names, str); //ctx->vmmode = vmmode; return u; }
/* allocate a local memory file find the next unused mfile in the local memory table */ static Xpost_Memory_File *xpost_interpreter_alloc_local_memory(void) { int i; for (i = 0; i < MAXMFILE; i++) { if (itpdata->ltab[i].base == NULL) { return &itpdata->ltab[i]; } } XPOST_LOG_ERR("cannot allocate Xpost_Memory_File, ltab exhausted"); return NULL; }
/* add a string to the ternary search tree */ static int tstinsert(Xpost_Memory_File *mem, unsigned int tadr, const char *s, unsigned int *retval) { tst *p; unsigned int t; //temporary unsigned int nstk; int ret; if (!tadr) { if (!xpost_memory_file_alloc(mem, sizeof(tst), &tadr)) { XPOST_LOG_ERR("cannot allocate tree node"); return VMerror; } p = (void *)(mem->base + tadr); p->val = *s; p->lo = p->eq = p->hi = 0; } p = (void *)(mem->base + tadr); if ((unsigned int)*s < p->val) { ret = tstinsert(mem, p->lo, s, &t); if (ret) return ret; p = (void *)(mem->base + tadr); //recalc pointer p->lo = t; } else if ((unsigned int)*s == p->val) { if (*s) { ret = tstinsert(mem, p->eq, ++s, &t); if (ret) return ret; p = (void *)(mem->base + tadr); //recalc pointer p->eq = t; }else { xpost_memory_table_get_addr(mem, XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK, &nstk); p->eq = xpost_stack_count(mem, nstk); /* payload when val == '\0' */ } } else { ret = tstinsert(mem, p->hi, s, &t); if (ret) return ret; p = (void *)(mem->base + tadr); //recalc pointer p->hi = t; } //return tadr; *retval = tadr; return 0; }
/* call window device's event_handler function which should check for Events or Messages from the underlying Window System, process one or more of them, and then return 0. it should leave all stacks undisturbed. */ int idleproc (Xpost_Context *ctx) { int ret; if ((xpost_object_get_type(ctx->event_handler) == operatortype) && (xpost_object_get_type(ctx->window_device) == dicttype)) { if (!xpost_stack_push(ctx->lo, ctx->os, ctx->window_device)) { return stackoverflow; } ret = xpost_operator_exec(ctx, ctx->event_handler.mark_.padw); if (ret) { XPOST_LOG_ERR("event_handler returned %d (%s)", ret, errorname[ret]); XPOST_LOG_ERR("disabling event_handler"); ctx->event_handler = null; return ret; } } return 0; }
END_TEST START_TEST(xpost_memory_not_init) { Xpost_Memory_File mem = {0}; unsigned int addr; int ret; mem.base = NULL; XPOST_LOG_ERR("you should see an error just below"); ret = xpost_memory_file_alloc(&mem, 64, &addr); ck_assert_int_eq (ret, 0); /* ck_assert_int_eq (xpost_memory_file_grow(&mem, 4096), 0); */ /* ck_assert_int_eq (xpost_memory_file_exit(&mem), 0); */ }
/* allocate a context-id and associated context struct returns cid; a context in state zero is considered available for allocation, this corresponds to the C_FREE enumeration constant. */ static int xpost_interpreter_cid_init(unsigned int *cid) { unsigned int startid = nextid; /*printf("cid_init\n"); */ while ( xpost_interpreter_cid_get_context(++nextid)->state != 0 ) { if (nextid == startid + MAXCONTEXT) { XPOST_LOG_ERR("ctab full. cannot create new process"); return 0; } } *cid = nextid; return 1; }
/* is it marked? */ static int _xpost_garbage_ent_is_marked(Xpost_Memory_File *mem, unsigned int ent, int *retval) { if (!mem) return 0; { Xpost_Memory_Table *tab = (void *)(mem->base); if (!xpost_memory_table_find_relative(mem,&tab,&ent)) { XPOST_LOG_ERR("cannot find table for ent %u", ent); return 0; } *retval = (tab->tab[ent].mark & XPOST_MEMORY_TABLE_MARK_DATA_MARK_MASK) >> XPOST_MEMORY_TABLE_MARK_DATA_MARK_OFFSET; } return 1; }
/* set the MARK in the mark in the tab[ent] */ static int _xpost_garbage_mark_ent(Xpost_Memory_File *mem, unsigned int ent) { Xpost_Memory_Table *tab; if (!mem) return 0; if (ent < mem->start) return 1; tab = (void *)(mem->base); if (!xpost_memory_table_find_relative(mem,&tab,&ent)) { XPOST_LOG_ERR("cannot find table for ent %u", ent); return 0; } tab->tab[ent].mark |= XPOST_MEMORY_TABLE_MARK_DATA_MARK_MASK; return 1; }
/* extract token from file */ static int evalfile(Xpost_Context *ctx) { Xpost_Object b,f,t; int ret; f = xpost_stack_pop(ctx->lo, ctx->es); if (!xpost_stack_push(ctx->lo, ctx->os, f)) return stackoverflow; assert(ctx->gl->base); /*xpost_operator_exec(ctx, xpost_operator_cons(ctx, "token",NULL,0,0).mark_.padw); */ ret = xpost_operator_exec(ctx, ctx->opcode_shortcuts.token); if (ret) return ret; b = xpost_stack_pop(ctx->lo, ctx->os); if (b.int_.val) { t = xpost_stack_pop(ctx->lo, ctx->os); if (!xpost_stack_push(ctx->lo, ctx->es, f)) return execstackoverflow; if (xpost_object_get_type(t)==arraytype) { if (!xpost_stack_push(ctx->lo, ctx->os, t)) return stackoverflow; } else { if (!xpost_stack_push(ctx->lo, ctx->es, t)) return execstackoverflow; } } else { ret = xpost_file_object_close(ctx->lo, f); if (ret) XPOST_LOG_ERR("%s error closing file", errorname[ret]); } return 0; }
/* set global pagesize, initialize eval's jump-tabl allocate global itpdata interpreter instance call xpost_interpreter_init which initializes the first context */ static int initalldata(const char *device) { int ret; initevaltype(); xpost_object_install_dict_get_access(xpost_dict_get_access); xpost_object_install_dict_set_access(xpost_dict_set_access); /* allocate the top-level itpdata data structure. */ null = xpost_object_cvlit(null); itpdata = malloc(sizeof*itpdata); if (!itpdata) { XPOST_LOG_ERR("itpdata=malloc failed"); return 0; } memset(itpdata, 0, sizeof*itpdata); /* allocate and initialize the first context structure and associated memory structures. populate OPTAB and systemdict with operators. push systemdict, globaldict, and userdict on dict stack */ ret = xpost_interpreter_init(itpdata, device); if (!ret) { return 0; } /* set global shortcut to context_0 (the only context in a single-threaded interpreter) TODO remove this variable */ xpost_ctx = &itpdata->ctab[0]; return 1; }
/* save restore - rewind vm to saved state */ static int Vrestore (Xpost_Context *ctx, Xpost_Object V) { int z; unsigned int vs; int ret; ret = xpost_memory_table_get_addr(ctx->lo, XPOST_MEMORY_TABLE_SPECIAL_SAVE_STACK, &vs); if (!ret) { XPOST_LOG_ERR("cannot retrieve address for save stack"); return VMerror; } z = xpost_stack_count(ctx->lo, vs); while(z > V.save_.lev) { xpost_save_restore_snapshot(ctx->lo); z--; } printf("restore\n"); return 0; }
/* traverse the contents of composite objects if markall is true, this is a collection of global vm, so we must mark objects and recurse even if it means switching memory files */ static int _xpost_garbage_mark_object(Xpost_Context *ctx, Xpost_Memory_File *mem, Xpost_Object o, int markall) { unsigned int ad; int ret; if (!mem) return 0; switch(xpost_object_get_type(o)) { default: break; case arraytype: #ifdef DEBUG_GC printf("markobject: %d, %s (size %d)\n", xpost_object_get_ent(o), xpost_object_type_names[xpost_object_get_type(o)], o.comp_.sz); #endif if (xpost_context_select_memory(ctx, o) != mem) { if (markall) mem = xpost_context_select_memory(ctx, o); else break; } if (!mem) return 0; if (!_xpost_garbage_ent_is_marked(mem, xpost_object_get_ent(o), &ret)) return 0; if (!ret) { ret = _xpost_garbage_mark_ent(mem, xpost_object_get_ent(o)); if (!ret) { XPOST_LOG_ERR("cannot mark array"); return 0; } ret = xpost_memory_table_get_addr(mem, xpost_object_get_ent(o), &ad); if (!ret) { XPOST_LOG_ERR("cannot retrieve address for array ent %u", xpost_object_get_ent(o)); return 0; } if (!_xpost_garbage_mark_array(ctx, mem, ad, o.comp_.sz, markall)) return 0; } break; case dicttype: #ifdef DEBUG_GC printf("markobject: %d, %s (size %d)\n", xpost_object_get_ent(o), xpost_object_type_names[xpost_object_get_type(o)], o.comp_.sz); #endif if (xpost_context_select_memory(ctx, o) != mem) { if (markall) mem = xpost_context_select_memory(ctx, o); else break; } if (!_xpost_garbage_ent_is_marked(mem, xpost_object_get_ent(o), &ret)) return 0; if (!ret) { ret = _xpost_garbage_mark_ent(mem, xpost_object_get_ent(o)); if (!ret) { XPOST_LOG_ERR("cannot mark dict"); return 0; } ret = xpost_memory_table_get_addr(mem, xpost_object_get_ent(o), &ad); if (!ret) { XPOST_LOG_ERR("cannot retrieve address for dict ent %u", xpost_object_get_ent(o)); return 0; } if (!_xpost_garbage_mark_dict(ctx, mem, ad, markall)) return 0; } break; case stringtype: #ifdef DEBUG_GC printf("markobject: %d, %s (size %d)\n", xpost_object_get_ent(o), xpost_object_type_names[xpost_object_get_type(o)], o.comp_.sz); #endif if (xpost_context_select_memory(ctx, o) != mem) { if (markall) mem = xpost_context_select_memory(ctx, o); else break; } ret = _xpost_garbage_mark_ent(mem, xpost_object_get_ent(o)); if (!ret) { XPOST_LOG_ERR("cannot mark string"); return 0; } break; case filetype: if (mem == ctx->gl) { printf("file found in global vm\n"); } else { ret = _xpost_garbage_mark_ent(mem, o.mark_.padw); if (!ret) { XPOST_LOG_ERR("cannot mark file"); return 0; } } break; } return 1; }
/* called by mainloop() after propagated error codes. pushes postscript-level error procedures and resumes normal execution. */ static void _onerror(Xpost_Context *ctx, unsigned int err) { Xpost_Object sd; Xpost_Object ed; Xpost_Object dollarerror; if (err > unknownerror) err = unknownerror; if (!validate_context(ctx)) XPOST_LOG_ERR("context not valid"); if (itpdata->in_onerror > 5) { fprintf(stderr, "LOOP in error handler\nabort\n"); ++ctx->quit; /*exit(undefinedresult); */ } ++itpdata->in_onerror; #ifdef EMITONERROR fprintf(stderr, "err: %s\n", errorname[err]); #endif /* reset stack */ if ((xpost_object_get_type(ctx->currentobject) == operatortype) && (ctx->currentobject.tag & XPOST_OBJECT_TAG_DATA_FLAG_OPARGSINHOLD)) { int n = ctx->currentobject.mark_.pad0; int i; for (i = 0; i < n; i++) { xpost_stack_push(ctx->lo, ctx->os, xpost_stack_bottomup_fetch(ctx->lo, ctx->hold, i)); } } /* printf("1\n"); */ sd = xpost_stack_bottomup_fetch(ctx->lo, ctx->ds, 0); /* printf("2\n"); */ dollarerror = xpost_dict_get(ctx, sd, namedollarerror); if (xpost_object_get_type(dollarerror) == invalidtype) { XPOST_LOG_ERR("cannot load $error dict for error: %s", errorname[err]); xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "stop"))); /*itpdata->in_onerror = 0; */ return; } /* printf("3\n"); */ /* printf("4\n"); */ /* printf("5\n"); */ xpost_stack_push(ctx->lo, ctx->os, ctx->currentobject); #if 0 /* printf("6\n"); */ xpost_stack_push(ctx->lo, ctx->os, xpost_object_cvlit(xpost_name_cons(ctx, errorname[err]))); /* printf("7\n"); */ xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "signalerror"))); #endif ed = xpost_dict_get(ctx, sd, nameerrordict); xpost_stack_push(ctx->lo, ctx->es, xpost_dict_get(ctx, ed, xpost_name_cons(ctx, errorname[err]))); /* printf("8\n"); */ itpdata->in_onerror = 0; }
/* determine GLOBAL/LOCAL clear all marks, mark all root stacks, sweep. return reclaimed size or -1 if error occured. */ int xpost_garbage_collect(Xpost_Memory_File *mem, int dosweep, int markall) { unsigned int i; unsigned int *cid; Xpost_Context *ctx = NULL; int isglobal; unsigned int sz = 0; unsigned int ad; int ret; if (mem->interpreter_get_initializing()) /* do not collect while initializing */ return 0; /* printf("\ncollect:\n"); */ /* determine global/local */ isglobal = 0; ret = xpost_memory_table_get_addr(mem, XPOST_MEMORY_TABLE_SPECIAL_CONTEXT_LIST, &ad); if (!ret) { XPOST_LOG_ERR("cannot load context list"); return -1; } cid = (void *)(mem->base + ad); for (i = 0; i < MAXCONTEXT && cid[i]; i++) { ctx = mem->interpreter_cid_get_context(cid[i]); if (ctx->state != 0) { if (mem == ctx->gl) { isglobal = 1; break; } } } #ifdef DEBUG_GC printf("using cid=%d\n", ctx->id); #endif if (isglobal) { return 0; /* do not perform global collections at this time */ _xpost_garbage_unmark(mem); ret = xpost_memory_table_get_addr(mem, XPOST_MEMORY_TABLE_SPECIAL_SAVE_STACK, &ad); if (!ret) { XPOST_LOG_ERR("cannot load save stack for %s memory", mem == ctx->gl? "global" : "local"); return -1; } if (!_xpost_garbage_mark_save(ctx, mem, ad)) return -1; ret = xpost_memory_table_get_addr(mem, XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK, &ad); if (!ret) { XPOST_LOG_ERR("cannot load name stack for %s memory", mem == ctx->gl? "global" : "local"); return -1; } if (!_xpost_garbage_mark_stack(ctx, mem, ad, markall)) return -1; for (i = 0; i < MAXCONTEXT && cid[i]; i++) { ctx = mem->interpreter_cid_get_context(cid[i]); xpost_garbage_collect(ctx->lo, 0, markall); } } else { /* local */ //printf("collect!\n"); _xpost_garbage_unmark(mem); ret = xpost_memory_table_get_addr(mem, XPOST_MEMORY_TABLE_SPECIAL_SAVE_STACK, &ad); if (!ret) { XPOST_LOG_ERR("cannot load save stack for %s memory", mem == ctx->gl? "global" : "local"); return -1; } if (!_xpost_garbage_mark_save(ctx, mem, ad)) return -1; ret = xpost_memory_table_get_addr(mem, XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK, &ad); if (!ret) { XPOST_LOG_ERR("cannot load name stack for %s memory", mem == ctx->gl? "global" : "local"); return -1; } #ifdef DEBUG_GC printf("marking name stack\n"); #endif if (!_xpost_garbage_mark_stack(ctx, mem, ad, markall)) return -1; for (i = 0; i < MAXCONTEXT && cid[i]; i++) { ctx = mem->interpreter_cid_get_context(cid[i]); #ifdef DEBUG_GC printf("marking os\n"); #endif if (!_xpost_garbage_mark_stack(ctx, mem, ctx->os, markall)) return -1; #ifdef DEBUG_GC printf("marking ds\n"); #endif if (!_xpost_garbage_mark_stack(ctx, mem, ctx->ds, markall)) return -1; #ifdef DEBUG_GC printf("marking es\n"); #endif if (!_xpost_garbage_mark_stack(ctx, mem, ctx->es, markall)) return -1; #ifdef DEBUG_GC printf("marking hold\n"); #endif if (!_xpost_garbage_mark_stack(ctx, mem, ctx->hold, markall)) return -1; #ifdef DEBUG_GC printf("marking window device\n"); #endif if (!_xpost_garbage_mark_object(ctx, mem, ctx->window_device, markall)) return -1; } } if (dosweep) { #ifdef DEBUG_GC printf("sweep\n"); #endif sz += _xpost_garbage_sweep(mem); if (isglobal) { for (i = 0; i < MAXCONTEXT && cid[i]; i++) { ctx = mem->interpreter_cid_get_context(cid[i]); sz += _xpost_garbage_sweep(ctx->lo); } } } printf("collect recovered %u bytes\n", sz); return sz; }
/* mark all allocations referred to by objects in save object's stack of saverec_'s */ static int _xpost_garbage_mark_save_stack(Xpost_Context *ctx, Xpost_Memory_File *mem, unsigned int stackadr) { if (!mem) return 0; { Xpost_Stack *s = (Xpost_Stack *)(mem->base + stackadr); unsigned int i; unsigned int ad; int ret; (void)ctx; #ifdef DEBUG_GC printf("marking save stack of size %u\n", xpost_stack_count(mem, stackadr)); #endif next: for (i=0; i < s->top; i++) { /* _xpost_garbage_mark_object(ctx, mem, s->data[i]); */ /* _xpost_garbage_mark_save_stack(ctx, mem, s->data[i].save_.stk); */ ret = _xpost_garbage_mark_ent(mem, s->data[i].saverec_.src); if (!ret) { XPOST_LOG_ERR("cannot mark array"); return 0; } ret = _xpost_garbage_mark_ent(mem, s->data[i].saverec_.cpy); if (!ret) { XPOST_LOG_ERR("cannot mark array"); return 0; } if (s->data[i].saverec_.tag == dicttype) { ret = xpost_memory_table_get_addr(mem, s->data[i].saverec_.src, &ad); if (!ret) { XPOST_LOG_ERR("cannot retrieve address for ent %u", s->data[i].saverec_.src); return 0; } if (!_xpost_garbage_mark_dict(ctx, mem, ad, 0)) return 0; ret = xpost_memory_table_get_addr(mem, s->data[i].saverec_.cpy, &ad); if (!ret) { XPOST_LOG_ERR("cannot retrieve address for ent %u", s->data[i].saverec_.cpy); return 0; } if (!_xpost_garbage_mark_dict(ctx, mem, ad, 0)) return 0; } if (s->data[i].saverec_.tag == arraytype) { unsigned int sz = s->data[i].saverec_.pad; ret = xpost_memory_table_get_addr(mem, s->data[i].saverec_.src, &ad); if (!ret) { XPOST_LOG_ERR("cannot retrieve address for array ent %u", s->data[i].saverec_.src); return 0; } if (!_xpost_garbage_mark_array(ctx, mem, ad, sz, 0)) return 0; ret = xpost_memory_table_get_addr(mem, s->data[i].saverec_.cpy, &ad); if (!ret) { XPOST_LOG_ERR("cannot retrieve address for array ent %u", s->data[i].saverec_.cpy); return 0; } if (!_xpost_garbage_mark_array(ctx, mem, ad, sz, 0)) return 0; } } if (i==XPOST_STACK_SEGMENT_SIZE) { /* ie. s->top == XPOST_STACK_SEGMENT_SIZE */ s = (Xpost_Stack *)(mem->base + s->nextseg); goto next; } if (s->nextseg) { xpost_stack_free(mem, s->nextseg); s->nextseg = 0; } } return 1; }
/* initialize the name string stacks and name search trees (per memory file). seed the search trees. initialize and populate the optab and systemdict (global memory file). push systemdict on dict stack. allocate and push globaldict on dict stack. allocate and push userdict on dict stack. return 1 on success, 0 on failure */ static int _xpost_interpreter_extra_context_init(Xpost_Context *ctx, const char *device) { int ret; ret = xpost_name_init(ctx); /* NAMES NAMET */ if (!ret) { xpost_memory_file_exit(ctx->lo); xpost_memory_file_exit(ctx->gl); return 0; } ctx->vmmode = GLOBAL; ret = xpost_operator_init_optab(ctx); /* allocate and zero the optab structure */ if (!ret) { xpost_memory_file_exit(ctx->lo); xpost_memory_file_exit(ctx->gl); return 0; } /* seed the tree with a word from the middle of the alphabet */ /* middle of the start */ /* middle of the end */ if (xpost_object_get_type(xpost_name_cons(ctx, "maxlength")) == invalidtype) return 0; if (xpost_object_get_type(xpost_name_cons(ctx, "getinterval")) == invalidtype) return 0; if (xpost_object_get_type(xpost_name_cons(ctx, "setmiterlimit")) == invalidtype) return 0; if (xpost_object_get_type((namedollarerror = xpost_name_cons(ctx, "$error"))) == invalidtype) return 0; if (xpost_object_get_type((nameerrordict = xpost_name_cons(ctx, "errordict"))) == invalidtype) return 0; xpost_oplib_init_ops(ctx); /* populate the optab (and systemdict) with operators */ { Xpost_Object gd; /*globaldict */ gd = xpost_dict_cons (ctx, 100); if (xpost_object_get_type(gd) == nulltype) { XPOST_LOG_ERR("cannot allocate globaldict"); return 0; } ret = xpost_dict_put(ctx, xpost_stack_bottomup_fetch(ctx->lo, ctx->ds, 0), xpost_name_cons(ctx, "globaldict"), gd); if (ret) return 0; xpost_stack_push(ctx->lo, ctx->ds, gd); } ctx->vmmode = LOCAL; /* seed the tree with a word from the middle of the alphabet */ /* middle of the start */ /* middle of the end */ if (xpost_object_get_type(xpost_name_cons(ctx, "minimal")) == invalidtype) return 0; if (xpost_object_get_type(xpost_name_cons(ctx, "interest")) == invalidtype) return 0; if (xpost_object_get_type(xpost_name_cons(ctx, "solitaire")) == invalidtype) return 0; { Xpost_Object ud; /*userdict */ ud = xpost_dict_cons (ctx, 100); if (xpost_object_get_type(ud) == nulltype) { XPOST_LOG_ERR("cannot allocate userdict"); return 0; } ret = xpost_dict_put(ctx, ud, xpost_name_cons(ctx, "userdict"), ud); if (ret) return 0; xpost_stack_push(ctx->lo, ctx->ds, ud); } ctx->device_str = device; return 1; }
int test_garbage_collect(int (*xpost_interpreter_cid_init)(unsigned int *cid), Xpost_Context *(*xpost_interpreter_cid_get_context)(unsigned int cid), int (*xpost_interpreter_get_initializing)(void), void (*xpost_interpreter_set_initializing)(int), Xpost_Memory_File *(*xpost_interpreter_alloc_local_memory)(void), Xpost_Memory_File *(*xpost_interpreter_alloc_global_memory)(void)) { if (!init_test_garbage(xpost_interpreter_cid_init, xpost_interpreter_cid_get_context, xpost_interpreter_get_initializing, xpost_interpreter_set_initializing, xpost_interpreter_alloc_local_memory, xpost_interpreter_alloc_global_memory)) return 0; { Xpost_Object str; unsigned int pre, post, sz, ret; pre = ctx->lo->used; str = xpost_string_cons(ctx, 7, "0123456"); post = ctx->lo->used; sz = post-pre; /* printf("str sz=%u\n", sz); */ xpost_stack_push(ctx->lo, ctx->os, str); _clear_hold(ctx); ret = collect(ctx->lo, 1, 0); //assert(ret == 0); if (ret != 0) { XPOST_LOG_ERR("Warning: collect returned %d, expected %d", ret, 0); } xpost_stack_pop(ctx->lo, ctx->os); _clear_hold(ctx); ret = collect(ctx->lo, 1, 0); /* printf("collect returned %u\n", ret); */ //assert(ret >= sz); if (! (ret >= sz) ) { XPOST_LOG_ERR("Warning: collect returned %d, expected >= %d", ret, sz); } } { Xpost_Object arr; unsigned int pre, post, sz, ret; pre = ctx->lo->used; arr = xpost_array_cons(ctx, 5); xpost_array_put(ctx, arr, 0, xpost_int_cons(12)); xpost_array_put(ctx, arr, 1, xpost_int_cons(13)); xpost_array_put(ctx, arr, 2, xpost_int_cons(14)); xpost_array_put(ctx, arr, 3, xpost_string_cons(ctx, 5, "fubar")); xpost_array_put(ctx, arr, 4, xpost_string_cons(ctx, 4, "buzz")); post = ctx->lo->used; sz = post-pre; xpost_stack_push(ctx->lo, ctx->os, arr); _clear_hold(ctx); ret = collect(ctx->lo, 1, 0); //assert(ret == 0); if (ret != 0) { XPOST_LOG_ERR("Warning: collect returned %d, expected %d", ret, 0); } xpost_stack_pop(ctx->lo, ctx->os); _clear_hold(ctx); ret = collect(ctx->lo, 1, 0); //assert(ret >= sz); if (! (ret >= sz) ) { XPOST_LOG_ERR("Warning: collect returned %d, expected >= %d", ret, sz); } } exit_test_garbage(); return 1; }
/* execute ps program until quit, fall-through to quit, SHOWPAGE_RETURN semantic, or error (default action: message, purge and quit). */ XPAPI int xpost_run(Xpost_Context *ctx, Xpost_Input_Type input_type, const void *inputptr, size_t set_size) { Xpost_Object lsav = null; int llev = 0; unsigned int vs; const char *ps_str = NULL; const char *ps_file = NULL; const FILE *ps_file_ptr = NULL; int ret; Xpost_Object device; Xpost_Object semantic; switch(input_type) { case XPOST_INPUT_FILENAME: ps_file = inputptr; break; case XPOST_INPUT_STRING: ps_str = inputptr; ps_file_ptr = tmpfile(); if (set_size) fwrite(ps_str, 1, set_size, (FILE*)ps_file_ptr); else fwrite(ps_str, 1, strlen(ps_str), (FILE*)ps_file_ptr); rewind((FILE*)ps_file_ptr); break; case XPOST_INPUT_FILEPTR: ps_file_ptr = inputptr; break; case XPOST_INPUT_RESUME: /* resuming a returned session, skip startup */ goto run; } /* prime the exec stack so it starts with a 'start*' procedure, and if it ever gets to the bottom, it quits. These procedures are all defined in data/init.ps */ xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons(ctx, "quit", NULL,0,0)); /* if ps_file is NULL: if stdin is a tty `start` proc defined in init.ps runs `executive` which prompts for user input else 'startstdin' executes stdin but does not prompt if ps_file is not NULL: 'startfile' executes a named file wrapped in a stopped context with handleerror */ if (ps_file) { /*printf("ps_file\n"); */ xpost_stack_push(ctx->lo, ctx->os, xpost_object_cvlit(xpost_string_cons(ctx, strlen(ps_file), ps_file))); xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "startfilename"))); } else if (ps_file_ptr) { xpost_stack_push(ctx->lo, ctx->os, xpost_object_cvlit(xpost_file_cons(ctx->lo, ps_file_ptr))); xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "startfile"))); } else { if (xpost_isatty(fileno(stdin))) xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "start"))); else xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_name_cons(ctx, "startstdin"))); } (void) xpost_save_create_snapshot_object(ctx->gl); lsav = xpost_save_create_snapshot_object(ctx->lo); /* Run! */ run: ctx->quit = 0; ctx->state = C_RUN; ret = mainloop(ctx); semantic = xpost_dict_get(ctx, xpost_stack_bottomup_fetch(ctx->lo, ctx->ds, 0), xpost_name_cons(ctx, "ShowpageSemantics")); if (semantic.int_.val == XPOST_SHOWPAGE_RETURN) return ret == 1 ? yieldtocaller : 0; XPOST_LOG_INFO("destroying device"); device = xpost_dict_get(ctx, xpost_stack_bottomup_fetch(ctx->lo, ctx->ds, 2), xpost_name_cons(ctx, "DEVICE")); XPOST_LOG_INFO("device type=%s", xpost_object_type_names[xpost_object_get_type(device)]); /*xpost_operator_dump(ctx, 1); // is this pointer value constant? */ if (xpost_object_get_type(device) == arraytype){ XPOST_LOG_INFO("running proc"); xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons(ctx, "quit", NULL,0,0)); xpost_stack_push(ctx->lo, ctx->es, device); ctx->quit = 0; mainloop(ctx); device = xpost_stack_pop(ctx->lo, ctx->os); } if (xpost_object_get_type(device) == dicttype) { Xpost_Object Destroy; XPOST_LOG_INFO("destroying device dict"); Destroy = xpost_dict_get(ctx, device, xpost_name_cons(ctx, "Destroy")); if (xpost_object_get_type(Destroy) == operatortype) { int res; xpost_stack_push(ctx->lo, ctx->os, device); res = xpost_operator_exec(ctx, Destroy.mark_.padw); if (res) XPOST_LOG_ERR("%s error destroying device", errorname[res]); else XPOST_LOG_INFO("destroyed device"); } } xpost_save_restore_snapshot(ctx->gl); xpost_memory_table_get_addr(ctx->lo, XPOST_MEMORY_TABLE_SPECIAL_SAVE_STACK, &vs); if (xpost_object_get_type(lsav) == savetype) { for ( llev = xpost_stack_count(ctx->lo, vs); llev > lsav.save_.lev; llev-- ) { xpost_save_restore_snapshot(ctx->lo); } } return noerror; }
/* load init.ps (which also loads err.ps) while systemdict is writeable ignore invalidaccess errors. */ static void loadinitps(Xpost_Context *ctx) { char buf[1024]; char path_init_ps[XPOST_PATH_MAX]; struct stat statbuf; char *path_init; char *path; int n; assert(ctx->gl->base); xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons(ctx, "quit", NULL,0,0)); ctx->ignoreinvalidaccess = 1; #define XPOST_PATH_INIT \ do \ { \ snprintf(path_init_ps, sizeof(path_init_ps), "%s/init.ps", path); \ if (stat(path_init_ps, &statbuf) == 0) \ { \ path_init = path; \ goto load_init_ps; \ } \ else \ XPOST_LOG_DBG("init.ps not present in", path_init_ps); \ } while (0) /* environment variable XPOST_DATA_DIR */ if ((path = getenv("XPOST_DATA_DIR"))) XPOST_PATH_INIT; /* directory of the shared library */ path = (char *)xpost_data_dir_get(); /* always well-defined */ XPOST_PATH_INIT; #ifdef PACKAGE_DATA_DIR { static char x[] = PACKAGE_DATA_DIR; path = x; } XPOST_PATH_INIT; #endif XPOST_LOG_ERR("init.ps can not be found"); return; load_init_ps: /* backslashes are not supported in path because they are inserted in * PostScript files, and PostScript */ #ifdef _WIN32 path = path_init_ps; while (*path++) if (*path == '\\') *path = '/'; path = path_init; while (*path++) if (*path == '\\') *path = '/'; #endif n = snprintf(buf, sizeof(buf), "(%s) (r) file cvx " "/DATA_DIR (%s) def exec ", path_init_ps, path_init); xpost_stack_push(ctx->lo, ctx->es, xpost_object_cvx(xpost_string_cons(ctx, n, buf))); ctx->quit = 0; mainloop(ctx); ctx->ignoreinvalidaccess = 0; }
/* create an executable context using the given device, output configuration, and semantics. */ XPAPI Xpost_Context *xpost_create(const char *device, Xpost_Output_Type output_type, const void *outputptr, Xpost_Showpage_Semantics semantics, Xpost_Output_Message output_msg, Xpost_Set_Size set_size, int width, int height) { Xpost_Object sd, ud; int ret; const char *outfile = NULL; const char *bufferin = NULL; char **bufferout = NULL; int quiet; switch (output_msg) { case XPOST_OUTPUT_MESSAGE_QUIET: quiet = 1; _xpost_interpreter_is_tracing = 0; break; case XPOST_OUTPUT_MESSAGE_VERBOSE: quiet = 0; _xpost_interpreter_is_tracing = 0; break; case XPOST_OUTPUT_MESSAGE_TRACING: quiet = 0; _xpost_interpreter_is_tracing = 1; break; default: XPOST_LOG_ERR("Wrong output message value"); return NULL;; } switch (output_type) { case XPOST_OUTPUT_FILENAME: outfile = outputptr; break; case XPOST_OUTPUT_BUFFERIN: bufferin = outputptr; break; case XPOST_OUTPUT_BUFFEROUT: bufferout = (char **)outputptr; break; case XPOST_OUTPUT_DEFAULT: break; } #if 0 test_memory(); if (!test_garbage_collect(xpost_interpreter_cid_init, xpost_interpreter_cid_get_context, xpost_interpreter_get_initializing, xpost_interpreter_set_initializing, xpost_interpreter_alloc_local_memory, xpost_interpreter_alloc_global_memory)) return NULL; #endif nextid = 0; /*reset process counter */ /* Allocate and initialize all interpreter data structures. */ ret = initalldata(device); if (!ret) { return NULL; } /* extract systemdict and userdict for additional definitions */ sd = xpost_stack_bottomup_fetch(xpost_ctx->lo, xpost_ctx->ds, 0); ud = xpost_stack_bottomup_fetch(xpost_ctx->lo, xpost_ctx->ds, 2); setlocalconfig(xpost_ctx, sd, device, outfile, bufferin, bufferout, semantics, set_size, width, height); if (quiet) { xpost_dict_put(xpost_ctx, sd /*xpost_stack_bottomup_fetch(ctx->lo, ctx->ds, 0)*/ , xpost_name_cons(xpost_ctx, "QUIET"), null); } xpost_stack_clear(xpost_ctx->lo, xpost_ctx->hold); xpost_interpreter_set_initializing(0); loadinitps(xpost_ctx); ret = copyudtosd(xpost_ctx, ud, sd); if (ret) { XPOST_LOG_ERR("%s error in copyudtosd", errorname[ret]); return NULL; } /* make systemdict readonly FIXME: use new access semantics */ xpost_dict_put(xpost_ctx, sd, xpost_name_cons(xpost_ctx, "systemdict"), sd); xpost_object_set_access(xpost_ctx, sd, XPOST_OBJECT_TAG_ACCESS_READ_ONLY); #if 0 if (!xpost_stack_bottomup_replace(xpost_ctx->lo, xpost_ctx->ds, 0, xpost_object_set_access(xpost_ctx, sd, XPOST_OBJECT_TAG_ACCESS_READ_ONLY))) { XPOST_LOG_ERR("cannot replace systemdict in dict stack"); return NULL; } #endif xpost_interpreter_set_initializing(0); return xpost_ctx; }
/* initialize the name special entities XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK, NAME_TREE */ int xpost_name_init(Xpost_Context *ctx) { Xpost_Memory_Table *tab; unsigned int ent; unsigned int t; unsigned int mode; unsigned int nstk; int ret; mode = ctx->vmmode; ctx->vmmode = GLOBAL; ret = xpost_memory_table_alloc(ctx->gl, 0, 0, &ent); //gl:NAMES if (!ret) { return 0; } //assert(ent == XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK); if (ent != XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK) XPOST_LOG_ERR("Warning: name stack is not in special position"); ret = xpost_memory_table_alloc(ctx->gl, 0, 0, &ent); //gl:NAMET if (!ret) { return 0; } //assert(ent == XPOST_MEMORY_TABLE_SPECIAL_NAME_TREE); if (ent != XPOST_MEMORY_TABLE_SPECIAL_NAME_TREE) XPOST_LOG_ERR("Warning: name tree is not in special position"); xpost_stack_init(ctx->gl, &t); tab = &ctx->gl->table; //recalc pointer tab->tab[XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK].adr = t; tab->tab[XPOST_MEMORY_TABLE_SPECIAL_NAME_TREE].adr = 0; xpost_memory_table_get_addr(ctx->gl, XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK, &nstk); xpost_stack_push(ctx->gl, nstk, xpost_string_cons(ctx, CNT_STR("_not_a_name_"))); assert (xpost_object_get_ent(xpost_stack_topdown_fetch(ctx->gl, nstk, 0)) == XPOST_MEMORY_TABLE_SPECIAL_BOGUS_NAME); ctx->vmmode = LOCAL; ret = xpost_memory_table_alloc(ctx->lo, 0, 0, &ent); //lo:NAMES if (!ret) { return 0; } //assert(ent == XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK); if (ent != XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK) XPOST_LOG_ERR("Warning: name stack is not in special position"); ret = xpost_memory_table_alloc(ctx->lo, 0, 0, &ent); //lo:NAMET if (!ret) { return 0; } //assert(ent == XPOST_MEMORY_TABLE_SPECIAL_NAME_TREE); if (ent != XPOST_MEMORY_TABLE_SPECIAL_NAME_TREE) XPOST_LOG_ERR("Warning: name tree is not in special position"); xpost_stack_init(ctx->lo, &t); tab = &ctx->lo->table; //recalc pointer tab->tab[XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK].adr = t; tab->tab[XPOST_MEMORY_TABLE_SPECIAL_NAME_TREE].adr = 0; xpost_memory_table_get_addr(ctx->lo, XPOST_MEMORY_TABLE_SPECIAL_NAME_STACK, &nstk); xpost_stack_push(ctx->lo, nstk, xpost_string_cons(ctx, CNT_STR("_not_a_name_"))); //assert (xpost_object_get_ent(xpost_stack_topdown_fetch(ctx->lo, nstk, 0)) == XPOST_MEMORY_TABLE_SPECIAL_BOGUS_NAME); if (xpost_object_get_ent(xpost_stack_topdown_fetch(ctx->lo, nstk, 0)) != XPOST_MEMORY_TABLE_SPECIAL_BOGUS_NAME) XPOST_LOG_ERR("Warning: bogus name not in special position"); ctx->vmmode = mode; return 1; }
/* any string cvs string convert any object to string representation */ static int AScvs (Xpost_Context *ctx, Xpost_Object any, Xpost_Object str) { char nostringval[] = "-nostringval-"; char strue[] = "true"; char sfalse[] = "false"; char smark[] = "-mark-"; char ssave[] = "-save-"; int n; int ret; switch(xpost_object_get_type(any)) { default: if (str.comp_.sz < sizeof(nostringval)-1) return rangecheck; memcpy(xpost_string_get_pointer(ctx, str), nostringval, sizeof(nostringval)-1); str.comp_.sz = sizeof(nostringval)-1; break; case savetype: if (str.comp_.sz < sizeof(ssave)-1) return rangecheck; memcpy(xpost_string_get_pointer(ctx, str), ssave, sizeof(ssave)-1); str.comp_.sz = sizeof(ssave)-1; break; case marktype: if (str.comp_.sz < sizeof(smark)-1) return rangecheck; memcpy(xpost_string_get_pointer(ctx, str), smark, sizeof(smark)-1); str.comp_.sz = sizeof(smark)-1; break; case booleantype: { if (any.int_.val) { if (str.comp_.sz < sizeof(strue)-1) return rangecheck; memcpy(xpost_string_get_pointer(ctx, str), strue, sizeof(strue)-1); str.comp_.sz = sizeof(strue)-1; } else { if (str.comp_.sz < sizeof(sfalse)-1) return rangecheck; memcpy(xpost_string_get_pointer(ctx, str), sfalse, sizeof(sfalse)-1); str.comp_.sz = sizeof(sfalse)-1; } } break; case integertype: { //n = conv_rad(any.int_.val, 10, xpost_string_get_pointer(ctx, str), str.comp_.sz); char *s = xpost_string_get_pointer(ctx, str); int sz = str.comp_.sz; n = 0; if (any.int_.val < 0) { s[n++] = '-'; any.int_.val = abs(any.int_.val); --sz; } n += conv_integ((real)any.int_.val, s + n, sz); if (n == -1) return rangecheck; if (n < str.comp_.sz) str.comp_.sz = n; break; } case realtype: n = conv_real(any.real_.val, xpost_string_get_pointer(ctx, str), str.comp_.sz); if (n == -1) return rangecheck; if (n < str.comp_.sz) str.comp_.sz = n; break; case operatortype: { unsigned int optadr; Xpost_Operator *optab; Xpost_Operator op; Xpost_Object_Mark nm; ret = xpost_memory_table_get_addr(ctx->gl, XPOST_MEMORY_TABLE_SPECIAL_OPERATOR_TABLE, &optadr); if (!ret) { XPOST_LOG_ERR("cannot load optab!"); return VMerror; } optab = (void *)(ctx->gl->base + optadr); op = optab[any.mark_.padw]; nm.tag = nametype | XPOST_OBJECT_TAG_DATA_FLAG_BANK; nm.pad0 = 0; nm.padw = op.name; any.mark_ = nm; } /*@fallthrough@*/ case nametype: any = xpost_name_get_string(ctx, any); /*@fallthrough@*/ case stringtype: if (any.comp_.sz > str.comp_.sz) return rangecheck; if (any.comp_.sz < str.comp_.sz) str.comp_.sz = any.comp_.sz; memcpy(xpost_string_get_pointer(ctx, str), xpost_string_get_pointer(ctx, any), any.comp_.sz); break; } xpost_stack_push(ctx->lo, ctx->os, str); return 0; }