+ if (! (*func) (p, info))
+ goto out;
+ }
+ out:
+ table->frozen = 0;
+}
+\f
+unsigned long
+bfd_hash_set_default_size (unsigned long hash_size)
+{
+ /* Extend this prime list if you want more granularity of hash table size. */
+ static const unsigned long hash_size_primes[] =
+ {
+ 31, 61, 127, 251, 509, 1021, 2039, 4091, 8191, 16381, 32749, 65537
+ };
+ unsigned int _index;
+
+ /* Work out best prime number near the hash_size. */
+ for (_index = 0; _index < ARRAY_SIZE (hash_size_primes) - 1; ++_index)
+ if (hash_size <= hash_size_primes[_index])
+ break;
+
+ bfd_default_hash_table_size = hash_size_primes[_index];
+ return bfd_default_hash_table_size;
+}
+\f
+/* A few different object file formats (a.out, COFF, ELF) use a string
+ table. These functions support adding strings to a string table,
+ returning the byte offset, and writing out the table.
+
+ Possible improvements:
+ + look for strings matching trailing substrings of other strings
+ + better data structures? balanced trees?
+ + look at reducing memory use elsewhere -- maybe if we didn't have
+ to construct the entire symbol table at once, we could get by
+ with smaller amounts of VM? (What effect does that have on the
+ string table reductions?) */
+
+/* An entry in the strtab hash table. */
+
+struct strtab_hash_entry
+{
+ struct bfd_hash_entry root;
+ /* Index in string table. */
+ bfd_size_type index;
+ /* Next string in strtab. */
+ struct strtab_hash_entry *next;
+};
+
+/* The strtab hash table. */
+
+struct bfd_strtab_hash
+{
+ struct bfd_hash_table table;
+ /* Size of strtab--also next available index. */
+ bfd_size_type size;
+ /* First string in strtab. */
+ struct strtab_hash_entry *first;
+ /* Last string in strtab. */
+ struct strtab_hash_entry *last;
+ /* Whether to precede strings with a two byte length, as in the
+ XCOFF .debug section. */
+ bfd_boolean xcoff;
+};
+
+/* Routine to create an entry in a strtab. */
+
+static struct bfd_hash_entry *
+strtab_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
+{
+ struct strtab_hash_entry *ret = (struct strtab_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == NULL)
+ ret = (struct strtab_hash_entry *) bfd_hash_allocate (table,
+ sizeof (* ret));
+ if (ret == NULL)
+ return NULL;
+
+ /* Call the allocation method of the superclass. */
+ ret = (struct strtab_hash_entry *)
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string);
+
+ if (ret)
+ {
+ /* Initialize the local fields. */
+ ret->index = (bfd_size_type) -1;
+ ret->next = NULL;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Look up an entry in an strtab. */
+
+#define strtab_hash_lookup(t, string, create, copy) \
+ ((struct strtab_hash_entry *) \
+ bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
+
+/* Create a new strtab. */
+
+struct bfd_strtab_hash *
+_bfd_stringtab_init (void)
+{
+ struct bfd_strtab_hash *table;
+ size_t amt = sizeof (* table);
+
+ table = (struct bfd_strtab_hash *) bfd_malloc (amt);
+ if (table == NULL)
+ return NULL;
+
+ if (!bfd_hash_table_init (&table->table, strtab_hash_newfunc,
+ sizeof (struct strtab_hash_entry)))
+ {
+ free (table);
+ return NULL;
+ }
+
+ table->size = 0;
+ table->first = NULL;
+ table->last = NULL;
+ table->xcoff = FALSE;
+
+ return table;
+}
+
+/* Create a new strtab in which the strings are output in the format
+ used in the XCOFF .debug section: a two byte length precedes each
+ string. */
+
+struct bfd_strtab_hash *
+_bfd_xcoff_stringtab_init (void)
+{
+ struct bfd_strtab_hash *ret;
+
+ ret = _bfd_stringtab_init ();
+ if (ret != NULL)
+ ret->xcoff = TRUE;
+ return ret;
+}
+
+/* Free a strtab. */
+
+void
+_bfd_stringtab_free (struct bfd_strtab_hash *table)
+{
+ bfd_hash_table_free (&table->table);
+ free (table);
+}
+
+/* Get the index of a string in a strtab, adding it if it is not
+ already present. If HASH is FALSE, we don't really use the hash
+ table, and we don't eliminate duplicate strings. If COPY is true
+ then store a copy of STR if creating a new entry. */
+
+bfd_size_type
+_bfd_stringtab_add (struct bfd_strtab_hash *tab,
+ const char *str,
+ bfd_boolean hash,
+ bfd_boolean copy)
+{
+ struct strtab_hash_entry *entry;
+
+ if (hash)
+ {
+ entry = strtab_hash_lookup (tab, str, TRUE, copy);
+ if (entry == NULL)
+ return (bfd_size_type) -1;
+ }
+ else
+ {
+ entry = (struct strtab_hash_entry *) bfd_hash_allocate (&tab->table,
+ sizeof (* entry));
+ if (entry == NULL)
+ return (bfd_size_type) -1;
+ if (! copy)
+ entry->root.string = str;
+ else