~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to psi/iname.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
 
2
   All Rights Reserved.
 
3
  
 
4
   This software is provided AS-IS with no warranty, either express or
 
5
   implied.
 
6
 
 
7
   This software is distributed under license and may not be copied, modified
 
8
   or distributed except as expressly authorized under the terms of that
 
9
   license.  Refer to licensing information at http://www.artifex.com/
 
10
   or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
 
11
   San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
 
12
*/
 
13
 
 
14
/* $Id: iname.c 9179 2008-10-21 16:26:09Z leonardo $ */
 
15
/* Name lookup for Ghostscript interpreter */
 
16
#include "memory_.h"
 
17
#include "string_.h"
 
18
#include "ghost.h"
 
19
#include "gsstruct.h"
 
20
#include "gxobj.h"              /* for o_set_unmarked */
 
21
#include "ierrors.h"
 
22
#include "inamedef.h"
 
23
#include "imemory.h"            /* for isave.h */
 
24
#include "isave.h"
 
25
#include "store.h"
 
26
 
 
27
/* Public values */
 
28
const uint name_max_string = max_name_string;
 
29
 
 
30
/* Define the permutation table for name hashing. */
 
31
static const byte hash_permutation[256] = {
 
32
    NAME_HASH_PERMUTATION_DATA
 
33
};
 
34
 
 
35
/* Define the data for the 1-character names. */
 
36
static const byte nt_1char_names[NT_1CHAR_SIZE] = {
 
37
    NT_1CHAR_NAMES_DATA
 
38
};
 
39
 
 
40
/* Structure descriptors */
 
41
gs_private_st_simple(st_name_sub_table, name_sub_table, "name_sub_table");
 
42
gs_private_st_composite(st_name_string_sub_table, name_string_sub_table_t,
 
43
                        "name_string_sub_table_t",
 
44
                        name_string_sub_enum_ptrs, name_string_sub_reloc_ptrs);
 
45
gs_private_st_composite(st_name_table, name_table, "name_table",
 
46
                        name_table_enum_ptrs, name_table_reloc_ptrs);
 
47
 
 
48
/* Forward references */
 
49
static int name_alloc_sub(name_table *);
 
50
static void name_free_sub(name_table *, uint);
 
51
static void name_scan_sub(name_table *, uint, bool);
 
52
 
 
53
/* Debugging printout */
 
54
#ifdef DEBUG
 
55
static void
 
56
name_print(const char *msg, const name_table *nt, uint nidx, const int *pflag)
 
57
{
 
58
    const name_string_t *pnstr = names_index_string_inline(nt, nidx);
 
59
    const name *pname = names_index_ptr_inline(nt, nidx);
 
60
    const byte *str = pnstr->string_bytes;
 
61
 
 
62
    dlprintf1("[n]%s", msg);
 
63
    if (pflag)
 
64
        dprintf1("(%d)", *pflag);
 
65
    dprintf2(" (0x%lx#%u)", (ulong)pname, nidx);
 
66
    debug_print_string(str, pnstr->string_size);
 
67
    dprintf2("(0x%lx,%u)\n", (ulong)str, pnstr->string_size);
 
68
}
 
69
#  define if_debug_name(msg, nt, nidx, pflag)\
 
70
     if ( gs_debug_c('n') ) name_print(msg, nt, nidx, pflag)
 
71
#else
 
72
#  define if_debug_name(msg, nt, nidx, pflag) DO_NOTHING
 
73
#endif
 
74
 
 
75
/* Initialize a name table */
 
76
name_table *
 
77
names_init(ulong count, gs_ref_memory_t *imem)
 
