1ff2e18ba5e50dd2d1becd3cd6a25343578c10b8
markd
  Tue Apr 21 14:09:04 2026 -0700
rework of htslib/UDC integration to use htslib hfile driver mechanism

diff --git src/hg/hgTables/bam.c src/hg/hgTables/bam.c
index c60ce61ed6a..f746aea50a3 100644
--- src/hg/hgTables/bam.c
+++ src/hg/hgTables/bam.c
@@ -233,33 +233,37 @@
     errAbort("Reached output limit of %d data values, please make region smaller,\n\tor set a higher output line limit with the filter settings.", bigFileMaxOutput());
 /* Clean up and exit. */
 hashFree(&fieldHash);
 freeMem(fieldArray);
 freeMem(columnArray);
 }
 
 int cigarWidth(char *cigar, int cigarSize)
 /* Return width of alignment as encoded in cigar format string. */
 {
 int tLength=0;
 char *s, *end = cigar + cigarSize;
 s = cigar;
 while (s < end)
     {
+    while (s < end && isspace(*s))
+        s++;
+    if (s >= end)
+        break;
     int digCount = countLeadingDigits(s);
     if (digCount <= 0)
-        errAbort("expecting number got %s in cigarWidth", s);
+        errAbort("expecting number got '%s' in cigarWidth", s);
     int n = atoi(s);
     s += digCount;
     char op = *s++;
     switch (op)
 	{
 	case '=': // match (gapless aligned block)
 	case 'X': // mismatch (gapless aligned block)
 	case 'M': // match or mismatch (gapless aligned block)
 	    tLength += n;
 	    break;
 	case 'I': // inserted in query
 	    break;
 	case 'D': // deleted from query
 	case 'N': // long deletion from query (intron as opposed to small del)
 	    tLength += n;
@@ -346,31 +350,31 @@
 {
 /* Read 10000 items from bam file,  or if they ask for a big list, then 4x what they ask for. */
 char *fileName = bamFileName(table, conn, NULL);
 
 samfile_t *fh = bamOpen(fileName, NULL);
 struct lm *lm = lmInit(0);
 int orderedCount = count * 4;
 if (orderedCount < 10000)
     orderedCount = 10000;
 bam_hdr_t *header = sam_hdr_read(fh);
 if (fh->format.format == cram)
     {
     char *cacheDir = cfgOption("cramRef");
     struct trackDb *tdb = findTdbForTable(database, curTrack, table, ctLookupName);
     char *refUrl = trackDbSetting(tdb, "refUrl");
-    cram_set_cache_url(fh, cacheDir, refUrl);  
+    cramCheckRefs(fh, refUrl, cacheDir);
     }
 struct samAlignment *sam, *samList = bamReadNextSamAlignments(fh, header, orderedCount, lm);
 
 /* Shuffle list and extract qNames from first count of them. */
 shuffleList(&samList);
 struct slName *randomIdList = NULL;
 int i;
 for (i=0, sam = samList; i<count && sam != NULL; ++i, sam = sam->next)
      slNameAddHead(&randomIdList, sam->qName);
 
 /* Clean up and go home. */
 lmCleanup(&lm);
 bamClose(&fh);
 freez(&fileName);
 return randomIdList;
@@ -422,31 +426,31 @@
     {
     hPrintf("<TH>%s</TH>", col->name);
     ++colIx;
     }
 hPrintf("</TR>\n");
 
 /* Fetch sample rows. */
 samfile_t *fh = bamOpen(fileName, NULL);
 struct lm *lm = lmInit(0);
 bam_hdr_t *header = sam_hdr_read(fh);
 if (fh->format.format == cram)
     {
     char *cacheDir = cfgOption("cramRef");
     struct trackDb *tdb = findTdbForTable(database, curTrack, table, ctLookupName);
     char *refUrl = trackDbSetting(tdb, "refUrl");
-    cram_set_cache_url(fh, cacheDir, refUrl);  
+    cramCheckRefs(fh, refUrl, cacheDir);
     }
 struct samAlignment *sam, *samList = bamReadNextSamAlignments(fh, header, 10, lm);
 
 /* Print sample lines. */
 char *row[SAMALIGNMENT_NUM_COLS];
 char numBuf[BAM_NUM_BUF_SIZE];
 for (sam=samList; sam != NULL; sam = sam->next)
     {
     samAlignmentToRow(sam, numBuf, row);
     hPrintf("<TR>");
     for (colIx=0; colIx<colCount; ++colIx)
         {
         hPrintf("<TD>");
         xmlEscapeStringToFile(row[colIx], stdout);
         hPrintf("</TD>");