98faa189349f1bb9b033f314ffe327541bacf290 chmalee Tue Mar 31 15:17:30 2026 -0700 Add a new hgFindSpec setting, searchItemLabel, that allows using hgFindSpec defined labels (with variable substitution) as the label for each line of a search result. This only works for bigBed tracks. refs #37299 diff --git src/lib/common.c src/lib/common.c index a06ee397ba2..16f4f1317ef 100644 --- src/lib/common.c +++ src/lib/common.c @@ -1,22 +1,23 @@ /* Commonly used routines in a wide range of applications. * Strings, singly-linked lists, and a little file i/o. * * This file is copyright 2002 Jim Kent, but license is hereby * granted for all use - public, private or commercial. */ #include "common.h" +#include "dystring.h" #include "errAbort.h" #include "portable.h" #include "linefile.h" #include "hash.h" #include "sqlNum.h" void *cloneMem(void *pt, size_t size) /* Allocate a new buffer of given size, and copy pt to it. */ { void *newPt = needLargeMem(size); memcpy(newPt, pt, size); return newPt; } static char *cloneStringZExt(const char *s, int size, int copySize) @@ -1808,30 +1809,76 @@ { strLen = ptr - string; strcpy(resultPtr, string); string = ptr + oldLen; resultPtr += strLen; strcpy(resultPtr, new); resultPtr += newLen; ptr = strstr(string, old); } strcpy(resultPtr, string); return result; } +char *replaceFieldInPattern(char *pattern, int fieldCount, char **fieldNames, char **fieldVals) +/* Given a pattern containing $fieldName or ${fieldName} variable references, replace each + * variable with the corresponding value from fieldVals. The ${} form prevents ambiguity + * when one field name is a prefix of another (e.g. "chrom" vs "chromStart"). */ +{ +int i; +struct dyString *result = dyStringNew(256), *sub = NULL; +dyStringAppend(result, pattern); +for (i = 0; i < fieldCount; ++i) + { + if (fieldVals[i] == NULL || fieldNames[i] == NULL) + continue; + + char *field = fieldNames[i]; + int fieldLen = strlen(field); + char *bareSpec = needMem(fieldLen + 2); + char *bracedSpec = needMem(fieldLen + 4); + *bareSpec = '$'; + *bracedSpec = '$'; + bracedSpec[1] = '{'; + strcpy(bareSpec + 1, field); + strcpy(bracedSpec + 2, field); + bracedSpec[fieldLen + 2] = '}'; + bracedSpec[fieldLen + 3] = '\0'; + + if (stringIn(bracedSpec, result->string)) + { + sub = dyStringSub(result->string, bracedSpec, fieldVals[i]); + dyStringFree(&result); + result = sub; + sub = NULL; + } + // the user may have both a ${} enclosed instance and a non-enclosed one + // also note that if the value substituted above is the field name itself with + // a leading $, then we will substitute again + sub = dyStringSub(result->string, bareSpec, fieldVals[i]); + + dyStringFree(&result); + freeMem(bareSpec); + freeMem(bracedSpec); + result = sub; + sub = NULL; + } +return dyStringCannibalize(&result); +} + int strSwapStrs(char *string, int sz,char *oldStr, char *newStr) /* Swaps all occurrences of the old with the new in string. Need not be same size Swaps in place but restricted by sz. Returns count of swaps or -1 for sz failure. */ { // WARNING: called at low level, so no errors allowed. int count = 0; char *p=NULL; for(p=strstr(string,oldStr);p!=NULL;p=strstr(p+strlen(oldStr),oldStr)) count++; if (count == 0) return 0; if((strlen(string)+(count*(strlen(newStr) - strlen(oldStr))))>=sz) return -1; for(p=strstr(string,oldStr);p!=NULL;p=strstr(p+strlen(newStr),oldStr)) {