e1a373956ea8f5a93f7c63208e1ee39a1aceb4de
braney
  Wed Aug 31 11:44:17 2011 -0700
fix bug in bigWigMerge #4561.  Add test that would have found it.
diff --git src/utils/bigWigMerge/bigWigMerge.c src/utils/bigWigMerge/bigWigMerge.c
index 58ce49f..5eda7e2 100644
--- src/utils/bigWigMerge/bigWigMerge.c
+++ src/utils/bigWigMerge/bigWigMerge.c
@@ -24,57 +24,69 @@
   "   -clip=NNN.N - values higher than this are clipped to this value\n"
   );
 }
 
 double clThreshold = 0.0;
 double clAdjust = 0.0;
 double clClip = BIGDOUBLE;
 
 static struct optionSpec options[] = {
    {"threshold", OPTION_DOUBLE},
    {"adjust", OPTION_DOUBLE},
    {"clip", OPTION_DOUBLE},
    {NULL, 0},
 };
 
-struct slName *getAllChroms(struct bbiFile *fileList)
+
+static int bbiChromInfoCmpStringsWithEmbeddedNumbers(const void *va, const void *vb)
+/* Compare strings such as gene names that may have embedded numbers,
+ * so that bmp4a comes before bmp14a */
+{
+const struct bbiChromInfo *a = *((struct bbiChromInfo **)va);
+const struct bbiChromInfo *b = *((struct bbiChromInfo **)vb);
+return cmpStringsWithEmbeddedNumbers(a->name, b->name);
+}
+
+struct bbiChromInfo *getAllChroms(struct bbiFile *fileList)
 /* Read chromosomes from all files and make sure they agree, and return merged list. */
 {
 struct bbiFile *file;
 struct hash *hash = hashNew(0);
-struct slName *nameList = NULL;
+struct bbiChromInfo *nameList = NULL;
 for (file = fileList; file != NULL; file = file->next)
     {
-    struct bbiChromInfo *info, *infoList = bbiChromList(file);
-    for (info = infoList; info != NULL; info = info->next)
+    struct bbiChromInfo *info, *next, *infoList = bbiChromList(file);
+    for (info = infoList; info != NULL; info = next)
         {
+	next = info->next;
+
 	struct bbiChromInfo *oldInfo = hashFindVal(hash, info->name);
 	if (oldInfo != NULL)
 	    {
 	    if (info->size != oldInfo->size)
 		errAbort("ERROR: Merging from different assemblies? "
 		         "Chromosome %s is %d in %s but %d in another file",
 			 info->name, (int)(info->size), file->fileName, (int)oldInfo->size);
 	    }
 	else
 	    {
 	    hashAdd(hash, info->name, info);
-	    slNameAddHead(&nameList, info->name);
+	    slAddHead(&nameList, info);
 	    }
 	}
     }
-slSort(&nameList, slNameCmpStringsWithEmbeddedNumbers);
+slSort(&nameList, bbiChromInfoCmpStringsWithEmbeddedNumbers);
 return nameList;
 }
 
 boolean allStartEndSame(struct bbiInterval *ivList)
 /* Return true if all items in list start and end the same place. */
 {
 int start = ivList->start, end = ivList->end;
 struct bbiInterval *iv;
 for (iv = ivList->next; iv != NULL; iv = iv->next)
     {
     if (iv->start != start || iv->end != end)
         return FALSE;
     }
 return TRUE;
 }
@@ -96,41 +108,41 @@
 
 void bigWigMerge(int inCount, char *inFiles[], char *outFile)
 /* bigWigMerge - Merge together multiple bigWigs into a single one.. */
 {
 /* Make a list of open bigWig files. */
 struct bbiFile *inFile, *inFileList = NULL;
 int i;
 for (i=0; i<inCount; ++i)
     {
     inFile = bigWigFileOpen(inFiles[i]);
     slAddTail(&inFileList, inFile);
     }
 
 FILE *f = mustOpen(outFile, "w");
 
-struct slName *chrom, *chromList = getAllChroms(inFileList);
+struct bbiChromInfo *chrom, *chromList = getAllChroms(inFileList);
 verbose(1, "Got %d chromosomes from %d bigWigs\nProcessing", 
 	slCount(chromList), slCount(inFileList));
 double *mergeBuf = NULL;
 int mergeBufSize = 0;
 for (chrom = chromList; chrom != NULL; chrom = chrom->next)
     {
     struct lm *lm = lmInit(0);
 
     /* Make sure merge buffer is big enough. */
-    int chromSize = bbiChromSize(inFileList, chrom->name);
+    int chromSize = chrom->size;
     verboseDot();
     verbose(2, "Processing %s (%d bases)\n", chrom->name, chromSize);
     if (chromSize > mergeBufSize)
         {
 	mergeBufSize = chromSize;
 	freeMem(mergeBuf);
 	mergeBuf = needHugeMem(mergeBufSize * sizeof(double));
 	}
     int i;
     for (i=0; i<chromSize; ++i)
         mergeBuf[i] = 0.0;
 
     /* Loop through each input file grabbing data and merging it in. */
     for (inFile = inFileList; inFile != NULL; inFile = inFile->next)
         {