78
{
 
79
    gs_memory_t *mem = (gs_memory_t *)imem;
 
80
    name_table *nt;
 
81
    int i;
 
82
 
 
83
    if (count == 0)
 
84
        count = max_name_count + 1L;
 
85
    else if (count - 1 > max_name_count)
 
86
        return 0;
 
87
    nt = gs_alloc_struct(mem, name_table, &st_name_table, "name_init(nt)");
 
88
    if (nt == 0)
 
89
        return 0;
 
90
    memset(nt, 0, sizeof(name_table));
 
91
    nt->max_sub_count =
 
92
        ((count - 1) | nt_sub_index_mask) >> nt_log2_sub_size;
 
93
    nt->name_string_attrs = imemory_space(imem) | a_readonly;
 
94
    nt->memory = mem;
 
95
    /* Initialize the one-character names. */
 
96
    /* Start by creating the necessary sub-tables. */
 
97
    for (i = 0; i < NT_1CHAR_FIRST + NT_1CHAR_SIZE; i += nt_sub_size) {
 
98
        int code = name_alloc_sub(nt);
 
99
 
 
100
        if (code < 0) {
 
101
            while (nt->sub_next > 0)
 
102
                name_free_sub(nt, --(nt->sub_next));
 
103
            gs_free_object(mem, nt, "name_init(nt)");
 
104
            return 0;
 
105
        }
 
106
    }
 
107
    for (i = -1; i < NT_1CHAR_SIZE; i++) {
 
108
        uint ncnt = NT_1CHAR_FIRST + i;
 
109
        uint nidx = name_count_to_index(ncnt);
 
110
        name *pname = names_index_ptr_inline(nt, nidx);
 
111
        name_string_t *pnstr = names_index_string_inline(nt, nidx);
 
112
 
 
113
        if (i < 0)
 
114
            pnstr->string_bytes = nt_1char_names,
 
115
                pnstr->string_size = 0;
 
116
        else
 
117
            pnstr->string_bytes = nt_1char_names + i,
 
118
                pnstr->string_size = 1;
 
119
        pnstr->foreign_string = 1;
 
120
        pnstr->mark = 1;
 
121
        pname->pvalue = pv_no_defn;
 
122
    }
 
123
    nt->perm_count = NT_1CHAR_FIRST + NT_1CHAR_SIZE;
 
124
    /* Reconstruct the free list. */
 
125
    nt->free = 0;
 
126
    names_trace_finish(nt, NULL);
 
127
    return nt;
 
128
}
 
129
 
 
130
/* Get the allocator for the name table. */
 
131
gs_memory_t *
 
132
names_memory(const name_table * nt)
 
133
{
 
134
    return nt->memory;
 
135
}
 
136
 
 
137
/* Look up or enter a name in the table. */
 
138
/* Return 0 or an error code. */
 
139
/* The return may overlap the characters of the string! */
 
140
/* See iname.h for the meaning of enterflag. */
 
141
int
 
142
names_ref(name_table *nt, const byte *ptr, uint size, ref *pref, int enterflag)
 
