Index: trunk/Ohana/src/opihi/lib.data/queues.c
===================================================================
--- trunk/Ohana/src/opihi/lib.data/queues.c	(revision 4693)
+++ trunk/Ohana/src/opihi/lib.data/queues.c	(revision 4697)
@@ -1,3 +1,3 @@
-# include "opihi.h"
+# include "data.h"
 
 /* These functions are somewhat fragile: we cannot do multiple CreateQueue
@@ -56,15 +56,165 @@
 }
 
+void PushNamedQueue (char *name, char *line) {
+
+  Queue *queue;
+  
+  queue = FindQueue (name);
+  if (queue == NULL) {
+    queue = CreateQueue (name);
+  }
+  PushQueue (queue, line);
+  return;
+}
+
+/* push line onto queue.  return chars create new lines */
 void PushQueue (Queue *queue, char *line) {
 
   int N;
-
+  char *p, *q;
+
+  p = line;
+  q = strchr (line, '\n');
   N = queue[0].Nlines;
-  queue[0].lines[N] = strcreate (line);
-  queue[0].Nlines ++;
-  if (queue[0].Nlines == queue[0].NLINES) {
-    queue[0].NLINES += 10;
-    REALLOCATE (queue[0].lines, char *, queue[0].NLINES);
-  }    
+  while (q != NULL) {
+    queue[0].lines[N] = strncreate (p, q - p);
+    N++;
+    CHECK_REALLOCATE (queue[0].lines, char *, queue[0].NLINES, N, 16);
+    p = q + 1;
+    q = strchr (p, '\n');
+  }    
+  if (*p) {
+    queue[0].lines[N] = strcreate (p);
+    N++;
+    CHECK_REALLOCATE (queue[0].lines, char *, queue[0].NLINES, N, 16);
+  }
+  queue[0].Nlines = N;
+  return;
+}
+
+char *ChooseKey (char *line, int Key) {
+
+  int i;
+  char *key, *p;
+
+  key = line;
+  if (Key != -1) {
+    for (i = 0; (i < Key) && (key != NULL); i++) {
+      p = nextword (key);
+      key = p;
+    }
+    key = thisword (key);
+  } 
+  return (key);
+}
+
+/* push line onto queue, skipping existing matches (optionally by key) */
+void PushQueueUnique (Queue *queue, char *line, int Key) {
+
+  int i, j, N, found;
+  char *p, *q, *key1, *key2;
+  Queue tmp;
+
+  /* init tmp queue */
+  tmp.Nlines = 0;
+  tmp.NLINES = 16;
+  ALLOCATE (tmp.lines, char *, tmp.NLINES);
+
+  /* push entries on tmp queue */
+  p = line;
+  q = strchr (line, '\n');
+  N = tmp.Nlines;
+  while (q != NULL) {
+    tmp.lines[N] = strncreate (p, q - p);
+    N++;
+    CHECK_REALLOCATE (tmp.lines, char *, tmp.NLINES, N, 16);
+    p = q + 1;
+    q = strchr (p, '\n');
+  }    
+  if (*p) {
+    tmp.lines[N] = strcreate (p);
+    N++;
+    CHECK_REALLOCATE (tmp.lines, char *, tmp.NLINES, N, 16);
+  }
+  tmp.Nlines = N;
+
+  /* add unique entries in tmp to queue */
+  for (i = 0; i < tmp.Nlines; i++) {
+    key1 = ChooseKey (tmp.lines[i], Key);
+    if (key1 == NULL) continue;
+    found = FALSE;
+    for (j = 0; !found && (j < queue[0].Nlines); j++) {
+      key2 = ChooseKey (queue[0].lines[j], Key);
+      if (key2 == NULL) continue;
+      if (strcmp (key1, key2)) {
+	if (Key != -1) free (key2);
+	continue;
+      }
+      found = TRUE;
+      if (Key != -1) free (key2);
+    }      
+    if (!found) PushQueue (queue, tmp.lines[i]);
+    if (Key != -1) free (key1);
+  }
+  for (i = 0; i < tmp.Nlines; i++) {
+    free (tmp.lines[i]);
+  } 
+  free (tmp.lines);
+  return;
+}
+
+/* push line onto queue, replacing matches (optionally by Key) */
+void PushQueueReplace (Queue *queue, char *line, int Key) {
+
+  int i, j, N, found;
+  char *p, *q, *key1, *key2;
+  Queue tmp;
+
+  /* init tmp queue */
+  tmp.Nlines = 0;
+  tmp.NLINES = 16;
+  ALLOCATE (tmp.lines, char *, tmp.NLINES);
+
+  /* push entries on tmp queue */
+  p = line;
+  q = strchr (line, '\n');
+  N = tmp.Nlines;
+  while (q != NULL) {
+    tmp.lines[N] = strncreate (p, q - p);
+    N++;
+    CHECK_REALLOCATE (tmp.lines, char *, tmp.NLINES, N, 16);
+    p = q + 1;
+    q = strchr (p, '\n');
+  }    
+  if (*p) {
+    tmp.lines[N] = strcreate (p);
+    N++;
+    CHECK_REALLOCATE (tmp.lines, char *, tmp.NLINES, N, 16);
+  }
+  tmp.Nlines = N;
+
+  /* add unique entries in tmp to queue */
+  for (i = 0; i < tmp.Nlines; i++) {
+    key1 = ChooseKey (tmp.lines[i], Key);
+    if (key1 == NULL) continue;
+    found = FALSE;
+    for (j = 0; !found && (j < queue[0].Nlines); j++) {
+      key2 = ChooseKey (queue[0].lines[j], Key);
+      if (key2 == NULL) continue;
+      if (strcmp (key1, key2)) {
+	if (Key != -1) free (key2);
+	continue;
+      }
+      queue[0].lines[j] = strcreate (tmp.lines[i]);
+      found = TRUE;
+      if (Key != -1) free (key2);
+    }      
+    if (!found) PushQueue (queue, tmp.lines[i]);
+    if (Key != -1) free (key1);
+  }
+  for (i = 0; i < tmp.Nlines; i++) {
+    free (tmp.lines[i]);
+  } 
+  free (tmp.lines);
   return;
 }
