9da759daff220e6433da737debffcc2e81f4de18 chmalee Tue Aug 11 09:52:37 2026 -0700 Fixes from code review, refs #38064 diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c index fca35355391..387b2028ea5 100644 --- src/hg/hgTracks/simpleTracks.c +++ src/hg/hgTracks/simpleTracks.c @@ -4282,47 +4282,52 @@ struct itemColorSpec /* A user-chosen color for a single item, set via the right-click "Color this item" menu. */ { Color color; /* The chosen color. */ boolean wholeItem; /* TRUE to recolor the item glyph, FALSE for a background highlight. */ }; static struct itemColorSpec *itemColorLookup(struct track *tg, void *item) /* Return the user-chosen color spec for this item, or NULL. Matches on mapItemName, itemName, or * genomic position ("pos:chrom:start-end"), the same identities the JS uses to build the record. * Nameless items (e.g. bed3) have no usable name, so the position key identifies them. */ { if (itemColorHash == NULL) return NULL; -char key[2048]; +static struct dyString *key = NULL; +if (!key) + key = dyStringNew(0); struct itemColorSpec *spec = NULL; if (tg->mapItemName != NULL) { - safef(key, sizeof key, "%s\t%s", tg->track, tg->mapItemName(tg, item)); - spec = hashFindVal(itemColorHash, key); + dyStringClear(key); + dyStringPrintf(key, "%s\t%s", tg->track, tg->mapItemName(tg, item)); + spec = hashFindVal(itemColorHash, dyStringContents(key)); } if (spec == NULL && tg->itemName != NULL) { - safef(key, sizeof key, "%s\t%s", tg->track, tg->itemName(tg, item)); - spec = hashFindVal(itemColorHash, key); + dyStringClear(key); + dyStringPrintf(key, "%s\t%s", tg->track, tg->itemName(tg, item)); + spec = hashFindVal(itemColorHash, dyStringContents(key)); } if (spec == NULL && tg->itemStart != NULL && tg->itemEnd != NULL) { - safef(key, sizeof key, "%s\tpos:%s:%d-%d", tg->track, chromName, + dyStringClear(key); + dyStringPrintf(key, "%s\tpos:%s:%d-%d", tg->track, chromName, tg->itemStart(tg, item), tg->itemEnd(tg, item)); - spec = hashFindVal(itemColorHash, key); + spec = hashFindVal(itemColorHash, dyStringContents(key)); } return spec; } boolean itemColorOverride(struct track *tg, void *item, Color *retColor, boolean *retWholeItem) /* If the user set a per-item color for this item (via right-click), return TRUE and fill in the * color and whether it recolors the whole item; otherwise return FALSE. Lets non-linkedFeatures * draw routines (e.g. bedDrawSimpleAt) honor right-click item colors. */ { struct itemColorSpec *spec = itemColorLookup(tg, item); if (spec == NULL) return FALSE; if (retColor != NULL) *retColor = spec->color; if (retWholeItem != NULL) @@ -16349,51 +16354,55 @@ hgFindMatchesShowHighlight = TRUE; // default to showing the highlight searched item label. } void createItemColorHash() /* Read the itemColors cart variable into a hash of per-item colors keyed by "track\titemName", * keeping only records for the current database. The cart format is db#track#mode#itemName#hexColor * records joined by '|', where mode is "item" (recolor the glyph) or "bg" (background highlight). * The color is the last '#' field so that item names containing '#' are tolerated; item names * containing '|' are not supported. The cart value is user-editable, so malformed records (bad * color, missing fields) are skipped rather than aborting the image. */ { char *itemColors = cartOptionalString(cart, "itemColors"); if (isEmpty(itemColors)) return; struct slName *recordList = slNameListFromString(itemColors, '|'), *record; +struct dyString *colorSpec = dyStringNew(0); +struct dyString *keyStr = dyStringNew(0); for (record = recordList; record != NULL; record = record->next) { char *p = record->name; char *db = cloneNextWordByDelimiter(&p, '#'); char *track = cloneNextWordByDelimiter(&p, '#'); char *mode = cloneNextWordByDelimiter(&p, '#'); char *lastHash = (p != NULL) ? strrchr(p, '#') : NULL; if (!isEmpty(db) && !isEmpty(track) && !isEmpty(mode) && lastHash != NULL && sameString(db, database)) { *lastHash = '\0'; char *itemName = p; char *hex = lastHash + 1; - char colorSpec[16]; - safef(colorSpec, sizeof colorSpec, "#%s", hex); + dyStringPrintf(colorSpec, "#%s", hex); unsigned rgb; - if (!isEmpty(itemName) && htmlColorForCode(colorSpec, &rgb)) + if (!isEmpty(itemName) && htmlColorForCode(dyStringContents(colorSpec), &rgb)) { struct itemColorSpec *spec; AllocVar(spec); spec->color = bedColorToGfxColor(rgb); spec->wholeItem = sameString(mode, "item"); - char key[2048]; - safef(key, sizeof key, "%s\t%s", track, itemName); + dyStringPrintf(keyStr, "%s\t%s", track, itemName); if (itemColorHash == NULL) itemColorHash = newHash(0); - hashAdd(itemColorHash, key, spec); + hashAdd(itemColorHash, dyStringContents(keyStr), spec); } + dyStringClear(keyStr); + dyStringClear(colorSpec); } freeMem(db); freeMem(track); freeMem(mode); } +dyStringFree(&keyStr); +dyStringFree(&colorSpec); slFreeList(&recordList); }