glyphs: replace open-addressed glyphname hashtable with sorted index
The open-addressed glyphname_hashtable stored each canonical
"G_xxx" name as a dupstr'd string in its bucket: ~9577 small heap
allocations and ~290 KB of resident name strings, on top of ~256 KB
of 32768-bucket scaffolding kept at <50% load for probe performance.
On classic Mac OS the populate cost (quadratic small-allocation in a
fragmented Memory Manager heap) dominated startup time -- many
seconds on an SE/30 -- and ~800 KB resident is meaningful on the
small machines the port targets.
Switch to a sorted (hash, glyph) index sized exactly to the number
of named glyphs:
struct glyphname_hashtable_entry_t {
uint32 hash;
int glyphnum;
};
populate_glyphname_hashtable() allocates one block of MAX_GLYPH
entries (no per-name strings), fills it via compose_glyph_name() +
glyph_hash(), and qsort()s ascending by hash. Lookup binary-searches
the hash column, then walks any equal-hash neighbours verifying each
candidate by reconstructing its canonical name and strcmpi'ing it
back -- collisions are rare with 9577 uniformly-distributed 32-bit
hashes.
Other changes that fall out:
* Extract compose_glyph_name() from parse_id's bulk-iteration switch
so it is the single source of truth for "glyph number -> canonical
name". Called by find_glyph_in_hashtable for collision
verification, by populate_glyphname_hashtable, by the
--dumpglyphnames path, and by wizcustom_glyphnames.
* empty_glyphname_hashtable() reduces to free(ptr); no per-entry
strings to release.
* Drop find_glyphname_in_hashtable_by_glyphnum (no longer used --
wizcustom_glyphnames iterates compose_glyph_name directly).
* Drop the res_fill_hashtable parse_id mode; populate iterates
directly.
Memory drops from ~800 KB to ~75 KB. One allocation instead of
~9578. Lookup goes from O(1) to O(log N) but N ~ 9577 means ~14
comparisons per probe -- well under what the upstream cache ever
cost in practice.
Function names (populate_glyphname_hashtable, etc.) are kept for
extern.h compatibility; the data structure is now a sorted index,
"hashtable" in the names is historical.
--dumpglyphnames output is byte-identical.
This commit is contained in:
+333
-401
@@ -11,7 +11,7 @@ extern struct enum_dump objdump[];
|
|||||||
|
|
||||||
#define Fprintf (void) fprintf
|
#define Fprintf (void) fprintf
|
||||||
|
|
||||||
enum reserved_activities { res_nothing, res_dump_glyphnames, res_fill_hashtable };
|
enum reserved_activities { res_nothing, res_dump_glyphnames };
|
||||||
enum things_to_find { find_nothing, find_pm, find_oc, find_cmap, find_glyph };
|
enum things_to_find { find_nothing, find_pm, find_oc, find_cmap, find_glyph };
|
||||||
struct find_struct {
|
struct find_struct {
|
||||||
enum things_to_find findtype;
|
enum things_to_find findtype;
|
||||||
@@ -27,20 +27,18 @@ struct find_struct {
|
|||||||
};
|
};
|
||||||
static const struct find_struct zero_find = { 0 };
|
static const struct find_struct zero_find = { 0 };
|
||||||
struct glyphname_hashtable_entry_t {
|
struct glyphname_hashtable_entry_t {
|
||||||
int glyphnum;
|
uint32 hash;
|
||||||
char *id;
|
int glyphnum; /* NO_GLYPH (==MAX_GLYPH) marks an empty bucket */
|
||||||
};
|
};
|
||||||
static struct glyphname_hashtable_entry_t *glyphname_hashtable_ptr;
|
static struct glyphname_hashtable_entry_t *glyphname_hashtable_ptr;
|
||||||
static unsigned glyphname_hashtable_lsize;
|
static size_t glyphname_hashtable_count;
|
||||||
static size_t glyphname_hashtable_size;
|
static struct find_struct to_custom_symbol_find;
|
||||||
static struct find_struct glyphname_hashtable_find, to_custom_symbol_find;
|
|
||||||
static const long nonzero_black = CLR_BLACK | NH_BASIC_COLOR;
|
static const long nonzero_black = CLR_BLACK | NH_BASIC_COLOR;
|
||||||
|
|
||||||
staticfn void init_glyphname_hashtable(void);
|
staticfn int find_glyph_in_hashtable(const char *id);
|
||||||
staticfn void add_glyph_to_glyphname_hashtable(int glyphnum, const char *id);
|
staticfn int cmp_glyphname_entry(const void *a, const void *b);
|
||||||
staticfn int find_glyph_in_cache(const char *id);
|
|
||||||
staticfn char *find_glyphname_in_hashtable_by_glyphnum(int glyphnum);
|
|
||||||
staticfn uint32 glyph_hash(const char *id);
|
staticfn uint32 glyph_hash(const char *id);
|
||||||
|
staticfn int compose_glyph_name(int glyph, char *buf, size_t bufsz);
|
||||||
staticfn void to_custom_symset_entry_callback(int glyph,
|
staticfn void to_custom_symset_entry_callback(int glyph,
|
||||||
struct find_struct *findwhat);
|
struct find_struct *findwhat);
|
||||||
staticfn int parse_id(const char *id, struct find_struct *findwhat);
|
staticfn int parse_id(const char *id, struct find_struct *findwhat);
|
||||||
@@ -196,6 +194,239 @@ fix_glyphname(char *str)
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Build the canonical "G_xxx" identifier for the given glyph into buf.
|
||||||
|
* Returns 1 if a name was produced, 0 if this glyph has no canonical name
|
||||||
|
* (a few unused object indices); buf[0] is set to '\0' in that case.
|
||||||
|
* Used by parse_id's bulk-iteration paths, by find_glyph_in_hashtable to
|
||||||
|
* verify hash matches, by populate_glyphname_hashtable to fill the table,
|
||||||
|
* and by wizcustom_glyphnames. */
|
||||||
|
staticfn int
|
||||||
|
compose_glyph_name(int glyph, char *buf, size_t bufsz)
|
||||||
|
{
|
||||||
|
int i, j, mnum, cmap_offset = 0;
|
||||||
|
boolean skip_base = FALSE;
|
||||||
|
const char *buf2, *buf3, *buf4;
|
||||||
|
char tmpbuf[4][QBUFSZ];
|
||||||
|
|
||||||
|
if (bufsz < 2)
|
||||||
|
return 0;
|
||||||
|
buf[0] = '\0';
|
||||||
|
tmpbuf[0][0] = tmpbuf[1][0] = tmpbuf[2][0] = tmpbuf[3][0] = '\0';
|
||||||
|
|
||||||
|
/* compute cmap_offset (the start of SYM_PCHAR entries in loadsyms[]) */
|
||||||
|
i = 0;
|
||||||
|
while (loadsyms[i].range) {
|
||||||
|
if (!cmap_offset && loadsyms[i].range == SYM_PCHAR)
|
||||||
|
cmap_offset = i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyph_is_monster(glyph)) {
|
||||||
|
buf2 = "";
|
||||||
|
buf3 = monsdump[glyph_to_mon(glyph)].nm;
|
||||||
|
if (glyph_is_normal_male_monster(glyph)) {
|
||||||
|
buf2 = "male_";
|
||||||
|
} else if (glyph_is_normal_female_monster(glyph)) {
|
||||||
|
buf2 = "female_";
|
||||||
|
} else if (glyph_is_ridden_male_monster(glyph)) {
|
||||||
|
buf2 = "ridden_male_";
|
||||||
|
} else if (glyph_is_ridden_female_monster(glyph)) {
|
||||||
|
buf2 = "ridden_female_";
|
||||||
|
} else if (glyph_is_detected_male_monster(glyph)) {
|
||||||
|
buf2 = "detected_male_";
|
||||||
|
} else if (glyph_is_detected_female_monster(glyph)) {
|
||||||
|
buf2 = "detected_female_";
|
||||||
|
} else if (glyph_is_male_pet(glyph)) {
|
||||||
|
buf2 = "pet_male_";
|
||||||
|
} else if (glyph_is_female_pet(glyph)) {
|
||||||
|
buf2 = "pet_female_";
|
||||||
|
}
|
||||||
|
Strcpy(buf, "G_");
|
||||||
|
Strcat(buf, buf2);
|
||||||
|
Strcat(buf, buf3);
|
||||||
|
} else if (glyph_is_body(glyph)) {
|
||||||
|
buf2 = glyph_is_body_piletop(glyph) ? "piletop_body_" : "body_";
|
||||||
|
buf3 = monsdump[glyph_to_body_corpsenm(glyph)].nm;
|
||||||
|
Strcpy(buf, "G_");
|
||||||
|
Strcat(buf, buf2);
|
||||||
|
Strcat(buf, buf3);
|
||||||
|
} else if (glyph_is_statue(glyph)) {
|
||||||
|
buf2 = glyph_is_fem_statue_piletop(glyph)
|
||||||
|
? "piletop_statue_of_female_"
|
||||||
|
: glyph_is_fem_statue(glyph)
|
||||||
|
? "statue_of_female_"
|
||||||
|
: glyph_is_male_statue_piletop(glyph)
|
||||||
|
? "piletop_statue_of_male_"
|
||||||
|
: glyph_is_male_statue(glyph)
|
||||||
|
? "statue_of_male_"
|
||||||
|
: "";
|
||||||
|
buf3 = monsdump[glyph_to_statue_corpsenm(glyph)].nm;
|
||||||
|
Strcpy(buf, "G_");
|
||||||
|
Strcat(buf, buf2);
|
||||||
|
Strcat(buf, buf3);
|
||||||
|
} else if (glyph_is_object(glyph)) {
|
||||||
|
i = glyph_to_obj(glyph);
|
||||||
|
if (((i > SCR_STINKING_CLOUD) && (i < SCR_MAIL))
|
||||||
|
|| ((i > WAN_LIGHTNING) && (i < GOLD_PIECE))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ((i >= WAN_LIGHT) && (i <= WAN_LIGHTNING))
|
||||||
|
buf2 = "wand of ";
|
||||||
|
else if ((i >= SPE_DIG) && (i < SPE_BLANK_PAPER))
|
||||||
|
buf2 = "spellbook of ";
|
||||||
|
else if ((i >= SCR_ENCHANT_ARMOR) && (i <= SCR_STINKING_CLOUD))
|
||||||
|
buf2 = "scroll of ";
|
||||||
|
else if ((i >= POT_GAIN_ABILITY) && (i <= POT_WATER))
|
||||||
|
buf2 = (i == POT_WATER) ? "flask of n" : "potion of ";
|
||||||
|
else if ((i >= RIN_ADORNMENT) && (i <= RIN_PROTECTION_FROM_SHAPE_CHAN))
|
||||||
|
buf2 = "ring of ";
|
||||||
|
else if (i == LAND_MINE)
|
||||||
|
buf2 = "unset ";
|
||||||
|
else
|
||||||
|
buf2 = "";
|
||||||
|
buf3 = (i == SCR_BLANK_PAPER) ? "blank scroll"
|
||||||
|
: (i == SPE_BLANK_PAPER) ? "blank spellbook"
|
||||||
|
: (i == SLIME_MOLD) ? "slime mold"
|
||||||
|
: obj_descr[i].oc_name
|
||||||
|
? obj_descr[i].oc_name
|
||||||
|
: obj_descr[i].oc_descr;
|
||||||
|
Strcpy(buf, "G_");
|
||||||
|
if (glyph_is_normal_piletop_obj(glyph))
|
||||||
|
Strcat(buf, "piletop_");
|
||||||
|
Strcat(buf, buf2);
|
||||||
|
Strcat(buf, buf3);
|
||||||
|
} else if (glyph_is_cmap(glyph) || glyph_is_cmap_zap(glyph)
|
||||||
|
|| glyph_is_swallow(glyph) || glyph_is_explosion(glyph)) {
|
||||||
|
int cmap = -1;
|
||||||
|
|
||||||
|
buf2 = "";
|
||||||
|
buf3 = "";
|
||||||
|
buf4 = "";
|
||||||
|
if (glyph == GLYPH_CMAP_OFF) {
|
||||||
|
cmap = S_stone;
|
||||||
|
buf3 = "stone substrate";
|
||||||
|
skip_base = TRUE;
|
||||||
|
} else if (glyph_is_cmap_gehennom(glyph)) {
|
||||||
|
cmap = (glyph - GLYPH_CMAP_GEH_OFF) + S_vwall;
|
||||||
|
buf4 = "_gehennom";
|
||||||
|
} else if (glyph_is_cmap_knox(glyph)) {
|
||||||
|
cmap = (glyph - GLYPH_CMAP_KNOX_OFF) + S_vwall;
|
||||||
|
buf4 = "_knox";
|
||||||
|
} else if (glyph_is_cmap_main(glyph)) {
|
||||||
|
cmap = (glyph - GLYPH_CMAP_MAIN_OFF) + S_vwall;
|
||||||
|
buf4 = "_main";
|
||||||
|
} else if (glyph_is_cmap_mines(glyph)) {
|
||||||
|
cmap = (glyph - GLYPH_CMAP_MINES_OFF) + S_vwall;
|
||||||
|
buf4 = "_mines";
|
||||||
|
} else if (glyph_is_cmap_sokoban(glyph)) {
|
||||||
|
cmap = (glyph - GLYPH_CMAP_SOKO_OFF) + S_vwall;
|
||||||
|
buf4 = "_sokoban";
|
||||||
|
} else if (glyph_is_cmap_a(glyph)) {
|
||||||
|
cmap = (glyph - GLYPH_CMAP_A_OFF) + S_ndoor;
|
||||||
|
} else if (glyph_is_cmap_altar(glyph)) {
|
||||||
|
static const char *const altar_text[] = {
|
||||||
|
"unaligned", "chaotic", "neutral",
|
||||||
|
"lawful", "other",
|
||||||
|
};
|
||||||
|
|
||||||
|
j = (glyph - GLYPH_ALTAR_OFF);
|
||||||
|
cmap = S_altar;
|
||||||
|
if (j != altar_other) {
|
||||||
|
Snprintf(tmpbuf[2], sizeof tmpbuf[2], "%s_", altar_text[j]);
|
||||||
|
buf2 = tmpbuf[2];
|
||||||
|
} else {
|
||||||
|
buf3 = "altar other";
|
||||||
|
skip_base = TRUE;
|
||||||
|
}
|
||||||
|
} else if (glyph_is_cmap_b(glyph)) {
|
||||||
|
cmap = (glyph - GLYPH_CMAP_B_OFF) + S_grave;
|
||||||
|
} else if (glyph_is_cmap_zap(glyph)) {
|
||||||
|
static const char *const zap_texts[] = {
|
||||||
|
"missile", "fire", "frost", "sleep",
|
||||||
|
"death", "lightning", "poison gas", "acid"
|
||||||
|
};
|
||||||
|
|
||||||
|
j = (glyph - GLYPH_ZAP_OFF);
|
||||||
|
cmap = (j % 4) + S_vbeam;
|
||||||
|
Snprintf(tmpbuf[2], sizeof tmpbuf[2], "%s",
|
||||||
|
loadsyms[cmap + cmap_offset].name + 2);
|
||||||
|
Snprintf(tmpbuf[3], sizeof tmpbuf[3], "%s zap %s",
|
||||||
|
zap_texts[j / 4], fix_glyphname(tmpbuf[2]));
|
||||||
|
buf3 = tmpbuf[3];
|
||||||
|
buf2 = "";
|
||||||
|
skip_base = TRUE;
|
||||||
|
} else if (glyph_is_cmap_c(glyph)) {
|
||||||
|
cmap = (glyph - GLYPH_CMAP_C_OFF) + S_digbeam;
|
||||||
|
} else if (glyph_is_swallow(glyph)) {
|
||||||
|
static const char *const swallow_texts[] = {
|
||||||
|
"top left", "top center", "top right",
|
||||||
|
"middle left", "middle right", "bottom left",
|
||||||
|
"bottom center", "bottom right",
|
||||||
|
};
|
||||||
|
|
||||||
|
j = glyph - GLYPH_SWALLOW_OFF;
|
||||||
|
cmap = glyph_to_swallow(glyph);
|
||||||
|
mnum = j / ((S_sw_br - S_sw_tl) + 1);
|
||||||
|
Strcpy(tmpbuf[3], "swallow ");
|
||||||
|
Strcat(tmpbuf[3], monsdump[mnum].nm);
|
||||||
|
Strcat(tmpbuf[3], " ");
|
||||||
|
Strcat(tmpbuf[3], swallow_texts[cmap]);
|
||||||
|
buf3 = tmpbuf[3];
|
||||||
|
skip_base = TRUE;
|
||||||
|
} else if (glyph_is_explosion(glyph)) {
|
||||||
|
static const char *const expl_type_texts[] = {
|
||||||
|
"dark", "noxious", "muddy", "wet",
|
||||||
|
"magical", "fiery", "frosty",
|
||||||
|
};
|
||||||
|
static const char *const expl_texts[] = {
|
||||||
|
"tl", "tc", "tr", "ml", "mc",
|
||||||
|
"mr", "bl", "bc", "br",
|
||||||
|
};
|
||||||
|
int expl;
|
||||||
|
|
||||||
|
j = glyph - GLYPH_EXPLODE_OFF;
|
||||||
|
expl = j / ((S_expl_br - S_expl_tl) + 1);
|
||||||
|
cmap = glyph_to_explosion(glyph) + S_expl_tl;
|
||||||
|
i = cmap - S_expl_tl;
|
||||||
|
Snprintf(tmpbuf[2], sizeof tmpbuf[2], "%s ",
|
||||||
|
expl_type_texts[expl]);
|
||||||
|
buf2 = tmpbuf[2];
|
||||||
|
Snprintf(tmpbuf[3], sizeof tmpbuf[3], "%s%s", "expl_",
|
||||||
|
expl_texts[i]);
|
||||||
|
buf3 = tmpbuf[3];
|
||||||
|
skip_base = TRUE;
|
||||||
|
}
|
||||||
|
if (!skip_base) {
|
||||||
|
if (cmap >= 0 && cmap < MAXPCHARS)
|
||||||
|
buf3 = loadsyms[cmap + cmap_offset].name + 2;
|
||||||
|
}
|
||||||
|
Strcpy(buf, "G_");
|
||||||
|
Strcat(buf, buf2);
|
||||||
|
Strcat(buf, buf3);
|
||||||
|
Strcat(buf, buf4);
|
||||||
|
} else if (glyph_is_invisible(glyph)) {
|
||||||
|
Strcpy(buf, "G_invisible");
|
||||||
|
} else if (glyph_is_nothing(glyph)) {
|
||||||
|
Strcpy(buf, "G_nothing");
|
||||||
|
} else if (glyph_is_unexplored(glyph)) {
|
||||||
|
Strcpy(buf, "G_unexplored");
|
||||||
|
} else if (glyph_is_warning(glyph)) {
|
||||||
|
j = glyph - GLYPH_WARNING_OFF;
|
||||||
|
Snprintf(buf, bufsz, "G_%s%d", "warning", j);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf[0] == '\0')
|
||||||
|
return 0;
|
||||||
|
if (memchr(buf, '\0', bufsz) == NULL) {
|
||||||
|
/* defensive: caller passed an undersized buffer */
|
||||||
|
buf[bufsz - 1] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fix_glyphname(buf + 2);
|
||||||
|
nhUse(mnum);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
glyph_to_cmap(int glyph)
|
glyph_to_cmap(int glyph)
|
||||||
{
|
{
|
||||||
@@ -283,152 +514,96 @@ glyph_find_core(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
When we start to process a config file or a symbol file,
|
* glyphname_hashtable is a sorted (hash, glyph) index of canonical
|
||||||
that might have G_ entries, generating all 9000+ glyphid
|
* "G_xxx" identifiers. populate_glyphname_hashtable() allocates one
|
||||||
for comparison repeatedly each time we encounter a G_
|
* block of MAX_GLYPH * sizeof(entry) (some entries go unused for the
|
||||||
entry to decipher, then comparing against them, is obviously
|
* scroll/gem appearance gaps), fills it via compose_glyph_name(), and
|
||||||
extremely performance-poor.
|
* sorts ascending by hash. Lookup is bsearch on the hash with
|
||||||
|
* compose_glyph_name()+strcmpi to disambiguate the rare collision.
|
||||||
|
*
|
||||||
|
* The name "hashtable" is historical; this is a sorted array, not an
|
||||||
|
* open-addressed hash table. The on-disk API in extern.h is kept so
|
||||||
|
* that callers (wizcmds.c, options.c) don't need to change.
|
||||||
|
*
|
||||||
|
* Memory: one alloc, ~75 KB for the 9577 named slots on a typical 5.0
|
||||||
|
* build (struct is 8 bytes, no per-name strings). The same data in
|
||||||
|
* upstream's open-addressed table cost ~256 KB for the buckets plus
|
||||||
|
* ~290 KB of dupstr'd names plus malloc overhead.
|
||||||
|
*/
|
||||||
|
|
||||||
Setting aside the "comparison" part for now (that has to be
|
staticfn int
|
||||||
done in some manner), we can likely do something about the
|
cmp_glyphname_entry(const void *a, const void *b)
|
||||||
repeated "generation" of the names for parsing prior to the
|
{
|
||||||
actual comparison part by generating them once, ahead of the
|
uint32 ha = ((const struct glyphname_hashtable_entry_t *) a)->hash;
|
||||||
bulk of the potential parsings. We can later free up
|
uint32 hb = ((const struct glyphname_hashtable_entry_t *) b)->hash;
|
||||||
all the memory those names consumed once the bulk parsing is
|
|
||||||
over with.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
if (ha < hb)
|
||||||
|
return -1;
|
||||||
|
if (ha > hb)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
populate_glyphname_hashtable(void)
|
populate_glyphname_hashtable(void)
|
||||||
{
|
{
|
||||||
int reslt = 0;
|
int glyph;
|
||||||
|
size_t n = 0;
|
||||||
|
char buf[BUFSZ];
|
||||||
|
|
||||||
if (!glyphname_hashtable_ptr) {
|
if (glyphname_hashtable_ptr)
|
||||||
init_glyphname_hashtable();
|
return;
|
||||||
}
|
glyphname_hashtable_ptr = (struct glyphname_hashtable_entry_t *) alloc(
|
||||||
if (glyphname_hashtable_ptr) {
|
MAX_GLYPH * sizeof (struct glyphname_hashtable_entry_t));
|
||||||
glyphname_hashtable_find = zero_find;
|
|
||||||
glyphname_hashtable_find.findtype = find_nothing;
|
for (glyph = 0; glyph < MAX_GLYPH; ++glyph) {
|
||||||
glyphname_hashtable_find.reserved = (genericptr_t) glyphname_hashtable_ptr;
|
if (compose_glyph_name(glyph, buf, sizeof buf)) {
|
||||||
glyphname_hashtable_find.restype = res_fill_hashtable;
|
glyphname_hashtable_ptr[n].hash = glyph_hash(buf);
|
||||||
reslt = parse_id((char *) 0, &glyphname_hashtable_find);
|
glyphname_hashtable_ptr[n].glyphnum = glyph;
|
||||||
if (!reslt) {
|
++n;
|
||||||
empty_glyphname_hashtable();
|
|
||||||
glyphname_hashtable_ptr = (struct glyphname_hashtable_entry_t *) 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
qsort(glyphname_hashtable_ptr, n,
|
||||||
|
sizeof glyphname_hashtable_ptr[0], cmp_glyphname_entry);
|
||||||
/*
|
glyphname_hashtable_count = n;
|
||||||
* The glyph ID cache is a simple double-hash table.
|
|
||||||
* The cache size is a power of two, and two hashes are derived from the
|
|
||||||
* cache ID. The first is a location in the table, and the second is an
|
|
||||||
* offset. On any collision, the second hash is added to the first until
|
|
||||||
* a match or an empty bucket is found.
|
|
||||||
* The second hash is an odd number, which is necessary and sufficient
|
|
||||||
* to traverse the entire table.
|
|
||||||
*/
|
|
||||||
|
|
||||||
staticfn void
|
|
||||||
init_glyphname_hashtable(void)
|
|
||||||
{
|
|
||||||
size_t glyph;
|
|
||||||
|
|
||||||
/* Cache size of power of 2 not less than 2*MAX_GLYPH */
|
|
||||||
glyphname_hashtable_lsize = 0;
|
|
||||||
glyphname_hashtable_size = 1;
|
|
||||||
while (glyphname_hashtable_size < 2*MAX_GLYPH) {
|
|
||||||
++glyphname_hashtable_lsize;
|
|
||||||
glyphname_hashtable_size <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
glyphname_hashtable_ptr = (struct glyphname_hashtable_entry_t *) alloc(
|
|
||||||
glyphname_hashtable_size * sizeof (struct glyphname_hashtable_entry_t));
|
|
||||||
for (glyph = 0; glyph < glyphname_hashtable_size; ++glyph) {
|
|
||||||
glyphname_hashtable_ptr[glyph].glyphnum = 0;
|
|
||||||
glyphname_hashtable_ptr[glyph].id = (char *) 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
empty_glyphname_hashtable(void)
|
empty_glyphname_hashtable(void)
|
||||||
{
|
{
|
||||||
size_t idx;
|
|
||||||
|
|
||||||
if (!glyphname_hashtable_ptr)
|
if (!glyphname_hashtable_ptr)
|
||||||
return;
|
return;
|
||||||
for (idx = 0; idx < glyphname_hashtable_size; ++idx) {
|
|
||||||
if (glyphname_hashtable_ptr[idx].id) {
|
|
||||||
free(glyphname_hashtable_ptr[idx].id);
|
|
||||||
glyphname_hashtable_ptr[idx].id = (char *) 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(glyphname_hashtable_ptr);
|
free(glyphname_hashtable_ptr);
|
||||||
glyphname_hashtable_ptr = (struct glyphname_hashtable_entry_t *) 0;
|
glyphname_hashtable_ptr = (struct glyphname_hashtable_entry_t *) 0;
|
||||||
}
|
glyphname_hashtable_count = 0;
|
||||||
|
|
||||||
staticfn void
|
|
||||||
add_glyph_to_glyphname_hashtable(int glyphnum, const char *id)
|
|
||||||
{
|
|
||||||
uint32 hash = glyph_hash(id);
|
|
||||||
size_t hash1 = (size_t) (hash & (glyphname_hashtable_size - 1));
|
|
||||||
size_t hash2 = (size_t)
|
|
||||||
(((hash >> glyphname_hashtable_lsize) & (glyphname_hashtable_size - 1)) | 1);
|
|
||||||
size_t i = hash1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (glyphname_hashtable_ptr[i].id == NULL) {
|
|
||||||
/* Empty bucket found */
|
|
||||||
glyphname_hashtable_ptr[i].id = dupstr(id);
|
|
||||||
glyphname_hashtable_ptr[i].glyphnum = glyphnum;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* For speed, assume that no ID occurs twice */
|
|
||||||
i = (i + hash2) & (glyphname_hashtable_size - 1);
|
|
||||||
} while (i != hash1);
|
|
||||||
/* This should never happen */
|
|
||||||
panic("glyphname_hashtable_ptr full");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
staticfn int
|
staticfn int
|
||||||
find_glyph_in_cache(const char *id)
|
find_glyph_in_hashtable(const char *id)
|
||||||
{
|
{
|
||||||
uint32 hash = glyph_hash(id);
|
uint32 want = glyph_hash(id);
|
||||||
size_t hash1 = (size_t) (hash & (glyphname_hashtable_size - 1));
|
size_t lo = 0, hi = glyphname_hashtable_count, mid;
|
||||||
size_t hash2 = (size_t)
|
char buf[BUFSZ];
|
||||||
(((hash >> glyphname_hashtable_lsize) & (glyphname_hashtable_size - 1)) | 1);
|
|
||||||
size_t i = hash1;
|
|
||||||
|
|
||||||
do {
|
/* Binary-search the sorted array for the first entry whose hash >= want. */
|
||||||
if (glyphname_hashtable_ptr[i].id == NULL) {
|
while (lo < hi) {
|
||||||
/* Empty bucket found */
|
mid = (lo + hi) >> 1;
|
||||||
return -1;
|
if (glyphname_hashtable_ptr[mid].hash < want)
|
||||||
}
|
lo = mid + 1;
|
||||||
if (strcmpi(id, glyphname_hashtable_ptr[i].id) == 0) {
|
else
|
||||||
/* Match found */
|
hi = mid;
|
||||||
return glyphname_hashtable_ptr[i].glyphnum;
|
|
||||||
}
|
|
||||||
i = (i + hash2) & (glyphname_hashtable_size - 1);
|
|
||||||
} while (i != hash1);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
staticfn char *
|
|
||||||
find_glyphname_in_hashtable_by_glyphnum(int glyphnum)
|
|
||||||
{
|
|
||||||
size_t idx;
|
|
||||||
|
|
||||||
if (!glyphname_hashtable_ptr)
|
|
||||||
return (char *) 0;
|
|
||||||
for (idx = 0; idx < glyphname_hashtable_size; ++idx) {
|
|
||||||
if (glyphname_hashtable_ptr[idx].glyphnum == glyphnum
|
|
||||||
&& glyphname_hashtable_ptr[idx].id != 0) {
|
|
||||||
/* Match found */
|
|
||||||
return glyphname_hashtable_ptr[idx].id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return (char *) 0;
|
/* Walk forward across any equal-hash neighbours, verifying each by
|
||||||
|
reconstructing the canonical name and strcmpi'ing it back. */
|
||||||
|
while (lo < glyphname_hashtable_count
|
||||||
|
&& glyphname_hashtable_ptr[lo].hash == want) {
|
||||||
|
int g = glyphname_hashtable_ptr[lo].glyphnum;
|
||||||
|
|
||||||
|
if (compose_glyph_name(g, buf, sizeof buf) && !strcmpi(id, buf))
|
||||||
|
return g;
|
||||||
|
++lo;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
staticfn uint32
|
staticfn uint32
|
||||||
@@ -808,15 +983,11 @@ void
|
|||||||
wizcustom_glyphnames(winid win)
|
wizcustom_glyphnames(winid win)
|
||||||
{
|
{
|
||||||
int glyphnum;
|
int glyphnum;
|
||||||
char *id;
|
char buf[BUFSZ];
|
||||||
|
|
||||||
if (!glyphname_hashtable_ptr)
|
|
||||||
return;
|
|
||||||
for (glyphnum = 0; glyphnum < MAX_GLYPH; ++glyphnum) {
|
for (glyphnum = 0; glyphnum < MAX_GLYPH; ++glyphnum) {
|
||||||
id = find_glyphname_in_hashtable_by_glyphnum(glyphnum);
|
if (compose_glyph_name(glyphnum, buf, sizeof buf))
|
||||||
if (id) {
|
wizcustom_callback(win, glyphnum, buf);
|
||||||
wizcustom_callback(win, glyphnum, id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -826,12 +997,11 @@ parse_id(
|
|||||||
struct find_struct *findwhat)
|
struct find_struct *findwhat)
|
||||||
{
|
{
|
||||||
FILE *fp = (FILE *) 0;
|
FILE *fp = (FILE *) 0;
|
||||||
int i = 0, j, mnum, glyph,
|
int i = 0, glyph,
|
||||||
pm_offset = 0, oc_offset = 0, cmap_offset = 0,
|
pm_offset = 0, oc_offset = 0, cmap_offset = 0,
|
||||||
pm_count = 0, oc_count = 0, cmap_count = 0;
|
pm_count = 0, oc_count = 0, cmap_count = 0;
|
||||||
boolean skip_base = FALSE, skip_this_one = FALSE, dump_ids = FALSE,
|
boolean dump_ids = FALSE, is_S = FALSE, is_G = FALSE;
|
||||||
filling_cache = FALSE, is_S = FALSE, is_G = FALSE;
|
char buf[BUFSZ];
|
||||||
char buf[4][QBUFSZ];
|
|
||||||
|
|
||||||
if (findwhat->findtype == find_nothing && findwhat->restype) {
|
if (findwhat->findtype == find_nothing && findwhat->restype) {
|
||||||
if (findwhat->restype == res_dump_glyphnames) {
|
if (findwhat->restype == res_dump_glyphnames) {
|
||||||
@@ -842,20 +1012,12 @@ parse_id(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (findwhat->restype == res_fill_hashtable) {
|
|
||||||
if (findwhat->reserved
|
|
||||||
&& findwhat->reserved == (genericptr_t) glyphname_hashtable_ptr) {
|
|
||||||
filling_cache = TRUE;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is_G = (id && id[0] == 'G' && id[1] == '_');
|
is_G = (id && id[0] == 'G' && id[1] == '_');
|
||||||
is_S = (id && id[0] == 'S' && id[1] == '_');
|
is_S = (id && id[0] == 'S' && id[1] == '_');
|
||||||
|
|
||||||
if ((is_G && !glyphname_hashtable_ptr) || filling_cache || dump_ids || is_S) {
|
if (dump_ids || is_S) {
|
||||||
while (loadsyms[i].range) {
|
while (loadsyms[i].range) {
|
||||||
if (!pm_offset && loadsyms[i].range == SYM_MON)
|
if (!pm_offset && loadsyms[i].range == SYM_MON)
|
||||||
pm_offset = i;
|
pm_offset = i;
|
||||||
@@ -872,259 +1034,31 @@ parse_id(
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_G || filling_cache || dump_ids) {
|
if (is_G && id) {
|
||||||
if (!filling_cache && id && glyphname_hashtable_ptr) {
|
/* Populate the hash table lazily, on first G_xxx lookup. */
|
||||||
int val = find_glyph_in_cache(id);
|
if (!glyphname_hashtable_ptr)
|
||||||
|
populate_glyphname_hashtable();
|
||||||
|
if (glyphname_hashtable_ptr) {
|
||||||
|
int val = find_glyph_in_hashtable(id);
|
||||||
|
|
||||||
if (val >= 0) {
|
if (val >= 0) {
|
||||||
findwhat->findtype = find_glyph;
|
findwhat->findtype = find_glyph;
|
||||||
findwhat->val = val;
|
findwhat->val = val;
|
||||||
findwhat->loadsyms_offset = 0;
|
findwhat->loadsyms_offset = 0;
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
const char *buf2, *buf3, *buf4;
|
return 0;
|
||||||
|
}
|
||||||
/* individual matching glyph entries */
|
if (dump_ids) {
|
||||||
for (glyph = 0; glyph < MAX_GLYPH; ++glyph) {
|
/* iterate and dump every named glyph */
|
||||||
skip_base = FALSE;
|
for (glyph = 0; glyph < MAX_GLYPH; ++glyph) {
|
||||||
skip_this_one = FALSE;
|
if (compose_glyph_name(glyph, buf, sizeof buf))
|
||||||
buf[0][0] = buf[1][0] = buf[2][0] = buf[3][0] = '\0';
|
Fprintf(fp, "(%04d) %s\n", glyph, buf);
|
||||||
if (glyph_is_monster(glyph)) {
|
}
|
||||||
/* buf2 will hold the distinguishing prefix */
|
return 1;
|
||||||
/* buf3 will hold the base name */
|
}
|
||||||
buf2 = "";
|
if (is_S) {
|
||||||
buf3 = monsdump[glyph_to_mon(glyph)].nm;
|
|
||||||
|
|
||||||
if (glyph_is_normal_male_monster(glyph)) {
|
|
||||||
buf2 = "male_";
|
|
||||||
} else if (glyph_is_normal_female_monster(glyph)) {
|
|
||||||
buf2 = "female_";
|
|
||||||
} else if (glyph_is_ridden_male_monster(glyph)) {
|
|
||||||
buf2 = "ridden_male_";
|
|
||||||
} else if (glyph_is_ridden_female_monster(glyph)) {
|
|
||||||
buf2 = "ridden_female_";
|
|
||||||
} else if (glyph_is_detected_male_monster(glyph)) {
|
|
||||||
buf2 = "detected_male_";
|
|
||||||
} else if (glyph_is_detected_female_monster(glyph)) {
|
|
||||||
buf2 = "detected_female_";
|
|
||||||
} else if (glyph_is_male_pet(glyph)) {
|
|
||||||
buf2 = "pet_male_";
|
|
||||||
} else if (glyph_is_female_pet(glyph)) {
|
|
||||||
buf2 = "pet_female_";
|
|
||||||
}
|
|
||||||
Strcpy(buf[0], "G_");
|
|
||||||
Strcat(buf[0], buf2);
|
|
||||||
Strcat(buf[0], buf3);
|
|
||||||
} else if (glyph_is_body(glyph)) {
|
|
||||||
/* buf2 will hold the distinguishing prefix */
|
|
||||||
/* buf3 will hold the base name */
|
|
||||||
buf2 = glyph_is_body_piletop(glyph)
|
|
||||||
? "piletop_body_"
|
|
||||||
: "body_";
|
|
||||||
buf3 = monsdump[glyph_to_body_corpsenm(glyph)].nm;
|
|
||||||
Strcpy(buf[0], "G_");
|
|
||||||
Strcat(buf[0], buf2);
|
|
||||||
Strcat(buf[0], buf3);
|
|
||||||
} else if (glyph_is_statue(glyph)) {
|
|
||||||
/* buf2 will hold the distinguishing prefix */
|
|
||||||
/* buf3 will hold the base name */
|
|
||||||
buf2 = glyph_is_fem_statue_piletop(glyph)
|
|
||||||
? "piletop_statue_of_female_"
|
|
||||||
: glyph_is_fem_statue(glyph)
|
|
||||||
? "statue_of_female_"
|
|
||||||
: glyph_is_male_statue_piletop(glyph)
|
|
||||||
? "piletop_statue_of_male_"
|
|
||||||
: glyph_is_male_statue(glyph)
|
|
||||||
? "statue_of_male_"
|
|
||||||
: ""; /* shouldn't happen */
|
|
||||||
buf3 = monsdump[glyph_to_statue_corpsenm(glyph)].nm;
|
|
||||||
Strcpy(buf[0], "G_");
|
|
||||||
Strcat(buf[0], buf2);
|
|
||||||
Strcat(buf[0], buf3);
|
|
||||||
} else if (glyph_is_object(glyph)) {
|
|
||||||
i = glyph_to_obj(glyph);
|
|
||||||
/* buf2 will hold the distinguishing prefix */
|
|
||||||
/* buf3 will hold the base name */
|
|
||||||
if (((i > SCR_STINKING_CLOUD) && (i < SCR_MAIL))
|
|
||||||
|| ((i > WAN_LIGHTNING) && (i < GOLD_PIECE)))
|
|
||||||
skip_this_one = TRUE;
|
|
||||||
if (!skip_this_one) {
|
|
||||||
if ((i >= WAN_LIGHT) && (i <= WAN_LIGHTNING))
|
|
||||||
buf2 = "wand of ";
|
|
||||||
else if ((i >= SPE_DIG) && (i < SPE_BLANK_PAPER))
|
|
||||||
buf2 = "spellbook of ";
|
|
||||||
else if ((i >= SCR_ENCHANT_ARMOR)
|
|
||||||
&& (i <= SCR_STINKING_CLOUD))
|
|
||||||
buf2 = "scroll of ";
|
|
||||||
else if ((i >= POT_GAIN_ABILITY) && (i <= POT_WATER))
|
|
||||||
buf2 = (i == POT_WATER) ? "flask of n"
|
|
||||||
: "potion of ";
|
|
||||||
else if ((i >= RIN_ADORNMENT)
|
|
||||||
&& (i <= RIN_PROTECTION_FROM_SHAPE_CHAN))
|
|
||||||
buf2 = "ring of ";
|
|
||||||
else if (i == LAND_MINE)
|
|
||||||
buf2 = "unset ";
|
|
||||||
else
|
|
||||||
buf2 = "";
|
|
||||||
buf3 = (i == SCR_BLANK_PAPER) ? "blank scroll"
|
|
||||||
: (i == SPE_BLANK_PAPER) ? "blank spellbook"
|
|
||||||
: (i == SLIME_MOLD) ? "slime mold"
|
|
||||||
: obj_descr[i].oc_name
|
|
||||||
? obj_descr[i].oc_name
|
|
||||||
: obj_descr[i].oc_descr;
|
|
||||||
Strcpy(buf[0], "G_");
|
|
||||||
if (glyph_is_normal_piletop_obj(glyph))
|
|
||||||
Strcat(buf[0], "piletop_");
|
|
||||||
Strcat(buf[0], buf2);
|
|
||||||
Strcat(buf[0], buf3);
|
|
||||||
}
|
|
||||||
} else if (glyph_is_cmap(glyph) || glyph_is_cmap_zap(glyph)
|
|
||||||
|| glyph_is_swallow(glyph)
|
|
||||||
|| glyph_is_explosion(glyph)) {
|
|
||||||
int cmap = -1;
|
|
||||||
|
|
||||||
/* buf2 will hold the distinguishing prefix */
|
|
||||||
/* buf3 will hold the base name */
|
|
||||||
/* buf4 will hold the distinguishing suffix */
|
|
||||||
buf2 = "";
|
|
||||||
buf3 = "";
|
|
||||||
buf4 = "";
|
|
||||||
if (glyph == GLYPH_CMAP_OFF) {
|
|
||||||
cmap = S_stone;
|
|
||||||
buf3 = "stone substrate";
|
|
||||||
skip_base = TRUE;
|
|
||||||
} else if (glyph_is_cmap_gehennom(glyph)) {
|
|
||||||
cmap = (glyph - GLYPH_CMAP_GEH_OFF) + S_vwall;
|
|
||||||
buf4 = "_gehennom";
|
|
||||||
} else if (glyph_is_cmap_knox(glyph)) {
|
|
||||||
cmap = (glyph - GLYPH_CMAP_KNOX_OFF) + S_vwall;
|
|
||||||
buf4 = "_knox";
|
|
||||||
} else if (glyph_is_cmap_main(glyph)) {
|
|
||||||
cmap = (glyph - GLYPH_CMAP_MAIN_OFF) + S_vwall;
|
|
||||||
buf4 = "_main";
|
|
||||||
} else if (glyph_is_cmap_mines(glyph)) {
|
|
||||||
cmap = (glyph - GLYPH_CMAP_MINES_OFF) + S_vwall;
|
|
||||||
buf4 = "_mines";
|
|
||||||
} else if (glyph_is_cmap_sokoban(glyph)) {
|
|
||||||
cmap = (glyph - GLYPH_CMAP_SOKO_OFF) + S_vwall;
|
|
||||||
buf4 = "_sokoban";
|
|
||||||
} else if (glyph_is_cmap_a(glyph)) {
|
|
||||||
cmap = (glyph - GLYPH_CMAP_A_OFF) + S_ndoor;
|
|
||||||
} else if (glyph_is_cmap_altar(glyph)) {
|
|
||||||
static const char *const altar_text[] = {
|
|
||||||
"unaligned", "chaotic", "neutral",
|
|
||||||
"lawful", "other",
|
|
||||||
};
|
|
||||||
|
|
||||||
j = (glyph - GLYPH_ALTAR_OFF);
|
|
||||||
cmap = S_altar;
|
|
||||||
if (j != altar_other) {
|
|
||||||
Snprintf(buf[2], sizeof buf[2], "%s_",
|
|
||||||
altar_text[j]);
|
|
||||||
buf2 = buf[2];
|
|
||||||
} else {
|
|
||||||
buf3 = "altar other";
|
|
||||||
skip_base = TRUE;
|
|
||||||
}
|
|
||||||
} else if (glyph_is_cmap_b(glyph)) {
|
|
||||||
cmap = (glyph - GLYPH_CMAP_B_OFF) + S_grave;
|
|
||||||
} else if (glyph_is_cmap_zap(glyph)) {
|
|
||||||
static const char *const zap_texts[] = {
|
|
||||||
"missile", "fire", "frost", "sleep",
|
|
||||||
"death", "lightning", "poison gas", "acid"
|
|
||||||
};
|
|
||||||
|
|
||||||
j = (glyph - GLYPH_ZAP_OFF);
|
|
||||||
cmap = (j % 4) + S_vbeam;
|
|
||||||
Snprintf(buf[2], sizeof buf[2], "%s",
|
|
||||||
loadsyms[cmap + cmap_offset].name + 2);
|
|
||||||
Snprintf(buf[3], sizeof buf[3], "%s zap %s",
|
|
||||||
zap_texts[j / 4], fix_glyphname(buf[2]));
|
|
||||||
buf3 = buf[3];
|
|
||||||
buf2 = "";
|
|
||||||
skip_base = TRUE;
|
|
||||||
} else if (glyph_is_cmap_c(glyph)) {
|
|
||||||
cmap = (glyph - GLYPH_CMAP_C_OFF) + S_digbeam;
|
|
||||||
} else if (glyph_is_swallow(glyph)) {
|
|
||||||
static const char *const swallow_texts[] = {
|
|
||||||
"top left", "top center", "top right",
|
|
||||||
"middle left", "middle right", "bottom left",
|
|
||||||
"bottom center", "bottom right",
|
|
||||||
};
|
|
||||||
|
|
||||||
j = glyph - GLYPH_SWALLOW_OFF;
|
|
||||||
cmap = glyph_to_swallow(glyph);
|
|
||||||
mnum = j / ((S_sw_br - S_sw_tl) + 1);
|
|
||||||
Strcpy(buf[3], "swallow ");
|
|
||||||
Strcat(buf[3], monsdump[mnum].nm);
|
|
||||||
Strcat(buf[3], " ");
|
|
||||||
Strcat(buf[3], swallow_texts[cmap]);
|
|
||||||
buf3 = buf[3];
|
|
||||||
skip_base = TRUE;
|
|
||||||
} else if (glyph_is_explosion(glyph)) {
|
|
||||||
static const char *const expl_type_texts[] = {
|
|
||||||
"dark", "noxious", "muddy", "wet",
|
|
||||||
"magical", "fiery", "frosty",
|
|
||||||
};
|
|
||||||
static const char *const expl_texts[] = {
|
|
||||||
"tl", "tc", "tr", "ml", "mc",
|
|
||||||
"mr", "bl", "bc", "br",
|
|
||||||
};
|
|
||||||
int expl;
|
|
||||||
|
|
||||||
j = glyph - GLYPH_EXPLODE_OFF;
|
|
||||||
expl = j / ((S_expl_br - S_expl_tl) + 1);
|
|
||||||
cmap = glyph_to_explosion(glyph) + S_expl_tl;
|
|
||||||
i = cmap - S_expl_tl;
|
|
||||||
Snprintf(buf[2], sizeof buf[2], "%s ",
|
|
||||||
expl_type_texts[expl]);
|
|
||||||
buf2 = buf[2];
|
|
||||||
Snprintf(buf[3], sizeof buf[3], "%s%s", "expl_",
|
|
||||||
expl_texts[i]);
|
|
||||||
buf3 = buf[3];
|
|
||||||
skip_base = TRUE;
|
|
||||||
}
|
|
||||||
if (!skip_base) {
|
|
||||||
if (cmap >= 0 && cmap < MAXPCHARS) {
|
|
||||||
buf3 = loadsyms[cmap + cmap_offset].name + 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Strcpy(buf[0], "G_");
|
|
||||||
Strcat(buf[0], buf2);
|
|
||||||
Strcat(buf[0], buf3);
|
|
||||||
Strcat(buf[0], buf4);
|
|
||||||
} else if (glyph_is_invisible(glyph)) {
|
|
||||||
Strcpy(buf[0], "G_invisible");
|
|
||||||
} else if (glyph_is_nothing(glyph)) {
|
|
||||||
Strcpy(buf[0], "G_nothing");
|
|
||||||
} else if (glyph_is_unexplored(glyph)) {
|
|
||||||
Strcpy(buf[0], "G_unexplored");
|
|
||||||
} else if (glyph_is_warning(glyph)) {
|
|
||||||
j = glyph - GLYPH_WARNING_OFF;
|
|
||||||
Snprintf(buf[0], sizeof buf[0], "G_%s%d", "warning", j);
|
|
||||||
}
|
|
||||||
if (memchr(buf[0], '\0', sizeof buf[0]) == NULL)
|
|
||||||
panic("parse_id: buf[0] overflowed");
|
|
||||||
if (!skip_this_one) {
|
|
||||||
fix_glyphname(buf[0]+2);
|
|
||||||
if (dump_ids) {
|
|
||||||
Fprintf(fp, "(%04d) %s\n", glyph, buf[0]);
|
|
||||||
} else if (filling_cache) {
|
|
||||||
add_glyph_to_glyphname_hashtable(glyph, buf[0]);
|
|
||||||
} else if (id) {
|
|
||||||
if (!strcmpi(id, buf[0])) {
|
|
||||||
findwhat->findtype = find_glyph;
|
|
||||||
findwhat->val = glyph;
|
|
||||||
findwhat->loadsyms_offset = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} /* not glyphname_hashtable_ptr */
|
|
||||||
} else if (is_S) {
|
|
||||||
/* cmap entries */
|
/* cmap entries */
|
||||||
for (i = 0; i < cmap_count; ++i) {
|
for (i = 0; i < cmap_count; ++i) {
|
||||||
if (!strcmpi(loadsyms[i + cmap_offset].name + 2, id + 2)) {
|
if (!strcmpi(loadsyms[i + cmap_offset].name + 2, id + 2)) {
|
||||||
@@ -1153,8 +1087,6 @@ parse_id(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dump_ids || filling_cache)
|
|
||||||
return 1;
|
|
||||||
findwhat->findtype = find_nothing;
|
findwhat->findtype = find_nothing;
|
||||||
findwhat->val = 0;
|
findwhat->val = 0;
|
||||||
findwhat->loadsyms_offset = 0;
|
findwhat->loadsyms_offset = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user