143
{
 
144
    name *pname;
 
145
    name_string_t *pnstr;
 
146
    uint nidx;
 
147
    uint *phash;
 
148
 
 
149
    /* Compute a hash for the string. */
 
150
    /* Make a special check for 1-character names. */
 
151
    switch (size) {
 
152
    case 0:
 
153
        nidx = name_count_to_index(1);
 
154
        pname = names_index_ptr_inline(nt, nidx);
 
155
        goto mkn;
 
156
    case 1:
 
157
        if (*ptr < NT_1CHAR_SIZE) {
 
158
            uint hash = *ptr + NT_1CHAR_FIRST;
 
159
 
 
160
            nidx = name_count_to_index(hash);
 
161
            pname = names_index_ptr_inline(nt, nidx);
 
162
            goto mkn;
 
163
        }
 
164
        /* falls through */
 
165
    default: {
 
166
        uint hash;
 
167
 
 
168
        NAME_HASH(hash, hash_permutation, ptr, size);
 
169
        phash = nt->hash + (hash & (NT_HASH_SIZE - 1));
 
170
    }
 
171
    }
 
172
 
 
173
    for (nidx = *phash; nidx != 0;
 
174
         nidx = name_next_index(nidx, pnstr)
 
175
        ) {
 
176
        pnstr = names_index_string_inline(nt, nidx);
 
177
        if (pnstr->string_size == size &&
 
178
            !memcmp_inline(ptr, pnstr->string_bytes, size)
 
179
            ) {
 
180
            pname = name_index_ptr_inline(nt, nidx);
 
181
            goto mkn;
 
182
        }
 
183
    }
 
184
    /* Name was not in the table.  Make a new entry. */
 
185
    if (enterflag < 0)
 
186
        return_error(e_undefined);
 
187
    if (size > max_name_string)
 
188
        return_error(e_limitcheck);
 
189
    nidx = nt->free;
 
190
    if (nidx == 0) {
 
191
        int code = name_alloc_sub(nt);
 
192
 
 
193
        if (code < 0)
 
194
            return code;
 
195
        nidx = nt->free;
 
196
    }
 
197
    pnstr = names_index_string_inline(nt, nidx);
 
198
    if (enterflag == 1) {
 
199
        byte *cptr = (byte *)gs_alloc_string(nt->memory, size,
 
200
                                             "names_ref(string)");
 
201
 
 
202
        if (cptr == 0)
 
203
            return_error(e_VMerror);
 
204
        memcpy(cptr, ptr, size);
 
205
        pnstr->string_bytes = cptr;
 
206
        pnstr->foreign_string = 0;
 
207
    } else {
 
208
        pnstr->string_bytes = ptr;
 
209
        pnstr->foreign_string = (enterflag == 0 ? 1 : 0);
 
210
    }
 
211
    pnstr->string_size = size;
 
212
    pname = name_index_ptr_inline(nt, nidx);
 
213
    pname->pvalue = pv_no_defn;
 
214
    nt->free = name_next_index(nidx, pnstr);
 
215
    set_name_next_index(nidx, pnstr, *phash);
 
216
    *phash = nidx;
 
217
    if_debug_name("new name", nt, nidx, &enterflag);
 
218
 mkn:
 
219
    make_name(pref, nidx, pname);
 
220
    return 0;
 
221
}
 
222
 
 
223
/* Get the string for a name. */
 
224
void
 
225
names_string_ref(const name_table * nt, const ref * pnref /* t_name */ ,
 
226
                 ref * psref /* result, t_string */ )
 
227
{
 
228
    const name_string_t *pnstr = names_string_inline(nt, pnref);
 
229
 
 
230
    make_const_string(psref,
 
231
                      (pnstr->foreign_string ? avm_foreign | a_readonly :
 
232
                       nt->name_string_attrs),
 
233
                      pnstr->string_size,
 
234
                      (const byte *)pnstr->string_bytes);
 
235
}
 
236
 
 
237
/* Convert a t_string object to a name. */
 
238
/* Copy the executable attribute. */
 
239
int
 
240
names_from_string(name_table * nt, const ref * psref, ref * pnref)
 
241
{
 
242
    int exec = r_has_attr(psref, a_executable);
 
243
    int code = names_ref(nt, psref->value.bytes, r_size(psref), pnref, 1);
 
244
 
 
245
    if (code < 0)
 
246
        return code;
 
247
    if (exec)
 
248
        r_set_attrs(pnref, a_executable);
 
249
    return code;
 
250
}
 
251
 
 
252
/* Enter a (permanently allocated) C string as a name. */
 
253
int
 
254
names_enter_string(name_table * nt, const char *str, ref * pref)
 
255
{
 
256
    return names_ref(nt, (const byte *)str, strlen(str), pref, 0);
 
257
}
 
258
 
 
259
/* Invalidate the value cache for a name. */
 
260
void
 
261
names_invalidate_value_cache(name_table * nt, const ref * pnref)
 
262
{
 
263
    pnref->value.pname->pvalue = pv_other;
 
264
}
 
265
 
 
266
/* Convert between names and indices. */
 
267
#undef names_index
 
268
name_index_t
 
269
names_index(const name_table * nt, const ref * pnref)
 
270
{
 
271
    return names_index_inline(nt, pnref);
 
272
}
 
273
void
 
274
names_index_ref(const name_table * nt, name_index_t index, ref * pnref)
 
275
{
 
276
    names_index_ref_inline(nt, index, pnref);
 
277
}
 
278
name *
 
279
names_index_ptr(const name_table * nt, name_index_t index)
 
