1a213bd0a224384e02c2efa5f2dbb9130515dc82 angie Fri Jun 26 17:18:55 2015 -0700 Oops, using sizeof instead of ArraySize was causing a SEGV when pasting bogus text with more than 5 words per line into the user regions box. diff --git src/hg/lib/userRegions.c src/hg/lib/userRegions.c index 5a335e9..6795cd0 100644 --- src/hg/lib/userRegions.c +++ src/hg/lib/userRegions.c @@ -1,202 +1,202 @@ /* userRegions: parse user regions entered as BED3, BED4 or chr:start-end * optionally followed by name. */ /* Copyright (C) 2015 The Regents of the University of California * See README in this or parent directory for licensing information. */ #include "common.h" #include "hui.h" #include "linefile.h" #include "trashDir.h" #include "userRegions.h" static boolean illegalCoordinate(char *db, char *chrom, int start, int end, char *line, int lineIx, struct dyString *dyWarn) /* verify start and end are legal for this chrom */ { int maxEnd = hChromSize(db, chrom); if (start < 0) { dyStringPrintf(dyWarn, "line %d: '%s': chromStart (%d) less than zero\n", lineIx, line, start); return TRUE; } if (end > maxEnd) { dyStringPrintf(dyWarn, "line %d: '%s': chromEnd (%d) greater than chrom length (%s:%d)\n", lineIx, line, end, chrom, maxEnd); return TRUE; } if (start > end) { dyStringPrintf(dyWarn, "line %d: '%s': chromStart (%d) greater than chromEnd (%d)\n", lineIx, line, start, end); return TRUE; } return FALSE; } static struct bed4 *parseRegionInput(char *db, char *inputString, int maxRegions, int maxErrs, struct dyString *dyWarn) /* scan the user region definition, turn into a bed list */ { int regionCount = 0; int errCount = 0; struct bed4 *bedList = NULL; struct lineFile *lf = lineFileOnString("userData", TRUE, inputString); char *line = NULL; while (lineFileNextReal(lf, &line)) { char *chromName = NULL; int chromStart = 0; int chromEnd = 0; char *regionName = NULL; // Chop a copy of line so we can display line if there's an error. char copy[strlen(line)+1]; safecpy(copy, sizeof(copy), line); char *words[5]; - int wordCount = chopByWhite(copy, words, sizeof(words)); + int wordCount = chopByWhite(copy, words, ArraySize(words)); boolean badFormat = FALSE; boolean gotError = FALSE; /* might be something of the form: chrom:start-end optionalRegionName */ if (((1 == wordCount) || (2 == wordCount)) && hgParseChromRange(NULL, words[0], &chromName, &chromStart, &chromEnd)) { if (2 == wordCount) regionName = cloneString(words[1]); } else if (!((3 == wordCount) || (4 == wordCount))) { dyStringPrintf(dyWarn, "line %d: '%s': " "unrecognized format. Please enter 3- or 4-column BED or " "a chr:start-end position range optionally followed by a name.\n", lf->lineIx, line); badFormat = TRUE; gotError = TRUE; } else { chromName = words[0]; // Make sure chromStart and chromEnd are numbers if (!isNumericString(words[1])) { dyStringPrintf(dyWarn, "line %d: '%s': chromStart must be a number but is '%s'\n", lf->lineIx, line, words[1]); gotError = TRUE; } if (!isNumericString(words[2])) { dyStringPrintf(dyWarn, "line %d: '%s': chromEnd must be a number but is '%s'\n", lf->lineIx, line, words[2]); gotError = TRUE; } if (! gotError) { chromStart = atoi(words[1]); chromEnd = atoi(words[2]); if (wordCount > 3) regionName = cloneString(words[3]); } } char *officialChromName = chromName ? hgOfficialChromName(db, chromName) : NULL; if (! badFormat) { if (NULL == officialChromName) { dyStringPrintf(dyWarn, "line %d: '%s': chrom name '%s' not recognized in this assembly\n", lf->lineIx, line, chromName ? chromName : words[0]); gotError = TRUE; } else if (illegalCoordinate(db, officialChromName, chromStart, chromEnd, line, lf->lineIx, dyWarn)) { gotError = TRUE; } } if (gotError) { errCount++; if (errCount > maxErrs && maxErrs > 0) { dyStringPrintf(dyWarn, "Exceeded maximum number of errors (%d), quitting\n", maxErrs); break; } else continue; } ++regionCount; if (regionCount > maxRegions && maxRegions > 0) { dyStringPrintf(dyWarn, "line %d: limit of %d region definitions exceeded, skipping the rest\n", lf->lineIx, maxRegions); break; } struct bed4 *bedEl = bed4New(officialChromName, chromStart, chromEnd, regionName); slAddHead(&bedList, bedEl); } lineFileClose(&lf); // Keep regions in same order as user entered them: slReverse(&bedList); return (bedList); } char *userRegionsParse(char *db, char *regionsText, int maxRegions, int maxErrs, int *retRegionCount, char **retWarnText) /* Parse user regions entered as BED3, BED4 or chr:start-end optionally followed by name. * Return name of trash file containing BED for parsed regions if regionsText contains * valid regions; otherwise NULL. * If maxRegions <= 0, it is ignored; likewise for maxErrs. * If retRegionCount is non-NULL, it will be set to the number of valid parsed regions * in the trash file. * If retWarnText is non-NULL, it will be set to a string containing warning and error * messages encountered while parsing input. */ { char *trashFileName = NULL; if (isNotEmpty(regionsText)) { char *copy = cloneString(regionsText); struct dyString *dyWarn = dyStringNew(0); struct bed4 *bedList = parseRegionInput(db, copy, maxRegions, maxErrs, dyWarn); if (retWarnText != NULL) { if (dyWarn->stringSize > 0) *retWarnText = dyStringCannibalize(&dyWarn); else { *retWarnText = NULL; dyStringFree(&dyWarn); } } int regionCount = slCount(bedList); if (retRegionCount != NULL) *retRegionCount = regionCount; if (regionCount > 0) { struct tempName tn; trashDirFile(&tn, "hgtData", "user", ".region"); trashFileName = cloneString(tn.forCgi); FILE *f = mustOpen(trashFileName, "w"); struct bed4 *bed; for (bed = bedList; bed; bed = bed->next ) { char *name = bed->name ? bed->name : ""; fprintf(f, "%s\t%d\t%d\t%s\n", bed->chrom, bed->chromStart, bed->chromEnd, name); } carefulClose(&f); } freeMem(copy); } else { if (retRegionCount != NULL) *retRegionCount = 0; if (retWarnText != NULL) *retWarnText = NULL; } return trashFileName; }