981b68955aada90b686af9ad7699e542c0ed24ff kate Tue Apr 13 12:22:00 2021 -0700 Extend #insert support in hgTrackDb to support variable substitution in filename. Prompted by single cell composite tracks, so subtracks can share a description page with subtrack-specific sections inserted. refs #27365 diff --git src/hg/makeDb/hgTrackDb/hgTrackDb.c src/hg/makeDb/hgTrackDb/hgTrackDb.c index b98e6cf..27113e8 100644 --- src/hg/makeDb/hgTrackDb/hgTrackDb.c +++ src/hg/makeDb/hgTrackDb/hgTrackDb.c @@ -376,89 +376,96 @@ // This regular expression matches an HTML comment that contains a // server-side-include-like syntax that tells us to replace the HTML // comment with the contents of some other HTML file (relative path) // [which itself may include such HTML comments]. // This regex has substrs: // * substrs[0] is the entire match // * substrs[1] is an optional '#if (db==xxxYyy1)' before #insert // * substrs[2] is the database from the #if, or empty if substrs[1] is empty // * substrs[3] is the relative path to pull in. const static char *insertHtmlRegex = ""; -static char *readHtmlRecursive(char *fileName, char *database) +static char *readHtmlRecursive(char *fileName, char *database, struct trackDb *tdb) /* Slurp in an html file. Wherever it contains insertHtmlRegex, recursively slurp that in * and replace insertHtmlRegex with the contents. */ { char *html; readInGulp(fileName, &html, NULL); if (isEmpty(html)) return html; regmatch_t substrs[4]; while (regexMatchSubstr(html, insertHtmlRegex, substrs, ArraySize(substrs))) { struct dyString *dy = dyStringNew(0); // All text before the regex match: dyStringAppendN(dy, html, substrs[0].rm_so); // Is there an #if before the #insert ? boolean doInsert = TRUE; if (substrs[1].rm_so != -1 && (! sameStringN(database, html+substrs[2].rm_so, (substrs[2].rm_eo - substrs[2].rm_so)))) doInsert = FALSE; if (doInsert) { // Recursively pull in inserted file contents from relative path, replacing regex match: char dir[PATH_LEN]; splitPath(fileName, dir, NULL, NULL); char insertFileName[PATH_LEN+FILENAME_LEN]; safecpy(insertFileName, sizeof(insertFileName), dir); safencat(insertFileName, sizeof(insertFileName), html+substrs[3].rm_so, (substrs[3].rm_eo - substrs[3].rm_so)); + char *varSubFilename = hVarSubst("readHtmlRecursive: var substitution error", + tdb, database, insertFileName); + if (varSubFilename) + safecpy(insertFileName, sizeof(insertFileName), varSubFilename); + if (differentString(fileName, insertFileName)) // protect against infinite loop + { if (!fileExists(insertFileName)) errAbort("readHtmlRecursive: relative path '%s' (#insert'ed in %s) not found", insertFileName, fileName); - char *insertedText = readHtmlRecursive(insertFileName, database); + char *insertedText = readHtmlRecursive(insertFileName, database, tdb); dyStringAppend(dy, insertedText); freez(&insertedText); } + } // All text after the regex match: dyStringAppend(dy, html+substrs[0].rm_eo); freez(&html); html = dyStringCannibalize(&dy); } return html; } static void layerOnHtml(char *dirName, struct trackDb *tdbList, char *database) /* Read in track HTML call bottom-up. */ { char fileName[512]; struct trackDb *td; for (td = tdbList; td != NULL; td = td->next) { if (isEmpty(td->html)) { char *htmlName = trackDbSetting(td, "html"); if (htmlName == NULL) htmlName = td->track; safef(fileName, sizeof(fileName), "%s/%s.html", dirName, htmlName); if (fileExists(fileName)) { - td->html = readHtmlRecursive(fileName, database); + td->html = readHtmlRecursive(fileName, database, td); // Check for note ASCII characters at higher levels of verboseness. // Normally, these are acceptable ISO-8859-1 characters if ((verboseLevel() >= 2) && hasNonAsciiChars(td->html)) verbose(2, "Note: non-printing or non-ASCII characters in %s\n", fileName); } } } } static char *subsituteVariables(struct hashEl *el, char *database) /* substitute variables where supported */ { char* val = (char*)el->val; char *name = el->name; /* Only some attribute support variable substitution, at least for now