fcd12f2b541d84822d13fb7b939c463248647f1f
tdreszer
  Fri Apr 15 17:42:16 2011 -0700
Add simple support for reading lines with continuation characters as single lines.
diff --git src/lib/linefile.c src/lib/linefile.c
index 083ddb2..b8ea9a6 100644
--- src/lib/linefile.c
+++ src/lib/linefile.c
@@ -668,47 +668,125 @@
 
 void lineFileExpectAtLeast(struct lineFile *lf, int expecting, int got)
 /* Check line has right number of words. */
 {
 if (got < expecting)
     errAbort("Expecting at least %d words line %d of %s got %d", 
 	    expecting, lf->lineIx, lf->fileName, got);
 }
 
 void lineFileShort(struct lineFile *lf)
 /* Complain that line is too short. */
 {
 errAbort("Short line %d of %s", lf->lineIx, lf->fileName);
 }
 
+void lineFileReuseFull(struct lineFile *lf)
+// Reuse last full line read.  Unlike lineFileReuse,
+// lineFileReuseFull only works with previous lineFileNextFull call
+{
+assert(lf->fullLine != NULL);
+lf->fullLineResuse = TRUE;
+}
+
+
+boolean lineFileNextFull(struct lineFile *lf, char **retStart, int *retSize)
+// Fetch next line from file joining up any that are continued by ending '\'
+// NOTE: comment lines can't be continued!  ("# comment \ \n more comment" is 2 lines.)
+{
+// May have requested reusing the last full line.
+if (lf->fullLineResuse)
+    {
+    assert(lf->fullLine != NULL);
+    lf->fullLineResuse = FALSE;
+    *retStart = dyStringContents(lf->fullLine);
+    if (retSize)
+        *retSize = dyStringLen(lf->fullLine);
+    return TRUE;
+    }
+
+*retStart = NULL;
+
+// Initialize memory if needed
+if (lf->fullLine == NULL)
+    lf->fullLine = dyStringNew(1024);
+dyStringClear(lf->fullLine);
+
+char *line;
+while (lineFileNext(lf, &line, NULL))
+    {
+    char *clippedText = skipLeadingSpaces(line);
+
+    // Fill lf memory in case of continued lines
+    if (dyStringLen(lf->fullLine) == 0)
+        {
+        dyStringAppend(lf->fullLine,line); // includes first line's whitespace.
+        *retStart = dyStringContents(lf->fullLine);
+        }
+    else if (clippedText[0] != '\0')
+        dyStringAppend(lf->fullLine,clippedText); // don't include continued line's leading spaces
+
+    // Will the next line continue this one?
+    if (clippedText[0] != '\0' && clippedText[0] != '#') // Comment lines can't be continued!
+        {
+        line = dyStringContents(lf->fullLine);
+        char *lastChar = lastNonWhitespaceChar(line);
+        if (lastChar != NULL && *lastChar == '\\')
+            {
+            if (lastChar > line && *(lastChar - 1) != '\\') // Not an escaped continuation char
+                {
+                dyStringResize(lf->fullLine,(lastChar - line)); // This clips off the last char and any trailing white-space in dyString
+                continue;
+                }
+            }
+        }
+    if (retSize)
+        *retSize = dyStringLen(lf->fullLine);
+    return TRUE;
+    }
+return FALSE;
+}
+
 boolean lineFileNextReal(struct lineFile *lf, char **retStart)
 /* Fetch next line from file that is not blank and 
  * does not start with a '#'. */
 {
 char *s, c;
 while (lineFileNext(lf, retStart, NULL))
     {
     s = skipLeadingSpaces(*retStart);
     c = s[0];
     if (c != 0 && c != '#')
-        {
 	return TRUE;
         }
+return FALSE;
+}
+
+boolean lineFileNextFullReal(struct lineFile *lf, char **retStart)
+// Fetch next line from file that is not blank and does not start with a '#'.
+// Continuation lines (ending in '\') are joined into a single line.
+{
+while (lineFileNextFull(lf, retStart, NULL))
+    {
+    char *clippedText = skipLeadingSpaces(*retStart);
+    if (clippedText[0] != '\0' && clippedText[0] != '#')
+        return TRUE;
     }
 return FALSE;
 }
 
+
 int lineFileChopNext(struct lineFile *lf, char *words[], int maxWords)
 /* Return next non-blank line that doesn't start with '#' chopped into words. */
 {
 int lineSize, wordCount;
 char *line;
 
 while (lineFileNext(lf, &line, &lineSize))
     {
     if (line[0] == '#')
         continue;
     wordCount = chopByWhite(line, words, maxWords);
     if (wordCount != 0)
         return wordCount;
     }
 return 0;