#include "obscure.h"
#include "hCommon.h"
#include "hash.h"
#include "binRange.h"
#include "bits.h"
#include "memgfx.h"
#include "hvGfx.h"
#include "portable.h"
#include "regexHelper.h"
#include "errAbort.h"
#include "dystring.h"
#include "nib.h"
#include "cheapcgi.h"
#include "htmshell.h"
#include "cart.h"
#include "jksql.h"
#include "dnautil.h"
#include "dnaseq.h"
#include "fa.h"
#include "fuzzyFind.h"
#include "seqOut.h"
#include "hdb.h"
#include "spDb.h"
#include "hui.h"
#include "hgRelate.h"
#include "htmlPage.h"
#include "psl.h"
#include "cogs.h"
#include "cogsxra.h"
#include "bed.h"
#include "cgh.h"
#include "agpFrag.h"
#include "agpGap.h"
#include "ctgPos.h"
#include "contigAcc.h"
#include "ctgPos2.h"
#include "clonePos.h"
#include "bactigPos.h"
#include "rmskOut.h"
#include "xenalign.h"
#include "isochores.h"
#include "simpleRepeat.h"
#include "cpgIsland.h"
#include "cpgIslandExt.h"
#include "genePred.h"
#include "genePredReader.h"
#include "pepPred.h"
#include "peptideAtlasPeptide.h"
#include "wabAli.h"
#include "genomicDups.h"
#include "est3.h"
#include "rnaGene.h"
#include "tRNAs.h"
#include "gbRNAs.h"
#include "encode/encodeRna.h"
#include "hgMaf.h"
#include "maf.h"
#include "stsMarker.h"
#include "stsMap.h"
#include "rhMapZfishInfo.h"
#include "recombRate.h"
#include "recombRateRat.h"
#include "recombRateMouse.h"
#include "stsInfo.h"
#include "stsInfo2.h"
#include "mouseSyn.h"
#include "mouseSynWhd.h"
#include "ensPhusionBlast.h"
#include "cytoBand.h"
#include "knownMore.h"
#include "snp125.h"
#include "snp125Ui.h"
#include "snp132Ext.h"
#include "snp.h"
#include "snpMap.h"
#include "snpExceptions.h"
#include "snp125Exceptions.h"
#include "snp125CodingCoordless.h"
#include "cnpIafrate.h"
#include "cnpIafrate2.h"
#include "cnpLocke.h"
#include "cnpSebat.h"
#include "cnpSebat2.h"
#include "cnpSharp.h"
#include "cnpSharp2.h"
#include "delHinds2.h"
#include "delConrad2.h"
#include "dgv.h"
#include "dgvPlus.h"
#include "tokenizer.h"
#include "softberryHom.h"
#include "borkPseudoHom.h"
#include "sanger22extra.h"
#include "ncbiRefLink.h"
#include "ncbiRefSeqLink.h"
#include "refLink.h"
#include "hgConfig.h"
#include "estPair.h"
#include "softPromoter.h"
#include "customTrack.h"
#include "myVariants.h"
#include "trackHub.h"
#include "hubConnect.h"
#include "sage.h"
#include "sageExp.h"
#include "pslWScore.h"
#include "lfs.h"
#include "mcnBreakpoints.h"
#include "fishClones.h"
#include "featureBits.h"
#include "web.h"
#include "dbDb.h"
#include "jaxOrtholog.h"
#include "dnaProbe.h"
#include "ancientRref.h"
#include "jointalign.h"
#include "gcPercent.h"
#include "genMapDb.h"
#include "altGraphX.h"
#include "geneGraph.h"
#include "stsMapMouse.h"
#include "stsInfoMouse.h"
#include "dbSnpRs.h"
#include "genomicSuperDups.h"
#include "celeraDupPositive.h"
#include "celeraCoverage.h"
#include "sample.h"
#include "axt.h"
#include "axtInfo.h"
#include "jaxQTL.h"
#include "jaxQTL3.h"
#include "wgRna.h"
#include "ncRna.h"
#include "gbProtAnn.h"
#include "hgSeq.h"
#include "chain.h"
#include "chainDb.h"
#include "chainNetDbLoad.h"
#include "chainToPsl.h"
#include "chainToAxt.h"
#include "netAlign.h"
#include "stsMapRat.h"
#include "stsInfoRat.h"
#include "stsMapMouseNew.h"
#include "stsInfoMouseNew.h"
#include "vegaInfo.h"
#include "vegaInfoZfish.h"
#include "ensInfo.h"
#include "scoredRef.h"
#include "blastTab.h"
#include "hdb.h"
#include "hgc.h"
#include "genbank.h"
#include "pseudoGeneLink.h"
#include "axtLib.h"
#include "ensFace.h"
#include "bdgpGeneInfo.h"
#include "flyBaseSwissProt.h"
#include "flyBase2004Xref.h"
#include "affy10KDetails.h"
#include "affy120KDetails.h"
#include "encode/encodeRegionInfo.h"
#include "encode/encodeErge.h"
#include "encode/encodeErgeHssCellLines.h"
#include "encode/encodeStanfordPromoters.h"
#include "encode/encodeStanfordPromotersAverage.h"
#include "encode/encodeIndels.h"
#include "encode/encodeHapMapAlleleFreq.h"
#include "hapmapSnps.h"
#include "hapmapAllelesOrtho.h"
#include "hapmapAllelesSummary.h"
#include "sgdDescription.h"
#include "sgdClone.h"
#include "tfbsCons.h"
#include "tfbsConsMap.h"
#include "tfbsConsSites.h"
#include "tfbsConsFactors.h"
#include "simpleNucDiff.h"
#include "bgiGeneInfo.h"
#include "bgiSnp.h"
#include "bgiGeneSnp.h"
#include "botDelay.h"
#include "vntr.h"
#include "zdobnovSynt.h"
#include "HInv.h"
#include "bed5FloatScore.h"
#include "bed6FloatScore.h"
#include "pscreen.h"
#include "jalview.h"
#include "flyreg.h"
#include "putaInfo.h"
#include "gencodeIntron.h"
#include "cutter.h"
#include "switchDbTss.h"
#include "chicken13kInfo.h"
#include "gapCalc.h"
#include "chainConnect.h"
#include "dv.h"
#include "dvBed.h"
#include "dvXref2.h"
#include "omimTitle.h"
#include "dless.h"
#include "gv.h"
#include "gvUi.h"
#include "protVar.h"
#include "oreganno.h"
#include "oregannoUi.h"
#include "pgSnp.h"
#include "pgPhenoAssoc.h"
#include "pgSiftPred.h"
#include "pgPolyphenPred.h"
#include "bedDetail.h"
#include "ec.h"
#include "transMapClick.h"
#include "retroClick.h"
#include "mgcClick.h"
#include "ccdsClick.h"
#include "gencodeClick.h"
#include "memalloc.h"
#include "trashDir.h"
#include "kg1ToKg2.h"
#include "wikiTrack.h"
#include "grp.h"
#include "omicia.h"
#include "atomDb.h"
#include "pcrResult.h"
#include "twoBit.h"
#include "itemConf.h"
#include "chromInfo.h"
#include "gbWarn.h"
#include "mammalPsg.h"
#include "net.h"
#include "jsHelper.h"
#include "virusClick.h"
#include "gwasCatalog.h"
#include "mdb.h"
#include "yaleGencodeAssoc.h"
#include "itemDetailsHtml.h"
#include "trackVersion.h"
#include "numtsClick.h"
#include "geneReviewsClick.h"
#include "bigBed.h"
#include "bigPsl.h"
#include "blatShare.h"
#include "bedTabix.h"
#include "longRange.h"
#include "hmmstats.h"
#include "aveStats.h"
#include "trix.h"
#include "bPlusTree.h"
#include "customFactory.h"
#include "dupTrack.h"
#include "iupac.h"
#include "clinvarSubLolly.h"
#include "jsHelper.h"
#include "errCatch.h"
#include "htslib/bgzf.h"
#include "htslib/kstring.h"
#include "pipeline.h"
#include "genark.h"
#include "chromAlias.h"
#include "dotPlot.h"
#include "quickLift.h"
#include "liftOver.h"
static char *rootDir = "hgcData";
#define LINESIZE 70 /* size of lines in comp seq feature */
#define MAX_DISPLAY_QUERY_SEQ_SIZE 5000000 // Big enough for HLA alts
struct cart *cart; /* User's settings. */
char *seqName; /* Name of sequence we're working on. */
int winStart, winEnd; /* Bounds of sequence. */
char *database; /* Name of mySQL database. */
char *organism; /* Colloquial name of organism. */
char *genome; /* common name, e.g. Mouse, Human */
char *scientificName; /* Scientific name of organism. */
/* for earlyBotCheck() function at the beginning of main() */
#define delayFraction 0.5 /* standard penalty is 1.0 for most CGIs */
/* this one is 0.5 */
boolean issueBotWarning = FALSE;
struct hash *trackHash; /* A hash of all tracks - trackDb valued */
void printLines(FILE *f, char *s, int lineSize);
char mousedb[] = "mm3";
#define NUMTRACKS 9
int prevColor[NUMTRACKS]; /* used to optimize color change html commands */
int currentColor[NUMTRACKS]; /* used to optimize color change html commands */
int maxShade = 9; /* Highest shade in a color gradient. */
Color shadesOfGray[10+1]; /* 10 shades of gray from white to black */
Color shadesOfRed[16];
boolean exprBedColorsMade = FALSE; /* Have the shades of red been made? */
int maxRGBShade = 16;
struct bed *sageExpList = NULL;
char ncbiOmimUrl[255] = {"https://www.ncbi.nlm.nih.gov/omim/"};
struct palInfo
{
char *chrom;
int left;
int right;
char *rnaName;
};
/* See this NCBI web doc for more info about entrezFormat:
* https://www.ncbi.nlm.nih.gov/entrez/query/static/linking.html */
char *entrezFormat = "https://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Search&db=%s&term=%s&doptcmdl=%s&tool=genome.ucsc.edu";
char *entrezPureSearchFormat = "https://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=PureSearch&db=%s&details_term=%s[%s] ";
char *ncbiGeneFormat = "https://www.ncbi.nlm.nih.gov/gene/%s";
char *entrezUidFormat = "https://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=%s&list_uids=%d&dopt=%s&tool=genome.ucsc.edu";
/* db=unists is not mentioned in NCBI's doc... so stick with this usage: */
char *unistsnameScript = "https://www.ncbi.nlm.nih.gov:80/entrez/query.fcgi?db=unists";
char *unistsScript = "https://www.ncbi.nlm.nih.gov/genome/sts/sts.cgi?uid=";
char *gdbScript = "http://www.gdb.org/gdb-bin/genera/accno?accessionNum=";
char *cloneDbScript = "https://www.ncbi.nlm.nih.gov/clone?term=";
char *traceScript = "https://www.ncbi.nlm.nih.gov/Traces/trace.cgi?cmd=retrieve&val=";
char *genMapDbScript = "http://genomics.med.upenn.edu/perl/genmapdb/byclonesearch.pl?clone=";
char *uniprotFormat = "http://www.uniprot.org/uniprot/%s";
char *dbSnpFormat = "https://www.ncbi.nlm.nih.gov/SNP/snp_ref.cgi?type=rs&rs=%s";
char *clinVarFormat = "https://www.ncbi.nlm.nih.gov/clinvar/?term=%s[clv_acc]";
/* variables for gv tables */
char *gvPrevCat = NULL;
char *gvPrevType = NULL;
/* initialized by getCtList() if necessary: */
struct customTrack *theCtList = NULL;
/* getDNA stuff actually works when the database doesn't exist! */
boolean dbIsFound = FALSE;
/* forwards */
char *getPredMRnaProtSeq(struct genePred *gp);
void doAltGraphXDetails(struct trackDb *tdb, char *item);
char* getEntrezNucleotideUrl(char *accession)
/* get URL for Entrez browser on a nucleotide. free resulting string */
{
char url[512];
safef(url, sizeof(url), entrezFormat, "Nucleotide", accession, "GenBank");
return cloneString(url);
}
void printNcbiGeneUrl(FILE *f, char *gene)
/* Print URL for Entrez browser on a nucleotide. */
{
fprintf(f, ncbiGeneFormat, gene);
}
void printEntrezNucleotideUrl(FILE *f, char *accession)
/* Print URL for Entrez browser on a nucleotide. */
{
fprintf(f, entrezFormat, "Nucleotide", accession, "GenBank");
}
void printEntrezEstUrl(FILE *f, char *accession)
/* Print URL for Entrez browser on a nucleotide. */
{
fprintf(f, entrezFormat, "nucest", accession, "GenBank");
}
void printEntrezProteinUrl(FILE *f, char *accession)
/* Print URL for Entrez browser on a protein. */
{
fprintf(f, entrezFormat, "Protein", accession, "GenPept");
}
static void printEntrezPubMedUrl(FILE *f, char *term)
/* Print URL for Entrez browser on a PubMed search. */
{
fprintf(f, entrezFormat, "PubMed", term, "DocSum");
}
static void printEntrezPubMedPureSearchUrl(FILE *f, char *term, char *keyword)
/* Print URL for Entrez browser on a PubMed search. */
{
fprintf(f, entrezPureSearchFormat, "PubMed", term, keyword);
}
void printEntrezPubMedUidAbstractUrl(FILE *f, int pmid)
/* Print URL for Entrez browser on a PubMed search. */
{
fprintf(f, entrezUidFormat, "PubMed", pmid, "Abstract");
}
void printEntrezPubMedUidUrl(FILE *f, int pmid)
/* Print URL for Entrez browser on a PubMed search. */
{
fprintf(f, entrezUidFormat, "PubMed", pmid, "Summary");
}
void printEntrezGeneUrl(FILE *f, int geneid)
/* Print URL for Entrez browser on a gene details page. */
{
fprintf(f, entrezUidFormat, "gene", geneid, "Graphics");
}
static void printEntrezOMIMUrl(FILE *f, int id)
/* Print URL for Entrez browser on an OMIM search. */
{
char buf[64];
snprintf(buf, sizeof(buf), "%d", id);
fprintf(f, entrezFormat, "OMIM", buf, "Detailed");
}
void printSwissProtAccUrl(FILE *f, char *accession)
/* Print URL for Swiss-Prot protein accession. */
{
fprintf(f, uniprotFormat, accession);
}
static void printSwissProtProteinUrl(FILE *f, char *accession)
/* Print URL for Swiss-Prot NiceProt on a protein. */
{
char *spAcc;
/* make sure accession number is used (not display ID) when linking to Swiss-Prot */
spAcc = uniProtFindPrimAcc(accession);
if (spAcc != NULL)
{
printSwissProtAccUrl(f, accession);
}
else
{
fprintf(f, uniprotFormat, accession);
}
}
static void printSwissProtVariationUrl(FILE *f, char *accession)
/* Print URL for Swiss-Prot variation data on a protein. */
{
if (accession != NULL)
{
fprintf(f, "\"http://www.expasy.org/cgi-bin/get-sprot-variant.pl?%s\"", accession);
}
}
static void printOmimUrl(FILE *f, char *term)
/* Print URL for OMIM data on a protein. */
{
if (term != NULL)
{
fprintf(f, "\"https://www.ncbi.nlm.nih.gov/omim/%s\"", term);
}
}
static void printEntrezUniSTSUrl(FILE *f, char *name)
/* Print URL for Entrez browser on a STS name. */
{
fprintf(f, "\"%s&term=%s\"", unistsnameScript, name);
}
static void printUnistsUrl(FILE *f, int id)
/* Print URL for UniSTS record for an id. */
{
fprintf(f, "\"%s%d\"", unistsScript, id);
}
/* Print URL for GDB browser for an id
* GDB currently inoperative, so have temporarily disabled this function
*
static void printGdbUrl(FILE *f, char *id)
{
fprintf(f, "%s", id);
}
*/
static void printCloneDbUrl(FILE *f, char *clone)
/* Print URL for Clone Registry at NCBI for a clone */
{
fprintf(f, "\"%s%s\"", cloneDbScript, clone);
}
static void printTraceTiUrl(FILE *f, char *name)
/* Print URL for Trace Archive at NCBI for a trace id (TI) */
{
fprintf(f, "\"%s%s\"", traceScript, name);
}
static void printTraceUrl(FILE *f, char *idType, char *name)
/* Print URL for Trace Archive at NCBI for an identifier specified by type */
{
fprintf(f, "\"%s%s%%3D%%27%s%%27\"", traceScript, idType, name);
}
static void printGenMapDbUrl(FILE *f, char *clone)
/* Print URL for GenMapDb at UPenn for a clone */
{
fprintf(f, "\"%s%s\"", genMapDbScript, clone);
}
static void printFlyBaseUrl(FILE *f, char *fbId)
/* Print URL for FlyBase browser. */
{
fprintf(f, "\"http://flybase.net/.bin/fbidq.html?%s\"", fbId);
}
static void printBDGPUrl(FILE *f, char *bdgpName)
/* Print URL for Berkeley Drosophila Genome Project browser. */
{
fprintf(f, "\"http://www.fruitfly.org/cgi-bin/annot/gene?%s\"", bdgpName);
}
char *hgTracksPathAndSettings()
/* Return path with hgTracks CGI path and session state variable. */
{
static struct dyString *dy = NULL;
if (dy == NULL)
{
dy = dyStringNew(128);
dyStringPrintf(dy, "%s?%s", hgTracksName(), cartSidUrlString(cart));
}
return dy->string;
}
char *hgcPathAndSettings()
/* Return path with this CGI script and session state variable. */
{
static struct dyString *dy = NULL;
if (dy == NULL)
{
dy = dyStringNew(128);
dyStringPrintf(dy, "%s?%s", hgcName(), cartSidUrlString(cart));
}
return dy->string;
}
static void hgcAnchorSomewhereExt(char *group, char *item, char *other, char *chrom, int start, int end, char *tbl)
/* Generate an anchor that calls click processing program with item
* and other parameters. */
{
char *itemSafe = cgiEncode(item);
printf("",
hgcPathAndSettings(), database, group, itemSafe, chrom, start, end, other, tbl);
freeMem(itemSafe);
}
void hgcAnchorSomewhere(char *group, char *item, char *other, char *chrom)
/* Generate an anchor that calls click processing program with item
* and other parameters. */
{
char *tbl = cgiUsualString("table", cgiString("g"));
hgcAnchorSomewhereExt(group, item, other, chrom, winStart, winEnd, tbl);
}
void hgcAnchorPosition(char *group, char *item)
/* Generate an anchor that calls click processing program with item
* and group parameters. */
{
char *tbl = cgiUsualString("table", cgiString("g"));
printf("",
hgcPathAndSettings(), database, group, item, tbl);
}
void hgcAnchorWindow(char *group, char *item, int thisWinStart,
int thisWinEnd, char *other, char *chrom)
/* Generate an anchor that calls click processing program with item
* and other parameters, INCLUDING the ability to specify left and
* right window positions different from the current window*/
{
printf("",
hgcPathAndSettings(), database, group, item, chrom,
thisWinStart, thisWinEnd, other);
}
void hgcAnchorJalview(char *item, char *fa)
/* Generate an anchor to jalview. */
{
struct dyString *dy = cgiUrlString();
printf("",
hgcName(), dy->string);
dyStringFree(&dy);
}
void hgcAnchorTranslatedChain(int item, char *other, char *chrom, int cdsStart, int cdsEnd)
/* Generate an anchor that calls click processing program with item
* and other parameters. */
{
char *tbl = cgiUsualString("table", cgiString("g"));
printf("",
hgcPathAndSettings(), database, "htcChainTransAli", item, chrom, winStart, winEnd, other,
tbl, cdsStart, cdsEnd);
}
void hgcAnchorPseudoGene(char *item, char *other, char *chrom, char *tag, int start, int end, char *qChrom, int qStart, int qEnd, int chainId, char *db2)
/* Generate an anchor to htcPseudoGene. */
{
char *encodedItem = cgiEncode(item);
printf("",
hgcPathAndSettings(), database, "htcPseudoGene", encodedItem, chrom, start, end,
other, db2, chainId, qChrom, qStart, qEnd, tag);
}
void hgcAnchorSomewhereDb(char *group, char *item, char *other,
char *chrom, char *db)
/* Generate an anchor that calls click processing program with item
* and other parameters. */
{
printf("",
hgcPathAndSettings(), group, item, chrom, winStart, winEnd, other, db);
}
void hgcAnchor(char *group, char *item, char *other)
/* Generate an anchor that calls click processing program with item
* and other parameters. */
{
hgcAnchorSomewhere(group, item, other, seqName);
}
void writeFramesetType()
/* Write document type that shows a frame set, rather than regular HTML. */
{
fputs("\n", stdout);
}
void htmlFramesetStart(char *title)
/* Write DOCTYPE HTML and HEAD sections for framesets. */
{
/* Print start of HTML. */
writeFramesetType();
puts("");
char *meta = getCspMetaHeader();
printf("\n%s%s\n\n\n", meta, title);
freeMem(meta);
}
boolean clipToChrom(int *pStart, int *pEnd)
/* Clip start/end coordinates to fit in chromosome. */
{
static int chromSize = -1;
if (chromSize < 0)
chromSize = hChromSize(database, seqName);
if (*pStart < 0) *pStart = 0;
if (*pEnd > chromSize) *pEnd = chromSize;
return *pStart < *pEnd;
}
struct genbankCds getCds(struct sqlConnection *conn, char *acc)
/* obtain and parse the CDS, errAbort if not found or invalid */
{
char query[256];
sqlSafef(query, sizeof(query), "select c.name from %s,%s c where (acc=\"%s\") and (c.id=cds)",
gbCdnaInfoTable,cdsTable, acc);
char *cdsStr = sqlQuickString(conn, query);
if (cdsStr == NULL)
errAbort("no CDS found for %s", acc);
struct genbankCds cds;
if (!genbankCdsParse(cdsStr, &cds))
errAbort("can't parse CDS for %s: %s", acc, cdsStr);
return cds;
}
void printCappedSequence(int start, int end, int extra)
/* Print DNA from start to end including extra at either end.
* Capitalize bits from start to end. */
{
struct dnaSeq *seq;
int s, e, i;
struct cfm *cfm;
if (!clipToChrom(&start, &end))
return;
s = start - extra;
e = end + extra;
clipToChrom(&s, &e);
printf("Here is the sequence around this feature: bases %d to %d of %s. "
"The bases that contain the feature itself are in upper case.
\n",
s, e, seqName);
seq = hDnaFromSeq(database, seqName, s, e, dnaLower);
toUpperN(seq->dna + (start-s), end - start);
printf("");
cfm = cfmNew(10, 50, TRUE, FALSE, stdout, s);
for (i=0; isize; ++i)
{
cfmOut(cfm, seq->dna[i], 0);
}
cfmFree(&cfm);
printf("
");
}
void printBand(char *chrom, int start, int end, boolean tableFormat)
/* Print all matching chromosome bands. */
/* Ignore end if it is zero. */
{
char sband[HDB_MAX_BAND_STRING], eband[HDB_MAX_BAND_STRING];
boolean gotS = FALSE;
boolean gotE = FALSE;
if (start < 0)
return;
gotS = hChromBand(database, chrom, start, sband);
/* if the start lookup fails, don't bother with the end lookup */
if (!gotS)
return;
/* if no end chrom, print start band and exit */
if (end == 0)
{
if (tableFormat)
printf("| Band: | %s |
\n",sband);
else
printf("Band: %s
\n", sband);
return;
}
gotE = hChromBand(database, chrom, end-1, eband);
/* if eband equals sband, just use sband */
if (gotE && sameString(sband,eband))
gotE = FALSE;
if (!gotE)
{
if (tableFormat)
printf("| Band: | %s |
\n",sband);
else
printf("Band: %s
\n", sband);
return;
}
if (tableFormat)
printf("| Bands: | %s - %s |
\n",sband, eband);
else
printf("Bands: %s - %s
\n", sband, eband);
}
void printPosOnChrom(char *chrom, int start, int end, char *strand,
boolean featDna, char *item)
/* Print position lines referenced to chromosome. Strand argument may be NULL */
{
printf("Position: "
"",
hgTracksPathAndSettings(), database, cgiEncode(chrom), start+1, end);
printf("%s:%d-%d
\n", chrom, start+1, end);
/* printBand(chrom, (start + end)/2, 0, FALSE); */
printBand(chrom, start, end, FALSE);
printf("Genomic Size: %d
\n", end - start);
if (strand != NULL && differentString(strand,".") && isNotEmpty(strand))
printf("Strand: %s
\n", strand);
else
strand = "?";
if (featDna && end > start)
{
char *tbl = cgiUsualString("table", cgiString("g"));
strand = cgiEncode(strand);
printf(""
"View DNA for this feature (%s/%s)
\n", hgcPathAndSettings(),
database, start, (item != NULL ? cgiEncode(item) : ""),
cgiEncode(chrom), start, end, strand, tbl, trackHubSkipHubName(database), trackHubSkipHubName(hGenome(database)));
}
}
void printPosOnScaffold(char *chrom, int start, int end, char *strand)
/* Print position lines referenced to scaffold. 'strand' argument may be null. */
{
char *scaffoldName;
int scaffoldStart, scaffoldEnd;
if (!hScaffoldPos(database, chrom, start, end, &scaffoldName, &scaffoldStart, &scaffoldEnd))
{
printPosOnChrom(chrom, start,end,strand, FALSE, NULL);
return;
}
printf("Scaffold: %s
\n", scaffoldName);
printf("Begin in Scaffold: %d
\n", scaffoldStart+1);
printf("End in Scaffold: %d
\n", scaffoldEnd);
printf("Genomic Size: %d
\n", scaffoldEnd - scaffoldStart);
if (strand != NULL)
printf("Strand: %s
\n", strand);
else
strand = "?";
}
void printPos(char *chrom, int start, int end, char *strand, boolean featDna,
char *item)
/* Print position lines. 'strand' argument may be null. */
{
if (sameWord(organism, "Fugu"))
/* Fugu is the only chrUn-based scaffold assembly, so it
* has non-general code here. Later scaffold assemblies
* treat scaffolds as chroms.*/
printPosOnScaffold(chrom, start, end, strand);
else
printPosOnChrom(chrom, start, end, strand, featDna, item);
}
void samplePrintPos(struct sample *smp, int smpSize)
/* Print first three fields of a sample 9 type structure in
* standard format. */
{
if ( smpSize != 9 )
errAbort("Invalid sample entry!\n It has %d fields instead of 9\n",
smpSize);
printf("Item: %s
\n", smp->name);
printf("Score: %d
\n", smp->score);
printf("Strand: %s
\n", smp->strand);
printPos(smp->chrom, smp->chromStart, smp->chromEnd, NULL, TRUE, smp->name);
}
// Many callers pass a track-specific struct cast to (struct bed *), relying on
// its bed-compatible leading fields (only the first bedSize fields are read).
// At -O3 GCC's -Warray-bounds flags those casts because the real object is
// smaller than struct bed; the accesses are safe by the bed-layout convention.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
void bedPrintPos(struct bed *bed, int bedSize, struct trackDb *tdb)
/* Print first bedSize fields of a bed type structure in
* standard format. */
{
char *strand = NULL;
if (bedSize >= 4 && bed->name[0] != 0)
{
char *label = "Item", *tdbLabel = NULL;
if (tdb && ((tdbLabel = trackDbSetting(tdb, "bedNameLabel")) != NULL))
label = tdbLabel;
printf("%s: %s
\n", label, bed->name);
}
if (bedSize >= 5)
{
if (!tdb || !trackDbSetting(tdb, "noScoreFilter"))
{
char *scoreLabel = trackDbSettingOrDefault(tdb, "scoreLabel", "Score");
printf("%s: %d
\n", scoreLabel, bed->score);
}
}
if (bedSize >= 6)
{
strand = bed->strand;
}
printPos(bed->chrom, bed->chromStart, bed->chromEnd, strand, TRUE, bed->name);
}
#pragma GCC diagnostic pop
void genericHeader(struct trackDb *tdb, char *item)
/* Put up generic track info. */
{
if (item != NULL && item[0] != 0)
cartWebStart(cart, database, "%s: %s (%s)", genome, tdb->longLabel, item);
else
cartWebStart(cart, database, "%s: %s", genome, tdb->longLabel);
// QA noticed that clicking the +- buttons to collapse item detail tables was
// generating messages in the Apache log if you went directly to an item page
// without first visiting hgTracks. Clicking those buttons causes a cartDump
// in order to save the state of visibility of the table, which in
// turn needs an hgsid in order to save the state correctly. However, because
// we aren't in a form, we have never saved the hgsid to a hidden
// input element, and so the javascript that creates the cartDump link attaches
// an empty 'hgsid=' parameter, which cartDump doesn't like. Since we aren't in
// a form, use the 'common' object to store the parameter so the links to cartDump
// are correct:
jsInlineF("var common = {hgsid:\"%s\"};\n", cartSessionId(cart));
}
void printItemDetailsHtml(struct trackDb *tdb, char *itemName)
/* if track has an itemDetailsHtml, retrieve and print the HTML */
{
char *tableName = trackDbSetting(tdb, "itemDetailsHtmlTable");
if (tableName != NULL)
{
struct sqlConnection *conn = hAllocConn(database);
struct itemDetailsHtml *html, *htmls;
// if the details table has chrom/start/end columns, then use these to lookup html
if (sqlColumnExists(conn, tableName, "chrom"))
{
char *chrom = cgiString("c");
int start = cgiInt("o");
int end = cgiInt("t");
htmls = sqlQueryObjs(conn, (sqlLoadFunc)itemDetailsHtmlLoad, sqlQueryMulti,
"select name, html from %s where \
name = '%s' and \
chrom = '%s' and \
start = '%d' and \
end = '%d'", tableName, itemName, chrom, start, end);
}
// otherwise, assume that the itemName is unique
else
htmls = sqlQueryObjs(conn, (sqlLoadFunc)itemDetailsHtmlLoad, sqlQueryMulti,
"select name, html from %s where name = '%s'", tableName, itemName);
for (html = htmls; html != NULL; html = html->next)
printf("
\n%s\n", html->html);
itemDetailsHtmlFreeList(&htmls);
hFreeConn(&conn);
}
}
char *getIdInUrl(struct trackDb *tdb, char *itemName)
/* If we have an idInUrlSql tag, look up itemName in that, else just
* return itemName. */
{
char *sql = trackDbSetting(tdb, "idInUrlSql");
char *id = itemName;
if (sql != NULL)
{
char query[1024];
sqlSafef(query, sizeof(query), sql, itemName);
struct sqlConnection *conn = hAllocConn(database);
id = sqlQuickString(conn, query);
hFreeConn(&conn);
}
return id;
}
char *getUrlSetting(struct trackDb *tdb, char* urlSetting)
/* get the "url" setting for the current track */
{
char *url;
if (sameWord(urlSetting, "url"))
url = tdb->url;
else
url = trackDbSetting(tdb, urlSetting);
return url;
}
void printIframe(struct trackDb *tdb, char *itemName)
/* print an iframe with the URL specified in trackDb (iframeUrl), can have
* the standard codes in it (like $$ for itemName, etc)
*/
{
char *url = getUrlSetting(tdb, "iframeUrl");
if (url==NULL)
return;
char *eUrl = replaceInUrl(url, itemName, cart, database, seqName, winStart, winEnd,
tdb->track, FALSE, NULL);
if (eUrl==NULL)
return;
char *iframeOptions = trackDbSettingOrDefault(tdb, "iframeOptions", "width='100%%' height='1024'");
// Resizing requires the hgcDetails pages to include a bit of javascript.
//
// Explanation how this works and why the javascript is needed:
// http://stackoverflow.com/questions/153152/resizing-an-iframe-based-on-content
// In short:
// - iframes have a fixed size in html, resizing can only be done in javascript
// - the iframed page cannot call the resize() function in the hgc html directly, as they have
// been loaded from different webservers
// - one way around it is that the iframed page includes a helper page on our server and
// send their size to the helper page (pages can call functions of included pages)
// - the helper page then sends the size back to hgc (pages on the same server can
// call each others' functions)
// width='%s' height='%s' src='%s' seamless scrolling='%s' frameborder='%s'
printf(" \
\
\
\
", eUrl, iframeOptions);
}
void printCustomUrlWithLabel(struct trackDb *tdb, char *itemName, char *itemLabel,
char *urlSetting, boolean encode, struct slPair *fields)
/* Print custom URL specified in trackDb settings. */
{
char urlLabelSetting[32];
// replace the $$ and other wildchards with the url given in tdb
char *url = getUrlSetting(tdb, urlSetting);
//char* eUrl = constructUrl(tdb, url, itemName, encode);
if (url==NULL || isEmpty(url))
return;
char *eUrl = replaceInUrl(url, itemName, cart, database, seqName, winStart, winEnd, tdb->track,
encode, fields);
if (eUrl==NULL)
return;
/* create the url label setting for trackDb from the url
setting prefix */
safef(urlLabelSetting, sizeof(urlLabelSetting), "%sLabel", urlSetting);
char *linkLabel = trackDbSettingOrDefault(tdb, urlLabelSetting, "Outside Link:");
char *eLinkLabel = replaceInUrl(linkLabel, itemName, cart, database, seqName, winStart, winEnd, tdb->track,
encode, fields);
// if we got no item name from hgTracks or the item name does not appear in the URL
// there is no need to show the item name at all
if (isEmpty(itemName) || !stringIn("$$", url))
{
printf("%s
",eUrl, eLinkLabel);
return;
}
printf("%s ",eLinkLabel);
printf("", eUrl);
if (sameWord(tdb->table, "npredGene"))
{
printf("%s (%s)
\n", itemName, "NCBI MapView");
}
else
{
char *label = itemName;
if (isNotEmpty(itemLabel) && differentString(itemName, itemLabel))
label = itemLabel;
printf("%s
\n", label);
}
//freeMem(&eUrl); small memory leak
}
void printCustomUrlWithFields(struct trackDb *tdb, char *itemName, char *itemLabel, boolean encode, struct slPair *fields)
/* Wrapper to call printCustomUrlWithLabel with additional fields to substitute */
{
char urlSetting[10];
safef(urlSetting, sizeof(urlSetting), "url");
printCustomUrlWithLabel(tdb, itemName, itemLabel, urlSetting, encode, fields);
}
void printCustomUrl(struct trackDb *tdb, char *itemName, boolean encode)
/* Wrapper to call printCustomUrlWithLabel using the url setting in trackDb */
{
printCustomUrlWithFields(tdb, itemName, itemName, encode, NULL);
}
void printOtherCustomUrlWithFields(struct trackDb *tdb, char *itemName, char *urlSetting,
boolean encode, struct slPair *fields)
/* Wrapper to call printCustomUrlWithLabel to use another url setting other than url in trackDb e.g. url2, this allows the use of multiple urls for a track
to be set in trackDb. */
{
printCustomUrlWithLabel(tdb, itemName, itemName, urlSetting, encode, fields);
}
void printOtherCustomUrl(struct trackDb *tdb, char *itemName, char* urlSetting, boolean encode)
/* Wrapper to call printCustomUrlWithLabel to use another url setting other than url in trackDb e.g. url2, this allows the use of multiple urls for a track
to be set in trackDb. */
{
printCustomUrlWithLabel(tdb, itemName, itemName, urlSetting, encode, NULL);
}
void genericSampleClick(struct sqlConnection *conn, struct trackDb *tdb,
char *item, int start, int smpSize)
/* Handle click in generic sample (wiggle) track. */
{
char table[HDB_MAX_TABLE_STRING];
boolean hasBin;
struct sample *smp;
char query[512];
struct sqlResult *sr;
char **row;
boolean firstTime = TRUE;
if (!hFindSplitTable(database, seqName, tdb->table, table, sizeof table, &hasBin))
errAbort("genericSampleClick track %s not found", tdb->table);
sqlSafef(query, sizeof query, "select * from %s where name = '%s' and chrom = '%s' and chromStart = %d",
table, item, seqName, start);
/*errAbort( "select * from %s where name = '%s' and chrom = '%s' and chromStart = %d",
table, item, seqName, start);*/
sr = sqlGetResult(conn, query);
while ((row = sqlNextRow(sr)) != NULL)
{
if (firstTime)
firstTime = FALSE;
else
htmlHorizontalLine();
smp = sampleLoad(row+hasBin);
samplePrintPos(smp, smpSize);
}
}
void showBedTopScorers(struct bed *bedList, char *item, int start, int max)
/* Show a list of track items sorted by descending score,
* with current item highlighted.
* max is upper bound on how many items will be displayed. */
{
int i;
struct bed *bed;
puts("Top-scoring elements in window:
");
for (i=0, bed=bedList; bed != NULL && i < max; bed=bed->next, i++)
{
if (sameWord(item, bed->name) && bed->chromStart == start)
printf(" %s ", bed->name);
else
printf(" %s ", bed->name);
printf("(%s:%d-%d) %d
\n",
bed->chrom, bed->chromStart+1, bed->chromEnd, bed->score);
}
if (bed != NULL)
printf("(list truncated -- more than %d elements)
\n", max);
}
void showBedTopScorersInWindow(struct sqlConnection *conn,
struct trackDb *tdb, char *item, int start,
int maxScorers, char *filterTable, int filterCt)
/* Show a list of track items in the current browser window, ordered by
* score. Track must be BED 5 or greater. maxScorers is upper bound on
* how many items will be displayed. If filterTable is not NULL and exists,
* it contains the 100K top-scorers in the entire track, and filterCt
* is the threshold for how many are candidates for display. */
{
struct sqlResult *sr = NULL;
char **row = NULL;
struct bed *bedList = NULL, *bed = NULL;
char table[HDB_MAX_TABLE_STRING];
boolean hasBin = FALSE;
char query[512];
if (filterTable)
{
/* Track display only shows top-scoring N elements -- restrict
* the list to these. Get them from the filter table */
hasBin = hOffsetPastBin(database, hDefaultChrom(database), filterTable);
sqlSafef(query, sizeof(query), "select * from %s order by score desc limit %d",
filterTable, filterCt);
}
else
{
if (!hFindSplitTable(database, seqName, tdb->table, table, sizeof table, &hasBin))
errAbort("showBedTopScorersInWindow track %s not found", tdb->table);
sqlSafef(query, sizeof(query),
"select * from %s where chrom = '%s' and chromEnd > %d and "
"chromStart < %d order by score desc",
table, seqName, winStart, winEnd);
}
sr = sqlGetResult(conn, query);
while ((row = sqlNextRow(sr)) != NULL)
{
bed = bedLoadN(row+hasBin, 5);
if (!filterTable
|| ( sameString(bed->chrom, seqName)
&& bed->chromStart < winEnd
&& bed->chromEnd > winStart))
{
slAddHead(&bedList, bed);
}
else
bedFree(&bed);
}
sqlFreeResult(&sr);
if (bedList == NULL)
return;
slReverse(&bedList);
showBedTopScorers(bedList, item, start, maxScorers);
}
void getBedTopScorers(struct sqlConnection *conn, struct trackDb *tdb,
char *table, char *item, int start, int bedSize)
/* This function determines if showTopScorers is set in trackDb and also */
/* if the filterTopScorers setting is on. Then it passes the relevant */
/* settings to showBedTopScorersInWindow() so that the top N scoring */
/* items in the window are listed on the details page */
{
char *showTopScorers = trackDbSetting(tdb, "showTopScorers");
char *filterTopScorers = trackDbSetting(tdb,"filterTopScorers");
boolean doFilterTopScorers = FALSE;
char *words[3];
char cartVar[512];
int filterTopScoreCt = 0;
char *filterTopScoreTable = NULL;
safef(cartVar, sizeof cartVar, "%s.%s", table, "filterTopScorersOn");
if (filterTopScorers != NULL)
{
if (chopLine(cloneString(filterTopScorers), words) == 3)
{
doFilterTopScorers = sameString(words[0], "on");
filterTopScoreCt = atoi(words[1]);
filterTopScoreTable = words[2];
}
}
if (bedSize >= 5 && showTopScorers != NULL)
{
/* list top-scoring elements in window */
int maxScorers = sqlUnsigned(showTopScorers);
doFilterTopScorers = cartCgiUsualBoolean(cart, cartVar, doFilterTopScorers);
if (doFilterTopScorers && hTableExists(database, filterTopScoreTable))
{
/* limit to those in the top N, from table */
safef(cartVar, sizeof cartVar, "%s.%s", table, "filterTopScorersCt");
filterTopScoreCt = cartCgiUsualInt(cart, cartVar, filterTopScoreCt);
}
else
/* show all */
filterTopScoreTable = NULL;
showBedTopScorersInWindow(conn, tdb, item, start, maxScorers,
filterTopScoreTable, filterTopScoreCt);
}
}
void linkToOtherBrowser(char *otherDb, char *chrom, int start, int end);
void linkToOtherBrowserExtra(char *otherDb, char *chrom, int start, int end, char *extra);
static void printCompareGenomeLinks(struct trackDb *tdb,char *name)
/* if "compareGenomeLinks" exists then a table of the same name in n different databases is sought.
if a row exist in the other db table matching the current item, then a link is printed */
{
char *setting = trackDbSettingClosestToHome(tdb,"compareGenomeLinks");
if (setting == NULL)
return;
struct sqlConnection *conn = hAllocConn(database); // Need only to connect to one db
if (conn == NULL)
return;
char *words[20];
setting = cloneString(setting);
int ix,cnt = chopLine(setting, words);
char query[512];
char extra[128];
boolean gotOne = FALSE;
for (ix=0;ixtable;
else
{
*table++ = '\0'; // assigns before advance
if ((words[ix] = strchr(table,'.')) != NULL)
{
*words[ix] = '\0';
column = ++words[ix]; // advance before assigns
}
}
sqlSafef(query,sizeof(query),"select chrom,chromStart,chromEnd from %s.%s where %s=\"%s\";",
db,table,column,name);
struct sqlResult *sr = sqlGetResult(conn, query);
if (sr == NULL)
continue;
char **row = sqlNextRow(sr);
if (row == NULL)
continue;
char *chrom = *row++;
int beg = atoi(*row++);
int end = atoi(*row);
if (!gotOne)
{
gotOne = TRUE;
printf("The item \"%s\" has been located in other genomes:\n
\n",name);
}
printf("- ");
safef(extra,sizeof(extra),"%s=full",tdb->track);
linkToOtherBrowserExtra(db, chrom, beg, end, extra);
printf("%s
\n",strSwapChar(title,'_',' '));
sqlFreeResult(&sr);
}
hFreeConn(&conn);
freeMem(setting);
if (gotOne)
printf("
\n");
else
printf("Currently the item \"%s\" has not been located in another genome.\n",name);
}
void mafPrettyOut(FILE *f, struct mafAli *maf, int lineSize,
boolean onlyDiff, int blockNo, struct hash *hash);
void doAtom( struct trackDb *tdb, char *item)
{
char table[HDB_MAX_TABLE_STRING];
boolean hasBin;
//struct bed *bed;
char query[512];
struct sqlResult *sr;
char **row;
//boolean firstTime = TRUE;
int start = cartInt(cart, "o");
//struct sqlConnection *conn = hAllocConn(database);
char *user = cfgOption("db.user");
char *password = cfgOption("db.password");
struct sqlConnection *sc;
struct atom ret;
genericHeader(tdb, item);
if (!hFindSplitTable(database, seqName, tdb->table, table, sizeof table, &hasBin))
errAbort("mafPrettyOut track %s not found", tdb->table);
#if 0
sqlSafef(query, sizeof query, "select * from %s where name = '%s' and chrom = '%s' and chromStart = %d", table, escapedName, seqName, start);
sr = sqlGetResult(conn, query);
printf("This is the item you clicked on:
\n");
while ((row = sqlNextRow(sr)) != NULL)
{
if (firstTime)
firstTime = FALSE;
else
htmlHorizontalLine();
bed = bedLoadN(row+hasBin, 4);
bedPrintPos(bed, 4, tdb);
}
sqlFreeResult(&sr);
sqlSafef(query, sizeof query, "select * from %s where name = '%s'", table, escapedName);
sr = sqlGetResult(conn, query);
while ((row = sqlNextRow(sr)) != NULL)
{
bed = bedLoadN(row+hasBin, 4);
if (bed->chromStart != start)
{
htmlHorizontalLine();
firstTime = FALSE;
printf("Another instances on %s:
\n",database);
bedPrintPos(bed, 4, tdb);
}
}
sqlFreeResult(&sr);
#endif
sc = sqlConnectRemote("localhost", user, password, "hgFixed");
sqlSafef(query, sizeof(query),
"select * from %s where name = '%s'", table, item);
sr = sqlGetResult(sc, query);
printf("Atom %s instances ('*' marks item you clicked on)
\n",item);
printf("
\n");
//printf("Ins#\tSpecies\t\tChrom\tStart\tEnd\tStrand\n");
printf( " # %-10s %-5s %12s %12s %10s %s %-10s %-10s\n",
"species","chrom", "start", "end", "length", "strand","fivePrime","threePrime");
while ((row = sqlNextRow(sr)) != NULL)
{
atomStaticLoad(row, &ret);
//atomOutput(&ret, stdout, '\t', '\n');
linkToOtherBrowser(ret.species, ret.chrom, ret.start, ret.end);
if (sameString(ret.chrom, seqName) && (start == ret.start) &&
sameString(ret.species, database))
printf("* ");
else
printf(" ");
printf( "%4d %-10s %-5s %12d %12d %10d %c %-10s %-10s\n",
ret.instance, ret.species,ret.chrom, ret.start + 1, ret.end,
ret.end - ret.start + 1, ret.strand[0],ret.fivePrime,ret.threePrime);
}
printf("");
sqlFreeResult(&sr);
if (!sameString("atom20080226d", table))
return;
printf("");
printf("");
printf("");
printf("");
printf("Suh Trees \n");
printf(" ",item);
printf(" |  ",item);
printf(" |
|---|
");
printf("NJ Trees \n");
printf(" ",item);
printf(" |  ",item);
printf(" |
|---|
");
/*
printf("Gap UPGMA Trees \n");
printf(" ",item);
printf(" |  ",item);
printf(" |
|---|
");
*/
return;
char buffer[4096];
struct mafFile *mf;
safef(buffer, sizeof buffer, "/gbdb/hgFixed/%s/%s.maf",table, item);
mf = mafMayOpen(buffer);
if (mf != NULL)
{
mafFileFree(&mf);
mf = mafReadAll(buffer);
struct mafAli *mafAli;
int count = 1;
int numBlocks = 0;
for (mafAli=mf->alignments; mafAli; mafAli = mafAli->next)
numBlocks++;
for (mafAli=mf->alignments; mafAli; mafAli = mafAli->next)
{
printf("
Multiple Alignment Block %d of %d
",
count, numBlocks);
mafPrettyOut(stdout, mafAli, 70, FALSE, count++, NULL);
if (mafAli->next != NULL)
{
struct mafAli *next = mafAli->next;
struct mafComp *comp1 = mafAli->components;
struct mafComp *comp2 = next->components;
printf("
Gaps:\n");
for(; comp1 ; comp1 = comp1->next, comp2 = comp2->next)
{
int diff;
char dbOnly[4096];
diff = comp2->start - (comp1->start + comp1->size);
safef(dbOnly, sizeof(dbOnly), "%s", comp1->src);
chopPrefix(dbOnly);
printf("%-20s %d\n",hOrganism(dbOnly), diff);
}
printf("
");
}
}
}
}
char **getIdNameMap(struct trackDb *tdb, struct asColumn *col, int *size)
/* Allocate and fill an array mapping id to name. Currently limited to specific columns. */
{
char *idNameTable = trackDbSetting(tdb, "sourceTable");
if (!idNameTable || differentString("sourceIds", col->name))
return NULL;
struct sqlResult *sr;
char query[256];
char **row;
char **idNames;
sqlSafef(query, sizeof(query), "select max(id) from %s", idNameTable);
struct sqlConnection *conn = hAllocConnTrack(database, tdb);
int maxId = sqlQuickNum(conn, query);
AllocArray(idNames, maxId+1);
sqlSafef(query, sizeof(query), "select id, name from %s", idNameTable);
sr = sqlGetResult(conn, query);
int id;
while ((row = sqlNextRow(sr)) != NULL)
{
id = sqlUnsigned(row[0]);
if (id > maxId)
errAbort("Internal error: id %d > maxId %d in %s", id, maxId, idNameTable);
idNames[id] = cloneString(row[1]);
}
sqlFreeResult(&sr);
hFreeConn(&conn);
if (size)
*size = maxId+1;
return idNames;
}
void printIdOrLinks(struct asColumn *col, struct hash *fieldToUrl, struct trackDb *tdb, char *idList)
/* if trackDb does not contain a "urls" entry for current column name, just print idList as it is.
* Otherwise treat idList as a comma-sep list of IDs and print one row per id, with a link to url,
* ($$ in url is OK, wildcards like $P, $p, are also OK)
* */
{
// try to find a fieldName=url setting in the "urls" tdb statement, print id if not found
char *url = NULL;
if (fieldToUrl != NULL)
url = (char*)hashFindVal(fieldToUrl, col->name);
if (url == NULL)
{
printf("\n", idList);
return;
}
// split the id into parts and print each part as a link
struct slName *slIds = slNameListFromComma(idList);
struct slName *itemId = NULL;
// handle id->name mapping for multi-source items
int nameCount;
char **idNames = getIdNameMap(tdb, col, &nameCount);
printf("");
for (itemId = slIds; itemId!=NULL; itemId = itemId->next)
{
if (itemId != slIds)
printf(", ");
char *itemName = trimSpaces(itemId->name);
if (idNames)
{
unsigned int id = sqlUnsigned(itemName);
if (id < nameCount)
itemName = idNames[sqlUnsigned(itemName)];
}
// a | character can optionally be used to separate the ID used for $$ from the name shown in the link (like in Wikimedia markup)
char *idForUrl = itemName;
boolean encode = TRUE;
if (strstr(itemName, "|"))
{
char *parts[2];
chopString(itemName, "|", parts, ArraySize(parts));
idForUrl = parts[0];
itemName = parts[1];
encode = FALSE; // assume the link is already encoded
}
if (startsWith("http", itemName)) // the ID may be a full URL already, encoding would destroy it
encode = FALSE;
char *idUrl = replaceInUrl(url, idForUrl, cart, database, seqName, winStart,
winEnd, tdb->track, encode, NULL);
printf("%s", idUrl, itemName);
}
printf(" | \n");
freeMem(slIds);
//freeMem(idNames);
}
char *readOneLineMaybeBgzip(char *fileOrUrl, bits64 offset, bits64 len)
/* If fileOrUrl is bgzip-compressed and indexed, then use htslib's bgzf functions to
* retrieve uncompressed data from offset; otherwise (plain text) use udc. If len is 0,
* read up to next '\n' delimiter. */
{
char *line = needMem(len+1);
if (endsWith(fileOrUrl, ".gz"))
{
BGZF *fp = bgzf_open(fileOrUrl, "r");
kstring_t str = { 0, 0, NULL };
if (bgzf_index_load(fp, fileOrUrl, ".gzi") < 0)
errAbort("bgzf_index_load failed to load .gzi index for %s", fileOrUrl);
if (bgzf_useek(fp, offset, SEEK_SET) < 0)
errAbort("bgzf_useek failed to seek to uncompressed offset %lld in %s", offset, fileOrUrl);
// bgzf_getline is faster than bgzf_read(), so we only use the len param for error checking
bits64 count = bgzf_getline(fp, '\n', &str);
if (count == 0)
errAbort("bgzf_getline unexpected end of file while parsing '%s'", fileOrUrl);
else if (count < 0)
errAbort("bgzf_getline unexpected error while parsing '%s'", fileOrUrl);
else if (len > 0 && count != len)
errAbort("bgzf_getline failed to read %lld bytes at uncompressed offset %lld in %s, got %lld",
len, offset, fileOrUrl, count);
line = ks_release(&str);
bgzf_close(fp);
}
else
{
struct udcFile *udcF = udcFileOpen(fileOrUrl, NULL);
udcSeek(udcF, offset);
line = udcReadLine(udcF);
if (line == NULL)
errAbort("error reading line from '%s'", fileOrUrl);
udcFileClose(&udcF);
}
return line;
}
int extraFieldsStart(struct trackDb *tdb, int fieldCount, struct asObject *as)
/* return the index of the first extra field */
{
int start = 0;
char *type = cloneString(tdb->type);
if (sameString(type, "bedMethyl"))
return 9;
char *word = nextWord(&type);
if (word && (sameWord(word,"bed") || startsWith("big", word)))
{
if (NULL != (word = nextWord(&type)))
start = sqlUnsigned(word);
else // custom beds and bigBeds may not have full type "begBed 9 +"
start = max(0,slCount(as->columnList) - fieldCount);
}
return start;
}
struct slPair *getExtraFields(struct trackDb *tdb, char **fields, int fieldCount)
/* return the extra field names and their values as a list of slPairs. */
{
struct asObject *as = asForDb(tdb, database);
if (as == NULL)
return NULL;
struct asColumn *col = as->columnList;
int start = extraFieldsStart(tdb, fieldCount, as);
// skip past known fields
for (;start !=0 && col != NULL;col=col->next)
if (start > 0)
start--;
struct slPair *extraFields = 0;
int count = 0;
for (;col != NULL && count < fieldCount;col=col->next)
{
struct slPair *slp;
AllocVar(slp);
char *fieldName = col->name;
char *fieldVal = fields[count];
slp->name = fieldName;
slp->val = fieldVal;
slAddHead(&extraFields, slp);
count++;
//printf("name %s, val %s, idx %d
", fieldName, fieldVal, count);
}
slReverse(extraFields);
return extraFields;
}
struct slPair *getFields(struct trackDb *tdb, char **row)
/* return field names and their values as a list of slPairs. */
// TODO: refactor with getExtraFields
{
struct asObject *as = asForDb(tdb, database);
if (as == NULL)
return NULL;
int fieldCount = slCount(as->columnList);
struct slPair *fields = NULL;
struct asColumn *col = as->columnList;
int count = 0;
for (count = 0; col != NULL && count < fieldCount; col = col->next)
{
struct slPair *field;
AllocVar(field);
char *fieldName = col->name;
char *fieldVal = row[count];
field->name = fieldName;
field->val = fieldVal;
slAddHead(&fields, field);
count++;
}
slReverse(fields);
return fields;
}
void printEmbeddedTable(struct trackDb *tdb, struct embeddedTbl *thisTbl, struct dyString *dy)
// Pretty print a '|' and ';' encoded table or a JSON encoded table from a bigBed field
{
jsIncludeFile("hgc.js", NULL);
if (isNotEmpty(thisTbl->encodedTbl))
{
if (startsWith("_json", thisTbl->field) || startsWith("json", thisTbl->field))
{
struct jsonElement *jsElem = NULL;
struct errCatch *errCatch = errCatchNew();
if (errCatchStart(errCatch))
jsElem = jsonParse(thisTbl->encodedTbl);
errCatchEnd(errCatch);
if (errCatch->gotError)
warn("ERROR: JSON field '%s' for track '%s' is malformed: %s", thisTbl->field, tdb->track, errCatch->message->string);
else if (errCatch->gotWarning)
warn("Warning: %s", errCatch->message->string);
errCatchFree(&errCatch);
if (jsElem != NULL)
{
char *labelStr = thisTbl->title != NULL ?
jsonStringEscape(thisTbl->title) :
jsonStringEscape(thisTbl->field);
dyStringPrintf(dy, "{label: \"%s\", data: %s},", labelStr, thisTbl->encodedTbl);
}
}
else
{
printf("| %s | ", htmlEncode(thisTbl->title));
printf("\n");
printf("| ");
char table[4096];
safef(table, sizeof(table), "%s", thisTbl->encodedTbl);
int swapped = strSwapStrs(table, 4096, ";", " | | ");
if (swapped == -1)
errAbort("Error substituting ';' for ' | ' in hgc.c:printEmbeddedTable()");
swapped = strSwapStrs(table, 4096, "|", "| ");
if (swapped == -1)
errAbort("Error substituting '|' for ' | ' in hgc.c:printEmbeddedTable()");
printf("%s | \n", table);
printf(" \n");
printf(" |
\n");
}
}
}
void printExtraDetailsTable(char *trackName, char *tableName, char *fileName, struct dyString *tableText)
// convert a tab-sep table to HTML
{
struct lineFile *lf = lineFileOnString(fileName, TRUE, tableText->string);
char *description = tableName != NULL ? tableName : "Additional Details";
printf("%s
\n", description);
printf("\n"); // closes bedExtraTbl
}
static struct slName *findFieldsInExtraFile(char *detailsTableUrl, struct asColumn *col, struct dyString *ds)
// return a list of the ${}-enclosed fields from an extra file
{
struct slName *foundFields = NULL;
char *table = udcFileReadAllIfExists(hReplaceGbdb(detailsTableUrl), NULL, 0, NULL);
if (table)
{
for (; col != NULL; col = col->next)
{
char field[256];
safef(field, sizeof(field), "${%s}", col->name);
if (stringIn(field, table))
{
struct slName *replaceField = slNameNew(col->name);
slAddHead(&foundFields, replaceField);
}
}
dyStringPrintf(ds, "%s", table);
if (foundFields)
slReverse(foundFields);
}
return foundFields;
}
#define TDB_DYNAMICTABLE_SETTING "detailsDynamicTable"
#define TDB_DYNAMICTABLE_SETTING_2 "extraTableFields"
void getExtraTableFields(struct trackDb *tdb, struct slName **retFieldNames, struct embeddedTbl **retList, struct hash *embeddedTblHash)
/* Parse the trackDb field TDB_DYNAMICTABLE_FIELD into the field names and titles specified,
* and fill out a hash keyed on the bigBed field name (which may be in an external file
* and not in the bigBed itself) to a helper struct for storing user defined tables. */
{
struct slName *tmp, *embeddedTblSetting = slNameListFromComma(trackDbSetting(tdb, TDB_DYNAMICTABLE_SETTING));
struct slName *embeddedTblSetting2 = slNameListFromComma(trackDbSetting(tdb, TDB_DYNAMICTABLE_SETTING_2));
char *title = NULL, *fieldName = NULL;
for (tmp = embeddedTblSetting; tmp != NULL; tmp = tmp->next)
{
title = NULL;
fieldName = cloneString(tmp->name);
if (strchr(tmp->name, '|'))
{
title = strchr(fieldName, '|');
*title++ = 0;
}
struct embeddedTbl *new;
AllocVar(new);
new->field = fieldName;
new->title = title != NULL ? cloneString(title) : fieldName;
slAddHead(retList, new);
slNameAddHead(retFieldNames, fieldName);
hashAdd(embeddedTblHash, fieldName, new);
}
for (tmp = embeddedTblSetting2; tmp != NULL; tmp = tmp->next)
{
title = NULL;
fieldName = cloneString(tmp->name);
if (strchr(tmp->name, '|'))
{
title = strchr(fieldName, '|');
*title++ = 0;
}
struct embeddedTbl *new;
AllocVar(new);
new->field = fieldName;
new->title = title != NULL ? cloneString(title) : fieldName;
slAddHead(retList, new);
slNameAddHead(retFieldNames, fieldName);
hashAdd(embeddedTblHash, fieldName, new);
}
}
static void printFieldLabelInner(char *entry, char *fieldName)
/* print the field label, the first column in the table, as a . Allow a
* longer description after a |-char, as some fields are not easy to
* understand. If fieldName is not NULL, add id="bfld_" to . */
{
char *afterPipe = strchr(entry, '|');
if (afterPipe)
*afterPipe = 0;
if (fieldName)
printf(" | %s", fieldName, entry);
else
printf(" | %s", entry);
if (afterPipe)
{
// Could also have a "?" icon and show the description on mouse over
afterPipe++; // skip past | character
printf("
| ");
}
void printFieldLabel(char *entry)
/* print the field label, the first column in the table, as a . Allow a
* longer description after a |-char, as some fields are not easy to
* understand. */
{
printFieldLabelInner(entry, NULL);
}
void printFieldLabelWithId(char *entry, char *fieldName)
/* Like printFieldLabel but adds id="bfld_" to the element,
* so JavaScript can find the row by field name. */
{
printFieldLabelInner(entry, fieldName);
}
static struct slName *detailsScriptFieldNames(struct trackDb *tdb)
/* Return list of bigBed field names used by detailsScript.* trackDb settings.
* These fields are rendered by JavaScript, so their values should not be printed in the HTML table.
* See also bigBedClick.c which parses the same settings to build JSON and load JS modules. */
{
struct slName *dsSettings = trackDbLocalSettingsWildMatch(tdb, DETAILS_SCRIPT_PREFIX);
struct slName *fieldNames = NULL;
struct slName *setting;
for (setting = dsSettings; setting != NULL; setting = setting->next)
{
char *dot1 = strchr(setting->name, '.');
if (dot1)
{
char *dot2 = strchr(dot1 + 1, '.');
if (dot2)
slNameAddHead(&fieldNames, dot2 + 1);
}
}
slFreeList(&dsSettings);
return fieldNames;
}
#define TDB_STATICTABLE_SETTING "extraDetailsTable"
#define TDB_STATICTABLE_SETTING_2 "detailsStaticTable"
int extraFieldsPrintAs(struct trackDb *tdb,struct sqlResult *sr,char **fields,int fieldCount, struct asObject *as)
// Any extra bed or bigBed fields (defined in as and occurring after N in bed N + types.
// sr may be null for bigBeds.
// Returns number of extra fields actually printed.
{
// We are trying to print extra fields so we need to figure out how many fields to skip
int start = extraFieldsStart(tdb, fieldCount, as);
struct asColumn *col = as->columnList;
char *urlsStr = trackDbSettingClosestToHomeOrDefault(tdb, "urls", NULL);
struct hash* fieldToUrl = hashFromString(urlsStr);
boolean skipEmptyFields = trackDbSettingOn(tdb, "skipEmptyFields");
// make list of fields to skip
char *skipFieldsStr = trackDbSetting(tdb, "skipFields");
struct slName *skipIds = NULL;
if (skipFieldsStr)
skipIds = slNameListFromComma(skipFieldsStr);
struct slName *dsScriptFields = detailsScriptFieldNames(tdb);
// make list of fields that are separated from other fields
char *sepFieldsStr = trackDbSetting(tdb, "sepFields");
struct slName *sepFields = NULL;
if (sepFieldsStr)
sepFields = slNameListFromComma(sepFieldsStr);
// make list of fields that we want to substitute
// this setting has format description|URLorFilePath, with the stuff before the pipe optional
char *extraDetailsTableName = NULL, *extraDetails = cloneString(trackDbSetting(tdb, TDB_STATICTABLE_SETTING));
if (extraDetails && strchr(extraDetails,'|'))
{
extraDetailsTableName = extraDetails;
extraDetails = strchr(extraDetails,'|');
*extraDetails++ = 0;
}
struct dyString *extraTblStr = dyStringNew(0);
struct slName *detailsTableFields = NULL;
if (extraDetails)
detailsTableFields = findFieldsInExtraFile(extraDetails, col, extraTblStr);
char *extraDetails2TableName = NULL, *extraDetails2 = cloneString(trackDbSetting(tdb, TDB_STATICTABLE_SETTING_2));
if (extraDetails2 && strchr(extraDetails2,'|'))
{
extraDetails2TableName = extraDetails2;
extraDetails2 = strchr(extraDetails2,'|');
*extraDetails2++ = 0;
}
struct dyString *extraTbl2Str = dyStringNew(0);
struct slName *detailsTable2Fields = NULL;
if (extraDetails2)
detailsTable2Fields = findFieldsInExtraFile(extraDetails2, col, extraTbl2Str);
struct hash *embeddedTblHash = hashNew(0);
struct slName *embeddedTblFields = NULL;
struct embeddedTbl *embeddedTblList = NULL;
getExtraTableFields(tdb, &embeddedTblFields, &embeddedTblList, embeddedTblHash);
// iterate over fields, print as table rows
int count = 0;
int printCount = 0;
for (;col != NULL && count < fieldCount;col=col->next)
{
if (start > 0) // skip past already known fields
{
start--;
continue;
}
int ix = count;
if (sr != NULL)
{
ix = sqlFieldColumn(sr, col->name); // If sr provided, name must match sql columnn name!
if (ix == -1 || ix > fieldCount) // so extraField really just provides a label
continue;
}
char *fieldName = col->name;
count++;
// don't print this field if we are gonna print it later in a custom table
if (detailsTableFields && slNameInList(detailsTableFields, fieldName))
{
int fieldLen = strlen(fieldName);
char *replaceField = needMem(fieldLen+4);
replaceField[0] = '$';
replaceField[1] = '{';
strcpy(replaceField+2, fieldName);
replaceField[fieldLen+2] = '}';
replaceField[fieldLen+3] = 0;
extraTblStr = dyStringSub(extraTblStr->string, replaceField, fields[ix]);
continue;
}
// don't print this field if we are gonna print it later in a custom table
if (detailsTable2Fields && slNameInList(detailsTable2Fields, fieldName))
{
int fieldLen = strlen(fieldName);
char *replaceField = needMem(fieldLen+4);
replaceField[0] = '$';
replaceField[1] = '{';
strcpy(replaceField+2, fieldName);
replaceField[fieldLen+2] = '}';
replaceField[fieldLen+3] = 0;
extraTbl2Str = dyStringSub(extraTbl2Str->string, replaceField, fields[ix]);
continue;
}
// similar to above, if the field contains an embedded table skip it here
// and print it later
if (embeddedTblFields)
{
struct embeddedTbl *new = hashFindVal(embeddedTblHash, fieldName);
if (new)
{
new->encodedTbl = fields[ix];
// this field will get printed later somehow, so make sure the
// rest of this code knows to not open more table tags and close
// the correct ones
printCount++;
continue;
}
}
// do not print a row if the fieldName from the .as file is in the "skipFields" list
// or if a field name starts with _. This makes bigBed extra fields consistent with
// external extra fields in that _ field names have some meaning and are not shown
if (startsWith("_", fieldName) || (skipIds && slNameInList(skipIds, fieldName)))
continue;
// skip this row if it's empty and "skipEmptyFields" option is set
if (skipEmptyFields && isEmpty(fields[ix]))
continue;
if (printCount == 0)
printf(" \n\n | |