13f82230e99ae409f1128dd1d4a668af3110379e
tdreszer
  Mon Apr 18 14:12:51 2011 -0700
Streamlined and optimized continuation line code as Jim's suggests this is critical path.
diff --git src/lib/ra.c src/lib/ra.c
index 3cb6a41..11fbd39 100644
--- src/lib/ra.c
+++ src/lib/ra.c
@@ -42,88 +42,67 @@
     }
 lineFileReuse(lf);
 return TRUE;
 }
 
 boolean raNextTagVal(struct lineFile *lf, char **retTag, char **retVal, struct dyString *dyRecord)
 // Read next line.  Return FALSE at end of file or blank line.  Otherwise fill in
 // *retTag and *retVal and return TRUE.  If dy parameter is non-null, then the text parsed
 // gets appended to dy. Continuation lines in RA file will be joined to produce tag and val,
 // but dy will be filled with the unedited multiple lines containing the continuation chars.
 // NOTE: retTag & retVal, if returned, point to static mem which will be overwritten on next call!
 {
 *retTag = NULL;
 *retVal = NULL;
 
-// Old function returned pointers to lf memory, but joining continuation lines requires new mem.
-// Not wishing to force memory management on callers, static memeory is held here!
-static struct dyString *dyFullLine = NULL;   // static must be initialized with constant
-if (dyFullLine == NULL)
-    dyFullLine = dyStringNew(1024);
-dyStringClear(dyFullLine);
-
-char *line;
-while (lineFileNext(lf, &line, NULL)) // NOTE: While it would be nice to use lineFileNextFull here,
-    {                                 // we cannot because we need the true lines to fill dyRecord
+char *line, *raw;
+int lineLen,rawLen;
+while (lineFileNextFull(lf, &line, &lineLen, &raw, &rawLen)) // Joins continuation lines
+    {
     char *clippedText = skipLeadingSpaces(line);
-    if (clippedText == NULL || clippedText[0] == 0)
+    if (*clippedText == 0)
         {
         if (dyRecord)
             lineFileReuse(lf);   // Just so don't loose leading space in dy.
-        break;
+        return FALSE;
         }
 
     // Append whatever line was read from file.
     if (dyRecord)
        {
-       dyStringAppend(dyRecord, line); // Line may contain continuation chars
+        if (raw != NULL)
+            {
+            dyStringAppendN(dyRecord, raw, rawLen);
+            }
+       else
+            dyStringAppendN(dyRecord, line, lineLen);
        dyStringAppendC(dyRecord,'\n');
        }
 
-    // ignores commented lines
-    if (clippedText[0] == '#')
+    // Skip comments
+    if (*clippedText == '#')
         {
         if (startsWith("#EOF", clippedText))
-            break;
+           return FALSE;
         else
             continue;
         }
-
-    // Something we are interested in so add to static memory
-    eraseTrailingSpaces(clippedText);   // don't bother with trailing whitespace
-
-    // Join continued lines
-    char *lastChar = clippedText + (strlen(clippedText) - 1);
-    if (*lastChar == '\\')
-        {
-        if (lastChar > clippedText && *(lastChar - 1) != '\\') // Not an escaped continuation char
-            {
-            *lastChar = '\0';
-            dyStringAppend(dyFullLine,clippedText);
-            continue; // More to look forward to.
-            }
-        }
-    dyStringAppend(dyFullLine,clippedText);
-    break;
-    }
-if (dyStringLen(dyFullLine) > 0)
-    {
-    line = dyStringContents(dyFullLine);
     *retTag = nextWord(&line);
     *retVal = trimSpaces(line);
+    return TRUE;
     }
-return (*retTag != NULL);
+return FALSE;
 }
 
 boolean raNextTagValUnjoined(struct lineFile *lf, char **retTag, char **retVal,
                              struct dyString *dy)
 // NOTE: this is the former raNextTagVal routine is ignorant of continuation lines.
 //       It is provided in case older RAs need it.
 // Read next line.  Return FALSE at end of file or blank line.  Otherwise
 // fill in *retTag and *retVal and return TRUE.
 // If dy parameter is non-null, then the text parsed gets appended to dy.
 {
 char *line;
 for (;;)
     {
     if (!lineFileNext(lf, &line, NULL))
        return FALSE;
@@ -201,90 +180,49 @@
     {
     slPairAdd(&list, key, cloneString(val)); // val is already cloned so just pass it through.
     }
 
 slReverse(&list);
 return list;
 }
 
 struct slPair *raNextStanzaLinesAndUntouched(struct lineFile *lf)
 // Return list of lines starting from current position, up through last line of next stanza.
 // May return a few blank/comment lines at end with no real stanza.
 // Will join continuation lines, allocating memory as needed.
 // returns pairs with name=joined line and if joined,
 // val will contain raw lines '\'s and linefeeds, else val will be NULL.
 {
-struct dyString *dyFullLine      = dyStringNew(1024);
-struct dyString *dyUntouched = dyStringNew(1024);
 struct slPair *pairs = NULL;
-boolean buildingContinuation = FALSE;
 boolean stanzaStarted = FALSE;
-char *line;
-while (lineFileNext(lf, &line, NULL))
+char *line, *raw;
+int lineLen,rawLen;
+while (lineFileNextFull(lf, &line, &lineLen, &raw, &rawLen)) // Joins continuation lines
     {
     char *clippedText = skipLeadingSpaces(line);
 
-    // When to break?  After the stanza is over.  But first detect that it has started.
-    if (!buildingContinuation)
-        {
         if (stanzaStarted && clippedText[0] == 0)
             {
             lineFileReuse(lf);
             break;
             }
         if (!stanzaStarted && clippedText[0] != 0 && clippedText[0] != '#')
             stanzaStarted = TRUE; // Comments don't start stanzas and may be followed by blanks
-        }
-
-    // build full lines
-    dyStringAppend(dyUntouched,line);
-    if (dyStringLen(dyFullLine) == 0)
-        dyStringAppend(dyFullLine,line); // includes first line's whitespace.
-    else if (clippedText[0] != '\0')
-        dyStringAppend(dyFullLine,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(dyFullLine);
-        char *lastChar = lastNonwhitespaceChar(line);
-        if (lastChar != NULL && *lastChar == '\\')
-            {
-            if (lastChar > line && *(lastChar - 1) != '\\') // Not an escaped continuation char
-                {
-                // This clips off the last char and any trailing white-space in dyString
-                dyStringResize(dyFullLine,(lastChar - line));
-                dyStringAppendC(dyUntouched,'\n'); // Untouched lines delimited by newlines
-                buildingContinuation = TRUE;
-                continue;
-                }
-            }
-        }
-    if (buildingContinuation)
-        slPairAdd(&pairs, dyStringContents(dyFullLine),
-                   cloneString(dyStringContents(dyUntouched)));
-    else
-        slPairAdd(&pairs, dyStringContents(dyFullLine), NULL);
 
-    // Ready to start the next full line
-    dyStringClear(dyFullLine);
-    dyStringClear(dyUntouched);
-    buildingContinuation = FALSE;
+    slPairAdd(&pairs, line,(raw != NULL?cloneString(raw):NULL));
     }
 slReverse(&pairs);
-dyStringFree(&dyFullLine);
-dyStringFree(&dyUntouched);
 return pairs;
 }
 
 struct hash *raFromString(char *string)
 /* Return hash of key/value pairs from string.
  * As above freeHash this when done. */
 {
 char *dupe = cloneString(string);
 char *s = dupe, *lineEnd;
 struct hash *hash = newHash(7);
 char *key, *val;
 
 for (;;)
     {
     s = skipLeadingSpaces(s);