22c5248388280556ba7c846adea6af4e9ae2aa50 kent Sun Aug 11 10:22:02 2019 -0700 Adding replace function. diff --git src/lib/strex.c src/lib/strex.c index 16d8de2..7eb7c3a 100644 --- src/lib/strex.c +++ src/lib/strex.c @@ -44,30 +44,31 @@ }; enum strexBuiltInFunc /* One of these for each builtIn. We'll just do a switch to implement * Each built in function needs a value here, to keep it simple there's * aa correspondence between these names and the built in function name */ { strexBuiltInTrim, strexBuiltInBetween, strexBuiltInSplit, strexBuiltInNow, strexBuiltInMd5, strexBuiltInSeparate, strexBuiltInUncsv, strexBuiltInUntsv, + strexBuiltInReplace, }; struct strexBuiltIn /* Information to describe a built in function */ { char *name; /* Name in strex language: trim, split, etc */ enum strexBuiltInFunc func; /* enum version: strexBuiltInTrim strexBuiltInSplit etc. */ int paramCount; /* Number of parameters, not flexible in this language! */ enum strexType *paramTypes; /* Array of types, one for each parameter */ }; union strexVal /* Some value of arbirary type that can be of any type corresponding to strexType */ { boolean b; @@ -136,37 +137,38 @@ struct tokenizer *tkz; /* Get next text input from here */ struct hash *builtInHash; /* Hash of built in functions */ }; /* Some predefined lists of parameter types */ static enum strexType oneString[] = {strexTypeString}; // static enum strexType twoStrings[] = {strexTypeString, strexTypeString}; static enum strexType threeStrings[] = {strexTypeString, strexTypeString, strexTypeString}; static enum strexType stringInt[] = {strexTypeString, strexTypeInt}; static enum strexType stringStringInt[] = {strexTypeString, strexTypeString, strexTypeInt}; /* There's one element here for each built in function. There's also a few switches you'll need to * fill in if you add a new built in function. */ static struct strexBuiltIn builtins[] = { { "trim", strexBuiltInTrim, 1, oneString, }, - { "between", strexBuiltInBetween, 3, threeStrings, }, + { "between", strexBuiltInBetween, 3, threeStrings }, { "split", strexBuiltInSplit, 2, stringInt }, { "now", strexBuiltInNow, 0, NULL }, { "md5", strexBuiltInMd5, 1, oneString }, { "separate", strexBuiltInSeparate, 3, stringStringInt }, { "uncsv", strexBuiltInUncsv, 2, stringInt }, { "untsv", strexBuiltInUntsv, 2, stringInt }, + { "replace", strexBuiltInReplace, 3, threeStrings }, }; static struct hash *hashBuiltIns() /* Build a hash of builtins keyed by name */ { struct hash *hash = hashNew(0); int i; for (i=0; i<ArraySize(builtins); ++i) hashAdd(hash, builtins[i].name, &builtins[i]); return hash; } static struct strexIn *strexInNew(char *expression, char *fileName, int fileLineNumber) /* Return a new strexIn structure wrapped around expression */ { @@ -953,30 +955,39 @@ if (ix >= count) errAbort("There aren't %d fields separated by %s in %s", ix+1, splitter, string); char **row; lmAllocArray(lm, row, count); char *scratch = lmCloneString(lm, string); chopByChar(scratch, splitter[0], row, count); return row[ix]; } static char *untsvString(char *tsvIn, int ix, struct lm *lm) /* Return the tab separated value at given index living somewhere in lm. */ { return separateString(tsvIn, "\t", ix, lm); } +static char *replaceString(char *in, char *oldVal, char *newVal, struct lm *lm) +/* Replace every occurrence of oldVal with newVal in string */ +{ +char *s = replaceChars(in, oldVal, newVal); +char *result = lmCloneString(lm, s); // Move to local memory +freeMem(s); +return result; +} + static struct strexEval strexEvalCallBuiltIn(struct strexParse *p, void *record, StrexEvalLookup lookup, struct lm *lm) /* Handle parse tree generated by an indexed array. */ { struct strexBuiltIn *builtIn = p->val.builtIn; struct strexEval res; res.type = strexTypeString; switch (builtIn->func) { case strexBuiltInTrim: { struct strexEval a = strexLocalEval(p->children, record, lookup, lm); res.val.s = trimSpaces(a.val.s); break; } @@ -1022,30 +1033,38 @@ } case strexBuiltInUncsv: { struct strexEval a = strexLocalEval(p->children, record, lookup, lm); struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); res.val.s = uncsvString(a.val.s, b.val.i, lm); break; } case strexBuiltInUntsv: { struct strexEval a = strexLocalEval(p->children, record, lookup, lm); struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); res.val.s = untsvString(a.val.s, b.val.i, lm); break; } + case strexBuiltInReplace: + { + struct strexEval a = strexLocalEval(p->children, record, lookup, lm); + struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); + struct strexEval c = strexLocalEval(p->children->next->next, record, lookup, lm); + res.val.s = replaceString(a.val.s, b.val.s, c.val.s, lm); + break; + } } return res; } static struct strexEval strexLocalEval(struct strexParse *p, void *record, StrexEvalLookup lookup, struct lm *lm) /* Evaluate self on parse tree, allocating memory if needed from lm. */ { struct strexEval res; switch (p->op) { case strexOpLiteral: res.val = p->val; res.type = p->type;