fc13db4566f67eda0bb8d608c8cd691b559a1930
angie
  Fri May 22 16:32:00 2015 -0700
Add chrom, chromStart, chromEnd back into the autoSql for wig and bigWig annoStreamers.
Now the columns can be selected/deselected the usual way instead of being fudged into
the output with no choice.
refs #14579

diff --git src/lib/annoFormatTab.c src/lib/annoFormatTab.c
index dde5d8f..9df06f0 100644
--- src/lib/annoFormatTab.c
+++ src/lib/annoFormatTab.c
@@ -47,58 +47,44 @@
     char fullName[PATH_LEN];
     makeFullColumnName(fullName, sizeof(fullName), sourceName, colName);
     int vis = hashIntValDefault(self->columnVis, fullName, 1);
     if (vis == 0)
         return FALSE;
     }
 return TRUE;
 }
 
 static void printHeaderColumns(struct annoFormatTab *self, struct annoStreamer *source,
                                boolean isFirst)
 /* Print names of included columns from this source. */
 {
 FILE *f = self->f;
 char *sourceName = source->name;
-char fullName[PATH_LEN];
-if (source->rowType == arWig)
-    {
-    // Fudge in the row's chrom, start, end as output columns even though they're not in autoSql
-    if (isFirst)
-	{
-        makeFullColumnName(fullName, sizeof(fullName), sourceName, "chrom");
-        fprintf(f, "#%s", fullName);
-	isFirst = FALSE;
-	}
-    makeFullColumnName(fullName, sizeof(fullName), sourceName, "start");
-    fprintf(f, "\t%s", fullName);
-    makeFullColumnName(fullName, sizeof(fullName), sourceName, "end");
-    fprintf(f, "\t%s", fullName);
-    }
 struct asColumn *col;
 int i;
 for (col = source->asObj->columnList, i = 0;  col != NULL;  col = col->next, i++)
     {
     if (columnIsIncluded(self, sourceName, col->name))
         {
         if (isFirst)
             {
             fputc('#', f);
             isFirst = FALSE;
             }
         else
             fputc('\t', f);
+        char fullName[PATH_LEN];
         makeFullColumnName(fullName, sizeof(fullName), sourceName, col->name);
         fputs(fullName, f);
         }
     }
 }
 
 static void aftInitialize(struct annoFormatter *vSelf, struct annoStreamer *primary,
 			  struct annoStreamer *integrators)
 /* Print header, regardless of whether we get any data after this. */
 {
 struct annoFormatTab *self = (struct annoFormatTab *)vSelf;
 if (self->needHeader)
     {
     char *primaryHeader = primary->getHeader(primary);
     if (isNotEmpty(primaryHeader))
@@ -112,54 +98,65 @@
     }
 }
 
 static double wigRowAvg(struct annoRow *row)
 /* Return the average value of floats in row->data. */
 {
 float *vector = row->data;
 int len = row->end - row->start;
 double sum = 0.0;
 int i;
 for (i = 0;  i < len;  i++)
     sum += vector[i];
 return sum / (double)len;
 }
 
+static char **bed4WordsFromAnnoRow(struct annoRow *row, char *fourth)
+/* Return an array of 4 words with row's chrom, chromStart, and chromEnd, and cloned fourth. */
+{
+char **words;
+AllocArray(words, 4);
+words[0] = cloneString(row->chrom);
+char buf[PATH_LEN];
+safef(buf, sizeof(buf), "%u", row->start);
+words[1] = cloneString(buf);
+safef(buf, sizeof(buf), "%u", row->end);
+words[2] = cloneString(buf);
+words[3] = cloneString(fourth);
+return words;
+}
+
 static char **wordsFromWigRowAvg(struct annoRow *row)
-/* Return an array of strings with a single string containing the average of values in row. */
+/* Return chrom, chromStart, chromEnd and a string containing the average of values in row. */
 {
 double avg = wigRowAvg(row);
-char **words;
-AllocArray(words, 1);
 char avgStr[32];
 safef(avgStr, sizeof(avgStr), "%lf", avg);
-words[0] = cloneString(avgStr);
-return words;
+return bed4WordsFromAnnoRow(row, avgStr);
 }
 
 static char **wordsFromWigRowVals(struct annoRow *row)
-/* Return an array of strings with a single string containing comma-sep per-base wiggle values. */
+/* Return chrom, chromStart, chromEnd and a string containing comma-sep per-base wiggle values. */
 {
 float *vector = row->data;
 int len = row->end - row->start;
 struct dyString *dy = dyStringNew(10*len);
 int i;
 for (i = 0;  i < len;  i++)
     dyStringPrintf(dy, "%g,", vector[i]);
-char **words;
-AllocArray(words, 1);
-words[0] = dyStringCannibalize(&dy);
+char **words = bed4WordsFromAnnoRow(row, dy->string);
+dyStringFree(&dy);
 return words;
 }
 
 static char **wordsFromRow(struct annoRow *row, struct annoStreamer *source,
 			   boolean *retFreeWhenDone)
 /* If source->rowType is arWords, return its words.  Otherwise translate row->data into words. */
 {
 if (row == NULL)
     return NULL;
 boolean freeWhenDone = FALSE;
 char **words = NULL;
 if (source->rowType == arWords)
     words = row->data;
 else if (source->rowType == arWig)
     {
@@ -175,61 +172,49 @@
     errAbort("annoFormatTab: unrecognized row type %d from source %s",
 	     source->rowType, source->name);
 if (retFreeWhenDone != NULL)
     *retFreeWhenDone = freeWhenDone;
 return words;
 }
 
 static void printColumns(struct annoFormatTab *self, struct annoStreamer *streamer,
 			 struct annoRow *row, boolean isFirst)
 /* Print columns in streamer's row (if NULL, print the right number of empty fields). */
 {
 FILE *f = self->f;
 char *sourceName = streamer->name;
 boolean freeWhenDone = FALSE;
 char **words = wordsFromRow(row, streamer, &freeWhenDone);
-if (streamer->rowType == arWig)
-    {
-    // Fudge in the row's chrom, start, end as output columns even though they're not in autoSql
-    if (isFirst)
-	{
-	if (row != NULL)
-	    fputs(row->chrom, f);
-	isFirst = FALSE;
-	}
-    if (row != NULL)
-	fprintf(f, "\t%u\t%u", row->start, row->end);
-    else
-	fputs("\t\t", f);
-    }
 struct asColumn *col;
 int i;
 for (col = streamer->asObj->columnList, i = 0;  col != NULL;  col = col->next, i++)
     {
     if (columnIsIncluded(self, sourceName, col->name))
         {
         if (isFirst)
             isFirst = FALSE;
         else
             fputc('\t', f);
         if (words != NULL)
             fputs((words[i] ? words[i] : ""), f);
         }
     }
+int wordCount = i;
 if (freeWhenDone)
     {
-    freeMem(words[0]);
+    for (i = 0;  i < wordCount;  i++)
+        freeMem(words[i]);
     freeMem(words);
     }
 }
 
 static void aftComment(struct annoFormatter *fSelf, char *content)
 /* Print out a comment line. */
 {
 if (strchr(content, '\n'))
     errAbort("aftComment: no multi-line input");
 struct annoFormatTab *self = (struct annoFormatTab *)fSelf;
 fprintf(self->f, "# %s\n", content);
 }
 
 static void aftFormatOne(struct annoFormatter *vSelf, struct annoStreamRows *primaryData,
 			 struct annoStreamRows *gratorData, int gratorCount)