61dc7885a5f1001e2bc189501379088f2b53379d galt Mon Feb 23 15:42:36 2026 -0800 fixes things found automated codereview. for bigBedCmdSupport lib moved slAddHead, removed stray debugmsg and fixed comment and added static keyword. fixed bigChainToChain chromFound = FALSE, removed stray test makefile, fixed existing typo "tines", and added a missing space after issing space before optionMultiVal(). refs #37146 diff --git src/lib/bigBedCmdSupport.c src/lib/bigBedCmdSupport.c index 32235727e69..92401e9a21e 100644 --- src/lib/bigBedCmdSupport.c +++ src/lib/bigBedCmdSupport.c @@ -1,215 +1,213 @@ /* bigBedCmdSupport - functions to support writing bigBed related commands. */ /* Copyright (C) 2022 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "bigBedCmdSupport.h" #include "basicBed.h" #include "options.h" #include "hash.h" static void outputHeader(struct bbiFile *bbi, FILE *f, char startChar) /* output a header from the autoSql in the file, startChar is '#' or 0 to omit */ { char *asText = bigBedAutoSqlText(bbi); if (asText == NULL) errAbort("bigBed files does not contain an autoSql schema"); struct asObject *asObj = asParseText(asText); char sep = startChar; for (struct asColumn *asCol = asObj->columnList; asCol != NULL; asCol = asCol->next) { if (sep != '\0') fputc(sep, f); fputs(asCol->name, f); sep = '\t'; } fputc('\n', f); } void bigBedCmdOutputHeader(struct bbiFile *bbi, FILE *f) /* output a autoSql-style header from the autoSql in the file */ { outputHeader(bbi, f, '#'); } void bigBedCmdOutputTsvHeader(struct bbiFile *bbi, FILE *f) /* output a TSV-style header from the autoSql in the file */ { outputHeader(bbi, f, '\0'); } struct hash *makeChromHash(struct bbiChromInfo *chromList) // make a fast searchable hash from chromList { struct hash *chromHash = hashNew(10); struct bbiChromInfo *chrom; for (chrom = chromList; chrom != NULL; chrom = chrom->next) { hashAdd(chromHash, cloneString(chrom->name), NULL); } return chromHash; } static struct bed *bed3FromPositionString(char *line) /* Read positions line and return bed 3. */ { char *chrom; int start, end; struct bed *bed = NULL; /* Convert input to bed record */ char *val = cloneString(line); mustParseRange(val, &chrom, &start, &end); // does not subtract 1 - verbose(1,"bed3FromPositionString after mustParseRange chrom=%s\n", chrom); // used to use parseRegion which checks for overflow, // but only catches start < 1 because of integer overflow. if (start < 1) errAbort("invalid range, start=%d < 1, but first base is 1 or more", start); --start; if (start > end) errAbort("invalid range, (start - 1)=%d > end=%d", start, end); AllocVar(bed); bed->chrom=cloneString(chrom); bed->chromStart=start; bed->chromEnd=end; freez(&val); return bed; } struct bed *bed3FromPositions(char *fileName) /* Read positions file and retrun bed 3 list. */ { struct lineFile *lf = lineFileOpen(fileName, TRUE); struct bed *bed = NULL, *bedList = NULL; char *line; /* Convert input to bed file */ while (lineFileNextReal(lf, &line)) { bed = bed3FromPositionString(line); - } slAddHead(&bedList, bed); + } lineFileClose(&lf); return bedList; } -struct bed *bedLoad3Plus(char *fileName) +static struct bed *bedLoad3Plus(char *fileName) /* Determines how many fields are in a bedFile and load all beds from * a tab-separated file. Dispose of this with bedFreeList(). * Small change by Michael to require only 3 or more fields. Meaning we will accept bed3 */ { struct bed *list = NULL; struct lineFile *lf = lineFileOpen(fileName, TRUE); char *line, *row[bedKnownFields]; while (lineFileNextReal(lf, &line)) { int numFields = chopByWhite(line, row, ArraySize(row)); if (numFields < 3) errAbort("file %s doesn't appear to be in bed format. At least 3 fields required, got %d", fileName, numFields); slAddHead(&list, bedLoadN(row, numFields)); } lineFileClose(&lf); slReverse(&list); return list; } struct bed *bedLoad3FromRangeOption(struct slName *ranges) /* Determines how many fields are in a bedFile and load all beds from - * a tab-separated file. Dispose of this with bedFreeList(). - * Small change by Michael to require only 3 or more fields. Meaning we will accept bed3 + * possibly multiple -range parameters. Dispose of this with bedFreeList(). */ { struct slName *range = NULL; struct bed *bed, *list = NULL; char *row[bedKnownFields]; for(range=ranges; range; range=range->next) { if (strchr(range->name, ':')) { bed = bed3FromPositionString(range->name); } else { char *val=cloneString(range->name); int numFields = chopByWhite(val, row, ArraySize(row)); if (numFields != 3) errAbort("range %s doesn't appear to be in bed format. 3 fields required, got %d", range->name, numFields); bed = bedLoadN(row, numFields); freez(&val); } slAddHead(&list, bed); } slReverse(&list); return list; } void genericBigToNonBigFromBed(struct bbiFile *bbi, struct hash *chromHash, char *bedFileName, FILE *outFile, void (*processChromChunk)(struct bbiFile *bbi, char *chrom, int start, int end, char *bedName, FILE *f) ) /* Read list of ranges from bed file chrom start end. * Automatically sort them by chrom, start. If bed4 pass bed->name too. */ { struct bed *bed, *bedList = bedLoad3Plus(bedFileName); slSort(&bedList, bedCmp); for (bed = bedList; bed != NULL; bed = bed->next) { if (chromHash && !hashLookup(chromHash, bed->chrom)) errAbort("invalid chrom = %s not found", bed->chrom); if (bed->chromStart > bed->chromEnd) errAbort("invalid range, start=%u > end=%u", bed->chromStart, bed->chromEnd); processChromChunk(bbi, bed->chrom, bed->chromStart, bed->chromEnd, bed->name, outFile); } bedFreeList(&bedList); } void genericBigToNonBigFromRange(struct bbiFile *bbi, struct hash *chromHash, FILE *outFile, struct slName *ranges, void (*processChromChunk)(struct bbiFile *bbi, char *chrom, int start, int end, char *bedName, FILE *f) ) /* Read list of ranges as chrom start end or chrom:start-end. * Automatically sort them by chrom, start. */ { struct bed *bed, *bedList = bedLoad3FromRangeOption(ranges); slSort(&bedList, bedCmp); for (bed = bedList; bed != NULL; bed = bed->next) { if (chromHash && !hashLookup(chromHash, bed->chrom)) errAbort("invalid chrom = %s not found", bed->chrom); if (bed->chromStart > bed->chromEnd) errAbort("invalid range, start=%u > end=%u", bed->chromStart, bed->chromEnd); processChromChunk(bbi, bed->chrom, bed->chromStart, bed->chromEnd, bed->name, outFile); } bedFreeList(&bedList); } void genericBigToNonBigFromPos(struct bbiFile *bbi, struct hash *chromHash, char *posFileName, FILE *outFile, void (*processChromChunk)(struct bbiFile *bbi, char *chrom, int start, int end, char *bedName, FILE *f) ) { /* Read positions from file (chrom:start-end). starts are 1-based, * but after conversion to bed3 list, they are 0-based. * Automatically sort them by chrom, start */ struct bed *bed, *bedList = bed3FromPositions(posFileName); slSort(&bedList, bedCmp); for (bed = bedList; bed != NULL; bed = bed->next) { if (chromHash && !hashLookup(chromHash, bed->chrom)) errAbort("invalid chrom = %s not found", bed->chrom); if (bed->chromStart > bed->chromEnd) errAbort("invalid range, start=%u > end=%u", bed->chromStart, bed->chromEnd); processChromChunk(bbi, bed->chrom, bed->chromStart, bed->chromEnd, NULL, outFile); } bedFreeList(&bedList); }