Beispiel #1
0
/* 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;
}
Beispiel #2
0
/*
   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;
}
Beispiel #3
0
/* 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;
Beispiel #4
0
/* 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;
}
Beispiel #5
0
/* 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;
}
Beispiel #6
0
/* 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;
}
Beispiel #7
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;
}
Beispiel #8
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); */
}
Beispiel #9
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;
}
Beispiel #10
0
/* 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;
}
Beispiel #11
0
/* 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;
}
Beispiel #12
0
/* 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;
}
Beispiel #13
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;
}
Beispiel #14
0
/* 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;
}
Beispiel #15
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;
}
Beispiel #16
0
/* 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;
}
Beispiel #17
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;
}
Beispiel #18
0
/* 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;
}
Beispiel #19
0
/* 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;
}
Beispiel #20
0
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;
}
Beispiel #21
0
/*
   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;
}
Beispiel #22
0
/*
   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;
}
Beispiel #23
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;
}
Beispiel #24
0
/* 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;
}
Beispiel #25
0
/* 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;
}