8a0946dd6870f10cde056ba243f1fb4ec1fd16b4
angie
  Thu Feb 27 11:58:33 2014 -0800
Adding support for plain VCF custom tracks (as opposed to VCF+tabix),since users seem to want to upload VCF, and as long as the file is
not too big it will work OK.  This means adding a new track type
vcf (as opposed to vcfTabix) and supporting it in hgTracks, hgTrackUi,
hgc, hgTables and hgVai.  (and others I've forgotten?)
refs #12416

diff --git src/hg/lib/customPp.c src/hg/lib/customPp.c
index 112fc2d..53942ac 100644
--- src/hg/lib/customPp.c
+++ src/hg/lib/customPp.c
@@ -32,30 +32,31 @@
 AllocVar(cpp);
 cpp->fileStack = lf;
 return cpp;
 }
 
 void customPpFree(struct customPp **pCpp)
 /* Close files and free up customPp. */
 {
 struct customPp *cpp = *pCpp;
 if (cpp)
     {
     lineFileCloseList(&cpp->fileStack);
     slFreeList(&cpp->browserLines);
     slFreeList(&cpp->reusedLines);
     freeMem(cpp->inReuse);
+    slFreeList(&cpp->skippedLines);
     }
 }
 
 char *customPpNext(struct customPp *cpp)
 /* Return next line. */
 {
 /* Check first for line to reuse. */
 struct slName *reused = cpp->reusedLines;
 if (reused)
     {
     /* We need to keep line actually reusing in memory until next
      * call to customPpNext, so we move it to inReuse rather than
      * immediately freeing it. */
     freeMem(cpp->inReuse);   
     cpp->reusedLines = reused->next;
@@ -93,53 +94,67 @@
 		continue;
 		}
 	    }
 	return line;
 	}
     else
         {
 	cpp->fileStack = lf->next;
 	lineFileClose(&lf);
 	}
     }
 return NULL;
 }
 
 char *customPpNextReal(struct customPp *cpp)
-/* Return next line that's nonempty and non-space. */
+/* Return next line that's nonempty, non-space and not a comment.
+ * Save skipped comment lines to cpp->skippedLines. */
 {
+slFreeList(&cpp->skippedLines);
 for (;;)
     {
     char *line = customPpNext(cpp);
     if (line == NULL)
         return line;
     char *s = skipLeadingSpaces(line);
     char c = *s;
     if (c != 0 && c != '#')
         return line;
+    else if (c == '#')
+	slNameAddHead(&cpp->skippedLines, line);
     }
 }
 
 void customPpReuse(struct customPp *cpp, char *line)
 /* Reuse line.  May be called many times before next customPpNext/NextReal.
  * Should be called with last line to be reused first if called multiply. */
 {
 struct slName *s = slNameNew(line);
 slAddHead(&cpp->reusedLines, s);
 }
 
 struct slName *customPpTakeBrowserLines(struct customPp *cpp)
 /* Grab browser lines from cpp, which will no longer have them. */
 {
 struct slName *browserLines = cpp->browserLines;
 cpp->browserLines = NULL;
 return browserLines;
 }
 
+struct slName *customPpCloneSkippedLines(struct customPp *cpp)
+/* Return a clone of most recent nonempty skipped (comment/header) lines from cpp,
+ * which will still have them.  slFreeList when done. */
+{
+struct slName *skippedLines = NULL, *sl;
+for (sl = cpp->skippedLines;  sl != NULL;  sl = sl->next)
+    slNameAddHead(&skippedLines, sl->name);
+return skippedLines;
+}
+
 char *customPpFileName(struct customPp *cpp)
 /* Return the name of the current file being parsed (top of fileStack), or NULL
  * if fileStack is NULL.  Free when done. */
 {
 if (cpp->fileStack == NULL)
     return NULL;
 return cloneString(cpp->fileStack->fileName);
 }