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/inc/maf.h src/inc/maf.h index 095a514c85e..33d2c6e5912 100644 --- src/inc/maf.h +++ src/inc/maf.h @@ -66,35 +66,59 @@ int size; /* Size in sequence (does not include dashes). */ char *text; /* The sequence including dashes. */ char *quality; /* The quality data (same length as text, or NULL). */ char leftStatus; /* the syntenic status of the alignment before us vis a vis ourselves */ int leftLen; /* length related information for the previous alignment for the species */ char rightStatus; /* the syntenic status of the alignment after us vis a vis ourselves */ int rightLen; /* length related information for the following alignment for the species */ }; void mafCompFree(struct mafComp **pObj); /* Free up a maf component. */ void mafCompFreeList(struct mafComp **pList); /* Free up a list of maf components. */ -char *mafCompGetSrcDb(struct mafComp *mc, char *buf, int bufSize); -/* parse the srcDb name from the mafComp src name, return NULL if no srcDb */ - -char *mafCompGetSrcName(struct mafComp *mc); -/* parse the src sequence name from the mafComp src name */ +char *mafSplitSrcGetChrom(char *src, char *database); +/* src is one of: chrom, db|chrom, or db.chrom. Return a pointer to the chrom part and + * truncate src in place so it holds only the db. See mafSrcDb for the simpler + * non-destructive first-dot-only version used by the track display code. + * + * The hard part is that BOTH db and chrom may themselves contain dots, so the db/chrom + * split is not simply "the first dot" or "the middle dot". We resolve it like this, + * in order: + * 1. A pipe '|' is always an explicit, unambiguous separator -- use it if present. + * 2. No dot at all -> the whole string is the chrom, and src is left untouched, so a + * caller that wants the db gets the whole string too. + * 3. If the caller passed the reference 'database' and src begins with "<database>.", + * split right there. This nails the master component whether or not database itself + * contains a dot (e.g. a GenArk db like GCF_000001405.40). The match must end at a + * dot, so "hg38" does not claim "hg38Patch11.chr1". 'database' is trusted as + * given: it wins over the GCA_/GCF_ rule below. + * 4. A GenArk accession db (GCA_/GCF_) is the only db that legitimately carries an + * internal dot -- its accession.version adds exactly one -- so its db ends at the + * SECOND dot and the chrom follows. A GCA_/GCF_ name with no second dot has no + * chrom to hand back, so it falls through to step 5 ("GCA_123.1" -> db "GCA_123", + * chrom "1"). + * 5. Every other db (hg38, mm10, a species name, ...) has no dot, so split at the FIRST + * dot; anything after it (including further dots, e.g. an accession.version chrom) is + * the chrom. + * + * There is no universal way to resolve an ambiguous multi-dot name from the dots alone: if + * the db part is itself a dotted accession that is not a GenArk GCA_/GCF_ id (e.g. a bare + * INSDC accession used as the assembly), step 5 may split it in the wrong place. For those, + * use the pipe form db|chrom, which is always unambiguous. */ struct mafRegDef /* MAF region definition (r line) */ { char *type; // type of definition, one of constants below (not malloced) int size; // region size char *id; // identifiers }; extern char *mafRegDefTxUpstream; // transcription start size upstream region struct mafRegDef *mafRegDefNew(char *type, int size, char *id); /* construct a new mafRegDef object */ void mafRegDefFree(struct mafRegDef **mrdPtr); /* Free a mafRegDef object */