280
{
 
281
    return names_index_ptr_inline(nt, index);
 
282
}
 
283
 
 
284
/* Get the index of the next valid name. */
 
285
/* The argument is 0 or a valid index. */
 
286
/* Return 0 if there are no more. */
 
287
name_index_t
 
288
names_next_valid_index(name_table * nt, name_index_t nidx)
 
289
{
 
290
    const name_string_sub_table_t *ssub =
 
291
        nt->sub[nidx >> nt_log2_sub_size].strings;
 
292
    const name_string_t *pnstr;
 
293
 
 
294
    do {
 
295
        ++nidx;
 
296
        if ((nidx & nt_sub_index_mask) == 0)
 
297
            for (;; nidx += nt_sub_size) {
 
298
                if ((nidx >> nt_log2_sub_size) >= nt->sub_count)
 
299
                    return 0;
 
300
                ssub = nt->sub[nidx >> nt_log2_sub_size].strings;
 
301
                if (ssub != 0)
 
302
                    break;
 
303
            }
 
304
        pnstr = &ssub->strings[nidx & nt_sub_index_mask];
 
305
    }
 
306
    while (pnstr->string_bytes == 0);
 
307
    return nidx;
 
308
}
 
309
 
 
310
/* ------ Garbage collection ------ */
 
311
 
 
312
/* Unmark all non-permanent names before a garbage collection. */
 
313
void
 
314
names_unmark_all(name_table * nt)
 
315
{
 
316
    uint si;
 
317
    name_string_sub_table_t *ssub;
 
318
 
 
319
    for (si = 0; si < nt->sub_count; ++si)
 
320
        if ((ssub = nt->sub[si].strings) != 0) {
 
321
            uint i;
 
322
 
 
323
            /* We can make the test much more efficient if we want.... */
 
324
            for (i = 0; i < nt_sub_size; ++i)
 
325
                if (name_index_to_count((si << nt_log2_sub_size) + i) >=
 
326
                    nt->perm_count)
 
327
                    ssub->strings[i].mark = 0;
 
328
        }
 
329
}
 
330
 
 
331
/* Mark a name.  Return true if new mark.  We export this so we can mark */
 
332
/* character names in the character cache. */
 
333
bool
 
334
names_mark_index(name_table * nt, name_index_t nidx)
 
335
{
 
336
    name_string_t *pnstr = names_index_string_inline(nt, nidx);
 
337
 
 
338
    if (pnstr->mark)
 
339
        return false;
 
340
    pnstr->mark = 1;
 
341
    return true;
 
342
}
 
343
 
 
344
/* Get the object (sub-table) containing a name. */
 
345
/* The garbage collector needs this so it can relocate pointers to names. */
 
346
void /*obj_header_t */ *
 
347
names_ref_sub_table(name_table * nt, const ref * pnref)
 
348
{
 
349
    /* When this procedure is called, the pointers from the name table */
 
350
    /* to the sub-tables may or may not have been relocated already, */
 
351
    /* so we can't use them.  Instead, we have to work backwards from */
 
352
    /* the name pointer itself. */
 
353
    return pnref->value.pname - (r_size(pnref) & nt_sub_index_mask);
 
354
}
 
355
void /*obj_header_t */ *
 
356
names_index_sub_table(name_table * nt, name_index_t index)
 
357
{
 
358
    return nt->sub[index >> nt_log2_sub_size].names;
 
359
}
 
360
void /*obj_header_t */ *
 
361
names_index_string_sub_table(name_table * nt, name_index_t index)
 
362
{
 
363
    return nt->sub[index >> nt_log2_sub_size].strings;
 
364
}
 
365
 
 
366
/*
 
367
 * Clean up the name table after the trace/mark phase of a garbage
 
368
 * collection, by removing names that aren't marked.  gcst == NULL indicates
 
369
 * we're doing this for initialization or restore rather than for a GC.
 
370
 */
 
371
void
 
372
names_trace_finish(name_table * nt, gc_state_t * gcst)
 
