2070aedea88da26aee0af3e2fd867b67140b09b5
lrnassar
  Wed Aug 5 16:59:19 2026 -0700
Move the maf sequence-name splitter into jkweb so both summary tools share one copy. refs #37928

mafSplitSrcGetChrom existed as two independent copies, in hgLoadMafSummary.c and
mafToBigMafSummary.c, and they had diverged: only the first had the GenArk accession
rule added by 2db6bab8db0. It now lives in src/lib/maf.c, with the rules documented
in maf.h.

mafToBigMafSummary therefore picks up the GenArk rule it was missing, so a dotted
GenArk name like GCA_009914755.4.CM034974.1 now keeps its accession version instead of
dropping it, which matches what hprc90waySummary already holds.

Also removes mafCompGetSrcDb and mafCompGetSrcName from maf.c and maf.h. Both were
first-dot splitters with no callers anywhere in the tree.

diff --git src/lib/maf.c src/lib/maf.c
index 2930fa43b4d..6141c5ae922 100644
--- src/lib/maf.c
+++ src/lib/maf.c
@@ -390,52 +390,76 @@
 }
 
 void mafCompFreeList(struct mafComp **pList)
 /* Free up a list of maf components. */
 {
 struct mafComp *el, *next;
 
 for (el = *pList; el != NULL; el = next)
     {
     next = el->next;
     mafCompFree(&el);
     }
 *pList = NULL;
 }
 
-char *mafCompGetSrcDb(struct mafComp *mc, char *buf, int bufSize)
-/* parse the srcDb name from the mafComp src name, return NULL if no srcDb */
+char *mafSplitSrcGetChrom(char *src, char *database)
+/* Split a maf sequence name into its db and chrom: truncate src in place so it holds only
+ * the db, and return a pointer to the chrom.  The numbered steps below are spelled out in
+ * maf.h, which is the authority on the rules.  See mafSrcDb for the simpler
+ * non-destructive first-dot-only version used by the track display code. */
 {
-char *e = strchr(mc->src, '.');
-if (e == NULL)
-    return NULL;
-int len = e - mc->src;
-if (len >= bufSize-1)
-    errAbort("srcDb name in \"%s\" overflows buffer length of %d", mc->src, bufSize);
-strncpy(buf, mc->src, len);
-buf[len] = '\0';
-return buf;
+/* 1. A pipe is always an explicit db|chrom separator. */
+char *pipe = strchr(src, '|');
+if (pipe != NULL)
+    {
+    *pipe = '\0';
+    return pipe + 1;
     }
 
-char *mafCompGetSrcName(struct mafComp *mc)
-/* parse the src sequence name from the mafComp src name */
+/* 2. No separator at all: the whole string is the chrom, and src is left whole. */
+char *dot1 = strchr(src, '.');
+if (dot1 == NULL)
+    return src;
+
+/* 3. When we know the reference database and src starts with "<database>.", split there. */
+if (database != NULL)
     {
-char *e = strchr(mc->src, '.');
-if (e == NULL)
-    return mc->src;
-else
-    return e+1;
+    int dbLen = strlen(database);
+    if (startsWith(database, src) && src[dbLen] == '.')
+        {
+        src[dbLen] = '\0';
+        return src + dbLen + 1;
+        }
+    }
+
+/* 4. A GenArk accession db (GCA_/GCF_) carries one internal dot (accession.version),
+ *    so the db ends at the second dot. */
+if (startsWith("GCA_", src) || startsWith("GCF_", src))
+    {
+    char *dot2 = strchr(dot1 + 1, '.');
+    if (dot2 != NULL)
+        {
+        *dot2 = '\0';
+        return dot2 + 1;
+        }
+    // accession with no chrom after the version: fall through to the first-dot split
+    }
+
+/* 5. Ordinary db with no dot: split at the first dot. */
+*dot1 = '\0';
+return dot1 + 1;
 }
 
 int mafPlusStart(struct mafComp *comp)
 /* Return start relative to plus strand of src. */
 {
 if (comp->strand == '-') 
     return comp->srcSize - (comp->start + comp->size);
 else
     return comp->start;
 }
 
 void mafAliFree(struct mafAli **pObj)
 /* Free up a maf alignment. */
 {
 struct mafAli *obj = *pObj;