Exemplo n.º 1
0
/*
 * Allocate a path on the heap, and initialize it.  If shared is NULL,
 * allocate a segments object; if shared is an existing path, share its
 * segments.
 */
gx_path *
gx_path_alloc_shared(const gx_path * shared, gs_memory_t * mem,
                     client_name_t cname)
{
    gx_path *ppath = gs_alloc_struct(mem, gx_path, &st_path, cname);

    if (ppath == 0)
        return 0;
    ppath->procs = &default_path_procs;
    if (shared) {
        if (shared->segments == &shared->local_segments) {
            lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
                     (ulong) shared);
            gs_free_object(mem, ppath, cname);
            return 0;
        }
        *ppath = *shared;
        rc_increment(ppath->segments);
    } else {
        int code = path_alloc_segments(&ppath->segments, mem, cname);

        if (code < 0) {
            gs_free_object(mem, ppath, cname);
            return 0;
        }
        gx_path_init_contents(ppath);
    }
    ppath->memory = mem;
    ppath->allocation = path_allocated_on_heap;
    return ppath;
}
Exemplo n.º 2
0
/* See gdevpdfx.h for why this is needed. */
const char *
pprintg1(stream * s, const char *format, floatp v)
{
    const char *fp = pprintf_scan(s, format);
    char dot, str[150];

#ifdef DEBUG
    if (*fp == 0 || fp[1] != 'g')	/* shouldn't happen! */
	lprintf1("Bad format in pprintg: %s\n", format);
#endif
    sprintf(str, "%f", 1.5);
    dot = str[1]; /* locale-dependent */
    sprintf(str, "%g", v);
    if (strchr(str, 'e')) {
	/* Bad news.  Try again using f-format. */
	sprintf(str, (fabs(v) > 1 ? "%1.1f" : "%1.8f"), v);
    }
    /* Juggling locales isn't thread-safe. Posix me harder. */
    if (dot != '.') {
        char *pdot = strchr(str, dot); 
        if (pdot)
            *pdot = '.';
    }
    pputs_short(s, str);
    return pprintf_scan(s, fp + 2);
}
Exemplo n.º 3
0
static int
test4(gs_state * pgs, gs_memory_t * mem)
{
    gs_c_param_list list;
    float resv[2];
    gs_param_float_array ares;
    int code;
    gx_device *dev = gs_currentdevice(pgs);

    gs_c_param_list_write(&list, mem);
    resv[0] = resv[1] = 100;
    ares.data = resv;
    ares.size = 2;
    ares.persistent = true;
    code = param_write_float_array((gs_param_list *) & list,
                                   "HWResolution", &ares);
    if (code < 0) {
        lprintf1("Writing HWResolution failed: %d\n", code);
        gs_abort(mem);
    }
    gs_c_param_list_read(&list);
    code = gs_putdeviceparams(dev, (gs_param_list *) & list);
    gs_c_param_list_release(&list);
    if (code < 0) {
        lprintf1("Setting HWResolution failed: %d\n", code);
        gs_abort(mem);
    }
    gs_initmatrix(pgs);
    gs_initclip(pgs);
    if (code == 1) {
        code = (*dev_proc(dev, open_device)) (dev);
        if (code < 0) {
            lprintf1("Reopening device failed: %d\n", code);
            gs_abort(mem);
        }
    }
    gs_moveto(pgs, 0.0, 72.0);
    gs_rlineto(pgs, 72.0, 0.0);
    gs_rlineto(pgs, 0.0, 72.0);
    gs_closepath(pgs);
    gs_stroke(pgs);
    return 0;
}
Exemplo n.º 4
0
/* Print (a) string(s) using a format. */
const char *
pprints1(stream * s, const char *format, const char *str)
{
    const char *fp = pprintf_scan(s, format);

#ifdef DEBUG
    if (*fp == 0 || fp[1] != 's')	/* shouldn't happen! */
	lprintf1("Bad format in pprints: %s\n", format);
#endif
    pputs_short(s, str);
    return pprintf_scan(s, fp + 2);
}
Exemplo n.º 5
0
/* Print (an) int value(s) using a format. */
const char *
pprintd1(stream * s, const char *format, int v)
{
    const char *fp = pprintf_scan(s, format);
    char str[25];

#ifdef DEBUG
    if (*fp == 0 || fp[1] != 'd')	/* shouldn't happen! */
	lprintf1("Bad format in pprintd1: %s\n", format);
#endif
    sprintf(str, "%d", v);
    pputs_short(s, str);
    return pprintf_scan(s, fp + 2);
}
Exemplo n.º 6
0
static void
jpeg_free(j_common_ptr cinfo, void *data, const char *info)
{
    jpeg_compress_data *jcd = cinfo2jcd(cinfo);
    gs_memory_t *mem = jcd->memory;
    jpeg_block_t  *p  =  jcd->blocks;
    jpeg_block_t **pp = &jcd->blocks;

    gs_free_object(mem, data, info);
    while(p && p->data != data)
      { pp = &p->next;
        p = p->next;
      }
    if(p == 0)
      lprintf1("Freeing unrecorded JPEG data 0x%lx!\n", (ulong)data);
    else
      *pp = p->next;
    gs_free_object(mem, p, "jpeg_free(block)");
}
Exemplo n.º 7
0
/* otherwise, return the element type. */
int
gx_path_enum_next(gs_path_enum * penum, gs_fixed_point ppts[3])
{
    const segment *pseg = penum->pseg;

    if (pseg == 0) {		/* We've enumerated all the segments, but there might be */
	/* a trailing moveto. */
	const gx_path *ppath = penum->path;

	if (path_last_is_moveto(ppath) && !penum->moveto_done) {	/* Handle a trailing moveto */
	    penum->moveto_done = true;
	    penum->notes = sn_none;
	    ppts[0] = ppath->position;
	    return gs_pe_moveto;
	}
	return 0;
    }
    penum->pseg = pseg->next;
    penum->notes = pseg->notes;
    switch (pseg->type) {
	case s_start:
	    ppts[0] = pseg->pt;
	    return gs_pe_moveto;
	case s_line:
	    ppts[0] = pseg->pt;
	    return gs_pe_lineto;
	case s_line_close:
	    ppts[0] = pseg->pt;
	    return gs_pe_closepath;
	case s_curve:
#define pcseg ((const curve_segment *)pseg)
	    ppts[0] = pcseg->p1;
	    ppts[1] = pcseg->p2;
	    ppts[2] = pseg->pt;
	    return gs_pe_curveto;
#undef pcseg
	default:
	    lprintf1("bad type %x in gx_path_enum_next!\n", pseg->type);
	    return_error(gs_error_Fatal);
    }
}
Exemplo n.º 8
0
/*
 * Initialize a stack-allocated path.  This doesn't allocate anything,
 * but may still share the segments.
 */
