f56f480add42cd89cb03aa1fc6ff503a1c5e4203 kent Thu Aug 15 09:01:34 2019 -0700 Made now return time in the ISO 1806 format variant the expresses it in local time with an offset to GMT. Moved around some sections in the doc file. diff --git src/lib/strex.c src/lib/strex.c index a86b81b..ffe3e39 100644 --- src/lib/strex.c +++ src/lib/strex.c @@ -374,30 +374,33 @@ in->tkz->lf->fileName); } static void skipOverRequired(struct strexIn *in, char *expecting) /* Make sure that next token is tok, and skip over it. */ { tokenizerMustHaveNext(in->tkz); if (!sameWord(in->tkz->string, expecting)) expectingGot(in, expecting, in->tkz->string); } static struct strexParse *strexParseExpression(struct strexIn *in); /* Parse out an expression with a single value */ +static struct strexParse *strexParseOr(struct strexIn *in); +/* Parse out logical/string or binary operator. Lowest level logical op, before conditional */ + static struct strexParse *strexParseAtom(struct strexIn *in) /* Return low level (symbol or literal) or a parenthesis enclosed expression. */ { struct tokenizer *tkz = in->tkz; char *tok = tokenizerMustHaveNext(tkz); struct strexParse *p; AllocVar(p); char c = tok[0]; if (c == '\'' || c == '"') { p->op = strexOpLiteral; p->type = strexTypeString; int len = strlen(tok+1); p->val.s = cloneStringZ(tok+1, len-1); } @@ -612,31 +615,31 @@ { /* Check that the current op, is a pure symbol. */ if (function->op != strexOpSymbol) errAbort("Unexpected '(' line %d of %s", tkz->lf->lineIx, tkz->lf->fileName); /* Look up function to call and complain if it doesn't exist */ char *functionName = function->val.s; /* Deal with special named ops like pick */ if (sameString(functionName, "pick")) { /* Yay, the pick operation. It looks like * pick( keyExp, key1, val1, key2, val2, ..., keyN, valN) * the logic is to evaluate keyExp, and then pick one of the valN's to return, * the one where the keyN is the same as keyExp */ - struct strexParse *keyExp = strexParseExpression(in); + struct strexParse *keyExp = strexParseOr(in); slAddHead(&function->children, keyExp); skipOverRequired(in, "?"); struct strexParse *firstVal = NULL; for (;;) { struct strexParse *key = strexParseCoerce(strexParseExpression(in), keyExp->type); slAddHead(&function->children, key); skipOverRequired(in, ":"); struct strexParse *val = strexParseExpression(in); if (firstVal == NULL) firstVal = val; else { if (firstVal->type != val->type) @@ -886,31 +889,31 @@ l = strexParseCoerce(l, childType); r = strexParseCoerce(r, childType); /* Create the binary operation */ AllocVar(p); p->op = strexOpAnd; p->type = childType; /* Now hang children onto node. */ p->children = l; l->next = r; } } static struct strexParse *strexParseOr(struct strexIn *in) -/* Parse out plus or minus. */ +/* Parse out logical/string or binary operator. */ { struct tokenizer *tkz = in->tkz; struct strexParse *p = strexParseAnd(in); for (;;) { char *tok = tokenizerNext(tkz); if (tok == NULL || differentString(tok, "or")) { tokenizerReuse(tkz); return p; } /* What we've parsed so far becomes left side of binary op, next term ends up on right. */ struct strexParse *l = p; struct strexParse *r = strexParseAnd(in); @@ -1347,32 +1350,36 @@ struct strexEval c = strexLocalEval(p->children->next->next, record, lookup, lm); char *between = stringBetween(a.val.s, c.val.s, b.val.s); res.val.s = emptyForNull(lmCloneString(lm, between)); freeMem(between); break; } case strexBuiltInSplit: { struct strexEval a = strexLocalEval(p->children, record, lookup, lm); struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); res.val.s = splitString(a.val.s, b.val.i, lm); break; } case strexBuiltInNow: { - time_t now = time(NULL); - res.val.s = lmCloneString(lm, ctime(&now)); + time_t now; + time(&now); + char buf[64]; + // strftime(buf, sizeof buf, "%FT%TZ", gmtime(&now)); + strftime(buf, sizeof buf, "%FT%T%z", localtime(&now)); + res.val.s = lmCloneString(lm, buf); eraseTrailingSpaces(res.val.s); break; } case strexBuiltInMd5: { struct strexEval a = strexLocalEval(p->children, record, lookup, lm); char *md5 = hmacMd5("", a.val.s); res.val.s = lmCloneString(lm, md5); freez(&md5); break; } case strexBuiltInSeparate: { struct strexEval a = strexLocalEval(p->children, record, lookup, lm); struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm);