33350fe38ad2c46108db7cd96e0ec0d956c7c6cb
gperez2
Fri Sep 13 12:14:25 2024 -0700
Revert "show table browser only exons when track contains genes, refs #27633"
This reverts commit e0cf10a674d7aac55aff8d39d169440716eb3f74.
diff --git src/hg/lib/featureBits.c src/hg/lib/featureBits.c
index 40da489..b3be45c 100644
--- src/hg/lib/featureBits.c
+++ src/hg/lib/featureBits.c
@@ -1,798 +1,798 @@
/* FeatureBits - convert features tables to bitmaps. */
/* Copyright (C) 2014 The Regents of the University of California
* See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
#include "common.h"
#include "jksql.h"
#include "hdb.h"
#include "bits.h"
#include "cart.h"
#include "cheapcgi.h"
#include "trackDb.h"
#include "bed.h"
#include "psl.h"
#include "genePred.h"
#include "rmskOut.h"
#include "featureBits.h"
#include "fa.h"
/* By default, clip features to the search range. It's important to clip
* when featureBits output will be used to populate Bits etc. But allow
* the user to turn off clipping if they don't want it. */
boolean clipToWin = TRUE;
void featureBitsFree(struct featureBits **pBits)
/* Free up feature bits. */
{
struct featureBits *bits;
if ((bits = *pBits) != NULL)
{
freeMem(bits->name);
freeMem(bits->chrom);
freez(pBits);
}
}
void featureBitsFreeList(struct featureBits **pList)
/* Free up a list of featureBits */
{
struct featureBits *el, *next;
for (el = *pList; el != NULL; el = next)
{
next = el->next;
featureBitsFree(&el);
}
*pList = NULL;
}
static boolean fetchQualifiers(char *type, char *qualifier, char *extra, int *retSize)
/* Return true if qualifier is of type. Convert extra to *retSize. */
{
if (qualifier != NULL && sameWord(qualifier, type))
{
int size = 0;
if (extra != NULL)
size = atoi(extra);
*retSize = size;
return TRUE;
}
else
return FALSE;
}
static boolean scoreQualifier(char *qualifier, char *extra, int *retSize)
/* Return TRUE if it's a score qualifier. */
{
return fetchQualifiers("score", qualifier, extra, retSize);
}
static boolean upstreamQualifier(char *qualifier, char *extra, int *retSize)
/* Return TRUE if it's a upstream qualifier. */
{
return fetchQualifiers("upstream", qualifier, extra, retSize);
}
static boolean upstreamAllQualifier(char *qualifier, char *extra, int *retSize)
/* Return TRUE if it's a upstreamAll qualifier. */
{
return fetchQualifiers("upstreamAll", qualifier, extra, retSize);
}
static boolean exonQualifier(char *qualifier, char *extra, int *retSize)
/* Return TRUE if it's a exon qualifier. */
{
return fetchQualifiers("exon", qualifier, extra, retSize);
}
static boolean intronQualifier(char *qualifier, char *extra, int *retSize)
/* Return TRUE if it's a exon qualifier. */
{
return fetchQualifiers("intron", qualifier, extra, retSize);
}
static boolean cdsQualifier(char *qualifier, char *extra, int *retSize)
/* Return TRUE if it's a cds qualifier. */
{
return fetchQualifiers("cds", qualifier, extra, retSize);
}
static boolean endQualifier(char *qualifier, char *extra, int *retSize)
/* Return TRUE if it's an end or downstream qualifier. */
{
boolean res = fetchQualifiers("downstream", qualifier, extra, retSize);
if (res)
return res;
return fetchQualifiers("end", qualifier, extra, retSize);
}
static boolean endAllQualifier(char *qualifier, char *extra, int *retSize)
/* Return TRUE if it's an endAll or downstreamAll qualifier. */
{
boolean res = fetchQualifiers("downstreamAll", qualifier, extra, retSize);
if (res)
return res;
return fetchQualifiers("endAll", qualifier, extra, retSize);
}
static boolean utr3Qualifier(char *qualifier, char *extra, int *retSize)
/* Return TRUE if it's a utr3 qualifier. */
{
return fetchQualifiers("utr3", qualifier, extra, retSize);
}
static boolean utr5Qualifier(char *qualifier, char *extra, int *retSize)
/* Return TRUE if it's a utr5 qualifier. */
{
return fetchQualifiers("utr5", qualifier, extra, retSize);
}
boolean fbUnderstandTrack(char *db, struct trackDb *tdb)
/* Return TRUE if can turn track into a set of ranges or bits. */
{
if (startsWith("bigWig", tdb->type))
return FALSE;
if ((tdb != NULL) && startsWith("big", tdb->type) && !startsWith("bigWig", tdb->type))
return TRUE;
struct hTableInfo *hti = hFindTableInfo(db, NULL, tdb->table);
if (hti == NULL)
return FALSE;
else
return hti->isPos;
}
static void fbAddFeature(char *db, struct featureBits **pList, char *name,
char *chrom, int start, int size, char strand,
int winStart, int winEnd)
/* Add new feature to head of list. Name can be NULL. */
{
struct featureBits *fb;
int s, e;
char nameBuf[512];
int chromSize = hChromSize(db, chrom);
if (name == NULL)
safef(nameBuf, sizeof(nameBuf), "%s:%d-%d", chrom, start+1, start+size);
else
safef(nameBuf, sizeof(nameBuf), "%s %s:%d-%d", name, chrom, start+1,
start+size);
s = start;
e = s + size;
/* Padding might push us off the edge of the chrom; if so, truncate: */
if (s < 0)
s = 0;
if (e > chromSize)
e = chromSize;
if (clipToWin)
{
if (s < winStart) s = winStart;
if (e > winEnd) e = winEnd;
}
if (s < e)
{
AllocVar(fb);
fb->name = cloneString(nameBuf);
fb->chrom = cloneString(chrom);
fb->start = s;
fb->end = e;
fb->strand = strand;
slAddHead(pList, fb);
}
}
static void setRangePlusExtra(char *db, struct featureBits **pList,
char *name, char *chrom, int s, int e, char strand,
int extraStart, int extraEnd,
int winStart, int winEnd)
/* Set range between s and e plus possibly some extra. */
{
int w;
s -= extraStart;
e += extraEnd;
w = e - s;
fbAddFeature(db, pList, name, chrom, s, w, strand, winStart,winEnd);
}
char frForStrand(char strand)
/* Return 'r' for '-', else 'f' */
{
if (strand == '-')
return 'r';
else
return 'f';
}
static void parseTrackQualifier(char *trackQualifier, char **retTrack,
char **retQualifier, char **retExtra)
/* Parse track:qualifier:extra. */
{
char *words[4];
int wordCount;
words[1] = words[2] = words[3] = 0;
wordCount = chopString(trackQualifier, ":", words, ArraySize(words));
if (wordCount < 1)
errAbort("empty trackQualifier");
*retTrack = words[0];
*retQualifier = words[1];
*retExtra = words[2];
}
void fbOptionsHtiCart(struct hTableInfo *hti, struct cart *cart)
/* Print out an HTML table with radio buttons for featureBits options.
* Use defaults from CGI and cart. */
{
boolean isGene;
char *setting, *fbQual;
-if (sameString("genePred", hti->type) || sameString("bigGenePred", hti->type))
- isGene = TRUE;
-else
+if (sameString("psl", hti->type))
isGene = FALSE;
+else
+ isGene = TRUE;
puts("
\n");
fbQual = cartCgiUsualString(cart, "fbQual", "whole");
cgiMakeRadioButton("fbQual", "whole", sameString(fbQual, "whole"));
if (isGene)
puts(" Whole Gene | ");
else
puts(" Whole Alignment | ");
puts(" |
\n");
cgiMakeRadioButton("fbQual", "upstreamAll", sameString(fbQual, "upstreamAll"));
puts(" Upstream by | ");
setting = cartCgiUsualString(cart, "fbUpBases", "200");
cgiMakeTextVar("fbUpBases", setting, 8);
puts(" bases |
\n");
if (hti->hasBlocks)
{
cgiMakeRadioButton("fbQual", "exon", sameString(fbQual, "exon"));
if (isGene)
puts(" Exons plus | ");
else
puts(" Blocks plus | ");
setting = cartCgiUsualString(cart, "fbExonBases", "0");
cgiMakeTextVar("fbExonBases", setting, 8);
puts(" bases at each end |
\n");
cgiMakeRadioButton("fbQual", "intron", sameString(fbQual, "intron"));
if (isGene)
puts(" Introns plus | ");
else
puts(" Regions between blocks plus | ");
setting = cartCgiUsualString(cart, "fbIntronBases", "0");
cgiMakeTextVar("fbIntronBases", setting, 8);
puts(" bases at each end |
\n");
}
if (hti->hasBlocks && hti->hasCDS)
{
cgiMakeRadioButton("fbQual", "utr5", sameString(fbQual, "utr5"));
puts(" 5' UTR Exons | ");
puts(" |
\n");
cgiMakeRadioButton("fbQual", "cds", sameString(fbQual, "cds"));
puts(" Coding Exons | ");
puts(" |
\n");
cgiMakeRadioButton("fbQual", "utr3", sameString(fbQual, "utr3"));
puts(" 3' UTR Exons | ");
puts(" |
\n");
}
else if (hti->hasCDS)
{
cgiMakeRadioButton("fbQual", "utr5", sameString(fbQual, "utr5"));
puts(" 5' UTR | ");
puts(" |
\n");
cgiMakeRadioButton("fbQual", "cds", sameString(fbQual, "cds"));
puts(" CDS | ");
puts(" |
\n");
cgiMakeRadioButton("fbQual", "utr3", sameString(fbQual, "utr3"));
puts(" 3' UTR | ");
puts(" |
\n");
}
cgiMakeRadioButton("fbQual", "endAll", sameString(fbQual, "endAll"));
puts(" Downstream by | ");
setting = cartCgiUsualString(cart, "fbDownBases", "200");
cgiMakeTextVar("fbDownBases", setting, 8);
puts(" bases |
");
puts("Note: if a feature is close to the beginning or end of a chromosome \n"
"and upstream/downstream bases are added, they may be truncated \n"
"in order to avoid extending past the edge of the chromosome.
");
}
void fbOptionsHti(struct hTableInfo *hti)
/* Print out an HTML table with radio buttons for featureBits options.
* Use defaults from CGI. */
{
fbOptionsHtiCart(hti, NULL);
}
void fbOptions(char *db, char *track)
/* Print out an HTML table with radio buttons for featureBits options. */
{
struct hTableInfo *hti = hFindTableInfo(db, NULL, track);
if (hti == NULL)
errAbort("Could not find table info for table %s in database %s",
track, db);
fbOptionsHti(hti);
}
char *fbOptionsToQualifier()
/* Translate CGI variable created by fbOptions() to a featureBits qualifier. */
{
char qual[128];
char *fbQual = cgiOptionalString("fbQual");
if (fbQual == NULL)
return NULL;
if (sameString(fbQual, "whole"))
qual[0] = 0;
else if (sameString(fbQual, "exon"))
safef(qual, sizeof(qual), "%s:%s", fbQual, cgiString("fbExonBases"));
else if (sameString(fbQual, "intron"))
safef(qual, sizeof(qual), "%s:%s", fbQual,
cgiString("fbIntronBases"));
else if (sameString(fbQual, "upstreamAll"))
safef(qual, sizeof(qual), "%s:%s", fbQual, cgiString("fbUpBases"));
else if (sameString(fbQual, "upstream"))
safef(qual, sizeof(qual), "%s:%s", fbQual, cgiString("fbUpBases"));
else if (sameString(fbQual, "endAll"))
safef(qual, sizeof(qual), "%s:%s", fbQual, cgiString("fbDownBases"));
else if (sameString(fbQual, "end"))
safef(qual, sizeof(qual), "%s:%s", fbQual, cgiString("fbDownBases"));
else
strcpy(qual, fbQual);
return(cloneString(qual));
}
struct featureBits *fbFromBed(char *db, char *trackQualifier, struct hTableInfo *hti,
struct bed *bedList, int chromStart, int chromEnd,
boolean clipToWindow, boolean filterOutNoUTR)
/* Translate a list of bed items into featureBits. */
{
struct bed *bed;
struct featureBits *fbList = NULL;
char nameBuf[512];
char *fName;
char *track, *qualifier, *extra;
boolean doUp = FALSE, doEnd = FALSE, doCds = FALSE, doExon = FALSE,
doUtr3 = FALSE, doUtr5 = FALSE, doIntron = FALSE, doScore = FALSE,
doUpAll = FALSE, doEndAll = FALSE;
int promoSize = 0, extraSize = 0, endSize = 0, scoreThreshold = 0;
boolean canDoIntrons, canDoUTR, canDoScore;
boolean oldClipToWin = clipToWin;
int i, count, *starts, *sizes;
int s, e;
clipToWin = clipToWindow;
trackQualifier = cloneString(trackQualifier);
parseTrackQualifier(trackQualifier, &track, &qualifier, &extra);
canDoUTR = hti->hasCDS;
canDoIntrons = hti->hasBlocks;
canDoScore = (hti->scoreField[0] != 0);
if ((doScore = scoreQualifier(qualifier, extra, &scoreThreshold)) != FALSE)
{
if (! canDoScore)
errAbort("Can't handle score on table %s, sorry", track);
}
if ((doUpAll = upstreamAllQualifier(qualifier, extra, &promoSize)) != FALSE)
{
}
else if ((doUp = upstreamQualifier(qualifier, extra, &promoSize)) != FALSE)
{
}
else if ((doEnd = endQualifier(qualifier, extra, &endSize)) != FALSE)
{
}
else if ((doEndAll = endAllQualifier(qualifier, extra, &endSize)) != FALSE)
{
}
else if ((doExon = exonQualifier(qualifier, extra, &extraSize)) != FALSE)
{
if (! canDoIntrons)
errAbort("Can't handle exon on table %s, sorry", track);
}
else if ((doIntron = intronQualifier(qualifier, extra, &extraSize)) != FALSE)
{
if (! canDoIntrons)
errAbort("Can't handle intron on table %s, sorry", track);
}
else if ((doCds = cdsQualifier(qualifier, extra, &extraSize)) != FALSE)
{
if (! canDoUTR)
errAbort("Can't handle cds on table %s, sorry", track);
}
else if ((doUtr3 = utr3Qualifier(qualifier, extra, &extraSize)) != FALSE)
{
if (! canDoUTR)
errAbort("Can't handle utr3 on table %s, sorry", track);
}
else if ((doUtr5 = utr5Qualifier(qualifier, extra, &extraSize)) != FALSE)
{
if (! canDoUTR)
errAbort("Can't handle utr5 on table %s, sorry", track);
}
if (doUpAll || doEndAll)
filterOutNoUTR = FALSE;
for (bed = bedList; bed != NULL; bed = bed->next)
{
if (doUp || doUpAll)
{
if (!canDoUTR || !filterOutNoUTR ||
((bed->chromStart != bed->thickStart) &&
(bed->chromEnd != bed->thickEnd)))
{
if (bed->strand[0] == '-')
{
s = bed->chromEnd;
e = s + promoSize;
}
else
{
e = bed->chromStart;
s = e - promoSize;
}
safef(nameBuf, sizeof(nameBuf), "%s_up_%d_%s_%d_%c",
bed->name, promoSize, bed->chrom, s+1,
frForStrand(bed->strand[0]));
fbAddFeature(db, &fbList, nameBuf, bed->chrom, s, e - s,
bed->strand[0], chromStart, chromEnd);
}
}
else if (doEnd || doEndAll)
{
if (!canDoUTR || !filterOutNoUTR ||
((bed->chromStart != bed->thickStart) &&
(bed->chromEnd != bed->thickEnd)))
{
if (bed->strand[0] == '-')
{
e = bed->chromStart;
s = e - endSize;
}
else
{
s = bed->chromEnd;
e = s + endSize;
}
safef(nameBuf, sizeof(nameBuf), "%s_end_%d_%s_%d_%c",
bed->name, endSize, bed->chrom, s+1,
frForStrand(bed->strand[0]));
fbAddFeature(db, &fbList, nameBuf, bed->chrom, s, e - s,
bed->strand[0], chromStart, chromEnd);
}
}
else if (doIntron)
{
count = bed->blockCount;
starts = bed->chromStarts;
sizes = bed->blockSizes;
for (i=1; istrand[0] == '+' ? i - 1 : count - 1 - i;
s = bed->chromStart + starts[i-1] + sizes[i-1];
e = bed->chromStart + starts[i];
safef(nameBuf, sizeof(nameBuf), "%s_intron_%d_%d_%s_%d_%c",
bed->name, intronNum, extraSize, bed->chrom, s+1,
frForStrand(bed->strand[0]));
setRangePlusExtra(db, &fbList, nameBuf, bed->chrom, s, e,
bed->strand[0], extraSize, extraSize,
chromStart, chromEnd);
}
}
else
{
if (canDoIntrons)
{
// doExon is the default action.
count = bed->blockCount;
starts = bed->chromStarts;
sizes = bed->blockSizes;
for (i=0; ichromStart + starts[i];
e = bed->chromStart + starts[i] + sizes[i];
if (doCds)
{
if ((e < bed->thickStart) || (s > bed->thickEnd)) continue;
if (s < bed->thickStart) s = bed->thickStart;
if (e > bed->thickEnd) e = bed->thickEnd;
fName = "cds";
}
else if (doUtr5)
{
if (bed->strand[0] == '-')
{
if (e < bed->thickEnd) continue;
if (s < bed->thickEnd) s = bed->thickEnd;
}
else
{
if (s > bed->thickStart) continue;
if (e > bed->thickStart) e = bed->thickStart;
}
fName = "utr5";
}
else if (doUtr3)
{
if (bed->strand[0] == '-')
{
if (s > bed->thickStart) continue;
if (e > bed->thickStart) e = bed->thickStart;
}
else
{
if (e < bed->thickEnd) continue;
if (s < bed->thickEnd) s = bed->thickEnd;
}
fName = "utr3";
}
else
{
fName = "exon";
}
if (!doScore || (doScore && bed->score >= scoreThreshold))
{
// the -1 is because we output exon numbers starting at 0
int exonNum = bed->strand[0] == '+' ? i : count - 1 - i;
safef(nameBuf, sizeof(nameBuf), "%s_%s_%d_%d_%s_%d_%c",
bed->name, fName, exonNum, extraSize, bed->chrom, s+1,
frForStrand(bed->strand[0]));
setRangePlusExtra(db, &fbList, nameBuf, bed->chrom, s, e,
bed->strand[0], extraSize, extraSize,
chromStart, chromEnd);
}
}
}
else
{
if (doCds)
{
s = bed->thickStart;
e = bed->thickEnd;
fName = "cds";
}
else if (doUtr5)
{
if (bed->strand[0] == '-')
{
s = bed->thickEnd;
e = bed->chromEnd;
}
else
{
s = bed->chromStart;
e = bed->thickStart;
}
fName = "utr5";
}
else if (doUtr3)
{
if (bed->strand[0] == '-')
{
s = bed->chromStart;
e = bed->thickStart;
}
else
{
s = bed->thickEnd;
e = bed->chromEnd;
}
fName = "utr3";
}
else
{
s = bed->chromStart;
e = bed->chromEnd;
fName = "whole";
}
if (!doScore || (doScore && bed->score >= scoreThreshold))
{
safef(nameBuf, sizeof(nameBuf), "%s_%s_%d_%s_%d_%c",
bed->name, fName, extraSize, bed->chrom, s+1,
frForStrand(bed->strand[0]));
setRangePlusExtra(db, &fbList, nameBuf, bed->chrom, s, e,
bed->strand[0], extraSize, extraSize,
chromStart, chromEnd);
}
}
}
}
clipToWin = oldClipToWin;
freeMem(trackQualifier);
slReverse(&fbList);
return fbList;
}
struct featureBits *fbGetRangeQuery(char *db, char *trackQualifier,
char *chrom, int chromStart, int chromEnd, char *sqlConstraints,
boolean clipToWindow, boolean filterOutNoUTR)
/* Get features in range that match sqlConstraints. */
{
struct hTableInfo *hti;
struct bed *bedList;
struct featureBits *fbList;
char *tQ, *track, *qualifier, *extra;
tQ = cloneString(trackQualifier);
parseTrackQualifier(tQ, &track, &qualifier, &extra);
hti = hFindTableInfo(db, NULL, track);
if (hti == NULL)
errAbort("Could not find table info for table %s in database %s",
track, db);
bedList = hGetBedRange(db, track, chrom, chromStart, chromEnd,
sqlConstraints);
fbList = fbFromBed(db, trackQualifier, hti, bedList, chromStart, chromEnd,
clipToWindow, filterOutNoUTR);
bedFreeList(&bedList);
return(fbList);
}
struct featureBits *fbGetRange(char *db, char *trackQualifier, char *chrom,
int chromStart, int chromEnd)
/* Get features in range that match sqlConstraints. */
{
return(fbGetRangeQuery(db, trackQualifier,
chrom, chromStart, chromEnd, NULL, TRUE, TRUE));
}
void fbOrBits(Bits *bits, int bitSize, struct featureBits *fbList, int bitOffset)
/* Or in bits. Bits should have bitSize bits. */
{
int s, e, w;
struct featureBits *fb;
for (fb = fbList; fb != NULL; fb = fb->next)
{
s = fb->start - bitOffset;
e = fb->end - bitOffset;
if (e > bitSize) e = bitSize;
if (s < 0) s = 0;
w = e - s;
if (w > 0)
bitSetRange(bits, s , w);
}
}
void fbOrTableBits(char *db, Bits *bits, char *trackQualifier, char *chrom,
int chromSize, struct sqlConnection *conn)
/* Ors in features in track on chromosome into bits. */
{
struct featureBits *fbList = fbGetRange(db, trackQualifier, chrom, 0, chromSize);
fbOrBits(bits, chromSize, fbList, 0);
featureBitsFreeList(&fbList);
}
void fbOrTableBitsQueryMinSize(char *db, Bits *bits, char *trackQualifier, char *chrom,
int chromSize, struct sqlConnection *conn, char *sqlConstraints,
boolean clipToWindow, boolean filterOutNoUTR, int minSize)
/* Ors in features matching sqlConstraints in track on chromosome into bits.
Skips featureBits that are less than minSize. minSize is useful for introns where
things less than a given threshold are alignment gaps rather than introns. */
{
struct featureBits *goodList = NULL, *badList = NULL, *fb = NULL, *fbNext = NULL;
struct featureBits *fbList = fbGetRangeQuery(db, trackQualifier, chrom, 0,
chromSize, sqlConstraints,
clipToWindow, filterOutNoUTR);
if(minSize > 0)
{
for(fb = fbList; fb != NULL; fb = fbNext)
{
fbNext = fb->next;
if(fb->end - fb->start > minSize)
{
slAddHead(&goodList, fb);
}
else
{
slAddHead(&badList, fb);
}
}
}
else
{
goodList = fbList;
}
fbOrBits(bits, chromSize, goodList, 0);
featureBitsFreeList(&goodList);
featureBitsFreeList(&badList);
}
void fbOrTableBitsQuery(char *db, Bits *bits, char *trackQualifier, char *chrom,
int chromSize, struct sqlConnection *conn, char *sqlConstraints,
boolean clipToWindow, boolean filterOutNoUTR)
/* Ors in features matching sqlConstraints in track on chromosome into bits. */
{
fbOrTableBitsQueryMinSize(db, bits, trackQualifier, chrom, chromSize, conn,
sqlConstraints, clipToWindow, filterOutNoUTR, 0);
}
struct bed *fbToBedOne(struct featureBits *fb)
/* Translate a featureBits item into (scoreless) bed 6. */
{
struct bed *bed;
AllocVar(bed);
bed->chrom = cloneString(fb->chrom);
bed->chromStart = fb->start;
bed->chromEnd = fb->end;
bed->name = cloneString(fb->name);
bed->strand[0] = fb->strand;
return bed;
}
struct bed *fbToBed(struct featureBits *fbList)
/* Translate a list of featureBits items into (scoreless) bed 6. */
{
struct bed *bedList = NULL, *bed;
struct featureBits *fb;
for (fb=fbList; fb != NULL; fb=fb->next)
{
bed = fbToBedOne(fb);
slAddHead(&bedList, bed);
}
return(bedList);
}
void bitsToBed(char *db, Bits *bits, char *chrom, int chromSize, FILE *bed, FILE *fa,
int minSize)
/* Write out runs of bits of at least minSize as items in a bed file. */
{
int i;
boolean thisBit, lastBit = FALSE;
int start = 0;
int id = 0;
for (i=0; i= minSize)
{
if (bed)
fprintf(bed, "%s\t%d\t%d\t%s.%d\n", chrom, start, i, chrom, ++id);
if (fa)
{
char name[256];
struct dnaSeq *seq = hDnaFromSeq(db,chrom, start, i, dnaLower);
sprintf(name, "%s:%d-%d", chrom, start, i);
faWriteNext(fa, name, seq->dna, seq->size);
freeDnaSeq(&seq);
}
}
}
lastBit = thisBit;
}
if (lastBit && i-start >= minSize)
{
if (bed)
fprintf(bed, "%s\t%d\t%d\t%s.%d\n", chrom, start, i, chrom, ++id);
if (fa)
{
char name[256];
struct dnaSeq *seq = hDnaFromSeq(db, chrom, start, i, dnaLower);
sprintf(name, "%s:%d-%d", chrom, start, i);
faWriteNext(fa, name, seq->dna, seq->size);
freeDnaSeq(&seq);
}
}
}