373
{
 
374
    uint *phash = &nt->hash[0];
 
375
    int i;
 
376
 
 
377
    for (i = 0; i < NT_HASH_SIZE; phash++, i++) {
 
378
        name_index_t prev = 0;
 
379
        /*
 
380
         * The following initialization is only to pacify compilers:
 
381
         * pnprev is only referenced if prev has been set in the loop,
 
382
         * in which case pnprev is also set.
 
383
         */
 
384
        name_string_t *pnprev = 0;
 
385
        name_index_t nidx = *phash;
 
386
 
 
387
        while (nidx != 0) {
 
388
            name_string_t *pnstr = names_index_string_inline(nt, nidx);
 
389
            name_index_t next = name_next_index(nidx, pnstr);
 
390
 
 
391
            if (pnstr->mark) {
 
392
                prev = nidx;
 
393
                pnprev = pnstr;
 
394
            } else {
 
395
                if_debug_name("GC remove name", nt, nidx, NULL);
 
396
                /* Zero out the string data for the GC. */
 
397
                pnstr->string_bytes = 0;
 
398
                pnstr->string_size = 0;
 
399
                if (prev == 0)
 
400
                    *phash = next;
 
401
                else
 
402
                    set_name_next_index(prev, pnprev, next);
 
403
            }
 
404
            nidx = next;
 
405
        }
 
406
    }
 
407
    /* Reconstruct the free list. */
 
408
    nt->free = 0;
 
409
    for (i = nt->sub_count; --i >= 0;) {
 
410
        name_sub_table *sub = nt->sub[i].names;
 
411
        name_string_sub_table_t *ssub = nt->sub[i].strings;
 
412
 
 
413
        if (sub != 0) {
 
414
            int save_count = nt->sub_count;
 
415
 
 
416
            name_scan_sub(nt, i, true);
 
417
            if (save_count != nt->sub_count) {
 
418
                /* name_scan_sub has released the i-th entry. */
 
419
                continue;
 
420
            }
 
421
            if (nt->sub[i].names == 0 && gcst != 0) {
 
422
                /* Mark the just-freed sub-table as unmarked. */
 
423
                o_set_unmarked((obj_header_t *)sub - 1);
 
424
                o_set_unmarked((obj_header_t *)ssub - 1);
 
425
            }
 
426
        }
 
427
    }
 
428
    nt->sub_next = 0;
 
429
}
 
430
 
 
431
/* ------ Save/restore ------ */
 
432
 
 
433
/* Clean up the name table before a restore. */
 
434
/* Currently, this is never called, because the name table is allocated */
 
435
/* in system VM.  However, for a Level 1 system, we might choose to */
 
436
/* allocate the name table in global VM; in this case, this routine */
 
437
/* would be called before doing the global part of a top-level restore. */
 
438
/* Currently we don't make any attempt to optimize this. */
 
439
void
 
440
names_restore(name_table * nt, alloc_save_t * save)
 
441
{
 
442
    /* We simply mark all names older than the save, */
 
443
    /* and let names_trace_finish sort everything out. */
 
444
    uint si;
 
445
 
 
446
    for (si = 0; si < nt->sub_count; ++si)
 
447
        if (nt->sub[si].strings != 0) {
 
448
            uint i;
 
449
 
 
450
            for (i = 0; i < nt_sub_size; ++i) {
 
451
                name_string_t *pnstr =
 
452
                    names_index_string_inline(nt, (si << nt_log2_sub_size) + i);
 
453
 
 
454
                if (pnstr->string_bytes == 0)
 
455
                    pnstr->mark = 0;
 
456
                else if (pnstr->foreign_string) {
 
457
                    /* Avoid storing into a read-only name string. */
 
458
                    if (!pnstr->mark)
 
459
                        pnstr->mark = 1;
 
460
                } else
 
461
                    pnstr->mark =
 
462
                        !alloc_is_since_save(pnstr->string_bytes, save);
 
463
            }
 
464
        }
 
465
    names_trace_finish(nt, NULL);
 
466
}
 
467
 
 
468
/* ------ Internal procedures ------ */
 
469
 
 
470
/* Allocate the next sub-table. */
 
