+/* Quick & dirty string hash function. */
+static int
+hashSymbolName (const char *name)
+{
+ int hash = 0;
+
+ while (*name)
+ {
+ hash = (hash << 6) ^ *name;
+ name++;
+ }
+
+ if (hash < 0)
+ {
+ hash = -hash;
+ }
+
+ return hash % HTAB_SIZE;
+}
+
+/* Build a hash of all labels in the passed set of lines
+ * and how many times they are referenced.
+ */
+static void
+buildLabelRefCountHash (lineNode * head)
+{
+ lineNode *line;
+ const char *label;
+ int labelLen;
+ int i;
+
+ assert (labelHash == NULL);
+ labelHash = newHashTable (HTAB_SIZE);
+
+ /* First pass: locate all the labels. */
+ line = head;
+
+ while (line)
+ {
+ if (isLabelDefinition (line->line, &label, &labelLen)
+ && labelLen <= SDCC_NAME_MAX)
+ {
+ labelHashEntry *entry;
+
+ entry = traceAlloc (&_G.labels, Safe_alloc(sizeof (labelHashEntry)));
+
+ memcpy (entry->name, label, labelLen);
+ entry->name[labelLen] = 0;
+ entry->refCount = -1;
+
+ hTabAddItem (&labelHash, hashSymbolName (entry->name), entry);
+ }
+ line = line->next;
+ }
+
+
+ /* Second pass: for each line, note all the referenced labels. */
+ /* This is ugly, O(N^2) stuff. Optimizations welcome... */
+ line = head;
+ while (line)
+ {
+ for (i = 0; i < HTAB_SIZE; i++)
+ {
+ labelHashEntry *thisEntry;
+
+ thisEntry = hTabFirstItemWK (labelHash, i);
+
+ while (thisEntry)
+ {
+ if (strstr (line->line, thisEntry->name))
+ {
+ thisEntry->refCount++;
+ }
+ thisEntry = hTabNextItemWK (labelHash);
+ }
+ }
+ line = line->next;
+ }
+
+#if 0
+ /* Spew the contents of the table. Debugging fun only. */
+ for (i = 0; i < HTAB_SIZE; i++)
+ {
+ labelHashEntry *thisEntry;
+
+ thisEntry = hTabFirstItemWK (labelHash, i);
+
+ while (thisEntry)
+ {
+ fprintf (stderr, "label: %s ref %d\n",
+ thisEntry->name, thisEntry->refCount);
+ thisEntry = hTabNextItemWK (labelHash);
+ }
+ }
+#endif
+}
+
+/* How does this work?
+ peepHole
+ For each rule,
+ For each line,
+ Try to match
+ If it matches,
+ replace and restart.
+
+ matchRule
+ matchLine
+
+ Where is stuff allocated?
+
+*/
+