0019ae3b59457f94944a36cfa4bdebc72b017dba kent Sun Aug 11 20:36:23 2019 -0700 Adding new strip function. Making replace handle empty oldval in a useful way, as a way for setting defaults when a value is empty. diff --git src/lib/strex.c src/lib/strex.c index eecb5b1..c470a7a 100644 --- src/lib/strex.c +++ src/lib/strex.c @@ -45,30 +45,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, + strexBuiltInStrip, }; 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; @@ -128,47 +129,48 @@ struct strexParse *children; /* Points to oldest child if any. */ enum strexOp op; /* Operation at this node. */ enum strexType type; /* Return type of this operation. */ union strexVal val; /* Return value of this operation. */ }; struct strexIn /* Input to the strex parser - tokenizer and a hash full of built in functions. */ { 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 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 }, { "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 }, + { "strip", strexBuiltInStrip, 2, twoStrings }, }; 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 */ { @@ -958,35 +960,56 @@ 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 */ { +if (sameString(in, oldVal) ) + return lmCloneString(lm, newVal); // Simple case that also handles empty oldVal match empty in +else + { + if (isEmpty(oldVal)) + return lmCloneString(lm, in); + else + { char *s = replaceChars(in, oldVal, newVal); char *result = lmCloneString(lm, s); // Move to local memory freeMem(s); return result; } + } +} + +static char *stripAll(char *in, char *toRemove, struct lm *lm) +/* Remove every occurrence of any of the chars in toRemove from in. */ +{ +char *result = lmCloneString(lm, in); // Move to local memory +char c, *s = toRemove; +while ((c = *s++) != 0) + stripChar(result, c); +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; @@ -1041,30 +1064,37 @@ 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; } + case strexBuiltInStrip: + { + struct strexEval a = strexLocalEval(p->children, record, lookup, lm); + struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); + res.val.s = stripAll(a.val.s, b.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;