a434e74c8fe5c826a4da34050ec6b16589e0fd88 chmalee Tue Jul 13 14:56:14 2021 -0700 Remove attempt at fixing include bigDataUrl expansion, easier to fix the data than the code for now, refs #27767 diff --git src/hg/lib/trackDbCustom.c src/hg/lib/trackDbCustom.c index c3c3b7f..04336a4 100644 --- src/hg/lib/trackDbCustom.c +++ src/hg/lib/trackDbCustom.c @@ -1,1618 +1,1609 @@ /* trackDbCustom - custom (not autoSQL generated) code for working * with trackDb. This code is concerned with making the trackDb * MySQL table out of the trackDb.ra files. */ /* Copyright (C) 2014 The Regents of the University of California * See README in this or parent directory for licensing information. */ #include #include "common.h" #include "linefile.h" #include "jksql.h" #include "trackDb.h" #include "hdb.h" #include "hui.h" #include "ra.h" #include "hash.h" #include "net.h" #include "sqlNum.h" #include "obscure.h" #include "hgMaf.h" #include "customTrack.h" #include "regexHelper.h" #include "fieldedTable.h" #include "tagRepo.h" -#include "htmlPage.h" -#include "hubConnect.h" struct trackDb *trackDbNew() /* Allocate a new trackDb with just very minimal stuff filled in. */ { struct trackDb *tdb; AllocVar(tdb); tdb->canPack = 2; /* Unknown value. */ return tdb; } int trackDbCmp(const void *va, const void *vb) /* Compare to sort based on priority; use shortLabel as secondary sort key. * Note: parallel code to hgTracks.c:tgCmpPriority */ { const struct trackDb *a = *((struct trackDb **)va); const struct trackDb *b = *((struct trackDb **)vb); float dif = a->priority - b->priority; if (dif < 0) return -1; else if (dif == 0.0) return strcasecmp(a->shortLabel, b->shortLabel); else return 1; } int trackDbCmpShortLabel(const void *va, const void *vb) /* Sort track by shortLabel. */ { const struct trackDb *a = *((struct trackDb **)va); const struct trackDb *b = *((struct trackDb **)vb); return strcmp(a->shortLabel, b->shortLabel); } void parseColor(char *text, unsigned char *r, unsigned char *g, unsigned char *b) /* Turn comma-separated string of three numbers into three * color components. */ { char dupe[64]; safecpy(dupe, sizeof(dupe), text); char *words[4]; int wordCount; wordCount = chopString(dupe, ", \t", words, ArraySize(words)); if (wordCount != 3) errAbort("Expecting 3 comma separated values in %s.", text); *r = atoi(words[0]); *g = atoi(words[1]); *b = atoi(words[2]); } static unsigned char parseVisibility(char *value) /* Parse a visibility value */ { if (sameString(value, "hide") || sameString(value, "0")) return tvHide; else if (sameString(value, "dense") || sameString(value, "1")) return tvDense; else if (sameString(value, "full") || sameString(value, "2") || sameString(value, "show")) return tvFull; else if (sameString(value, "pack") || sameString(value, "3")) return tvPack; else if (sameString(value, "squish") || sameString(value, "4")) return tvSquish; else errAbort("Unknown visibility %s ", value); return tvHide; /* never reached */ } static void parseTrackLine(struct trackDb *bt, char *value, struct lineFile *lf) /* parse the track line */ { char *val2 = cloneString(value); bt->track = nextWord(&val2); // check for override option if (val2 != NULL) { val2 = trimSpaces(val2); if (!sameString(val2, "override")) errAbort("invalid track line: %s:%d: track %s", lf->fileName, lf->lineIx, value); bt->overrides = hashNew(0); } } static void trackDbAddRelease(struct trackDb *bt, char *releaseTag) /* Add release tag */ { hashAdd(bt->settingsHash, "release", cloneString(releaseTag)); } static void trackDbAddInfo(struct trackDb *bt, char *var, char *value, struct lineFile *lf) /* Add info from a variable/value pair to browser table. */ { -char *subbedUrl = NULL; if (sameString(var, "track")) parseTrackLine(bt, value, lf); -// Since we may have gotten here from an include statement, we -// need to expand the url relative to the include statement, and -// not later where the url will be expanded relative to the parent -// of the include statement -if (isHubTrack(bt->track) && trackSettingIsFile(var)) - subbedUrl = htmlExpandUrl(lf->fileName, value); if (bt->settingsHash == NULL) bt->settingsHash = hashNew(7); if (bt->viewHash == NULL) bt->viewHash = hashNew(7); -char *storeValue = cloneString(subbedUrl != NULL ? subbedUrl : value); +char *storeValue = cloneString(value); // squirrel away views if (startsWith("subGroup", var)) { char *ptr = strchr(value, ' '); if (ptr) *ptr = 0; hashAdd(bt->viewHash, value, storeValue); if (ptr) *ptr = ' '; } hashAdd(bt->settingsHash, var, storeValue); if (bt->overrides != NULL) hashAdd(bt->overrides, var, NULL); } //not needed? int bedDetailSizeFromType(char *type) /* parse bedSize from type line for bedDetail, assume 4 if none */ { int ret = 4; /* minimal expected */ char *words[3]; int wordCount = chopLine(cloneString(type), words); if (wordCount > 1) ret = atoi(words[1]) - 2; /* trackDb has field count, we want bedSize */ return ret; } void trackDbFieldsFromSettings(struct trackDb *bt) /* Update trackDb fields from settings hash */ { char *shortLabel = trackDbSetting(bt, "shortLabel"); if (shortLabel != NULL) bt->shortLabel = cloneString(shortLabel); char *longLabel = trackDbSetting(bt, "longLabel"); if (longLabel != NULL) bt->longLabel = cloneString(longLabel); char *priority = trackDbSetting(bt, "priority"); if (priority != NULL) bt->priority = atof(priority); char *url = trackDbSetting(bt, "url"); if (url != NULL) bt->url = cloneString(url); char *visibility = trackDbSetting(bt, "visibility"); if (visibility != NULL) bt->visibility = parseVisibility(visibility); char *color = trackDbSetting(bt, "color"); if (color != NULL) parseColor(color, &bt->colorR, &bt->colorG, &bt->colorB); char *altColor = trackDbSetting(bt, "altColor"); if (altColor != NULL) parseColor(altColor, &bt->altColorR, &bt->altColorG, &bt->altColorB); char *type = trackDbSetting(bt, "type"); if (type != NULL) bt->type = cloneString(type); if (trackDbSetting(bt, "spectrum") != NULL || trackDbSetting(bt, "useScore") != NULL) bt->useScore = TRUE; char *canPack = trackDbSetting(bt, "canPack"); if (canPack != NULL) bt->canPack = !(sameString(canPack, "0") || sameString(canPack, "off")); char *chromosomes = trackDbSetting(bt, "chromosomes"); if (chromosomes != NULL) sqlStringDynamicArray(chromosomes, &bt->restrictList, &bt->restrictCount); if (trackDbSetting(bt, "private") != NULL) bt->private = TRUE; char *grp = trackDbSetting(bt, "group"); if (grp != NULL) bt->grp = cloneString(grp); } static void replaceStr(char **varPtr, char *val) /** replace string in varPtr with val */ { freeMem(*varPtr); *varPtr = cloneString(val); } static void overrideField(struct trackDb *td, struct trackDb *overTd, char *var) /* Update override one field from override. */ { if (sameString(var, "track") || sameString(var, "release")) return; char *val = hashMustFindVal(overTd->settingsHash, var); struct hashEl *hel = hashStore(td->settingsHash, var); replaceStr((char**)&hel->val, val); } void trackDbOverride(struct trackDb *td, struct trackDb *overTd) /* apply an trackOverride trackDb entry to a trackDb entry */ { assert(overTd->overrides != NULL); struct hashEl *hel; struct hashCookie hc = hashFirst(overTd->overrides); while ((hel = hashNext(&hc)) != NULL) { overrideField(td, overTd, hel->name); } } static boolean packableType(char *type) /* Return TRUE if we can pack this type. */ { char *t = cloneString(type); char *s = firstWordInLine(t); boolean canPack = (sameString("psl", s) || sameString("chain", s) || sameString("bed", s) || sameString("genePred", s) || sameString("makeItems", s) || sameString("expRatio", s) || sameString("wigMaf", s) || sameString("factorSource", s) || sameString("bed5FloatScore", s) || sameString("bed6FloatScore", s) || sameString("altGraphX", s) || sameString("bam", s) || sameString("bedDetail", s) || sameString("bed8Attrs", s) || sameString("gvf", s) || sameString("vcfTabix", s) || sameString("vcf", s) || sameString("pgSnp", s) || sameString("narrowPeak", s) || sameString("broadPeak", s) || sameString("bigLolly", s) || sameString("peptideMapping", s) || sameString("barChart", s) || sameString("interact", s) || (!startsWithWord("bigWig", s) && startsWith("big", s)) ); freeMem(t); return canPack; } void trackDbPolish(struct trackDb *bt) /* Fill in missing values with defaults. */ { if (bt->shortLabel == NULL) bt->shortLabel = cloneString(bt->track); if (bt->longLabel == NULL) bt->longLabel = cloneString(bt->shortLabel); if (bt->altColorR == 0 && bt->altColorG == 0 && bt->altColorB == 0) { bt->altColorR = (255+bt->colorR)/2; bt->altColorG = (255+bt->colorG)/2; bt->altColorB = (255+bt->colorB)/2; } if (bt->type == NULL) bt->type = cloneString(""); if (bt->priority == 0) bt->priority = 100.0; if (bt->url == NULL) bt->url = cloneString(""); if (bt->html == NULL) bt->html = cloneString(""); if (bt->grp == NULL) bt->grp = cloneString("x"); if (bt->canPack == 2) bt->canPack = packableType(bt->type); if (bt->settings == NULL) bt->settings = cloneString(""); } char *trackDbInclude(char *raFile, char *line, char **releaseTag) /* Get include filename from trackDb line. Return NULL if line doesn't contain include */ { static char incFile[256]; char *file; if (startsWith("include", line)) { splitPath(raFile, incFile, NULL, NULL); nextWord(&line); file = nextQuotedWord(&line); strcat(incFile, file); *releaseTag = nextWord(&line); return cloneString(incFile); } else return NULL; } struct trackDb *trackDbFromOpenRa(struct lineFile *lf, char *releaseTag, struct dyString *incFiles) /* Load track info from ra file already opened as lineFile into list. If releaseTag is * non-NULL then only load tracks that mesh with release. If incFiles is not-NULL, put * list of included files in there. */ { char *raFile = lf->fileName; char *line, *word; struct trackDb *btList = NULL, *bt; boolean done = FALSE; char *incFile; for (;;) { /* Seek to next line that starts with 'track' */ for (;;) { char *subRelease; if (!lineFileNextFull(lf, &line, NULL, NULL, NULL)) { // NOTE: lineFileNextFull joins continuation lines done = TRUE; break; } line = skipLeadingSpaces(line); if (startsWithWord("track", line)) { lineFileReuseFull(lf); // NOTE: only works with previous lineFileNextFull call break; } else if ((incFile = trackDbInclude(raFile, line, &subRelease)) != NULL) { if (subRelease) trackDbCheckValidRelease(subRelease); if (releaseTag && subRelease && !sameString(subRelease, releaseTag)) errAbort("Include with release %s inside include with release %s line %d of %s", subRelease, releaseTag, lf->lineIx, lf->fileName); struct trackDb *incTdb = trackDbFromRa(incFile, subRelease, incFiles); btList = slCat(btList, incTdb); if (incFiles) dyStringPrintf(incFiles, "%s\n", incFile); } } if (done) break; /* Allocate track structure and fill it in until next blank line. */ bt = trackDbNew(); slAddHead(&btList, bt); for (;;) { /* Break at blank line or EOF. */ if (!lineFileNextFull(lf, &line, NULL, NULL, NULL)) // NOTE: joins continuation lines break; line = skipLeadingSpaces(line); if (line == NULL || line[0] == 0) break; /* Skip comments. */ if (line[0] == '#') continue; /* Parse out first word and decide what to do. */ word = nextWord(&line); if (line == NULL) errAbort("No value for %s line %d of %s", word, lf->lineIx, lf->fileName); line = trimSpaces(line); trackDbUpdateOldTag(&word, &line); if (releaseTag && sameString(word, "release")) { if (differentString(releaseTag, line)) errAbort("Release tag %s in stanza with include override %s, line %d of %s", line, releaseTag, lf->lineIx, lf->fileName); } else trackDbAddInfo(bt, word, line, lf); } if (releaseTag) trackDbAddRelease(bt, releaseTag); } slReverse(&btList); return btList; } boolean trackDbCheckValidRelease(char *tag) /* check to make sure release tag is valid */ { char *words[5]; int count = chopString(cloneString(tag), ",", words, ArraySize(words)); if (count > 3) return FALSE; int ii; for(ii=0; ii < count; ii++) if (!sameString(words[ii], "alpha") && !sameString(words[ii], "beta") && !sameString(words[ii], "public")) return FALSE; return TRUE; } struct trackDb *trackDbFromRa(char *raFile, char *releaseTag, struct dyString *incFiles) /* Load track info from ra file into list. If releaseTag is non-NULL * then only load tracks that mesh with release. if incFiles is non-null, * add included file names to it.*/ { struct lineFile *lf = udcWrapShortLineFile(raFile, NULL, 16*1024*1024); struct trackDb *tdbList = trackDbFromOpenRa(lf, releaseTag, incFiles); lineFileClose(&lf); return tdbList; } struct hash *trackDbHashSettings(struct trackDb *tdb) /* Force trackDb to hash up it's settings. Usually this is just * done on demand. Returns settings hash. */ { if (tdb->settingsHash == NULL) tdb->settingsHash = trackDbSettingsFromString(tdb, tdb->settings); return tdb->settingsHash; } struct hash *trackDbSettingsFromString(struct trackDb *tdb, char *string) /* Return hash of key/value pairs from string. Differs * from raFromString in that it passes the key/val * pair through the backwards compatability routines. */ { char *dupe = cloneString(string); char *s = dupe, *lineEnd; struct hash *hash = newHash(7); char *key, *val; for (;;) { s = skipLeadingSpaces(s); if (s == NULL || s[0] == 0) break; lineEnd = strchr(s, '\n'); if (lineEnd != NULL) *lineEnd++ = 0; key = nextWord(&s); val = skipLeadingSpaces(s); trackDbUpdateOldTag(&key, &val); s = lineEnd; val = lmCloneString(hash->lm, val); hashAdd(hash, key, val); if (tdb && startsWith("subGroup", key)) { char *storeValue = cloneString(val); char *ptr = strchr(val, ' '); if (ptr) *ptr = 0; if (tdb->viewHash == NULL) tdb->viewHash = newHash(5); hashAdd(tdb->viewHash, val, storeValue); if (ptr) *ptr = ' '; } } freeMem(dupe); return hash; } char *trackDbViewSetting(struct trackDb *tdb, char *name) /* Return view setting from tdb, but *not* any of it's parents. */ { if (tdb == NULL) errAbort("Program error: null tdb passed to trackDbSetting."); if (tdb->viewHash == NULL) return NULL; return hashFindVal(tdb->viewHash, name); } char *trackDbLocalSetting(struct trackDb *tdb, char *name) /* Return setting from tdb, but *not* any of it's parents. */ { if (tdb == NULL) errAbort("Program error: null tdb passed to trackDbSetting."); if (tdb->settingsHash == NULL) tdb->settingsHash = trackDbSettingsFromString(tdb, tdb->settings); return hashFindVal(tdb->settingsHash, name); } struct slName *trackDbLocalSettingsWildMatch(struct trackDb *tdb, char *expression) // Return local settings that match expression else NULL. In alpha order. { if (tdb == NULL) errAbort("Program error: null tdb passed to trackDbSetting."); if (tdb->settingsHash == NULL) tdb->settingsHash = trackDbSettingsFromString(tdb, tdb->settings); struct slName *slFoundVars = NULL; struct hashCookie brownie = hashFirst(tdb->settingsHash); struct hashEl* el = NULL; while ((el = hashNext(&brownie)) != NULL) { if (wildMatch(expression, el->name)) slNameAddHead(&slFoundVars, el->name); } if (slFoundVars != NULL) slNameSort(&slFoundVars); return slFoundVars; } struct slName *trackDbSettingsWildMatch(struct trackDb *tdb, char *expression) // Return settings in tdb tree that match expression else NULL. In alpha order, no duplicates. { struct trackDb *generation; struct slName *slFoundVars = NULL; for (generation = tdb; generation != NULL; generation = generation->parent) { struct slName *slFoundHere = trackDbLocalSettingsWildMatch(generation,expression); if (slFoundHere != NULL) { if (slFoundVars == NULL) slFoundVars = slFoundHere; else { struct slName *one = NULL; while ((one = slPopHead(&slFoundHere)) != NULL) { slNameStore(&slFoundVars, one->name); // Will only store if it is not already found! slNameFree(&one); // This means closest to home will work } } } } if (slFoundVars != NULL) slNameSort(&slFoundVars); return slFoundVars; } boolean trackDbSettingOn(struct trackDb *tdb, char *name) /* Return true if a tdb setting is "on" "true" or "enabled". */ { char *setting = trackDbSetting(tdb,name); return (setting && ( sameWord(setting,"on") || sameWord(setting,"true") || sameWord(setting,"enabled"))); } char *trackDbRequiredSetting(struct trackDb *tdb, char *name) /* Return setting string or squawk and die. */ { char *ret = trackDbSetting(tdb, name); if (ret == NULL) errAbort("Missing required '%s' setting in %s track", name, tdb->track); return ret; } char *trackDbSettingOrDefault(struct trackDb *tdb, char *name, char *defaultVal) /* Return setting string, or defaultVal if none exists */ { char *val = trackDbSetting(tdb, name); return (val == NULL ? defaultVal : val); } float trackDbFloatSettingOrDefault(struct trackDb *tdb, char *name, float defaultVal) /* Return setting, convert to a float, or defaultVal if none exists */ { char *val = trackDbSetting(tdb, name); if (val == NULL) return defaultVal; else return sqlFloat(trimSpaces(val)); } struct hashEl *trackDbSettingsLike(struct trackDb *tdb, char *wildStr) /* Return a list of settings whose names match wildStr (may contain wildcard * characters). Free the result with hashElFreeList. */ { struct hashEl *allSettings = hashElListHash(tdb->settingsHash); struct hashEl *matchingSettings = NULL; struct hashEl *hel = allSettings; while (hel != NULL) { struct hashEl *next = hel->next; if (wildMatch(wildStr, hel->name)) { slAddHead(&matchingSettings, hel); } else hashElFree(&hel); hel = next; } return matchingSettings; } char *maybeSkipHubPrefix(char *track) { if (!startsWith("hub_", track)) return track; char *nextUnderBar = strchr(track + sizeof "hub_", '_'); if (nextUnderBar) return nextUnderBar + 1; return track; } void trackDbSuperMarkup(struct trackDb *tdbList) /* Set trackDb from superTrack setting */ { struct trackDb *tdb; struct hash *superHash = hashNew(0); char *setting = NULL; char *words[3]; int wordCt = 0; /* find supertracks, setup their settings */ for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { setting = trackDbLocalSetting(tdb, "superTrack"); if (!setting) continue; wordCt = chopLine(cloneString(setting), words); if (sameWord("on", words[0])) { if (!hashLookup(superHash, tdb->track)) { hashAdd(superHash, maybeSkipHubPrefix(tdb->track), tdb); tdbMarkAsSuperTrack(tdb); if ((wordCt > 1) && sameString("show", words[1])) tdb->isShow = TRUE; } } freeMem(words[0]); } /* adjust settings on supertrack members after verifying they have * a supertrack configured in this trackDb */ for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { if (tdbIsSuperTrack(tdb) || tdb->parent != NULL) continue; setting = trackDbLocalSetting(tdb, "parent"); if (!setting) setting = trackDbLocalSetting(tdb, "superTrack"); // Old style if (!setting) continue; wordCt = chopLine(cloneString(setting), words); assert(differentString("on", words[0])); // already weeded out "superTrack on" char *parentName = maybeSkipHubPrefix(words[0]); tdb->parent = hashFindVal(superHash, parentName); if (tdb->parent) { tdbMarkAsSuperTrackChild(tdb); tdb->parentName = cloneString(parentName); if (wordCt > 1) tdb->visibility = max(0, hTvFromStringNoAbort(words[1])); } freeMem(words[0]); } hashFree(&superHash); } char *trackDbOrigAssembly(struct trackDb *tdb) /* return setting from trackDb, if any */ { return (trackDbSetting(tdb, "origAssembly")); } void trackDbPrintOrigAssembly(struct trackDb *tdb, char *database) /* Print lift information from trackDb, if any */ { char *origAssembly = trackDbOrigAssembly(tdb); if (origAssembly) { if (differentString(origAssembly, database)) { printf("Data coordinates converted via liftOver from: "); char *freeze = hFreezeFromDb(origAssembly); if (freeze == NULL) printf("%s
\n", origAssembly); else if (stringIn(origAssembly, freeze)) printf("%s
\n", freeze); else printf("%s (%s)
\n", freeze, origAssembly); } } } eCfgType cfgTypeFromTdb(struct trackDb *tdb, boolean warnIfNecessary) /* determine what kind of track specific configuration is needed, warn if not multi-view compatible */ { eCfgType cType = cfgNone; char *type = tdb->type; assert(type != NULL); if(startsWith("wigMaf", type) || startsWith("bigMaf", type)) cType = cfgWigMaf; else if(startsWith("wig", type) || startsWith("mathWig", type) || startsWith("bigWig", type) || startsWith("bedGraph", type) || startsWith("bamWig", type)) cType = cfgWig; else if(startsWith("bigGenePred", type)) cType = cfgGenePred; else if(startsWith("chain",type) || startsWith("bigChain",type)) cType = cfgChain; else if (startsWith("psl", type) || startsWith("bigPsl", type)) cType = cfgPsl; else if (sameWord("barChart", type) || sameWord("bigBarChart", type)) cType = cfgBarChart; else if (sameWord("interact", type) || sameWord("bigInteract", type)) cType = cfgInteract; else if (startsWith("bigLolly", type)) cType = cfgLollipop; else if (sameWord("bigDbSnp", type)) cType = cfgBigDbSnp; else if(startsWith("longTabix", type)) cType = cfgLong; else if (startsWith("netAlign", type) || startsWith("net", tdb->track)) // SPECIAL CASE from hgTrackUi which might not be needed cType = cfgNetAlign; else if(sameWord("bed5FloatScore", type) || sameWord("bed5FloatScoreWithFdr",type)) { if (bedScoreHasCfgUi(tdb)) cType = cfgBedScore; } else if (encodePeakHasCfgUi(tdb)) cType = cfgPeak; else if (startsWithWord("genePred",type) && !startsWith("encodeGencodeRaceFrags", tdb->track)) // SPECIAL CASE should fix in trackDb! cType = cfgGenePred; else if (sameWord("bedLogR",type) || sameWord("peptideMapping", type)) cType = cfgBedScore; // This is a catch-all for big* types that are not special-cased above. big* types after this // point are assumed to be flavors of bigBed. else if (startsWith("bed ", type) || startsWith("big", type) || startsWith("bedDetail", type)) { if (trackDbSetting(tdb, "bedFilter") != NULL) cType = cfgBedFilt; else if (!startsWith("big", type) || startsWith("bigBed", type)) { char *words[3]; int wordCount = chopLine(cloneString( type), words); if (( ((wordCount > 1) && (atoi(words[1]) >= 5)) || trackDbSetting(tdb, "scoreMin") != NULL) && // Historically needed 'bed n .' but encode didn't follow bed n . ( (wordCount >= 3) || (!tdbIsTrackUiTopLevel(tdb) && trackDbSettingClosestToHome(tdb, "wgEncode")))) { cType = cfgBedScore; if (!bedScoreHasCfgUi(tdb)) cType = cfgNone; // FIXME: UGLY SPECIAL CASE should be handled in trackDb! else if (startsWith("encodeGencodeIntron", tdb->track)) cType = cfgNone; } } else cType = cfgBedScore; } else if (startsWith("bam", type)) cType = cfgBam; else if (sameWord("vcfPhasedTrio", type) || sameWord("vcfTabix",type) || sameWord("vcf", type)) cType = cfgVcf; else if (sameWord("halSnake",type)) cType = cfgSnake; else if (sameWord("hic", type)) cType = cfgHic; // TODO: Only these are configurable so far if (cType == cfgNone && warnIfNecessary) { if (!startsWith("bed ", type) && !startsWith("bedDetail", type) && !startsWith("bigBed", type) && !startsWith("gvf", type) && !sameString("pgSnp", type) && subgroupFind(tdb, "view", NULL)) warn("Track type \"%s\" is not yet supported in multi-view composites for %s.",type,tdb->track); } return cType; } int configurableByAjax(struct trackDb *tdb, eCfgType cfgTypeIfKnown) // Is this track configurable by right-click popup, or in hgTrackUi subCfg? // returns 0 = no; <0=explicitly blocked; >0=allowed and will be cfgType if determined { if (tdbIsMultiTrackSubtrack(tdb)) return cfgNone; // multitrack subtracks are never allowed to be separately configured. int ctPopup = (int)cfgTypeIfKnown; if (ctPopup <= cfgNone) ctPopup = (int)cfgTypeFromTdb(tdb,FALSE); if (ctPopup <= cfgNone && !tdbIsSubtrack(tdb)) // subtracks must receive CfgType! ctPopup = cfgUndetermined; // cfgTypeFromTdb() does not work for every case. if (ctPopup > cfgNone) { if (regexMatch(tdb->track, "^snp[0-9]+") // Special cases to be removed || regexMatch(tdb->track, "^cons[0-9]+way") // (matches logic in json setup in imageV2.c) || startsWith("hapmapSnps", tdb->track) || startsWith("hapmapAlleles", tdb->track) || trackDbSettingBlocksConfiguration(tdb,TRUE)) ctPopup *= -1; } return ctPopup; } boolean trackDbNoInheritField(char *field) /* Suppress inheritance of specific fields. * NOTE: make more efficient if more of these are added */ { return (sameString(field, "pennantIcon")); } char *trackDbSetting(struct trackDb *tdb, char *name) /* Look for a trackDb setting from lowest level on up chain of parents, * excepting fields specifically defined as not inheritable */ { struct trackDb *generation; char *trackSetting = NULL; for (generation = tdb; generation != NULL; generation = generation->parent) { trackSetting = trackDbLocalSetting(generation, name); if (trackSetting != NULL || trackDbNoInheritField(name)) break; } return trackSetting; } void trackDbAddSetting(struct trackDb *bt, char *name, char *val) { /* Add a setting to a trackDb rec */ hashAdd(trackDbHashSettings(bt), name, cloneString(val)); } char *trackDbSettingByView(struct trackDb *tdb, char *name) /* For a subtrack of a multiview composite, get a setting stored in the view or any other * ancestor. */ { if (tdb->parent == NULL) return NULL; return trackDbSetting(tdb->parent, name); } char *trackDbSettingClosestToHomeOrDefault(struct trackDb *tdb, char *name, char *defaultVal) /* Look for a trackDb setting (or default) from lowest level on up chain of parents. */ { char *trackSetting = trackDbSetting(tdb,name); if (trackSetting == NULL) trackSetting = defaultVal; return trackSetting; } boolean trackDbSettingClosestToHomeOn(struct trackDb *tdb, char *name) /* Return true if a tdb setting closest to home is "on" "true" or "enabled". */ { char *setting = trackDbSetting(tdb,name); return (setting && ( sameWord(setting,"on") || sameWord(setting,"true") || sameWord(setting,"enabled") || atoi(setting) != 0)); } struct trackDb *subTdbFind(struct trackDb *parent,char *childName) /* Return child tdb if it exists in parent. */ { if (parent == NULL) return NULL; struct trackDb *found = NULL; struct slRef *tdbRef, *tdbRefList = trackDbListGetRefsToDescendants(parent->subtracks); for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next) { struct trackDb *tdb = tdbRef->val; if (sameString(tdb->track, childName)) { found = tdb; break; } } slFreeList(&tdbRefList); return found; } struct trackDb *tdbFindOrCreate(char *db,struct trackDb *parent,char *track) /* Find or creates the tdb for this track. May return NULL. */ { struct trackDb *tdb = NULL; if (parent != NULL) { if(sameString(parent->track, track)) tdb = parent; else if(consWiggleFind(db,parent,track) != NULL) tdb = parent; else tdb = subTdbFind(parent,track); } if (tdb == NULL && db != NULL) { struct sqlConnection *conn = hAllocConn(db); tdb = hMaybeTrackInfo(conn, track); hFreeConn(&conn); } return tdb; } #ifdef OMIT // NOTE: This may not be needed. struct trackDb *tdbFillInAncestry(char *db,struct trackDb *tdbChild) /* Finds parents and fills them in. Does not find siblings, however! */ { assert(tdbChild != NULL); struct trackDb *tdb = tdbChild; struct sqlConnection *conn = NULL; for (;tdb->parent != NULL;tdb = tdb->parent) ; // advance to highest parent already known // If track with no tdbParent has a parent setting then fill it in. for (;tdb->parent == NULL; tdb = tdb->parent) { char *parentTrack = trackDbLocalSetting(tdb,"parent"); if (parentTrack == NULL) break; if (conn == NULL) conn = hAllocConn(db); // Now there are 2 versions of this child! And what to do about views? tdb->parent = hMaybeTrackInfo(conn, parentTrack); printf("tdbFillInAncestry(%s): has %d children.",parentTrack,slCount(tdb->parent->subtracks)); } if (conn != NULL) hFreeConn(&conn); return tdb; } #endif///def OMIT boolean tdbIsView(struct trackDb *tdb,char **viewName) // Is this tdb a view? Will fill viewName if provided { if (tdbIsCompositeView(tdb)) { if (viewName) { *viewName = trackDbLocalSetting(tdb, "view"); if (*viewName == NULL) errAbort("track '%s' appears to be a view but does not have a " "view setting.", tdb->track); } return TRUE; } return FALSE; } char *tdbGetViewName(struct trackDb *tdb) // returns NULL the view name for view or child track (do not free) { char *view = NULL; if (tdbIsComposite(tdb)) return NULL; else if (tdbIsCompositeChild(tdb) && subgroupFind(tdb,"view",&view)) return view; else if (tdbIsView(tdb,&view)) return view; return NULL; } struct trackDb *trackDbLinkUpGenerations(struct trackDb *tdbList) /* Convert a list to a forest - filling in parent and subtrack pointers. * The exact topology of the forest is a little complex due to the * fact there are two "inheritance" systems - the superTrack system * and the subTrack system. In the superTrack system (which is on it's * way out) the superTrack's themselves have the tag: * superTrack on * and the children of superTracks have the tag: * superTrack parentName * In the subTrack system the parents have the tag: * compositeTrack on * and the children have the tag: * parent parentName * In this routine the subtracks are removed from the list, and stuffed into * the subtracks lists of their parents. The highest level parents stay on * the list. There can be multiple levels of inheritance. * For the supertracks the _parents_ are removed from the list. The only * reference to them in the returned forest is that they are in the parent * field of their children. The parents of supertracks have no subtracks * after this call currently. */ { struct trackDb *forest = NULL; struct hash *trackHash = hashNew(0); struct trackDb *tdb, *next; for (tdb = tdbList; tdb != NULL; tdb = tdb->next) hashAdd(trackHash, tdb->track, tdb); /* Do superTrack inheritance. This involves setting up the parent pointers to superTracks, * but removing the superTracks themselves from the list. */ struct trackDb *superlessList = NULL; trackDbSuperMarkup(tdbList); for (tdb = tdbList; tdb != NULL; tdb = next) { next = tdb->next; if (tdbIsSuperTrack(tdb)) tdb->next = NULL; else slAddHead(&superlessList, tdb); } /* Do subtrack hierarchy - filling in parent and subtracks fields. */ for (tdb = superlessList; tdb != NULL; tdb = next) { next = tdb->next; char *subtrackSetting = trackDbLocalSetting(tdb, "parent"); if (subtrackSetting != NULL && !tdbIsSuperTrackChild(tdb)) // superChildren cannot be in both subtracks list AND tdbList { char *parentName = cloneFirstWord(subtrackSetting); struct trackDb *parent = hashFindVal(trackHash, parentName); if (parent != NULL) { if (trackDbLocalSetting(tdb, "container")) { errAbort("Composite track '%s' cannot have child track '%s'," " which is a container multiWig.", parentName, tdb->track); } slAddHead(&parent->subtracks, tdb); // composite/multiWig children are ONLY subtracks tdb->parent = parent; } else { errAbort("Parent track %s of child %s doesn't exist", parentName, tdb->track); } freez(&parentName); } else { slAddHead(&forest, tdb); } } hashFree(&trackHash); return forest; } void trackDbPrioritizeContainerItems(struct trackDb *tdbList) /* Set priorities in containers if they have no priorities already set priorities are based upon 'sortOrder' setting or else shortLabel */ { int countOfSortedContainers = 0; // Walk through tdbs looking for containers struct trackDb *tdbContainer; for (tdbContainer = tdbList; tdbContainer != NULL; tdbContainer = tdbContainer->next) { if (tdbContainer->subtracks == NULL) continue; sortOrder_t *sortOrder = sortOrderGet(NULL,tdbContainer); boolean needsSorting = TRUE; // default float firstPriority = -1.0; sortableTdbItem *item,*itemsToSort = NULL; struct slRef *child, *childList = trackDbListGetRefsToDescendantLeaves(tdbContainer->subtracks); // Walk through tdbs looking for items contained for (child = childList; child != NULL; child = child->next) { struct trackDb *tdbItem = child->val; if( needsSorting && sortOrder == NULL ) // do we? { if( firstPriority == -1.0) // all 0 or all the same value firstPriority = tdbItem->priority; if(firstPriority != tdbItem->priority && (int)(tdbItem->priority + 0.9) > 0) { needsSorting = FALSE; break; } } // create an Item item = sortableTdbItemCreate(tdbItem,sortOrder); if(item != NULL) slAddHead(&itemsToSort, item); else { verbose(1,"Error: '%s' missing shortLabels or sortOrder setting is inconsistent.\n",tdbContainer->track); needsSorting = FALSE; sortableTdbItemCreate(tdbItem,sortOrder); break; } } // Does this container need to be sorted? if(needsSorting && slCount(itemsToSort)) { verbose(2,"Sorting '%s' with %d items\n",tdbContainer->track,slCount(itemsToSort)); sortTdbItemsAndUpdatePriorities(&itemsToSort); countOfSortedContainers++; } // cleanup sortOrderFree(&sortOrder); sortableTdbItemsFree(&itemsToSort); } } void trackDbAddTableField(struct trackDb *tdbList) /* Add table field by looking it up in settings. */ { struct trackDb *tdb; for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { char *table = trackDbLocalSetting(tdb, "table"); if (table != NULL) tdb->table = cloneString(table); else tdb->table = cloneString(tdb->track); } } void rGetRefsToDescendants(struct slRef **pList, struct trackDb *tdbList) /* Add all member of tdbList, and all of their children to pList recursively. */ /* Convert a list to a forest - filling in parent and subtrack pointers. * The exact topology of the forest is a little complex due to the * fact there are two "inheritance" systems - the superTrack system * and the subTrack system. In the superTrack system (which is on it's * way out) the superTrack's themselves have the tag: * superTrack on * and the children of superTracks have the tag: * superTrack parentName * In the subTrack system the parents have the tag: * compositeTrack on * and the children have the tag: * subTrack parentName * In this routine the subtracks are removed from the list, and stuffed into * the subtracks lists of their parents. The highest level parents stay on * the list. There can be multiple levels of inheritance. * For the supertracks the _parents_ are removed from the list. The only * reference to them in the returned forest is that they are in the parent * field of their children. The parents of supertracks have no subtracks * after this call currently. */ { struct trackDb *tdb; for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { refAdd(pList, tdb); rGetRefsToDescendants(pList, tdb->subtracks); } } struct slRef *trackDbListGetRefsToDescendants(struct trackDb *tdbList) /* Return reference list to everything in forest. Do slFreeList when done. */ { struct slRef *refList = NULL; rGetRefsToDescendants(&refList, tdbList); slReverse(&refList); return refList; } int trackDbCountDescendants(struct trackDb *tdb) /* Count the number of tracks in subtracks list and their subtracks too . */ { struct slRef *tdbRefList = trackDbListGetRefsToDescendants(tdb->subtracks); int result = slCount(tdbRefList); slFreeList(&tdbRefList); return result; } void rGetRefsToDescendantLeaves(struct slRef **pList, struct trackDb *tdbList) /* Add all leaf members of trackList, and any leaf descendants to pList recursively. */ { struct trackDb *tdb; for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { if (tdb->subtracks) rGetRefsToDescendantLeaves(pList, tdb->subtracks); else refAdd(pList, tdb); } } struct slRef *trackDbListGetRefsToDescendantLeaves(struct trackDb *tdbList) /* Return reference list all leaves in forest. Do slFreeList when done. */ { struct slRef *refList = NULL; rGetRefsToDescendantLeaves(&refList, tdbList); slReverse(&refList); return refList; } int trackDbCountDescendantLeaves(struct trackDb *tdb) /* Count the number of leaves in children list and their children. */ { struct slRef *leafRefs = trackDbListGetRefsToDescendantLeaves(tdb->subtracks); int result = slCount(leafRefs); slFreeList(&leafRefs); return result; } int trackDbRefCmp(const void *va, const void *vb) /* Do trackDbCmp on list of references as opposed to actual trackDbs. */ { const struct slRef *aRef = *((struct slRef **)va); const struct slRef *bRef = *((struct slRef **)vb); struct trackDb *a = aRef->val, *b = bRef->val; return trackDbCmp(&a, &b); } struct trackDb *trackDbTopLevelSelfOrParent(struct trackDb *tdb) /* Look for a parent who is a composite or multiTrack track and return that. Failing that * just return self. */ { struct trackDb *parent = tdbGetContainer(tdb); if (parent != NULL) return parent; else return tdb; } boolean trackDbUpdateOldTag(char **pTag, char **pVal) /* Look for obscolete tags and update them to new format. Return TRUE if any update * is done. Will allocate fresh memory for new tag and val if updated. */ { char *tag = *pTag; char *val = *pVal; boolean updated = FALSE; if (sameString(tag, "subTrack")) { tag = "parent"; updated = TRUE; } #ifdef SOON else if (sameString(tag, "compositeTrack")) { tag = "container"; val = "composite"; updated = TRUE; } else if (sameString(tag, "superTrack")) { if (sameWord(val, "on")) { tag = "container"; val = "folder"; } else { tag = "parent"; } updated = TRUE; } #endif /* SOON */ if (updated) { *pTag = cloneString(tag); *pVal = cloneString(val); } return updated; } static struct tdbExtras *tdbExtrasNew() // Return a new empty tdbExtras { struct tdbExtras *extras; AllocVar(extras); // Note no need for extras = AllocVar(extras) // Initialize any values that need an "empty" state extras->fourState = TDB_EXTRAS_EMPTY_STATE; // I guess it is 5 state! // pointers are NULL and booleans are FALSE by default return extras; } void tdbExtrasFree(struct tdbExtras **pTdbExtras) // Frees the tdbExtras structure { // Developer, add intelligent routines to free structures // NOTE: For now just leak contents, because complex structs would also leak freez(pTdbExtras); } static struct tdbExtras *tdbExtrasGet(struct trackDb *tdb) // Returns tdbExtras struct, initializing if needed. { if (tdb->tdbExtras == NULL) // Temporarily add this back in because Angie see asserts popping. tdb->tdbExtras = tdbExtrasNew(); return tdb->tdbExtras; } int tdbExtrasFourState(struct trackDb *tdb) // Returns subtrack four state if known, else TDB_EXTRAS_EMPTY_STATE { struct tdbExtras *extras = tdb->tdbExtras; if (extras) return extras->fourState; return TDB_EXTRAS_EMPTY_STATE; } void tdbExtrasFourStateSet(struct trackDb *tdb,int fourState) // Sets subtrack four state { tdbExtrasGet(tdb)->fourState = fourState; } boolean tdbExtrasReshapedComposite(struct trackDb *tdb) // Returns TRUE if composite has been declared as reshaped, else FALSE. { struct tdbExtras *extras = tdb->tdbExtras; if (extras) return extras->reshapedComposite; return FALSE; } void tdbExtrasReshapedCompositeSet(struct trackDb *tdb) // Declares that the composite has been reshaped. { tdbExtrasGet(tdb)->reshapedComposite = TRUE; } struct mdbObj *tdbExtrasMdb(struct trackDb *tdb) // Returns mdb metadata if already known, else NULL { struct tdbExtras *extras = tdb->tdbExtras; if (extras) return extras->mdb; return NULL; } void tdbExtrasMdbSet(struct trackDb *tdb,struct mdbObj *mdb) // Sets the mdb metadata structure for later retrieval. { tdbExtrasGet(tdb)->mdb = mdb; } struct _membersForAll *tdbExtrasMembersForAll(struct trackDb *tdb) // Returns composite view/dimension members for all, else NULL. { struct tdbExtras *extras = tdb->tdbExtras; if (extras) return extras->membersForAll; return NULL; } void tdbExtrasMembersForAllSet(struct trackDb *tdb, struct _membersForAll *membersForAll) // Sets the composite view/dimensions members for all for later retrieval. { tdbExtrasGet(tdb)->membersForAll = membersForAll; } members_t *tdbExtrasMembers(struct trackDb *tdb, char *groupNameOrTag) // Returns subtrack members if already known, else NULL { struct tdbExtras *extras = tdbExtrasGet(tdb); if (extras->membersHash == NULL) extras->membersHash = newHash(5); return (members_t *)hashFindVal(extras->membersHash, groupNameOrTag); } void tdbExtrasMembersSet(struct trackDb *tdb, char *groupNameOrTag, members_t *members) // Sets the subtrack members for later retrieval. { hashAdd(tdbExtrasGet(tdb)->membersHash, groupNameOrTag, members); } struct _membership *tdbExtrasMembership(struct trackDb *tdb) // Returns subtrack membership if already known, else NULL { struct tdbExtras *extras = tdb->tdbExtras; if (extras) return extras->membership; return tdbExtrasGet(tdb)->membership; } void tdbExtrasMembershipSet(struct trackDb *tdb,struct _membership *membership) // Sets the subtrack membership for later retrieval. { tdbExtrasGet(tdb)->membership = membership; } char *tdbBigFileName(struct sqlConnection *conn, struct trackDb *tdb) // Return file name associated with bigWig. Do a freeMem on returned string when done. { char *ret = NULL; char *fileName = trackDbSetting(tdb, "bigDataUrl"); // always takes precedence if (fileName != NULL) ret = cloneString(fileName); else if (conn != NULL) { char query[256]; sqlSafef(query, sizeof(query), "select fileName from %s", tdb->table); ret = sqlQuickString(conn, query); } // replace /gbdb if needed char *rewriteRet = hReplaceGbdb(ret); freeMem(ret); return rewriteRet; } static void rTdbTreeAllowPack(struct trackDb *tdb) // Force this tdb and all children to allow pack/squish { tdb->canPack = TRUE; struct trackDb *childTdb = tdb->subtracks; for ( ;childTdb!=NULL;childTdb=childTdb->next) rTdbTreeAllowPack(childTdb); } boolean rTdbTreeCanPack(struct trackDb *tdb) // Trees can pack as all or none, since they can share vis. { if (tdb->canPack == FALSE) { // If a single child of a composite can pack, then the entire composite can if (tdbIsComposite(tdb) || tdbIsCompositeView(tdb)) { struct trackDb *childTdb = tdb->subtracks; for ( ;childTdb!=NULL;childTdb=childTdb->next) { if (rTdbTreeCanPack(childTdb)) { tdb->canPack = TRUE; break; } } } // At the composite level if one was found then set the whole tree. if (tdb->canPack && tdbIsComposite(tdb)) rTdbTreeAllowPack(tdb); } return tdb->canPack; } void tdbSetCartVisibility(struct trackDb *tdb, struct cart *cart, char *vis) { // Set visibility in the cart. Handles all the complications necessary for subtracks. char buf[512]; cartSetString(cart, tdb->track, vis); if (tdbIsSubtrack(tdb)) { safef(buf,sizeof buf, "%s_sel", tdb->track); cartSetString(cart, buf, "1"); // Will reshape composite struct trackDb *composite = tdbGetComposite(tdb); if (composite && tdbIsSuperTrackChild(composite)) { safef(buf,sizeof buf, "%s_sel", composite->track); cartSetString(cart, buf, "1"); // Will reshape supertrack } } else if (tdbIsSuperTrackChild(tdb)) // solo track { safef(buf,sizeof buf, "%s_sel", tdb->track); cartSetString(cart, buf, "1"); // Will reshape supertrack } } boolean trackDbSettingBlocksConfiguration(struct trackDb *tdb, boolean onlyAjax) // Configuration dialogs may be explicitly blocked in tracDb settings { if (SETTING_IS_OFF(trackDbSettingClosestToHome(tdb, "configurable"))) return TRUE; // never configurable return (onlyAjax && SETTING_IS_OFF(trackDbSettingClosestToHome(tdb,"configureByPopup"))); } struct slPair *tabSepMetaPairs(char *tabSepMeta, struct trackDb *tdb, char *metaTag) { // If there's no file, there's no data. if (tabSepMeta == NULL) return NULL; // If the trackDb entry doesn't have a foreign key, there's no data. if (metaTag == NULL) return NULL; static char *cachedTableName = NULL; static struct hash *cachedHash = NULL; static struct fieldedTable *cachedTable = NULL; // Cache this table because there's a good chance we'll get called again with it. if ((cachedTableName == NULL) || differentString(tabSepMeta, cachedTableName)) { char *requiredFields[] = {"meta"}; cachedTable = fieldedTableFromTabFile(tabSepMeta, NULL, requiredFields, sizeof requiredFields / sizeof (char *)); cachedHash = fieldedTableUniqueIndex(cachedTable, requiredFields[0]); cachedTableName = cloneString(tabSepMeta); } // Look for this tag in the metadata. struct fieldedRow *fr = hashFindVal(cachedHash, metaTag); if (fr == NULL) return NULL; int ii; struct slPair *pairList = NULL; for(ii=0; ii < cachedTable->fieldCount; ii++) { char *fieldName = cachedTable->fields[ii]; char *fieldVal = fr->row[ii]; if (!isEmpty(fieldVal)) slAddHead(&pairList, slPairNew(fieldName, cloneString(fieldVal))); } slReverse(&pairList); return pairList; } int cmpPairAlpha(const void *e1, const void *e2) /* used with slSort to sort slPairs alphabetically */ { const struct slPair *a = *((struct slPair **)e1); const struct slPair *b = *((struct slPair **)e2); return strcmp(a->name, b->name); } static struct slPair *convertNameValueString(char *string) /* Convert a string composed of name=value pairs separated by white space. */ { char *clone = cloneString(string); int count = chopByWhiteRespectDoubleQuotes(clone,NULL,0); char **words = needMem(sizeof(char *) * count); count = chopByWhiteRespectDoubleQuotes(clone,words,count); if (count < 1 || words[0] == NULL) { errAbort("This is not formatted var=val pairs:\n\t%s\n",string); } int ix; struct slPair *pairList = NULL, *pair; for (ix = 0;ix