90f26ce1f4bd4f69b53d11569d4c4efc0c3386b7
braney
  Tue Dec 20 12:41:19 2016 -0800
make some utilities to turn mafs into bigMafs

diff --git src/lib/maf.c src/lib/maf.c
index 11d205d..e5ad062 100644
--- src/lib/maf.c
+++ src/lib/maf.c
@@ -1,898 +1,904 @@
 /* maf.c - Read/write maf format. */
 
 /* Copyright (C) 2014 The Regents of the University of California 
  * See README in this or parent directory for licensing information. */
 
 #include "common.h"
 #include "linefile.h"
 #include "errAbort.h"
 #include "obscure.h"
 #include "dnautil.h"
 #include "axt.h"
 #include "maf.h"
 #include "hash.h"
 #include "net.h"
 #include <fcntl.h>
 
 
 char *mafRegDefTxUpstream = "txupstream";  // transcription start size upstream region
 
 struct mafFile *mafMayOpen(char *fileName)
 /* Open up a maf file and verify header. */
 {
 struct mafFile *mf;
 struct lineFile *lf;
 char *line, *word;
 char *sig = "##maf";
 
 if ( hasProtocol(fileName))
     lf = lineFileUdcMayOpen(fileName, TRUE);
 else
     lf = lineFileMayOpen(fileName, TRUE);
 
 if (lf == NULL)
     return NULL;
 AllocVar(mf);
 mf->lf = lf;
 
 lineFileNeedNext(lf, &line, NULL);
 if (!startsWith(sig, line))
     {
     errAbort("%s does not start with %s", fileName, sig);
     }
 line += strlen(sig);
 
 while ((word = nextWord(&line)) != NULL)
     {
     /* Parse name=val. */
     char *name = word;
     char *val = strchr(word, '=');
     if (val == NULL)
        errAbort("Missing = after %s line 1 of %s\n", name, fileName);
     *val++ = 0;
 
     if (sameString(name, "version"))
         mf->version = atoi(val);
     else if (sameString(name, "scoring"))
         mf->scoring = cloneString(val);
     }
 if (mf->version == 0)
     errAbort("No version line 1 of %s\n", fileName);
 return mf;
 }
 
 struct mafFile *mafOpen(char *fileName)
 /* Open up a maf file.  Squawk and die if there's a problem. */
 {
 struct mafFile *mf = mafMayOpen(fileName);
 if (mf == NULL)
     errnoAbort("Couldn't open %s\n", fileName);
 return mf;
 }
 
 void mafRewind(struct mafFile *mf)
 /* Seek to beginning of open maf file */
 {
 if (mf == NULL)
     errAbort("maf file rewind failed -- file not open");
 lineFileSeek(mf->lf, 0, SEEK_SET);
 }
 
 static boolean nextLine(struct lineFile *lf, char **pLine)
 /* Get next line that is not a comment. */
 {
 for (;;)
     {
     if (!lineFileNext(lf, pLine, NULL))
         return FALSE;
     if (**pLine != '#')
         return TRUE;
     }
 }
 
 static void mafRegDefParse(struct mafFile *mf, struct mafAli *ali, char *line)
 /* parse a 'r' line of an 'a' paragraph. */
 {
 if (ali->regDef != NULL)
     errAbort("multiple 'r' lines in an alignment paragraph: %d of %s", mf->lf->lineIx, mf->lf->fileName);
 char *row[3];
 int wordCount = chopByWhite(line, row, ArraySize(row));
 if (wordCount != 3)
     lineFileExpectWords(mf->lf, 3+1, wordCount+1); // +1 for 'r'
 ali->regDef = mafRegDefNew(row[0], lineFileNeedFullNum(mf->lf, row, 1),
                            row[2]);
 }
 
 struct mafAli *mafNextWithPos(struct mafFile *mf, off_t *retOffset)
 /* Return next alignment in FILE or NULL if at end.  If retOffset is
  * nonNULL, return start offset of record in file. */
 {
 struct lineFile *lf = mf->lf;
 struct mafAli *ali;
 char *line, *word;
 
 /* Loop until get an alignment paragraph or reach end of file. */
 for (;;)
     {
     /* Get alignment header line.  If it's not there assume end of file. */
     if (!nextLine(lf, &line))
 	{
 	lineFileClose(&mf->lf);
 	return NULL;
 	}
 
     /* Parse alignment header line. */
     word = nextWord(&line);
     if (word == NULL)
 	continue;	/* Ignore blank lines. */
 	
     if (sameString(word, "a"))
 	{
 	if (retOffset != NULL)
 	    *retOffset = lineFileTell(mf->lf);
 	AllocVar(ali);
 	while ((word = nextWord(&line)) != NULL)
 	    {
 	    /* Parse name=val. */
 	    char *name = word;
 	    char *val = strchr(word, '=');
 	    if (val == NULL)
 	       errAbort("Missing = after %s line 1 of %s", name, lf->fileName);
 	    *val++ = 0;
 
 	    if (sameString(name, "score"))
 		ali->score = atof(val);
 	    }
 
 	/* Parse alignment components until blank line. */
 	for (;;)
 	    {
 	    if (!nextLine(lf, &line))
 		break;
 	    word = nextWord(&line);
 	    if (word == NULL)
 		break;
 	    if (sameString(word, "s") || sameString(word, "e"))
 		{
 		struct mafComp *comp;
 		int wordCount;
 		char *row[7];
 		int textSize;
 
 		/* Chop line up by white space.  This involves a few +-1's because
 		 * have already chopped out first word. */
 		row[0] = word;
 		wordCount = chopByWhite(line, row+1, ArraySize(row)-1) + 1; /* +-1 because of "s" */
 		lineFileExpectWords(lf, ArraySize(row), wordCount);
 		AllocVar(comp);
 
 		/* Convert ascii text representation to mafComp structure. */
 		comp->src = cloneString(row[1]);
 		comp->srcSize = lineFileNeedNum(lf, row, 5);
 		comp->strand = row[4][0];
 		comp->start = lineFileNeedNum(lf, row, 2);
 
 		if (sameString(word, "e"))
 		    {
 		    comp->size = 0;
 		    comp->rightLen = comp->leftLen = lineFileNeedNum(lf, row, 3);
 		    comp->rightStatus = comp->leftStatus = *row[6];
 		    }
 		else
 		    {
 		    comp->size = lineFileNeedNum(lf, row, 3);
 		    comp->text = cloneString(row[6]);
 		    textSize = strlen(comp->text);
 
 		    /* Fill in ali->text size. */
 		    if (ali->textSize == 0)
 			ali->textSize = textSize;
 		    else if (ali->textSize != textSize)
 			errAbort("Text size inconsistent (%d vs %d) line %d of %s",
 			    textSize, ali->textSize, lf->lineIx, lf->fileName);
 		    }
 
 		/* Do some sanity checking. */
 		if (comp->srcSize < 0 || comp->size < 0)
 		     errAbort("Got a negative size line %d of %s", lf->lineIx, lf->fileName);
 		if (comp->start < 0 || comp->start + comp->size > comp->srcSize)
 		     errAbort("Coordinates out of range line %d of %s", lf->lineIx, lf->fileName);
 		  
 		/* Add component to head of list. */
 		slAddHead(&ali->components, comp);
 		}
 	    if (sameString(word, "i"))
 		{
 		struct mafComp *comp;
 		int wordCount;
 		char *row[6];
 
 		/* Chop line up by white space.  This involves a few +-1's because
 		 * have already chopped out first word. */
 		row[0] = word;
 		wordCount = chopByWhite(line, row+1, ArraySize(row)-1) + 1; /* +-1 because of "s" */
 		lineFileExpectWords(lf, ArraySize(row), wordCount);
 		if (!sameString(row[1],ali->components->src))
 		    errAbort("i line src mismatch: i is %s :: s is %s\n", row[1], ali->components->src);
 
 		comp = ali->components;
 		comp->leftStatus = *row[2];
 		comp->leftLen = atoi(row[3]);
 		comp->rightStatus = *row[4];
 		comp->rightLen = atoi(row[5]);
 		}
             if (sameString(word, "q"))
 		{
 		struct mafComp *comp;
 		int wordCount;
 		char *row[3];
 
 		/* Chop line up by white space.  This involves a few +-1's because
 		 * have already chopped out first word. */
 		row[0] = word;
 		wordCount = chopByWhite(line, row+1, ArraySize(row)-1) + 1; /* +-1 because of "s" */
 		lineFileExpectWords(lf, ArraySize(row), wordCount);
 		if (!sameString(row[1],ali->components->src))
 		    errAbort("q line src mismatch: q is %s :: s is %s\n", row[1], ali->components->src);
 
 			comp = ali->components;
 			comp->quality = cloneString(row[2]);
 		}
 	    if (sameString(word, "r"))
                 mafRegDefParse(mf, ali, line);
 	    }
 	slReverse(&ali->components);
 	return ali;
 	}
     else  /* Skip over paragraph we don't understand. */
 	{
 	for (;;)
 	    {
 	    if (!nextLine(lf, &line))
 		return NULL;
             if (nextWord(&line) == NULL)
 		break;
 	    }
 	}
     }
 }
 
 
 struct mafAli *mafNext(struct mafFile *mf)
 /* Return next alignment in FILE or NULL if at end. */
 {
 return mafNextWithPos(mf, NULL);
 }
 
 
 struct mafFile *mafReadAll(char *fileName)
 /* Read all elements in a maf file */
 {
 struct mafFile *mf = mafOpen(fileName);
 struct mafAli *ali;
 while ((ali = mafNext(mf)) != NULL)
     {
     slAddHead(&mf->alignments, ali);
     }
 slReverse(&mf->alignments);
 return mf;
 }
 
 void mafWriteStart(FILE *f, char *scoring)
 /* Write maf header and scoring scheme name (may be null) */
 {
 fprintf(f, "##maf version=1");
 if (scoring != NULL)
     fprintf(f, " scoring=%s", scoring);
 fprintf(f, "\n");
 }
 
 
-void mafWrite(FILE *f, struct mafAli *ali)
+void mafWriteDelimiter(FILE *f, struct mafAli *ali, char delimiter)
 /* Write next alignment to file. */
 {
 struct mafComp *comp;
 int srcChars = 0, startChars = 0, sizeChars = 0, srcSizeChars = 0;
 
 /* Write out alignment header */
-fprintf(f, "a score=%f\n", ali->score);
+fprintf(f, "a score=%f%c", ali->score, delimiter);
 
 /* include region definition */
 if (ali->regDef != NULL)
-    fprintf(f, "r %s %d %s\n", ali->regDef->type, ali->regDef->size, ali->regDef->id);
+    fprintf(f, "r %s %d %s%c", ali->regDef->type, ali->regDef->size, ali->regDef->id, delimiter);
 
 /* Figure out length of each field. */
 for (comp = ali->components; comp != NULL; comp = comp->next)
     {
     int len = 0;
     /* a name like '.' will break some tools, so replace it
     * with a generic name */
     if (sameString(comp->src,"."))
 	comp->src=cloneString("defaultName");
     len = strlen(comp->src);
     if (srcChars < len)
         srcChars = len;
     len = digitsBaseTen(comp->start);
     if (startChars < len)
         startChars = len;
     len = digitsBaseTen(comp->size);
     if (sizeChars < len)
         sizeChars = len;
     len = digitsBaseTen(comp->srcSize);
     if (srcSizeChars < len)
         srcSizeChars = len;
     }
 
 /* Write out each component. */
 for (comp = ali->components; comp != NULL; comp = comp->next)
     {
     if ((comp->size == 0) && (comp->leftStatus))
-	fprintf(f, "e %-*s %*d %*d %c %*d %c\n", 
+	fprintf(f, "e %-*s %*d %*d %c %*d %c%c", 
 	    srcChars, comp->src, startChars, comp->start, 
 	    sizeChars, comp->leftLen, comp->strand, 
-	    srcSizeChars, comp->srcSize, comp->leftStatus);
+	    srcSizeChars, comp->srcSize, comp->leftStatus, delimiter);
     else
 	{
-	fprintf(f, "s %-*s %*d %*d %c %*d %s\n", 
+	fprintf(f, "s %-*s %*d %*d %c %*d %s%c", 
 	    srcChars, comp->src, startChars, comp->start, 
 	    sizeChars, comp->size, comp->strand, 
-	    srcSizeChars, comp->srcSize, comp->text);
+	    srcSizeChars, comp->srcSize, comp->text, delimiter);
 
 	if (comp->quality)
-		fprintf(f, "q %-*s %s\n",
+		fprintf(f, "q %-*s %s%c",
 		srcChars + startChars + sizeChars + srcSizeChars + 5,
-		comp->src, comp->quality);
+		comp->src, comp->quality, delimiter);
 
 	if (comp->leftStatus)
-	    fprintf(f,"i %-*s %c %d %c %d\n",srcChars,comp->src,
-		comp->leftStatus,comp->leftLen,comp->rightStatus,comp->rightLen);
+	    fprintf(f,"i %-*s %c %d %c %d%c",srcChars,comp->src,
+		comp->leftStatus,comp->leftLen,comp->rightStatus,comp->rightLen, delimiter);
 	}
 
     }
+}
+
+void mafWrite(FILE *f, struct mafAli *ali)
+/* Write next alignment to file. */
+{
+mafWriteDelimiter(f, ali, '\n');
 
 /* Write out blank separator line. */
 fprintf(f, "\n");
 }
 
 void mafWriteEnd(FILE *f)
 /* Write maf footer. In this case nothing */
 {
 }
 
 void mafWriteAll(struct mafFile *mf, char *fileName)
 /* Write out full mafFile. */
 {
 FILE *f = mustOpen(fileName, "w");
 struct mafAli *ali;
 mafWriteStart(f, mf->scoring);
 for (ali = mf->alignments; ali != NULL; ali = ali->next)
     mafWrite(f, ali);
 mafWriteEnd(f);
 carefulClose(&f);
 }
 
 void mafCompFree(struct mafComp **pObj)
 /* Free up a maf component. */
 {
 struct mafComp *obj = *pObj;
 if (obj == NULL)
     return;
 freeMem(obj->src);
 freeMem(obj->text);
 freeMem(obj->quality);
 freez(pObj);
 }
 
 void mafCompFreeList(struct mafComp **pList)
 /* Free up a list of maf components. */
 {
 struct mafComp *el, *next;
 
 for (el = *pList; el != NULL; el = next)
     {
     next = el->next;
     mafCompFree(&el);
     }
 *pList = NULL;
 }
 
 char *mafCompGetSrcDb(struct mafComp *mc, char *buf, int bufSize)
 /* parse the srcDb name from the mafComp src name, return NULL if no srcDb */
 {
 char *e = strchr(mc->src, '.');
 if (e == NULL)
     return NULL;
 int len = e - mc->src;
 if (len >= bufSize-1)
     errAbort("srcDb name in \"%s\" overflows buffer length of %d", mc->src, bufSize);
 strncpy(buf, mc->src, len);
 buf[len] = '\0';
 return buf;
 }
 
 char *mafCompGetSrcName(struct mafComp *mc)
 /* parse the src sequence name from the mafComp src name */
 {
 char *e = strchr(mc->src, '.');
 if (e == NULL)
     return mc->src;
 else
     return e+1;
 }
 
 int mafPlusStart(struct mafComp *comp)
 /* Return start relative to plus strand of src. */
 {
 if (comp->strand == '-') 
     return comp->srcSize - (comp->start + comp->size);
 else
     return comp->start;
 }
 
 void mafAliFree(struct mafAli **pObj)
 /* Free up a maf alignment. */
 {
 struct mafAli *obj = *pObj;
 if (obj == NULL)
     return;
 mafCompFreeList(&obj->components);
 mafRegDefFree(&obj->regDef);
 freez(pObj);
 }
 
 void mafAliFreeList(struct mafAli **pList)
 /* Free up a list of maf alignmentx. */
 {
 struct mafAli *el, *next;
 
 for (el = *pList; el != NULL; el = next)
     {
     next = el->next;
     mafAliFree(&el);
     }
 *pList = NULL;
 }
 
 void mafFileFree(struct mafFile **pObj)
 /* Free up a maf file. */
 {
 struct mafFile *obj = *pObj;
 if (obj == NULL)
     return;
 lineFileClose(&obj->lf);
 freeMem(obj->scoring);
 mafAliFreeList(&obj->alignments);
 freez(pObj);
 }
 
 void mafFileFreeList(struct mafFile **pList)
 /* Free up a list of maf files. */
 {
 struct mafFile *el, *next;
 
 for (el = *pList; el != NULL; el = next)
     {
     next = el->next;
     mafFileFree(&el);
     }
 *pList = NULL;
 }
 
 struct mafComp *mafMayFindComponent(struct mafAli *maf, char *src)
 /* Find component of given source. Return NULL if not found. */
 {
 struct mafComp *mc;
 for (mc = maf->components; mc != NULL; mc = mc->next)
     {
     if (sameString(mc->src, src))
         return mc;
     }
 return NULL;
 }
 
 struct mafComp *mafMayFindComponentDb(struct mafAli *maf, char *db)
 /* Find component of given database, allowing component to be 
  * labeled "db", or "db.chrom" . Return NULL if not found. */
 {
 struct mafComp *mc;
 char *p, *q;
 for (mc = maf->components; mc != NULL; mc = mc->next)
     {
     for (p = mc->src, q = db; *p && *q; p++, q++)
         {
         if (*p != *q)
             break;
         }
     if (*p == '.' && *q == 0)
         return mc;
     if (*p == *q)
         return mc;
     }
 return NULL;
 }
 
 struct mafComp *mafFindComponent(struct mafAli *maf, char *src)
 /* Find component of given source or die trying. */
 {
 struct mafComp *mc = mafMayFindComponent(maf, src);
 if (mc == NULL)
     errAbort("Couldn't find %s in maf", src);
 return mc;
 }
 
 struct mafComp *mafMayFindCompSpecies(struct mafAli *maf, char *species, char sepChar)
 /* Find component of given source that starts with species possibly followed by sepChar or \0 .
    Return NULL if not found. */
 {
 struct mafComp *mc;
 int speciesLen = strlen(species);
 
 for (mc = maf->components; mc != NULL; mc = mc->next)
     {
     if (startsWith(species, mc->src) )
 	{
 	char endChar = mc->src[speciesLen];
 
 	if ((endChar == '\0') || (endChar == sepChar))
 	    return mc;
 	}
     }
 return NULL;
 }
 
 
 struct mafComp *mafFindCompSpecies(struct mafAli *maf, char *species, char sepChar)
 /* Find component of given source that starts with species followed by sepChar
    or die trying. */
 {
 struct mafComp *mc = mafMayFindCompSpecies(maf, species, sepChar);
 if (mc == NULL)
     errAbort("Couldn't find %s%c or just %s... in maf", species,sepChar,species);
 return mc;
 }
 
 struct mafComp *mafMayFindCompPrefix(struct mafAli *maf, char *pre, char *sep)
 /* Find component of given source that starts with pre followed by sep.
    Return NULL if not found. */
 {
 struct mafComp *mc;
 char prefix[256];
 
 if (sep == NULL)
     sep = "";
 snprintf(prefix, 256, "%s%s", pre, sep);
 
 for (mc = maf->components; mc != NULL; mc = mc->next)
     {
     if (startsWith(prefix, mc->src))
         return mc;
     }
 return NULL;
 }
 
 struct mafComp *mafFindCompPrefix(struct mafAli *maf, char *pre, char *sep)
 /* Find component of given source that starts with pre followed by sep
    or die trying. */
 {
 struct mafComp *mc = mafMayFindCompPrefix(maf, pre, sep);
 if (mc == NULL)
     errAbort("Couldn't find %s%s... in maf", pre,sep);
 return mc;
 }
 
 struct mafComp *mafMayFindComponentInHash(struct mafAli *maf, struct hash *cHash) 
 /* Find arbitrary component of given source that matches any string in the cHash.
    Return NULL if not found. */
 {
 struct mafComp *mc;
 
 for (mc = maf->components; mc != NULL; mc = mc->next)
     {
     if (hashFindVal(cHash, mc->src))
         return mc;
     }
 return NULL;
 }
 
 struct mafComp *mafMayFindSpeciesInHash(struct mafAli *maf, struct hash *cHash, char sepChar) 
 /* Find arbitrary component of given who's source prefix (ended by sep)
    matches matches any string in the cHash.  Return NULL if not found. */
 {
 struct mafComp *mc;
 
 for (mc = maf->components; mc != NULL; mc = mc->next)
     {
     char *sep = strchr(mc->src, sepChar);
     if (sep != NULL)
         *sep = '\0';
     boolean hit = hashFindVal(cHash, mc->src) != NULL;
     if (sep != NULL)
         *sep = sepChar;
     if (hit)
         return mc;
     }
 return NULL;
 }
 
 boolean mafMayFindAllComponents(struct mafAli *maf, struct hash *cHash) 
 /* Find component of given source that starts matches any string in the cHash.
    Return NULL if not found. */
 {
 struct hashCookie cookie = hashFirst(cHash);
 struct hashEl *el;
 
 while ((el = hashNext(&cookie)) != NULL)
     if (mafMayFindComponent(maf, el->name) == NULL)
 	return FALSE;
 return TRUE;
 }
 
 struct mafAli *mafSubset(struct mafAli *maf, char *componentSource,
 	int newStart, int newEnd)
 {
 return mafSubsetE(maf, componentSource, newStart, newEnd, FALSE);
 }
 
 struct mafAli *mafSubsetE(struct mafAli *maf, char *componentSource,
 	int newStart, int newEnd, bool getInitialDashes)
 /* Extract subset of maf that intersects a given range
  * in a component sequence.  The newStart and newEnd
  * are given in the forward strand coordinates of the
  * component sequence.  The componentSource is typically
  * something like 'mm3.chr1'.  This will return NULL
  * if maf does not intersect range.  The score field
  * in the returned maf will not be filled in (since
  * we don't know which scoring scheme to use). */
 {
 struct mafComp *mcMaster = mafFindComponent(maf, componentSource);
 struct mafAli *subset;
 struct mafComp *mc, *subMc;
 char *s, *e;
 int textStart, textSize;
 
 /* Reverse complement input range if necessary. */
 if (mcMaster->strand == '-')
     reverseIntRange(&newStart, &newEnd, mcMaster->srcSize);
 
 /* Check if any real intersection and return NULL if not. */
 if (newStart >= newEnd)
     return NULL;
 if (newStart >= mcMaster->start + mcMaster->size)
     return NULL;
 if (newEnd <= mcMaster->start)
     return NULL;
 
 /* Clip to bounds of actual data. */
 if (newStart < mcMaster->start)
     newStart = mcMaster->start;
 if (newEnd > mcMaster->start + mcMaster->size)
     newEnd = mcMaster->start + mcMaster->size;
 
 /* Translate position in master sequence to position in
  * multiple alignment. */
 s = skipIgnoringDash(mcMaster->text, newStart - mcMaster->start, TRUE);
 e = skipIgnoringDash(s, newEnd - newStart, TRUE);
 textStart = s - mcMaster->text;
 textSize = e - s;
 
 if (getInitialDashes && (newStart == mcMaster->start))
     {
     textStart = 0;
     textSize += s - mcMaster->text;
     }
 
 /* Allocate subset structure and fill it in */
 AllocVar(subset);
 subset->textSize = textSize;
 for (mc = maf->components; mc != NULL; mc = mc->next)
     {
     AllocVar(subMc);
     subMc->src = cloneString(mc->src);
     subMc->srcSize = mc->srcSize;
     subMc->strand = mc->strand;
     if (mc->size != 0)
         {
         subMc->start = mc->start + countNonDash(mc->text, textStart);
         subMc->size = countNonDash(mc->text+textStart, textSize);
         subMc->text = cloneStringZ(mc->text + textStart, textSize);
         if (mc->quality != NULL)
             subMc->quality = cloneStringZ(mc->quality + textStart, textSize);
         }
     else
 	{
         /* empty row annotation */
         subMc->size = 0;
         subMc->start = mc->start;
 	}
 
     subMc->leftStatus = mc->leftStatus;
     subMc->leftLen = mc->leftLen;
     subMc->rightStatus = mc->rightStatus;
     subMc->rightLen = mc->rightLen;
 
     slAddHead(&subset->components, subMc);
     }
 slReverse(&subset->components);
 return subset;
 }
 
 void mafMoveComponentToTop(struct mafAli *maf, char *componentSource)
 /* Move given component to head of component list. */
 {
 struct mafComp *mcMaster = mafFindComponent(maf, componentSource);
 slRemoveEl(&maf->components, mcMaster);
 slAddHead(&maf->components, mcMaster);
 }
 
 boolean mafNeedSubset(struct mafAli *maf, char *componentSource,
 	int newStart, int newEnd)
 /* Return TRUE if maf only partially fits between newStart/newEnd
  * in given component. */
 {
 struct mafComp *mcMaster = mafFindComponent(maf, componentSource);
 
 /* Reverse complement input range if necessary. */
 if (mcMaster->strand == '-')
     reverseIntRange(&newStart, &newEnd, mcMaster->srcSize);
 
 return newStart > mcMaster->start || newEnd < mcMaster->start + mcMaster->size;
 }
 
 void mafFlipStrand(struct mafAli *maf)
 /* Reverse complement maf. */
 {
 struct mafComp *mc;
 for (mc = maf->components; mc != NULL; mc = mc->next)
     {
     int e = mc->start + mc->size;
     reverseIntRange(&mc->start, &e, mc->srcSize);
     if (mc->text != NULL)
         reverseComplement(mc->text, maf->textSize);
 	if (mc->quality != NULL)
 		reverseBytes(mc->quality, maf->textSize);
     if (mc->strand == '-')
         mc->strand = '+';
     else
         mc->strand = '-';
     char holdStatus = mc->leftStatus;
     mc->leftStatus = mc->rightStatus;
     mc->rightStatus = holdStatus;
     int holdLen = mc->leftLen;
     mc->leftLen = mc->rightLen;
     mc->rightLen = holdLen;
     }
 }
 
 void mafSrcDb(char *name, char *retDb, int retDbSize)
 /* Parse out just database part of name (up to but not including
  * first dot). If dot found, return entire name */
 {
 int len;
 char *e = strchr(name, '.');
 /* Put prefix up to dot into buf. */
 len = (e == NULL ? strlen(name) : e - name);
 if (len >= retDbSize)
      len = retDbSize-1;
 memcpy(retDb, name, len);
 retDb[len] = 0;
 }
 
 boolean mafColumnEmpty(struct mafAli *maf, int col)
 /* Return TRUE if the column is all '-' or '.' */
 {
 assert(col < maf->textSize);
 struct mafComp *comp;
 for (comp = maf->components; comp != NULL; comp = comp->next)
     if (comp->text != NULL)
         {
         char c = comp->text[col];
         if (c != '.' && c != '-')
             return FALSE;
         }
 return TRUE;
 }
 
 void mafStripEmptyColumns(struct mafAli *maf)
 /* Remove columns that are all '-' or '.' from  maf. */
 {
 /* Selectively copy over non-empty columns. */
 int readIx=0, writeIx = 0;
 struct mafComp *comp;
 for (readIx=0; readIx < maf->textSize; ++readIx)
     {
     if (!mafColumnEmpty(maf, readIx))
         {
         for (comp = maf->components; comp != NULL; comp = comp->next) 
             {
             if(comp->text != NULL)
                 comp->text[writeIx] = comp->text[readIx];
             if (comp->quality != NULL)
                 comp->quality[writeIx] = comp->quality[readIx];
             }
         ++writeIx;
         }
     }
 /* Zero terminate text, and update textSize. */
 for (comp = maf->components; comp != NULL; comp = comp->next)
     {
     if (comp->text != NULL)
         comp->text[writeIx] = 0;
     if (comp->quality != NULL)
         comp->quality[writeIx] = 0;
     }
 maf->textSize = writeIx;
 }
 
 struct mafRegDef *mafRegDefNew(char *type, int size, char *id)
 /* construct a new mafRegDef object */
 {
 struct mafRegDef *mrd;
 AllocVar(mrd);
 if (sameString(type, mafRegDefTxUpstream))
     mrd->type = mafRegDefTxUpstream;
 else
     errAbort("invalid mafRefDef type: %s", type);
 mrd->size = size;
 mrd->id = cloneString(id);
 return mrd;
 }
 
 void mafRegDefFree(struct mafRegDef **mrdPtr)
 /* Free a mafRegDef object */
 {
 struct mafRegDef *mrd = *mrdPtr;
 if (mrd != NULL)
     {
     freeMem(mrd->id);
     freeMem(mrd);
     *mrdPtr = NULL;
     }
 }
 
 boolean isContigOrTandem(char status)
 /* is status MAF_CONTIG_STATUS or MAF_TANDEM_STATUS */
 {
 return ((status == MAF_CONTIG_STATUS) ||
 	(status == MAF_TANDEM_STATUS));
 }
 
 struct mafComp *mafCompClone(struct mafComp *srcComp)
 /* clone a mafComp */
 {
 struct mafComp *comp;
 AllocVar(comp);
 comp->src = cloneString(srcComp->src);
 comp->srcSize = srcComp->srcSize;
 comp->strand = srcComp->strand;
 comp->start = srcComp->start;
 comp->size = srcComp->size;
 comp->text = cloneString(srcComp->text);
 comp->quality = cloneString(srcComp->quality);
 comp->leftStatus = srcComp->leftStatus;
 comp->leftLen = srcComp->leftLen;
 comp->rightStatus = srcComp->rightStatus;
 comp->rightLen = srcComp->rightLen;
 return comp;
 }
 
 static struct mafRegDef *mafRegDefClone(struct mafRegDef *srcRegDef)
 /* clone a srcRegDef */
 {
 return mafRegDefNew(srcRegDef->type, srcRegDef->size, srcRegDef->id);
 }
 
 struct mafAli *mafAliClone(struct mafAli *srcAli)
 /* clone a mafAli */
 {
 struct mafAli *ali;
 AllocVar(ali);
 ali->score = srcAli->score;
 struct mafComp *srcComp;
 for (srcComp = srcAli->components; srcComp != NULL; srcComp = srcComp->next)
     slAddHead(&ali->components, mafCompClone(srcComp));
 slReverse(&ali->components);
 ali->textSize = srcAli->textSize;
 if (srcAli->regDef != NULL)
     ali->regDef = mafRegDefClone(srcAli->regDef);
 return ali;
 }