struct psl *mirrorLmPsl(struct psl *psl, struct lm *lm) /* Reflect a psl into local memory. */ { struct psl *p = lmCloneMem(lm, psl, sizeof(*psl)); p->qNumInsert = psl->tNumInsert; p->tNumInsert = psl->qNumInsert; p->qBaseInsert = psl->tBaseInsert; p->tBaseInsert = psl->qBaseInsert; p->qName = lmCloneString(lm, psl->tName); p->tName = lmCloneString(lm, psl->qName); p->qSize = psl->tSize; p->tSize = psl->qSize; p->qStart = psl->tStart; p->tStart = psl->qStart; p->qEnd = psl->tEnd; p->tEnd = psl->qEnd; p->blockSizes = lmCloneMem(lm, psl->blockSizes, psl->blockCount*sizeof(psl->blockSizes[0])); p->qStarts = lmCloneMem(lm, psl->tStarts, psl->blockCount*sizeof(psl->tStarts[0])); p->tStarts = lmCloneMem(lm, psl->qStarts, psl->blockCount*sizeof(psl->tStarts[0])); if (p->strand[0] == '-') { reverseStartList(psl->qStarts, p->tStarts, p->blockSizes, p->blockCount, p->tSize); reverseStartList(psl->tStarts, p->qStarts, p->blockSizes, p->blockCount, p->qSize); reverseSizeList(psl->blockSizes, p->blockSizes, p->blockCount); } return p; }
void joinTwoInfo(char *spec1, char *spec2) /* joinTwoInfo - Look at two columns in two tables in mySQL and see how joinable they look.. */ { char *s1[4], *s2[4]; struct lm *lm = lmInit(0); int partCount = chopByChar(lmCloneString(lm, spec1), '.', s1, ArraySize(s1)); if (partCount != 3) usage(); partCount = chopByChar(lmCloneString(lm, spec2), '.', s2, ArraySize(s2)); if (partCount != 3) usage(); struct slName *list1 = getColumn(s1[0], s1[1], s1[2], lm); struct hash *uniq1 = uniqHash(list1); struct slName *list2 = getColumn(s2[0], s2[1], s2[2], lm); struct hash *uniq2 = uniqHash(list2); int countOneInTwo = countInHash(list1, uniq2); int countTwoInOne = countInHash(list2, uniq1); int countUniqOneInTwo = countUniqInHash(list1, uniq2); int countUniqTwoInOne = countUniqInHash(list2, uniq1); printf("%s: %d items, %d unique items, %d items (%d unique) in %s\n", spec1, slCount(list1), uniq1->elCount, countOneInTwo, countUniqOneInTwo, spec2); printf("%s: %d items, %d unique items, %d items (%d unique) in %s\n", spec2, slCount(list2), uniq2->elCount, countTwoInOne, countUniqTwoInOne, spec1); lmCleanup(&lm); }
static void addFilteredBedsOnRegion(char *fileName, struct region *region, char *table, struct asFilter *filter, struct lm *bedLm, struct bed **pBedList, struct hash *idHash, int *pMaxOut) /* Add relevant beds in reverse order to pBedList */ { struct lm *lm = lmInit(0); struct samAlignment *sam, *samList = bamFetchSamAlignment(fileName, region->chrom, region->start, region->end, lm); char *row[SAMALIGNMENT_NUM_COLS]; char numBuf[BAM_NUM_BUF_SIZE]; for (sam = samList; sam != NULL; sam = sam->next) { samAlignmentToRow(sam, numBuf, row); if (asFilterOnRow(filter, row)) { if ((idHash != NULL) && (hashLookup(idHash, sam->qName) == NULL)) continue; struct bed *bed; lmAllocVar(bedLm, bed); bed->chrom = lmCloneString(bedLm, sam->rName); bed->chromStart = sam->pos - 1; bed->chromEnd = bed->chromStart + cigarWidth(sam->cigar, strlen(sam->cigar)); bed->name = lmCloneString(bedLm, sam->qName); slAddHead(pBedList, bed); } (*pMaxOut)--; if (*pMaxOut <= 0) break; } lmCleanup(&lm); }
void mgcStatusTblAdd(struct mgcStatusTbl *mst, unsigned imageId, struct mgcStatusType *status, char *acc, char *organism, char* geneName) /* Add an entry to the table. acc maybe NULL */ { struct mgcStatus *ms; lmAllocVar(mst->lm, ms); ms->imageId = imageId; ms->status = status; if ((acc != NULL) && (acc[0] != '\0')) ms->acc = lmCloneString(mst->lm, acc); else ms->acc = NULL; safef(ms->organism, sizeof(ms->organism), "%s", organism); if ((geneName != NULL) && (geneName[0] != '\0')) ms->geneName = lmCloneString(mst->lm, geneName); else ms->geneName = NULL; if (mst->imageIdHash != NULL) { char key[64]; makeKey(imageId, key); hashAdd(mst->imageIdHash, key, ms); } if ((mst->accHash != NULL) && (acc != NULL)) hashAdd(mst->accHash, ms->acc, ms); }
struct variant *variantNew(char *chrom, unsigned start, unsigned end, unsigned numAlleles, char *slashSepAlleles, char *refAllele, struct lm *lm) /* Create a variant from basic information that is easy to extract from most other variant * formats: coords, allele count, string of slash-separated alleles and reference allele. */ { struct variant *variant; // We have a new variant! lmAllocVar(lm, variant); variant->chrom = lmCloneString(lm, chrom); variant->chromStart = start; variant->chromEnd = end; variant->numAlleles = numAlleles; // get the alleles. char *nextAlleleString = lmCloneString(lm, slashSepAlleles); int alleleNumber = 0; for( ; alleleNumber < numAlleles; alleleNumber++) { if (nextAlleleString == NULL) errAbort("number of alleles in /-separated string doesn't match numAlleles"); char *thisAlleleString = nextAlleleString; // advance pointer to next variant string // probably there's some kent routine to do this behind the curtain nextAlleleString = strchr(thisAlleleString, '/'); if (nextAlleleString) // null out '/' and move to next char { *nextAlleleString = 0; nextAlleleString++; } boolean isRefAllele = (sameWord(thisAlleleString, refAllele) || (isEmpty(refAllele) && sameString(thisAlleleString, "-"))); int alleleStringLength = strlen(thisAlleleString); if (isDash(thisAlleleString)) { alleleStringLength = 0; thisAlleleString[0] = '\0'; } // we have a new allele! struct allele *allele; AllocVar(allele); slAddHead(&variant->alleles, allele); allele->variant = variant; allele->length = alleleStringLength; allele->sequence = lmCloneString(lm, thisAlleleString); allele->isReference = isRefAllele; } slReverse(&variant->alleles); return variant; }
struct raField *raFieldNew(char *name, char *val, struct lm *lm) /* Return new raField. */ { struct raField *field; lmAllocVar(lm, field); field->name = lmCloneString(lm, name); val = emptyForNull(skipLeadingSpaces(val)); field->val = lmCloneString(lm, val); return field; }
char *raFoldInOneRetName(struct lineFile *lf, struct hash *hashOfHash) /* Fold in one record from ra file into hashOfHash. * This will add ra's and ra fields to whatever already * exists in the hashOfHash, overriding fields of the * same name if they exist already. */ { char *word, *line, *name; struct hash *ra; struct hashEl *hel; /* Get first nonempty non-comment line and make sure * it contains name. */ if (!lineFileNextReal(lf, &line)) return NULL; word = nextWord(&line); if (!sameString(word, "name")) errAbort("Expecting 'name' line %d of %s, got %s", lf->lineIx, lf->fileName, word); name = nextWord(&line); if (name == NULL) errAbort("Short name field line %d of %s", lf->lineIx, lf->fileName); /* Find ra hash associated with name, making up a new * one if need be. */ if ((ra = hashFindVal(hashOfHash, name)) == NULL) { ra = newHash(7); hashAdd(hashOfHash, name, ra); hashAdd(ra, "name", lmCloneString(ra->lm, name)); } /* Fill in fields of ra hash with data up to next * blank line or end of file. */ for (;;) { if (!lineFileNext(lf, &line, NULL)) break; line = skipLeadingSpaces(line); if (line[0] == 0) break; if (line[0] == '#') continue; word = nextWord(&line); line = skipLeadingSpaces(line); if (line == NULL) line = ""; hel = hashLookup(ra, word); if (hel == NULL) hel = hashAdd(ra, word, lmCloneString(ra->lm, line)); else hel->val = lmCloneString(ra->lm, line); } return hashFindVal(ra, "name"); }
struct slPair *tagStanzaAppend(struct tagStorm *tagStorm, struct tagStanza *stanza, char *tag, char *val) /* Add tag with given value to stanza */ { struct lm *lm = tagStorm->lm; struct slPair *pair; lmAllocVar(lm, pair); pair->name = lmCloneString(lm, tag); pair->val = lmCloneString(lm, val); slAddTail(&stanza->tagList, pair); return pair; }
struct geneLoc* geneLocNew(struct lm *lm, char *name, char *chrom, char *strand, int start, int end) /* Create a new geneLoc object */ { struct geneLoc *geneLoc; lmAllocVar(lm, geneLoc); geneLoc->name = lmCloneString(lm, name); geneLoc->chrom = lmCloneString(lm, chrom); strcpy(geneLoc->strand, strand); geneLoc->start = start; geneLoc->end = end; return geneLoc; }
struct raFile *raFileRead(char *fileName, struct raLevel *level, struct lm *lm) /* Read in file */ { struct dyString *dy = dyStringNew(0); struct raFile *raFile; lmAllocVar(lm, raFile); raFile->name = lmCloneString(lm, fileName); raFile->recordList = readRecordsFromFile(raFile, dy, lm); raFile->endSpace = lmCloneString(lm, dy->string); raFile->level = level; dyStringFree(&dy); return raFile; }
static void addBedElement(struct bed **bedList, char *chrom, unsigned start, unsigned end, unsigned count, struct lm *lm) { struct bed *bed; char name[128]; lmAllocVar(lm, bed); bed->chrom = lmCloneString(lm, chrom); bed->chromStart = start; bed->chromEnd = end; safef(name,ArraySize(name), "%s.%u", bed->chrom, count); bed->name = lmCloneString(lm, name); slAddHead(bedList, bed); }
struct gpFx *gpFxNew(char *allele, char *transcript, enum soTerm soNumber, enum detailType detailType, struct lm *lm) /* Fill in the common members of gpFx; leave soTerm-specific members for caller to fill in. */ { struct gpFx *effect; lmAllocVar(lm, effect); effect->allele = collapseDashes(lmCloneString(lm, allele)); if (isAllNt(effect->allele, strlen(effect->allele))) touppers(effect->allele); effect->transcript = lmCloneString(lm, transcript); effect->soNumber = soNumber; effect->detailType = detailType; return effect; }
int bamAddOneSamAlignment(const bam1_t *bam, void *data, bam_hdr_t *header) /* bam_fetch() calls this on each bam alignment retrieved. Translate each bam * into a samAlignment. */ { struct bamToSamHelper *helper = (struct bamToSamHelper *)data; struct lm *lm = helper->lm; struct samAlignment *sam; lmAllocVar(lm, sam); const bam1_core_t *core = &bam->core; struct dyString *dy = helper->dy; sam->qName = lmCloneString(lm, bam1_qname(bam)); sam->flag = core->flag; if (helper->chrom != NULL) sam->rName = helper->chrom; else sam->rName = lmCloneString(lm, header->target_name[core->tid]); sam->pos = core->pos + 1; sam->mapQ = core->qual; dyStringClear(dy); bamUnpackCigar(bam, dy); sam->cigar = lmCloneStringZ(lm, dy->string, dy->stringSize); if (core->mtid >= 0) { if (core->tid == core->mtid) sam->rNext = "="; else sam->rNext = lmCloneString(lm, header->target_name[core->mtid]); } else sam->rNext = "*"; sam->pNext = core->mpos + 1; sam->tLen = core->isize; sam->seq = lmAlloc(lm, core->l_qseq + 1); bamUnpackQuerySequence(bam, FALSE, sam->seq); char *bamQual = (char *)bam1_qual(bam); if (isAllSameChar(bamQual, core->l_qseq, -1)) sam->qual = "*"; else { sam->qual = lmCloneStringZ(lm, bamQual, core->l_qseq); addToChars(sam->qual, core->l_qseq, 33); } dyStringClear(dy); bamUnpackAux(bam, dy); sam->tagTypeVals = lmCloneStringZ(lm, dy->string, dy->stringSize); slAddHead(&helper->samList, sam); return 0; }
struct dnaSeq *genePredToGenomicSequence(struct genePred *pred, char *chromSeq, struct lm *lm) /* Return concatenated genomic sequence of exons of pred. */ { int txLen = 0; int i; for (i=0; i < pred->exonCount; i++) txLen += (pred->exonEnds[i] - pred->exonStarts[i]); char *seq = lmAlloc(lm, txLen + 1); int offset = 0; for (i=0; i < pred->exonCount; i++) { int blockStart = pred->exonStarts[i]; int blockSize = pred->exonEnds[i] - blockStart; memcpy(seq+offset, chromSeq+blockStart, blockSize*sizeof(*seq)); offset += blockSize; } if(pred->strand[0] == '-') reverseComplement(seq, txLen); struct dnaSeq *txSeq = NULL; lmAllocVar(lm, txSeq); txSeq->name = lmCloneString(lm, pred->name); txSeq->dna = seq; txSeq->size = txLen; return txSeq; }
static char *uintToString(struct lm *lm, uint num) { char buffer[10]; safef(buffer,sizeof buffer, "%d", num); return lmCloneString(lm, buffer); }
static void addPrimaryIdsToHash(struct sqlConnection *conn, struct hash *hash, char *idField, struct slName *tableList, struct lm *lm, char *extraWhere) /* For each table in tableList, query all idField values and add to hash, * id -> uppercased id for case-insensitive matching. */ { struct slName *table; struct sqlResult *sr; char **row; struct dyString *query = dyStringNew(0); for (table = tableList; table != NULL; table = table->next) { dyStringClear(query); sqlDyStringPrintf(query, "select %s from %s", idField, table->name); if (extraWhere != NULL) dyStringPrintf(query, " where %s", extraWhere); sr = sqlGetResult(conn, query->string); while ((row = sqlNextRow(sr)) != NULL) { if (isNotEmpty(row[0])) { char *origCase = lmCloneString(lm, row[0]); touppers(row[0]); hashAdd(hash, row[0], origCase); } } sqlFreeResult(&sr); } }
static void addMiscDiff(int iDiff, char *subField, char *val) /* add a misc diff to kvt, subField can be empty */ { char name[256]; safef(name, sizeof(name), "mdiff.%d%s", iDiff, subField); kvtAdd(kvt, lmCloneString(kvtMem, name), val); }
void peakClusterMakerAddFromSource(struct peakClusterMaker *maker, struct peakSource *source) /* Read through data source and add items to it to rangeTrees in maker */ { struct hash *chromHash = maker->chromHash; struct lineFile *lf = lineFileOpen(source->dataSource, TRUE); struct lm *lm = chromHash->lm; /* Local memory pool - share with hash */ char *row[source->minColCount]; struct peakItem *item; char *line; while (lineFileNextReal(lf, &line)) { char *asciiLine = lmCloneString(lm, line); int wordCount = chopByWhite(line, row, source->minColCount); lineFileExpectAtLeast(lf, source->minColCount, wordCount); char *chrom = row[source->chromColIx]; struct hashEl *hel = hashLookup(chromHash, chrom); if (hel == NULL) { struct rbTree *tree = rangeTreeNewDetailed(lm, maker->stack); hel = hashAdd(chromHash, chrom, tree); } struct rbTree *tree = hel->val; lmAllocVar(lm, item); item->chrom = hel->name; item->chromStart = sqlUnsigned(row[source->startColIx]); item->chromEnd = sqlUnsigned(row[source->endColIx]); item->score = sqlDouble(row[source->scoreColIx]) * source->normFactor; if (item->score > 1000) item->score = 1000; item->source = source; item->asciiLine = asciiLine; rangeTreeAddValList(tree, item->chromStart, item->chromEnd, item); } lineFileClose(&lf); }
struct exonFrames *cdsExonAddFrames(struct cdsExon *exon, int qStart, int qEnd, char qStrand, char *tName, int tStart, int tEnd, char frame, char geneStrand, int cdsOff) /* allocate a new mafFrames object and link it exon */ { struct orgGenes *genes = exon->gene->genes; struct exonFrames *ef; lmAllocVar(genes->memPool, ef); ef->exon = exon; /* fill in query part */ ef->mf.src = genes->srcDb; ef->srcStart = qStart; ef->srcEnd = qEnd; ef->srcStrand = qStrand; ef->cdsStart = cdsOff; ef->cdsEnd = cdsOff + (qEnd - qStart); /* fill in mafFrames part */ ef->mf.chrom = lmCloneString(genes->memPool, tName); ef->mf.chromStart = tStart; ef->mf.chromEnd = tEnd; ef->mf.frame = frame; ef->mf.strand[0] = geneStrand; ef->mf.name = exon->gene->name; ef->mf.prevFramePos = -1; ef->mf.nextFramePos = -1; slAddHead(&exon->frames, ef); exon->gene->numExonFrames++; return ef; }
static char *chromStrAlloc(struct orgGenes *genes, char *chrom) /* allocated a chrom name from the pool, caching the last allocated */ { if ((genes->curChrom == NULL) || !sameString(chrom, genes->curChrom)) genes->curChrom = lmCloneString(genes->memPool, chrom); return genes->curChrom; }
struct hash *raFromString(char *string) /* Return hash of key/value pairs from string. * As above freeHash this when done. */ { char *dupe = cloneString(string); char *s = dupe, *lineEnd; struct hash *hash = newHash(7); char *key, *val; for (;;) { s = skipLeadingSpaces(s); if (s == NULL || s[0] == 0) break; lineEnd = strchr(s, '\n'); if (lineEnd != NULL) *lineEnd++ = 0; key = nextWord(&s); val = skipLeadingSpaces(s); s = lineEnd; val = lmCloneString(hash->lm, val); hashAdd(hash, key, val); } freeMem(dupe); return hash; }
static char *gpFxModifyCodingSequence(char *oldCodingSeq, struct genePred *pred, int startInCds, int endInCds, struct allele *allele, int *retCdsBasesAdded, struct lm *lm) /* Return a new coding sequence that is oldCodingSeq with allele applied. */ { boolean isRc = (pred->strand[0] == '-'); char *newAlleleSeq = allele->sequence; int newAlLen = strlen(newAlleleSeq); if (! isAllNt(newAlleleSeq, newAlLen)) { // symbolic -- may be deletion or insertion, but we can't tell. :( newAlleleSeq = ""; newAlLen = 0; } if (isRc && newAlLen > 0) { newAlleleSeq = lmCloneString(lm, newAlleleSeq); reverseComplement(newAlleleSeq, newAlLen); } int variantSizeOnCds = endInCds - startInCds; if (variantSizeOnCds < 0) errAbort("gpFx: endInCds (%d) < startInCds (%d)", endInCds, startInCds); char *newCodingSeq = mergeAllele(oldCodingSeq, startInCds, variantSizeOnCds, newAlleleSeq, newAlLen, lm); // If newCodingSequence has an early stop, truncate there: truncateAtStopCodon(newCodingSeq); int variantSizeOnRef = allele->variant->chromEnd - allele->variant->chromStart; if (retCdsBasesAdded) *retCdsBasesAdded = allele->length - variantSizeOnRef; return newCodingSeq; }
static char * mergeAllele(char *transcript, int offset, int variantWidth, char *newAlleleSeq, int alleleLength, struct lm *lm) /* merge a variant into an allele */ { char *newTranscript = NULL; //#*** This will be incorrect for an MNV that spans exon boundary -- //#*** so we should also clip allele to cds portion(s?!) before calling this. if (variantWidth == alleleLength) { newTranscript = lmCloneString(lm, transcript); memcpy(&newTranscript[offset], newAlleleSeq, alleleLength); } else { int insertionSize = alleleLength - variantWidth; int newLength = strlen(transcript) + insertionSize; newTranscript = lmAlloc(lm, newLength + 1); char *restOfTranscript = &transcript[offset + variantWidth]; // copy over the part before the variant memcpy(newTranscript, transcript, offset); // copy in the new allele memcpy(&newTranscript[offset], newAlleleSeq, alleleLength); // copy in the part after the variant memcpy(&newTranscript[offset + alleleLength], restOfTranscript, strlen(restOfTranscript) + 1); } return newTranscript; }
static void addFilteredBedsOnRegion(char *fileName, struct region *region, char *table, struct asFilter *filter, struct lm *bedLm, struct bed **pBedList, struct hash *idHash, int *pMaxOut, boolean isTabix) /* Add relevant beds in reverse order to pBedList */ { struct vcfFile *vcff; if (isTabix) vcff = vcfTabixFileMayOpen(fileName, region->chrom, region->start, region->end, 100, *pMaxOut); else vcff = vcfFileMayOpen(fileName, region->chrom, region->start, region->end, 100, *pMaxOut, TRUE); if (vcff == NULL) noWarnAbort(); struct lm *lm = lmInit(0); char *row[VCFDATALINE_NUM_COLS]; char numBuf[VCF_NUM_BUF_SIZE]; // Temporary storage for row-ification: struct dyString *dyAlt = newDyString(1024); struct dyString *dyFilter = newDyString(1024); struct dyString *dyInfo = newDyString(1024); struct dyString *dyGt = newDyString(1024); struct vcfRecord *rec; for (rec = vcff->records; rec != NULL; rec = rec->next) { vcfRecordToRow(rec, region->chrom, numBuf, dyAlt, dyFilter, dyInfo, dyGt, row); if (asFilterOnRow(filter, row)) { if ((idHash != NULL) && (hashLookup(idHash, rec->name) == NULL)) continue; struct bed *bed; lmAllocVar(bedLm, bed); bed->chrom = lmCloneString(bedLm, region->chrom); bed->chromStart = rec->chromStart; bed->chromEnd = rec->chromEnd; bed->name = lmCloneString(bedLm, rec->name); slAddHead(pBedList, bed); } (*pMaxOut)--; if (*pMaxOut <= 0) break; } dyStringFree(&dyAlt); dyStringFree(&dyFilter); dyStringFree(&dyInfo); dyStringFree(&dyGt); lmCleanup(&lm); vcfFileFree(&vcff); }
void mgcStatusSetAcc(struct mgcStatusTbl *mst, struct mgcStatus *ms, char *acc) /* Change the accession on entry to the table. acc maybe NULL */ { if ((acc != NULL) && (acc[0] != '\0')) ms->acc = lmCloneString(mst->lm, acc); else ms->acc = NULL; }
struct annoRow *annoRowFromStringArray(char *chrom, uint start, uint end, boolean rightJoinFail, char **wordsIn, int numCols, struct lm *lm) /* Allocate & return an annoRow with words cloned from wordsIn. */ { struct annoRow *aRow; lmAllocVar(lm, aRow); aRow->chrom = lmCloneString(lm, chrom); aRow->start = start; aRow->end = end; aRow->rightJoinFail = rightJoinFail; char **words; lmAllocArray(lm, words, numCols); int i; for (i = 0; i < numCols; i++) words[i] = lmCloneString(lm, wordsIn[i]); aRow->data = words; return aRow; }
struct tagStorm *tagStormNew(char *name) /* Create a new, empty, tagStorm. */ { struct lm *lm = lmInit(0); struct tagStorm *tagStorm = lmAlloc(lm, sizeof(*tagStorm)); tagStorm->lm = lm; tagStorm->fileName = lmCloneString(lm, name); return tagStorm; }
char *lmCloneFirstWord(struct lm *lm, char *line) /* Clone first word in line */ { char *startFirstWord = skipLeadingSpaces(line); if (startFirstWord == NULL) return NULL; char *endFirstWord = skipToSpaces(startFirstWord); if (endFirstWord == NULL) return lmCloneString(lm, startFirstWord); else return lmCloneStringZ(lm, startFirstWord, endFirstWord - startFirstWord); }
void tagStormUpdateTag(struct tagStorm *tagStorm, struct tagStanza *stanza, char *tag, char *val) /* Add tag to stanza in storm, replacing existing tag if any. If tag is added it's added to * end. */ { struct lm *lm = tagStorm->lm; /* First loop through to replace an existing tag. */ struct slPair *pair; for (pair = stanza->tagList; pair != NULL; pair = pair->next) { if (sameString(pair->name, tag)) { pair->val = lmCloneString(lm, val); return; } } /* If didn't make it then add new tag (at end) */ lmAllocVar(lm, pair); pair->name = lmCloneString(lm, tag); pair->val = lmCloneString(lm, val); slAddTail(&stanza->tagList, pair); }
void loadCdsFile(char *cdsFile) /* read a CDS file into the global hash */ { struct lineFile *lf = lineFileOpen(cdsFile, TRUE); char *row[2]; gCdsTable = hashNew(20); while (lineFileNextRowTab(lf, row, 2)) hashAdd(gCdsTable, row[0], lmCloneString(gCdsTable->lm, row[1])); lineFileClose(&lf); }