e08ae97dc288749c2454fd98a10dc79f06e27cb5 max Tue Aug 11 06:16:20 2026 -0700 hgBlat/hgc: fixes from the v502 code review of the BLAT results pages, refs #37893 #4 blatOldTracks now falls back to "keep" (with a warning) on any value other than keep/hide/delete, instead of dropping into the destructive delete branch, so a typo in hg.conf can never silently discard a user's earlier BLAT tracks. #5 htmlEncode() (js/utils.js) now also escapes " and ', which the browser's text->markup conversion leaves alone. Every hgBlat caller puts the result in a double-quoted attribute, so an unescaped quote in the cart position string could break out of the attribute; the shared helper now honors its documented contract. #6 The non-BLAT alignment title no longer starts with a stray space. #7 open_memstream() is checked for NULL: on that failure the alignment renders straight to stdout instead of writing to a NULL FILE and calling fclose(NULL). The section reorder keys on the literal "
\n");
if (aliList != NULL)
{
for (leftAli = aliList; leftAli->left != NULL; leftAli = leftAli->left)
;
}
for (ali = leftAli; ali != NULL; ali = ali->right)
{
boolean utr = FALSE;
int off = ali->nStart-needle;
int count = ali->nEnd - ali->nStart;
if ((cdsE > 0) && ((cdsS-off-1) > 0))
utr = TRUE;
for (i=0; i (cdsE-off-1)) && (cdsE > 0))
utr = TRUE;
if (utr && (i == (cdsS-off)))
utr = FALSE;
if (toupper(ali->hStart[i]) == toupper(ali->nStart[i]))
{
if (utr)
colorFlags[off+i] = ((i == 0 || i == count-1) ? socOrange : socRed);
else
colorFlags[off+i] = ((i == 0 || i == count-1) ? socBrightBlue : socBlue);
if (upcMatch)
n[off+i] = toupper(n[off+i]);
}
if (accentRange)
{
if (off+i >= accentStart && off+i < accentEnd)
accentFlags[off+i] = TRUE;
}
}
}
for (i=0; i ");
cfmOutExt(cfm, n[i], seqOutColorLookup[(int)colorFlags[i]],
accentFlags[i], accentFlags[i], FALSE);
}
cfmFree(&cfm);
freeMem(n);
freeMem(accentFlags);
fprintf(f, "\n");
htmHorizontalLine(f);
}
void ffShowSideBySide(FILE *f, struct ffAli *leftAli, DNA *needle, int needleNumOffset,
DNA *haystack, int hayNumOffset, int haySize, int hayOffStart, int hayOffEnd,
int blockMaxGap, boolean rcHaystack, boolean initialNewline)
/* Print HTML side-by-side alignment of needle and haystack (no title or labels) to f.
* {hay,needle}NumOffset are the coords at which the DNA sequence begins.
* hayOff{Start,End} are the range of coords *relative to hayNumOffset* to which the
* alignment display will be clipped -- pass in {0,haySize} for no clipping. */
{
fprintf(f, "%s", initialNewline ? "\n" : "");
struct ffAli *ali, *lastAli = NULL;
struct baf baf;
/* NOTE: if rcHaystack, hayNumOffset changes here into the end, not start! */
if (rcHaystack)
hayNumOffset += haySize;
bafInit(&baf, needle, needleNumOffset, FALSE,
haystack, hayNumOffset, rcHaystack, f, 50, FALSE);
for (ali=leftAli; ali!=NULL; ali = ali->right)
{
int i;
boolean doBreak = TRUE;
if ((ali->hEnd - haystack) <= hayOffStart ||
(ali->hStart - haystack) >= hayOffEnd)
continue;
/* Decide whether to put in a line break and/or blank characters */
if (lastAli != NULL)
{
int nSkip = ali->nStart - lastAli->nEnd;
int hSkip = ali->hStart - lastAli->hEnd;
if (nSkip > 0 && nSkip <= blockMaxGap && hSkip == 0)
{
for (i=0; inEnd[i],'.');
doBreak = FALSE;
}
else if (hSkip > 0 && hSkip <= blockMaxGap && nSkip == 0)
{
for (i=0; ihEnd[i]);
doBreak = FALSE;
}
else if (hSkip == nSkip && hSkip <= blockMaxGap)
{
for (i=0; inEnd[i], lastAli->hEnd[i]);
doBreak = FALSE;
}
}
else
{
doBreak = FALSE;
}
if (doBreak)
bafFlushLine(&baf);
int offset = max(0, (hayOffStart - (ali->hStart - haystack)));
int nStart = offset + ali->nStart - needle;
int hStart = offset + ali->hStart - haystack;
bafSetPos(&baf, nStart, hStart);
if (doBreak || lastAli == NULL)
bafStartLine(&baf);
int aliLen = ali->nEnd - ali->nStart;
for (i=0; ihStart - haystack);
if (hayOff < hayOffStart)
continue;
if (hayOff >= hayOffEnd)
break;
bafOut(&baf, ali->nStart[i], ali->hStart[i]);
}
lastAli = ali;
}
if (leftAli != NULL)
bafFlushLineNoHr(&baf);
fprintf(f, " \n");
}
int ffShAliPart(FILE *f, struct ffAli *aliList,
char *needleName, DNA *needle, int needleSize, int needleNumOffset,
char *haystackName, DNA *haystack, int haySize, int hayNumOffset,
int blockMaxGap, boolean rcNeedle, boolean rcHaystack,
boolean showJumpTable,
boolean showNeedle, boolean showHaystack,
boolean showSideBySide, boolean upcMatch,
int cdsS, int cdsE, int hayPartS, int hayPartE)
/* Display parts of alignment on html page. If hayPartS..hayPartE is a
* smaller subrange of the alignment, highlight that part of the alignment
* in both needle and haystack with underline & bold, and show only that
* part of the haystack (plus padding). Returns number of blocks (after
* merging blocks separated by blockMaxGap or less). */
{
long i;
struct ffAli *ali;
struct ffAli *lastAli;
struct ffAli *leftAli = aliList;
struct ffAli *rightAli = aliList;
int maxSize = (needleSize > haySize ? needleSize : haySize);
char *colorFlags = needMem(maxSize);
int anchorCount = 0;
boolean restrictToWindow = FALSE;
int hayOffStart = 0, hayOffEnd = haySize;
int hayPaddedOffStart = 0, hayPaddedOffEnd = haySize;
int hayExtremity = rcHaystack ? (hayNumOffset + haySize) : hayNumOffset;
int nPartS=0, nPartE=0;
if (aliList != NULL)
{
while (leftAli->left != NULL) leftAli = leftAli->left;
while (rightAli->right != NULL) rightAli = rightAli->right;
}
/* If we are only showing part of the alignment, translate haystack window
* coords to needle window coords and haystack-offset window coords: */
if (hayPartS > (hayNumOffset + (leftAli->hStart - haystack)) ||
(hayPartE > 0 && hayPartE < (hayNumOffset + (rightAli->hEnd - haystack))))
{
DNA *haystackPartS;
DNA *haystackPartE;
restrictToWindow = TRUE;
if (rcHaystack)
{
haystackPartS = haystack + (haySize - (hayPartE - hayNumOffset));
haystackPartE = haystack + (haySize - (hayPartS - hayNumOffset));
}
else
{
haystackPartS = haystack + hayPartS - hayNumOffset;
haystackPartE = haystack + hayPartE - hayNumOffset;
}
boolean foundStart = FALSE;
hayOffStart = haystackPartS - haystack;
hayOffEnd = haystackPartE - haystack;
for (ali = leftAli; ali != NULL; ali = ali->right)
{
if (haystackPartS < ali->hEnd && !foundStart)
{
int offset = haystackPartS - ali->hStart;
if (offset < 0)
offset = 0;
nPartS = offset + ali->nStart - needle;
hayOffStart = offset + ali->hStart - haystack;
foundStart = TRUE;
}
if (haystackPartE > ali->hStart)
{
if (haystackPartE > ali->hEnd)
{
nPartE = ali->nEnd - needle;
hayOffEnd = ali->hEnd - haystack;
}
else
{
nPartE = haystackPartE - ali->hStart + ali->nStart - needle;
hayOffEnd = haystackPartE - haystack;
}
}
}
hayPaddedOffStart = max(0, (hayOffStart - 100));
hayPaddedOffEnd = min(haySize, (hayOffEnd + 100));
if (rcHaystack)
hayExtremity = hayNumOffset + haySize - hayPaddedOffStart;
else
hayExtremity = hayNumOffset + hayPaddedOffStart;
}
if (showJumpTable)
{
fputs("| ", f); if (restrictToWindow) fputs(" | ", f); fputs(" | ", f); fputs(" | ", f); fputs(" | ", f); fputs(" |
\n");
zeroBytes(colorFlags, haySize);
for (ali = leftAli; ali != NULL; ali = ali->right)
{
boolean utr = FALSE;
int i;
int off = ali->hStart-haystack;
int count = ali->hEnd - ali->hStart;
int offn = ali->nStart-needle;
if ((cdsE > 0) && ((cdsS-offn-1) > 0))
utr = TRUE;
for (i=0; i (cdsE-offn-1)) && (cdsE > 0))
utr = TRUE;
if (utr && (i == (cdsS-offn)))
utr = FALSE;
if (toupper(ali->hStart[i]) == toupper(ali->nStart[i]))
{
if (utr)
colorFlags[off+i] = ((i == 0 || i == count-1) ? socOrange : socRed);
else
colorFlags[off+i] = ((i == 0 || i == count-1) ? socBrightBlue : socBlue);
if (upcMatch)
h[off+i] = toupper(h[off+i]);
}
if (restrictToWindow && off+i >= hayOffStart && off+i < hayOffEnd)
accentFlags[off+i] = TRUE;
}
}
ali = leftAli;
lastAli = NULL;
while (ali && (ali->hEnd - haystack) <= hayPaddedOffStart)
ali = ali->right;
for (i = hayPaddedOffStart; i < hayPaddedOffEnd; ++i)
{
/* Put down "anchor" on first match position in haystack
* so user can hop here with a click on the needle. */
if (ali != NULL && i == ali->hStart - haystack)
{
if (lastAli == NULL || ali->hStart - lastAli->hEnd > blockMaxGap)
{
fprintf(f, "", ++anchorCount);
}
lastAli = ali;
ali = ali->right;
}
cfmOutExt(cfm, h[i], seqOutColorLookup[(int)colorFlags[i]],
accentFlags[i], accentFlags[i], FALSE);
}
cfmFree(&cfm);
freeMem(h);
fprintf(f, " \n");
htmHorizontalLine(f);
}
if (showSideBySide)
{
fprintf(f, "