static struct brokenRefPep *brokenRefPepObtain(struct brokenRefPepTbl *brpTbl, char *protAcc, int protSeqId, short protVer) /* get a brokenRefPep object if it exists, or create a new one. protSeqId * is 0 if not known, protVer is -1 if not known.*/ { struct hashEl *hel = hashStore(brpTbl->protAccHash, protAcc); struct brokenRefPep *brp = hel->val; if (brp == NULL) { lmAllocVar(brpTbl->protAccHash->lm, brp); hel->val = brp; brp->protSeqId = protSeqId; brp->protAcc = hel->name; brp->protVer = protVer; brp->newFaId = -1; brp->newFaOff = -1; } else { /* exists, update ids if needed */ if ((protSeqId > 0) && (brp->protSeqId > 0) && (protSeqId != brp->protSeqId)) errAbort("%s protSeqId mismatch", protAcc); if (brp->protSeqId == 0) brp->protSeqId = protSeqId; if ((protVer >= 0) && (brp->protVer >= 0) && (protVer != brp->protVer)) errAbort("%s protVer mismatch", protAcc); if (brp->protVer < 0) brp->protVer = protVer; } return brp; }
static struct slName *getGenomeDbs(struct gbConf *conf) /* get list of genome databases from variable names */ { // build hash of dbs struct hash *dbSet = hashNew(20); struct hashCookie cookie = hashFirst(conf->hash); struct hashEl *hel; while ((hel = hashNext(&cookie)) != NULL) { char *prefix = parsePrefix(hel->name); if (isGenomeDb(prefix)) hashStore(dbSet, prefix); } // convert to a list of dbs struct slName *dbs = NULL; cookie = hashFirst(dbSet); while ((hel = hashNext(&cookie)) != NULL) slSafeAddHead(&dbs, slNameNew(hel->name)); #ifdef DUMP_HASH_STATS hashPrintStats(dbSet, "gbConfDbSet", stderr); #endif hashFree(&dbSet); slSort(&dbs, slNameCmp); return dbs; }
static void loadPolyASizeRec(struct hash *pasHash, char **row) /* load one polyA size record into the hash table. This * places in hash localmem to reduce memory usage */ { struct polyASize pas, *pasRec; struct hashEl *recHel; polyASizeStaticLoad(row, &pas); recHel = hashStore(pasHash, pas.id); if (recHel->val != NULL) { /* record already exists for this id, validate */ pasRec = recHel->val; if ((pasRec->seqSize != pas.seqSize) ||(pasRec->tailPolyASize != pas.tailPolyASize) || (pasRec->headPolyTSize != pas.headPolyTSize)) errAbort("multiple polyA size records for %s with different data", pas.id); } else { /* add new record */ lmAllocVar(pasHash->lm, pasRec); pasRec->id = recHel->name; pasRec->seqSize = pas.seqSize; pasRec->tailPolyASize = pas.tailPolyASize; pasRec->headPolyTSize = pas.headPolyTSize; } }
void readBad(struct hash *badHash, char *fileName, int cloneWord) /* Read bad clones into hash. */ { char *words[8]; struct lineFile *lf = lineFileOpen(fileName, TRUE); int wordCount; char *acc; int badCount = 0; while ((wordCount = lineFileChop(lf, words)) != 0) { if (wordCount < cloneWord+1) { errAbort("Expecting at least %d words line %d of %s", cloneWord+1, lf->lineIx, lf->fileName); } acc = words[cloneWord]; chopSuffix(acc); if (!checkAccFormat(acc)) errAbort("Badly formatted accession line %d of %s", lf->lineIx, lf->fileName); hashStore(badHash, acc); ++badCount; } lineFileClose(&lf); printf("Got %d clones to avoid from %s\n", badCount, fileName); }
static void findReplaced(struct sqlConnection *conn, struct genomeInfo *genome, struct hash* ignoreTbl) /* find CCDSs that have been replaced. Done in a separate pass due to the * lack of sub-selects in mysql 4. */ { verbose(2, "begin findReplaced\n"); static char select[4096]; sqlSafef(select, sizeof(select), "SELECT " "CcdsUids.ccds_uid, GroupVersions.ccds_version " "FROM %s, Interpretations, InterpretationSubtypes " "WHERE %s " "AND (Interpretations.ccds_uid = CcdsUids.ccds_uid) " "AND (Interpretations.interpretation_subtype_uid = InterpretationSubtypes.interpretation_subtype_uid) " "AND (InterpretationSubtypes.interpretation_subtype in (\"Strand changed\", \"Location changed\", \"Merged\")) " "AND (Interpretations.val_description in (\"New CCDS\", \"Merged into\"))", mkCommonFrom(FALSE), mkCommonWhere(genome, conn, FALSE)); struct sqlResult *sr = sqlGetResult(conn, select); char **row; int cnt = 0; while ((row = sqlNextRow(sr)) != NULL) { struct hashEl *hel = hashStore(ignoreTbl, ccdsMkId(sqlUnsigned(row[0]), sqlUnsigned(row[1]))); hel->val = "replaced"; cnt++; verbose(4, " replaced: %s\n", hel->name); } sqlFreeResult(&sr); verbose(2, "end findReplaced: %d replaced CCDS found\n", cnt); }
static void findPartialMatches(struct sqlConnection *conn, struct genomeInfo *genome, struct hash* ignoreTbl) /* find CCDS interpretation_subtype of "Partial match". Done in a separate * pass due to the lack of sub-selects in mysql 4. */ { verbose(2, "begin findPartialMatches\n"); char select[4096]; sqlSafef(select, sizeof(select), "SELECT " "CcdsUids.ccds_uid, GroupVersions.ccds_version " "FROM %s, CcdsStatusVals, Interpretations, InterpretationSubtypes " "WHERE %s " "AND (CcdsStatusVals.ccds_status_val_uid = GroupVersions.ccds_status_val_uid) " "AND (Interpretations.group_version_uid = GroupVersions.group_version_uid) " "AND (Interpretations.interpretation_subtype_uid = InterpretationSubtypes.interpretation_subtype_uid) " "AND (InterpretationSubtypes.interpretation_subtype = \"Partial match\")", mkCommonFrom(FALSE), mkCommonWhere(genome, conn, FALSE)); struct sqlResult *sr = sqlGetResult(conn, select); char **row; int cnt = 0; while ((row = sqlNextRow(sr)) != NULL) { struct hashEl *hel = hashStore(ignoreTbl, ccdsMkId(sqlUnsigned(row[0]), sqlUnsigned(row[1]))); hel->val = "partial_match"; cnt++; verbose(4, " partial_match: %s\n", hel->name); } sqlFreeResult(&sr); verbose(2, "end findPartialMatches: %d partial matches found\n", cnt); }
static void addQueryNames(struct hash *qNameHash, struct pslTbl *pslTbl) /* add query names to the hash table if they are not already there. */ { struct hashCookie hc = hashFirst(pslTbl->queryHash); struct pslQuery *q; while ((q = hashNextVal(&hc)) != NULL) hashStore(qNameHash, q->qName); /* add if not there */ }
struct hash *uniqHash(struct slName *list) /* Return hash of unique items. */ { struct hash *hash = hashNew(0); struct slName *el; for (el = list; el != NULL; el = el->next) hashStore(hash, el->name); return hash; }
static struct prefixElems *prefixElemsObtain(struct hash *prefixMap, char *prefix) /* construct a new prefixElems */ { struct hashEl *hashEl = hashStore(prefixMap, prefix); if (hashEl->val == NULL) hashEl->val = prefixElemsNew(prefix); return hashEl->val; }
struct rbTree *genomeRangeTreeFindOrAddRangeTree(struct genomeRangeTree *tree, char *chrom) /* Find the rangeTree for this chromosome, or add new chrom and empty rangeTree if not found. */ { struct hashEl *hel; hel = hashStore(tree->hash, chrom); if (hel->val == NULL) /* need to add a new rangeTree */ hel->val = rangeTreeNewDetailed(tree->lm, tree->stack); return hel->val; }
static void parseIDAttr(struct gff3Ann *g3a, struct gff3AttrVals *attrVals) /* parse the ID attribute */ { checkSingleValAttr(g3a, attrVals); char *id = attrVals->vals->name; struct hashEl *hel = hashStore(g3a->file->byId, id); if (hel->val != NULL) gff3AnnErr(g3a, "duplicate annotation record with ID: %s", id); hel->val = g3a; g3a->id = id; }
void addFreqToHash(struct hash *freqHash, char *tag, char *id, int val) /* Add the frequency to the end of the list in the hash. */ /* This is done at each line in the frequencies file. */ { struct hashEl *el = hashStore(freqHash, tag); struct slPair *newOne; struct slPair **pList = (struct slPair **)&el->val; AllocVar(newOne); newOne->name = cloneString(id); newOne->val = intToPt(val); slAddHead(pList, newOne); }
void txCdsPredict(char *inFa, char *outCds, char *nmdBed, char *mafFile, boolean anyStart) /* txCdsPredict - Somewhat simple-minded ORF predictor using a weighting scheme.. */ { struct dnaSeq *rna, *rnaList = faReadAllDna(inFa); verbose(2, "Read %d sequences from %s\n", slCount(rnaList), inFa); /* Make up hash of bed records for NMD analysis. */ struct hash *nmdHash = hashNew(18); if (nmdBed != NULL) { struct bed *bed, *bedList = bedLoadNAll(nmdBed, 12); for (bed = bedList; bed != NULL; bed = bed->next) hashAdd(nmdHash, bed->name, bed); verbose(2, "Read %d beds from %s\n", nmdHash->elCount, nmdBed); } /* Make up hash of maf records for conservation analysis. */ struct hash *mafHash = hashNew(18); int otherSpeciesCount = 0; if (mafFile != NULL) { struct mafFile *mf = mafReadAll(mafFile); struct mafAli *maf; for (maf = mf->alignments; maf != NULL; maf = maf->next) hashAdd(mafHash, maf->components->src, maf); verbose(2, "Read %d alignments from %s\n", mafHash->elCount, mafFile); struct hash *uniqSpeciesHash = hashNew(0); for (maf = mf->alignments; maf != NULL; maf = maf->next) { struct mafComp *comp; for (comp = maf->components->next; comp != NULL; comp = comp->next) hashStore(uniqSpeciesHash, comp->src); } otherSpeciesCount = uniqSpeciesHash->elCount; verbose(2, "%d other species in %s\n", otherSpeciesCount, mafFile); } FILE *f = mustOpen(outCds, "w"); for (rna = rnaList; rna != NULL; rna = rna->next) { verbose(3, "%s\n", rna->name); struct cdsEvidence *orfList = orfsOnRna(rna, nmdHash, mafHash, otherSpeciesCount, anyStart); if (orfList != NULL) { slSort(&orfList, cdsEvidenceCmpScore); cdsEvidenceTabOut(orfList, f); } cdsEvidenceFreeList(&orfList); } carefulClose(&f); }
static void handleNoMapping(struct spMapper *sm, char *id, char reason) /* record id that can't be mapped */ { struct hashEl *hel = hashStore(sm->noMapTbl, id); if (hel->val == NULL) { if (reason == noUnirefMapping) sm->noUnirefMapCnt++; else if (reason == noKGMapping) sm->noSpIdMapCnt++; } hel->val = intToPt(reason); }
struct hash *hashFirstWord(char *fileName) /* Hash first word in each line of file */ { char *row[1]; struct hash *hash = newHash(0); struct lineFile *lf = lineFileOpen(fileName, TRUE); while (lineFileRow(lf, row)) { hashStore(hash, row[0]); } lineFileClose(&lf); return hash; }
static void checkOneSubGroups(char *compositeName, struct trackDb *td, struct subGroupData *sgd) { char *subGroups = trackDbSetting(td, "subGroups"); verbose(2, " checkOne %s %s\n", compositeName, td->track); if (subGroups && (sgd->nameHash == NULL)) { errAbort("subTrack %s has groups not defined in parent %s\n", td->track, compositeName); } else if (!subGroups && (sgd->nameHash != NULL)) { errAbort("subtrack %s is missing subGroups defined in parent %s\n", td->track, compositeName); } if (!subGroups && (sgd->nameHash == NULL)) return; /* nothing to do */ assert(sgd->nameHash != NULL); struct slPair *slPair, *slPairList = slPairFromString(subGroups); struct hash *foundHash = newHash(3); for (slPair = slPairList; slPair; slPair = slPair->next) { struct hashEl *hel = hashLookup( sgd->nameHash, slPair->name); if (hel == NULL) errAbort("subtrack %s has subGroup (%s) not found in parent\n", td->track, slPair->name); struct hash *subHash = hel->val; hashStore(foundHash, slPair->name); if (hashLookup(subHash, slPair->val) == NULL) { errAbort("subtrack %s has subGroup (%s) with value (%s) not found in parent\n", td->track, slPair->name, (char *)slPair->val); } } struct hashCookie cookie = hashFirst(sgd->nameHash); struct hashEl *hel; while ((hel = hashNext(&cookie)) != NULL) { if (hashLookup(foundHash, hel->name) == NULL) errAbort("subtrack %s is missing required subGroup %s\n", td->track, hel->name); } }
static void saveProtFastaPath(struct brokenRefPepTbl* brpTbl, struct brokenRefPep* brp, char *mrnaAcc, char *mrnaFa) /* save protein fasta file path; mangles mrnaFa string */ { char protFa[PATH_LEN]; safef(brp->mrnaAcc, sizeof(brp->mrnaAcc), "%s", mrnaAcc); chopSuffixAt(mrnaFa, '/'); safef(protFa, sizeof(protFa), "%s/pep.fa", mrnaFa); // ignore result from hashStore() (void) hashStore(brpTbl->protFaHash, protFa); safef(brp->newFaPath, sizeof(brp->newFaPath), "%s", protFa); brpTbl->numToRepair++; }
static void kgPairSave(struct spMapper *sm, char *qSpId, char *tSpId, char *queryId, char *targetId, float score) /* save a bi-directional e-value for a query/target pair */ { struct hashEl *queryHel = hashStore(sm->kgPairMap, queryId); struct hashEl *targetHel = hashStore(sm->kgPairMap, targetId); struct kgPair *kgPair = kgPairFind(queryHel, targetHel); if (kgPair != NULL) { if (((sm->scoreDir < 0) && (score < kgPair->score)) || ((sm->scoreDir > 0) && (score > kgPair->score))) { kgPair->score = score; /* better score */ verbose(3, "updating: %s <> %s -> %s <> %s: %0.3f\n", qSpId, tSpId, queryId, targetId, score); } } else { kgPairAdd(sm, queryHel, targetHel, score); verbose(3, "mapping: %s <> %s -> %s <> %s: %0.3f\n", qSpId, tSpId, queryId, targetId, score); } }
int countUniqInHash(struct slName *list, struct hash *hash) /* Count number of items in list that are also in hash */ { struct hash *uniqHash = hashNew(0); struct slName *el; for (el = list; el != NULL; el = el->next) { if (hashLookup(hash, el->name)) { hashStore(uniqHash, el->name); } } int count = uniqHash->elCount; hashFree(&uniqHash); return count; }
void checkOverlap(struct mdbObj *mdbObjs, struct group *groups) { int errs = 0; for(; mdbObjs; mdbObjs = mdbObjs->next) { struct mdbVar *mdbVar = hashFindVal(mdbObjs->varHash, "objType"); if (sameString(mdbVar->val, "composite")) continue; struct group *ourGroup = findGroup(mdbObjs, groups); if (ourGroup == NULL) errAbort("cannot find group for %s\n", mdbObjs->obj); mdbVar = hashFindVal(mdbObjs->varHash, "view"); if (mdbVar == NULL) errAbort("obj %s has no view", mdbObjs->obj); struct hashEl *hel; if (ourGroup->viewHash == NULL) ourGroup->viewHash = newHash(10); struct mdbVar *mdbReplicate = hashFindVal(mdbObjs->varHash, "replicate"); char buffer[10*1024]; if (mdbReplicate != NULL) { if (ourGroup->repHash == NULL) ourGroup->repHash = newHash(10); hashStore(ourGroup->repHash, mdbReplicate->val); safef(buffer, sizeof buffer, "%s-%s",mdbVar->val, mdbReplicate->val); } else safef(buffer, sizeof buffer, "%s",mdbVar->val); if ((hel = hashLookup(ourGroup->viewHash, buffer)) != NULL) { printf("two views of type %s in same group\n",buffer); printf("objects are %s and %s\n", (char *)hel->val, mdbObjs->obj); printGroup(ourGroup); errs++; } else hashAdd(ourGroup->viewHash, buffer, mdbObjs->obj); } if (errs) errAbort("aborting"); }
static struct hash* loadPslByQname(char* inPslFile) /* load PSLs in to hash by qName. Make sure target strand is positive * to make process easier later. */ { struct hash* pslsByQName = hashNew(0); struct psl *psls = pslLoadAll(inPslFile); struct psl *psl; while ((psl = slPopHead(&psls)) != NULL) { if (pslTStrand(psl) != '+') pslRc(psl); struct hashEl *hel = hashStore(pslsByQName, psl->qName); struct psl** queryPsls = (struct psl**)&hel->val; slAddHead(queryPsls, psl); } return pslsByQName; }
static struct hash *readLift(char *liftAcross) /* read in liftAcross file, create hash of srcName as hash key, * hash elements are simple lists of coordinate relationships * return them all sorted by start position */ { char *row[6]; struct hash *result = newHash(8); struct hashEl *hel = NULL; struct lineFile *lf = lineFileOpen(liftAcross, TRUE); while (lineFileNextRow(lf, row, ArraySize(row))) { struct liftSpec *liftSpec; hel = hashStore(result, row[0]); /* srcName hash */ AllocVar(liftSpec); liftSpec->start = sqlUnsigned(row[1]); /* src start */ liftSpec->end = sqlUnsigned(row[2]); /* src end */ liftSpec->dstName = cloneString(row[3]); /* dstName */ liftSpec->dstStart = sqlUnsigned(row[4]); /* dst start */ liftSpec->strand = '+'; /* dst strand */ if ('-' == *row[5]) liftSpec->strand = '-'; /* accumulate list of lift specs under the srcName hash */ slAddHead(&(hel->val), liftSpec); } /* Go through each srcName in the hash, and sort the list there by * the start coordinate of each item. The searching will expect * them to be in order. */ struct hashCookie cookie = hashFirst(result); while ((hel = hashNext(&cookie)) != NULL) { slSort(&(hel->val), lsStartCmp); if (verboseLevel() > 2) { struct liftSpec *ls; for (ls = hel->val; ls != NULL; ls = ls->next) verbose(3, "# %s\t%d\t%d\t%s\t%d\t%c\n", hel->name, ls->start, ls->end, ls->dstName, ls->dstStart, ls->strand); } } return result; }
static void addIfFirstMatch(struct dbDb *dbDb, enum dbDbMatchType type, int offset, char *target, char *term, struct hash *matchHash, struct dbDbMatch **pMatchList) /* If target doesn't already have a match in matchHash, compute matchLength and isWord, * and then add the new match to pMatchList and add target to matchHash. */ { if (dbDb->active && ! hashLookup(matchHash, target)) { char *termInTarget = (offset >= 0) ? target+offset : target; int matchLength = countSame(term, termInTarget); // is the match complete up to a word boundary in termInTarget? boolean isWord = (matchLength == strlen(term) && (termInTarget[matchLength] == '\0' || isspace(termInTarget[matchLength]))); boolean isComplete = sameString(term, target); struct dbDbMatch *match = dbDbMatchNew(dbDb, type, offset, isWord, isComplete); slAddHead(pMatchList, match); hashStore(matchHash, target); } }
struct sumStats *sumStatsGetForQuery(struct hash *queryStatsTbl, char *qName, unsigned qSize) /* lookup a stats on query by name, creating if it doesn't exist */ { struct hashEl *hel = hashStore(queryStatsTbl, qName); struct sumStats *qs = hel->val; if (qs == NULL) { AllocVar(qs); qs->qName = hel->name; /* use string in hash */ qs->queryCnt = 1; qs->minQSize = qs->maxQSize = qSize; hel->val = qs; } else if (qs->minQSize != qSize) errAbort("conflicting query sizes for %s: %d and %d", qName, qs->minQSize, qSize); return hel->val; }
static struct aHubMatch *filterTrixSearchMatches(struct dbDb *dbDbList, struct trixSearchResult *tsrList) /* Collect the assembly hub matches (not track hub matches) from a search in hub trix files. */ { if (tsrList == NULL) return NULL; struct aHubMatch *aHubMatchList = NULL; // Make a hash of local dbs so we can tell which hub dbs must be assembly hubs // not track hubs. struct hash *localDbs = hashNew(0); struct dbDb *dbDb; for (dbDb = dbDbList; dbDb != NULL; dbDb = dbDb->next) hashStore(localDbs, dbDb->name); // tsrList gives hub URLs which we can then look up in hubPublic. struct dyString *query = sqlDyStringCreate("select shortLabel,hubUrl,dbList from %s " "where hubUrl in (", hubPublicTableName()); struct trixSearchResult *tsr; for (tsr = tsrList; tsr != NULL; tsr = tsr->next) { if (tsr != tsrList) dyStringAppend(query, ", "); dyStringPrintf(query, "'%s'", tsr->itemId); } dyStringAppendC(query, ')'); struct sqlConnection *conn = hConnectCentral(); struct sqlResult *sr = sqlGetResult(conn, query->string); char **row; while ((row = sqlNextRow(sr)) != NULL) { char *shortLabel = row[0]; char *hubUrl = row[1]; struct slName *dbName, *dbList = slNameListFromComma(row[2]); for (dbName = dbList; dbName != NULL; dbName = dbName->next) if (! hashLookup(localDbs, dbName->name)) { slAddHead(&aHubMatchList, aHubMatchNew(shortLabel, hubUrl, dbName->name)); } } slReverse(&aHubMatchList); hDisconnectCentral(&conn); return aHubMatchList; }
void buildCutHash(char *file, struct hash *hash) /* Each line of file contains a file name. Put the * non-dir/non-suffix part onto hash. */ { struct lineFile *lf = lineFileOpen(file, TRUE); char dir[256], name[128], ext[64]; int lineSize; char *line; int count = 0; while (lineFileNext(lf, &line, &lineSize)) { splitPath(line, dir, name, ext); hashStore(hash, name); ++count; } lineFileClose(&lf); printf("%d clones in cut list %s\n", count, file); }
static void addVersionRa(boolean strict, char *database, char *dirName, char *raName, struct hash *trackHash) /* Read in tracks from raName and add them to table, pruning as required. Call * top-down so that track override will work. */ { struct trackDb *tdbList = trackDbFromRa(raName, NULL), *tdb; /* prune records of the incorrect release */ tdbList= pruneRelease(tdbList); /* load tracks, replacing higher-level ones with lower-level and * applying overrides*/ while ((tdb = slPopHead(&tdbList)) != NULL) { if (tdb->overrides != NULL) applyOverride(trackHash, tdb); else hashStore(trackHash, tdb->track)->val = tdb; } }
static struct querySizeCnt *querySizeCntGet(struct hash* querySizesTbl, char *qName, unsigned qSize) /* get entry with size and alignment count, create if not present. */ { struct hashEl *hel = hashStore(querySizesTbl, qName); struct querySizeCnt *qs = hel->val; if (qs != NULL) { if (qs->qSize != qSize) errAbort("conflicting query sizes for %s: %d and %d", qName, qs->qSize, qSize); } else { lmAllocVar(querySizesTbl->lm, qs); hel->val = qs; qs->qSize = qSize; } return qs; }
void endHandler(struct xap *xap, char *name) /* Called at end of a tag */ { struct type *type = xap->stack->object; char *text = skipLeadingSpaces(xap->stack->text->string); struct element *el; for (el = type->elements; el != NULL; el = el->next) { if (!el->seenThisRound) el->isOptional = TRUE; } if (text[0] == 0) { if (type->textAttribute != NULL) type->textAttribute->isOptional = TRUE; } else { int textLen = strlen(text); struct attribute *att = type->textAttribute; if (att == NULL) { type->textAttribute = AllocVar(att); att->name = "<text>"; att->values = hashNew(16); if (type->count != 0) att->isOptional = TRUE; } if (att->maxLen < textLen) att->maxLen = textLen; hashStore(att->values, text); att->count += 1; if (!att->nonInt) if (!isAllInt(text) || hasLeftPaddedZero(text)) att->nonInt = TRUE; if (!att->nonFloat) if (!isAllFloat(text)) att->nonFloat = TRUE; } type->count += 1; topType = type; }
static void parseSequenceRegion(struct gff3File *g3f, char *line) /* parse ##sequence-region seqid start end */ { char **words = dynChopStringWhite(g3f, line, 4, 4, NULL, "\"##sequence-region seqid start end\""); if (words == NULL) return; // got an error struct gff3SeqRegion *sr = gff3FileAlloc(g3f, sizeof(struct gff3SeqRegion)); sr->seqid = gff3FileCloneStr(g3f, words[1]); sr->start = gff3FileStrToInt(g3f, words[2])-1; sr->end = gff3FileStrToInt(g3f, words[3]); if (g3f->seqRegionMap == NULL) g3f->seqRegionMap = hashNew(0); struct hashEl *hel = hashStore(g3f->seqRegionMap, sr->seqid); if (hel->val != NULL) gff3FileErr(g3f, "duplicate ##sequence-region for %s", sr->seqid); else { hel->val = sr; slAddHead(&g3f->seqRegions, sr); } freeMem(words); }