471
static int
 
472
name_alloc_sub(name_table * nt)
 
473
{
 
474
    gs_memory_t *mem = nt->memory;
 
475
    uint sub_index = nt->sub_next;
 
476
    name_sub_table *sub;
 
477
    name_string_sub_table_t *ssub;
 
478
 
 
479
    for (;; ++sub_index) {
 
480
        if (sub_index > nt->max_sub_count)
 
481
            return_error(e_limitcheck);
 
482
        if (nt->sub[sub_index].names == 0)
 
483
            break;
 
484
    }
 
485
    nt->sub_next = sub_index + 1;
 
486
    if (nt->sub_next > nt->sub_count)
 
487
        nt->sub_count = nt->sub_next;
 
488
    sub = gs_alloc_struct(mem, name_sub_table, &st_name_sub_table,
 
489
                          "name_alloc_sub(sub-table)");
 
490
    ssub = gs_alloc_struct(mem, name_string_sub_table_t,
 
491
                           &st_name_string_sub_table,
 
492
                          "name_alloc_sub(string sub-table)");
 
493
    if (sub == 0 || ssub == 0) {
 
494
        gs_free_object(mem, ssub, "name_alloc_sub(string sub-table)");
 
495
        gs_free_object(mem, sub, "name_alloc_sub(sub-table)");
 
496
        return_error(e_VMerror);
 
497
    }
 
498
    memset(sub, 0, sizeof(name_sub_table));
 
499
    memset(ssub, 0, sizeof(name_string_sub_table_t));
 
500
    /* The following code is only used if EXTEND_NAMES is non-zero. */
 
501
#if name_extension_bits > 0
 
502
    sub->high_index = (sub_index >> (16 - nt_log2_sub_size)) << 16;
 
503
#endif
 
504
    nt->sub[sub_index].names = sub;
 
505
    nt->sub[sub_index].strings = ssub;
 
506
    /* Add the newly allocated entries to the free list. */
 
507
    /* Note that the free list will only be properly sorted if */
 
508
    /* it was empty initially. */
 
509
    name_scan_sub(nt, sub_index, false);
 
510
#ifdef DEBUG
 
511
    if (gs_debug_c('n')) {      /* Print the lengths of the hash chains. */
 
512
        int i0;
 
513
 
 
514
        for (i0 = 0; i0 < NT_HASH_SIZE; i0 += 16) {
 
515
            int i;
 
516
 
 
517
            dlprintf1("[n]chain %d:", i0);
 
518
            for (i = i0; i < i0 + 16; i++) {
 
519
                int n = 0;
 
520
                uint nidx;
 
521
 
 
522
                for (nidx = nt->hash[i]; nidx != 0;
 
523
                     nidx = name_next_index(nidx,
 
524
                                            names_index_string_inline(nt, nidx))
 
525
                    )
 
526
                    n++;
 
527
                dprintf1(" %d", n);
 
528
            }
 
529
            dputc('\n');
 
530
        }
 
531
    }
 
532
#endif
 
533
    return 0;
 
534
}
 
535
 
 
536
/* Free a sub-table. */
 
537
static void
 
538
name_free_sub(name_table * nt, uint sub_index)
 
539
{
 
540
    gs_free_object(nt->memory, nt->sub[sub_index].strings,
 
541
                   "name_free_sub(string sub-table)");
 
542
    gs_free_object(nt->memory, nt->sub[sub_index].names,
 
543
                   "name_free_sub(sub-table)");
 
544
    nt->sub[sub_index].names = 0;
 
545
    nt->sub[sub_index].strings = 0;
 
546
}
 
547
 
 
548
/* Scan a sub-table and add unmarked entries to the free list. */
 
549
/* We add the entries in decreasing count order, so the free list */
 
550
/* will stay sorted.  If all entries are unmarked and free_empty is true, */
 
551
/* free the sub-table. */
 
552
static void
 
553
name_scan_sub(name_table * nt, uint sub_index, bool free_empty)
 
