+ }
+ continue;
+ }
+ *lbp++ = *l++;
+ }
+
+ *lbp = '\0';
+ if (cl)
+ cl = connectLine (cl, newLineNode (lb));
+ else
+ lhead = cl = newLineNode (lb);
+ }
+
+ /* add the comments if any to the head of list */
+ if (comment)
+ {
+ lineNode *lc = comment;
+ while (lc->next)
+ lc = lc->next;
+ lc->next = lhead;
+ if (lhead)
+ lhead->prev = lc;
+ lhead = comment;
+ }
+
+ /* now we need to connect / replace the original chain */
+ /* if there is a prev then change it */
+ if ((*shead)->prev)
+ {
+ (*shead)->prev->next = lhead;
+ lhead->prev = (*shead)->prev;
+ }
+ else
+ *shead = lhead;
+ /* now for the tail */
+ if (stail && stail->next)
+ {
+ stail->next->prev = cl;
+ if (cl)
+ cl->next = stail->next;
+ }
+}
+
+/* Returns TRUE if this line is a label definition.
+
+ * If so, start will point to the start of the label name,
+ * and len will be it's length.
+ */
+bool
+isLabelDefinition (const char *line, const char **start, int *len)
+{
+ const char *cp = line;
+
+ /* This line is a label if if consists of:
+ * [optional whitespace] followed by identifier chars
+ * (alnum | $ | _ ) followed by a colon.
+ */
+
+ while (*cp && isspace (*cp))
+ {
+ cp++;
+ }
+
+ if (!*cp)
+ {
+ return FALSE;
+ }
+
+ *start = cp;
+
+ while (isalnum (*cp) || (*cp == '$') || (*cp == '_'))
+ {
+ cp++;
+ }
+
+ if ((cp == *start) || (*cp != ':'))
+ {
+ return FALSE;
+ }
+
+ *len = (cp - (*start));
+ return TRUE;
+}
+
+/* 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);