int
gx_path_init_local_shared(gx_path * ppath, const gx_path * shared,
                          gs_memory_t * mem)
{
    if (shared) {
        if (shared->segments == &shared->local_segments) {
            lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
                     (ulong) shared);
            return_error(gs_error_Fatal);
        }
        *ppath = *shared;
        rc_increment(ppath->segments);
    } else {
        rc_init_free(&ppath->local_segments, mem, 1,
                     rc_free_path_segments_local);
        ppath->segments = &ppath->local_segments;
        gx_path_init_contents(ppath);
    }
    ppath->memory = mem;
    ppath->allocation = path_allocated_on_stack;
    ppath->procs = &default_path_procs;
    return 0;
}
Exemplo n.º 9
0
int
gx_path_init_contained_shared(gx_path * ppath, const gx_path * shared,
                              gs_memory_t * mem, client_name_t cname)
{
    if (shared) {
        if (shared->segments == &shared->local_segments) {
            lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
                     (ulong) shared);
            return_error(gs_error_Fatal);
        }
        *ppath = *shared;
        rc_increment(ppath->segments);
    } else {
        int code = path_alloc_segments(&ppath->segments, mem, cname);

        if (code < 0)
            return code;
        gx_path_init_contents(ppath);
    }
    ppath->memory = mem;
    ppath->allocation = path_allocated_contained;
    ppath->procs = &default_path_procs;
    return 0;
}
Exemplo n.º 10
0
void
s_zlib_free(void *zmem, void *data)
{
    zlib_dynamic_state_t *const zds = zmem;
    gs_memory_t *mem = zds->memory->stable_memory;
    zlib_block_t *block = zds->blocks;

    gs_free_object(mem, data, "s_zlib_free(data)");
    for (; ; block = block->next) {
        if (block == 0) {
            lprintf1("Freeing unrecorded data 0x%lx!\n", (ulong)data);
            return;
        }
        if (block->data == data)
            break;
    }
    if (block->next)
        block->next->prev = block->prev;
    if (block->prev)
        block->prev->next = block->next;
    else
        zds->blocks = block->next;
    gs_free_object(mem, block, "s_zlib_free(block)");
}
Exemplo n.º 11
0
/* Initialize the operator table. */
int
op_init(i_ctx_t *i_ctx_p)
{
    const op_def *const *tptr;
    int code;

    /* Enter each operator into the appropriate dictionary. */

    for (tptr = op_defs_all; *tptr != 0; tptr++) {
	ref *pdict = systemdict;
	const op_def *def;
	const char *nstr;

	for (def = *tptr; (nstr = def->oname) != 0; def++)
	    if (op_def_is_begin_dict(def)) {
		ref nref;

		code = name_ref(imemory, (const byte *)nstr, strlen(nstr), &nref, -1);
		if (code < 0)
		    return code;
		if (!dict_find(systemdict, &nref, &pdict))
		    return_error(e_Fatal);
		if (!r_has_type(pdict, t_dictionary))
		    return_error(e_Fatal);
	    } else {
		ref oper;
		uint index_in_table = def - *tptr;
		uint opidx = (tptr - op_defs_all) * OP_DEFS_MAX_SIZE +
		    index_in_table;

		if (index_in_table >= OP_DEFS_MAX_SIZE) {
		    lprintf1("opdef overrun! %s\n", def->oname);
		    return_error(e_Fatal);
		}
		gs_interp_make_oper(&oper, def->proc, opidx);
		/* The first character of the name is a digit */
		/* giving the minimum acceptable number of operands. */
		/* Check to make sure it's within bounds. */
		if (*nstr - '0' > gs_interp_max_op_num_args)
		    return_error(e_Fatal);
		nstr++;
		/*
		 * Skip internal operators, and the second occurrence of
		 * operators with special indices.
		 */
		if (*nstr != '%' && r_size(&oper) == opidx) {
		    code =
			i_initial_enter_name_in(i_ctx_p, pdict, nstr, &oper);
		    if (code < 0)
			return code;
		}
	    }
    }
    /* Allocate the tables for `operator' procedures. */
    /* Make one of them local so we can have local operators. */

    if ((code = alloc_op_array_table(i_ctx_p, OP_ARRAY_TABLE_GLOBAL_SIZE,
				     avm_global, &op_array_table_global) < 0))
	return code;
    op_array_table_global.base_index = op_def_count;
    if ((code = gs_register_ref_root(imemory, NULL,
				     (void **)&op_array_table_global.root_p,
				     "op_array_table(global)")) < 0 ||
	(code = gs_register_struct_root(imemory, NULL,
				(void **)&op_array_table_global.nx_table,
					"op_array nx_table(global)")) < 0 ||
	(code = alloc_op_array_table(i_ctx_p, OP_ARRAY_TABLE_LOCAL_SIZE,
				     avm_local, &op_array_table_local) < 0)
	)
	return code;
    op_array_table_local.base_index =
	op_array_table_global.base_index +
	r_size(&op_array_table_global.table);
    if ((code = gs_register_ref_root(imemory, NULL,
				     (void **)&op_array_table_local.root_p,
				     "op_array_table(local)")) < 0 ||
	(code = gs_register_struct_root(imemory, NULL,
				(void **)&op_array_table_local.nx_table,
					"op_array nx_table(local)")) < 0
	)
	return code;

    return 0;
}
Exemplo n.º 12
0
static int
test10(gs_state * pgs, gs_memory_t * mem)
{
    gs_c_param_list list;
    gs_param_string nstr, OFstr;
    gs_param_float_array PSa;
    gs_param_float_array HWRa;
    gs_param_int_array HWSa;
    int HWSize[2];
    float HWResolution[2], PageSize[2];
    long MaxBitmap;
    int code;
    gx_device *dev = gs_currentdevice(pgs);
    float xlate_x, xlate_y;
    gs_rect cliprect;

    gs_c_param_list_write(&list, mem);
    code = gs_getdeviceparams(dev, (gs_param_list *) & list);
    if (code < 0) {
        lprintf1("getdeviceparams failed! code = %d\n", code);
        gs_abort(mem);
    }
    gs_c_param_list_read(&list);
    code = param_read_string((gs_param_list *) & list, "Name", &nstr);
    if (code < 0) {
        lprintf1("reading Name failed! code = %d\n", code);
        gs_abort(mem);
    }
    code = param_read_int_array((gs_param_list *) & list,
                                "HWSize", &HWSa);
    if (code < 0) {
        lprintf1("reading HWSize failed! code = %d\n", code);
        gs_abort(mem);
    }
    emprintf3(mem, "HWSize[%d] = [ %d, %d ]\n", HWSa.size,
              HWSa.data[0], HWSa.data[1]);
    code = param_read_float_array((gs_param_list *) & list,
                                  "HWResolution", &HWRa);
    if (code < 0) {
        lprintf1("reading Resolution failed! code = %d\n", code);
        gs_abort(mem);
    }
    emprintf3(mem, "HWResolution[%d] = [ %f, %f ]\n", HWRa.size,
              HWRa.data[0], HWRa.data[1]);
    code = param_read_float_array((gs_param_list *) & list,
                                  "PageSize", &PSa);
    if (code < 0) {
        lprintf1("reading PageSize failed! code = %d\n", code);
        gs_abort(mem);
    }
    emprintf3(mem, "PageSize[%d] = [ %f, %f ]\n", PSa.size,
              PSa.data[0], PSa.data[1]);
    code = param_read_long((gs_param_list *) & list,
                           "MaxBitmap", &MaxBitmap);
    if (code < 0) {
        lprintf1("reading MaxBitmap failed! code = %d\n", code);
        gs_abort(mem);
    }
    emprintf1(mem, "MaxBitmap = %ld\n", MaxBitmap);
    /* Switch to param list functions to "write" */
    gs_c_param_list_write(&list, mem);
    /* Always set the PageSize. */
    PageSize[0] = 72.0 * ypage_wid;
    PageSize[1] = 72.0 * xpage_len;
    PSa.data = PageSize;
    code = param_write_float_array((gs_param_list *) & list,
                                   "PageSize", &PSa);
    if (nstr.data[0] != 'v') {
        /* Set the OutputFile string file name */
        OFstr.persistent = false;
        OFstr.data = outfile;
        OFstr.size = strlen(outfile);
        code = param_write_string((gs_param_list *) & list,
                                  "OutputFile", &OFstr);
        if (code < 0) {
            lprintf1("setting OutputFile name failed, code=%d\n",
                     code);
            gs_abort(mem);
        }
        if (nstr.data[0] == 'x') {
            HWResolution[0] = HWResolution[1] = 72.0;
        } else {
            HWResolution[0] = HWResolution[1] = 360.0;
        }
        HWRa.data = HWResolution;
        HWSize[0] = (int)(HWResolution[0] * ypage_wid);
        HWSize[1] = (int)(HWResolution[1] * xpage_len);
        emprintf3(mem, "\tHWSize = [%d,%d], HWResolution = %f dpi\n",
                  HWSize[0], HWSize[1], HWResolution[0]);
        HWSa.data = HWSize;
        code = param_write_float_array((gs_param_list *) & list,
                                       "HWResolution", &HWRa);
        code = param_write_int_array((gs_param_list *) & list,
                                     "HWSize", &HWSa);
        MaxBitmap = 1000000L;
        code = param_write_long((gs_param_list *) & list,
                                "MaxBitmap", &MaxBitmap);
    }
    gs_c_param_list_read(&list);
    code = gs_putdeviceparams(dev, (gs_param_list *) & list);
    emprintf1(mem, "putdeviceparams: code=%d\n", code);
    gs_c_param_list_release(&list);

    /* note: initgraphics no longer resets the color or color space */
    gs_erasepage(pgs);
    gs_initgraphics(pgs);
    {
        gs_color_space *cs = gs_cspace_new_DeviceGray(mem);
        gs_setcolorspace(pgs, cs);
        gs_setcolorspace(pgs, cs);
        gs_decrement(cs, "test10 DeviceGray");
    }

    gs_clippath(pgs);
    gs_pathbbox(pgs, &cliprect);
    emprintf4(mem, "\tcliprect = [[%g,%g],[%g,%g]]\n",
              cliprect.p.x, cliprect.p.y, cliprect.q.x, cliprect.q.y);
    gs_newpath(pgs);

    switch (((rotate_value + 270) / 90) & 3) {
        default:
        case 0:		/* 0 = 360 degrees in PS == 90 degrees in printer */
            xlate_x = cliprect.p.x;
            xlate_y = cliprect.p.y;
            break;
        case 1:		/* 90 degrees in PS = 180 degrees printer */
            xlate_x = cliprect.q.x;
            xlate_y = cliprect.p.y;
            break;
        case 2:		/* 180 degrees in PS == 270 degrees in printer */
            xlate_x = cliprect.q.x;
            xlate_y = cliprect.q.y;
            break;
        case 3:		/* 270 degrees in PS == 0 degrees in printer */
            xlate_x = cliprect.p.x;
            xlate_y = cliprect.q.y;
            break;
    }
    emprintf2(mem, "translate origin to [ %f, %f ]\n", xlate_x, xlate_y);
    gs_translate(pgs, xlate_x, xlate_y);

    /* further move (before rotate) by user requested amount */
    gs_translate(pgs, 72.0 * (float)xmove_origin, 72.0 * (float)ymove_origin);

    gs_rotate(pgs, (float)rotate_value + 270.0);
    gs_scale(pgs, scale_x * 72.0 / 2032.0,
             scale_y * 72.0 / 2032.0);
    gs_setlinecap(pgs, gs_cap_butt);
    gs_setlinejoin(pgs, gs_join_bevel);
    gs_setfilladjust(pgs, 0.0, 0.0);

    capture_exec(pgs);
    return 0;
}
Exemplo n.º 13
0
int
main(int argc, const char *argv[])
{
    char achar = '0';
    gs_memory_t *mem;

    gs_state *pgs;
    const gx_device *const *list;
    gx_device *dev;
    gx_device_bbox *bbdev;
    int code;

    gp_init();
    mem = gs_malloc_init();
    gs_lib_init1(mem);
    if (argc < 2 || (achar = argv[1][0]) < '1' ||
        achar > '0' + countof(tests) - 1
        ) {
        lprintf1("Usage: gslib 1..%c\n", '0' + (char)countof(tests) - 1);
        gs_abort(mem);
    }
    gs_debug['@'] = 1;
    gs_debug['?'] = 1;
/*gs_debug['B'] = 1; *//****** PATCH ******/
/*gs_debug['L'] = 1; *//****** PATCH ******/
    /*
     * gs_iodev_init must be called after the rest of the inits, for
     * obscure reasons that really should be documented!
     */
    gs_iodev_init(mem);
/****** WRONG ******/
    gs_lib_device_list(&list, NULL);
    gs_copydevice(&dev, list[0], mem);
    check_device_separable(dev);
    gx_device_fill_in_procs(dev);
    bbdev =
        gs_alloc_struct_immovable(mem, gx_device_bbox, &st_device_bbox,
                                  "bbox");
    gx_device_bbox_init(bbdev, dev, mem);

    code = dev_proc(dev, get_profile)(dev, &bbdev->icc_struct);
    rc_increment(bbdev->icc_struct);

    /* Print out the device name just to test the gsparam.c API. */
    {
        gs_c_param_list list;
        gs_param_string nstr;

        gs_c_param_list_write(&list, mem);
        code = gs_getdeviceparams(dev, (gs_param_list *) & list);
        if (code < 0) {
            lprintf1("getdeviceparams failed! code = %d\n", code);
            gs_abort(mem);
        }
        gs_c_param_list_read(&list);
        code = param_read_string((gs_param_list *) & list, "Name", &nstr);
        if (code < 0) {
            lprintf1("reading Name failed! code = %d\n", code);
            gs_abort(mem);
        }
        dputs("Device name = ");
        debug_print_string(nstr.data, nstr.size);
        dputs("\n");
        gs_c_param_list_release(&list);
    }
    /*
     * If this is a device that takes an OutputFile, set the OutputFile
     * to "-" in the copy.
     */
    {
        gs_c_param_list list;
        gs_param_string nstr;

        gs_c_param_list_write(&list, mem);
        param_string_from_string(nstr, "-");
        code = param_write_string((gs_param_list *)&list, "OutputFile", &nstr);
        if (code < 0) {
            lprintf1("writing OutputFile failed! code = %d\n", code);
            gs_abort(mem);
        }
        gs_c_param_list_read(&list);
        code = gs_putdeviceparams(dev, (gs_param_list *)&list);
        gs_c_param_list_release(&list);
        if (code < 0 && code != gs_error_undefined) {
            lprintf1("putdeviceparams failed! code = %d\n", code);
            gs_abort(mem);
        }
    }
    dev = (gx_device *) bbdev;
    pgs = gs_state_alloc(mem);
    gs_setdevice_no_erase(pgs, dev);	/* can't erase yet */
    {
        gs_point dpi;
        gs_screen_halftone ht;

        gs_dtransform(pgs, 72.0, 72.0, &dpi);
        ht.frequency = min(fabs(dpi.x), fabs(dpi.y)) / 16.001;
        ht.angle = 0;
        ht.spot_function = odsf;
        gs_setscreen(pgs, &ht);
    }
    /* gsave and grestore (among other places) assume that */
    /* there are at least 2 gstates on the graphics stack. */
    /* Ensure that now. */
    gs_gsave(pgs);
    gs_erasepage(pgs);

    code = (*tests[achar - '1']) (pgs, mem);
    gs_output_page(pgs, 1, 1);
    {
        gs_rect bbox;

        gx_device_bbox_bbox(bbdev, &bbox);
        dprintf4("Bounding box: [%g %g %g %g]\n",
                 bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
    }
    if (code)
        dprintf1("**** Test returned code = %d.\n", code);
    dputs("Done.  Press <enter> to exit.");
    fgetc(mem->gs_lib_ctx->fstdin);
    gs_lib_finit(0, 0, mem);
    return 0;
#undef mem
}
Exemplo n.º 14
0
/* Remove an element from a dictionary. */
int
dict_undef(ref * pdref, const ref * pkey, dict_stack_t *pds)
{
    gs_ref_memory_t *mem;
    ref *pvslot;
    dict *pdict;
    uint index;
    int code = dict_find(pdref, pkey, &pvslot);

    switch (code) {
    case 0:
    case gs_error_dictfull:
        return_error(gs_error_undefined);
    case 1:
        break;
    default:			/* other error */
        return code;
    }
    /* Remove the entry from the dictionary. */
    pdict = pdref->value.pdict;
    index = pvslot - pdict->values.value.refs;
    mem = dict_memory(pdict);
    if (dict_is_packed(pdict)) {
        ref_packed *pkp = pdict->keys.value.writable_packed + index;
        bool must_save = ref_must_save_in(mem, &pdict->keys);

        if_debug3m('d', (const gs_memory_t *)mem,
                   "[d]0x%lx: removing key at 0%lx: 0x%x\n",
                   (ulong)pdict, (ulong)pkp, (uint)*pkp);
        /* See the initial comment for why it is safe not to save */
        /* the change if the keys array itself is new. */
        if (must_save)
            ref_do_save_in(mem, &pdict->keys, pkp, "dict_undef(key)");
        /*
         * Accumulating deleted entries slows down lookup.
         * Detect the easy case where we can use an empty entry
         * rather than a deleted one, namely, when the next entry
         * in the probe order is empty.
         */
        if (pkp[-1] == packed_key_empty) {
            /*
             * In this case we can replace any preceding deleted keys with
             * empty ones as well.
             */
            uint end = nslots(pdict);

            *pkp = packed_key_empty;
            if (must_save) {
                while (++index < end && *++pkp == packed_key_deleted) {
                    ref_do_save_in(mem, &pdict->keys, pkp, "dict_undef(key)");
                    *pkp = packed_key_empty;
                }
            } else {
                while (++index < end && *++pkp == packed_key_deleted)
                    *pkp = packed_key_empty;
            }
        } else
            *pkp = packed_key_deleted;
    } else {			/* not packed */
        ref *kp = pdict->keys.value.refs + index;

        if_debug4m('d', (const gs_memory_t *)mem,
                   "[d]0x%lx: removing key at 0%lx: 0x%lx 0x%lx\n",
                   (ulong)pdict, (ulong)kp, ((ulong *)kp)[0], ((ulong *)kp)[1]);
        make_null_old_in(mem, &pdict->keys, kp, "dict_undef(key)");
        /*
         * Accumulating deleted entries slows down lookup.
         * Detect the easy case where we can use an empty entry
         * rather than a deleted one, namely, when the next entry
         * in the probe order is empty.
         */
        if (!r_has_type(kp - 1, t_null) ||	/* full entry */
            r_has_attr(kp - 1, a_executable)	/* deleted or wraparound */
            )
            r_set_attrs(kp, a_executable);	/* mark as deleted */
    }
    ref_save_in(mem, pdref, &pdict->count, "dict_undef(count)");
    pdict->count.value.intval--;
    /* If the key is a name, update its 1-element cache. */
    if (r_has_type(pkey, t_name)) {
        name *pname = pkey->value.pname;

        if (pv_valid(pname->pvalue)) {
#ifdef DEBUG
            /* Check the the cache is correct. */
            if (!(pds && dstack_dict_is_permanent(pds, pdref)))
                lprintf1("dict_undef: cached name value pointer 0x%lx is incorrect!\n",
                         (ulong) pname->pvalue);
#endif
            /* Clear the cache */
            pname->pvalue = pv_no_defn;
        }
    }
    make_null_old_in(mem, &pdict->values, pvslot, "dict_undef(value)");
    return 0;
}