554
{
 
555
    name_string_sub_table_t *ssub = nt->sub[sub_index].strings;
 
556
    uint free = nt->free;
 
557
    uint nbase = sub_index << nt_log2_sub_size;
 
558
    uint ncnt = nbase + (nt_sub_size - 1);
 
559
    bool keep = !free_empty;
 
560
 
 
561
    if (ssub == 0)
 
562
        return;
 
563
    if (nbase == 0)
 
564
        nbase = 1, keep = true; /* don't free name 0 */
 
565
    for (;; --ncnt) {
 
566
        uint nidx = name_count_to_index(ncnt);
 
567
        name_string_t *pnstr = &ssub->strings[nidx & nt_sub_index_mask];
 
568
 
 
569
        if (pnstr->mark)
 
570
            keep = true;
 
571
        else {
 
572
            set_name_next_index(nidx, pnstr, free);
 
573
            free = nidx;
 
574
        }
 
575
        if (ncnt == nbase)
 
576
            break;
 
577
    }
 
578
    if (keep)
 
579
        nt->free = free;
 
580
    else {
 
581
        /* No marked entries, free the sub-table. */
 
582
        name_free_sub(nt, sub_index);
 
583
        if (sub_index == nt->sub_count - 1) {
 
584
            /* Back up over a final run of deleted sub-tables. */
 
585
            do {
 
586
                --sub_index;
 
587
            } while (nt->sub[sub_index].names == 0);
 
588
            nt->sub_count = sub_index + 1;
 
589
            if (nt->sub_next > sub_index)
 
590
                nt->sub_next = sub_index;
 
591
        } else if (nt->sub_next == sub_index)
 
592
            nt->sub_next--;
 
593
    }
 
594
}
 
595
 
 
596
/* Garbage collector enumeration and relocation procedures. */
 
597
static 
 
598
ENUM_PTRS_BEGIN_PROC(name_table_enum_ptrs)
 
599
{
 
600
    EV_CONST name_table *const nt = vptr;
 
601
    uint i = index >> 1;
 
602
 
 
603
    if (i >= nt->sub_count)
 
604
        return 0;
 
605
    if (index & 1)
 
606
        ENUM_RETURN(nt->sub[i].strings);
 
607
    else
 
608
        ENUM_RETURN(nt->sub[i].names);
 
609
}
 
610
ENUM_PTRS_END_PROC
 
611
static RELOC_PTRS_WITH(name_table_reloc_ptrs, name_table *nt)
 
612
{
 
613
    uint sub_count = nt->sub_count;
 
614
    uint i;
 
615
 
 
616
    /* Now we can relocate the sub-table pointers. */
 
617
    for (i = 0; i < sub_count; i++) {
 
618
        RELOC_VAR(nt->sub[i].names);
 
619
        RELOC_VAR(nt->sub[i].strings);
 
620
    }
 
621
    /*
 
622
     * We also need to relocate the cached value pointers.
 
623
     * We don't do this here, but in a separate scan over the
 
624
     * permanent dictionaries, at the very end of garbage collection.
 
625
     */
 
626
}
 
627
RELOC_PTRS_END
 
628
 
 
629
static ENUM_PTRS_BEGIN_PROC(name_string_sub_enum_ptrs)
 
630
{
 
631
    return 0;
 
632
}
 
633
ENUM_PTRS_END_PROC
 
634
static RELOC_PTRS_BEGIN(name_string_sub_reloc_ptrs)
 
635
{
 
636
    name_string_t *pnstr = ((name_string_sub_table_t *)vptr)->strings;
 
637
    uint i;
 
638
 
 
639
    for (i = 0; i < nt_sub_size; ++pnstr, ++i) {
 
640
        if (pnstr->string_bytes != 0 && !pnstr->foreign_string) {
 
641
            gs_const_string nstr;
 
642
 
 
643
            nstr.data = pnstr->string_bytes;
 
644
            nstr.size = pnstr->string_size;
 
645
            RELOC_CONST_STRING_VAR(nstr);
 
646
            pnstr->string_bytes = nstr.data;
 
647
        }
 
648
    }
 
649
}
 
650
RELOC_PTRS_END