mirror of
git://git.suckless.org/sbase
synced 2025-04-21 06:35:24 +00:00
expr: treat expressions as strs until evaluation
Comparison operations (>, <, =, etc.) and matching operations must operate originally provided string not one that has gone back and forth through string formatting. This caused operations such as the following to give incorrect results: ./expr 00003 : '.*' Before: 1 After: 5 This commit fixes that issue.
This commit is contained in:
parent
7d5b113423
commit
e50d533d59
71
expr.c
71
expr.c
@ -18,11 +18,13 @@ struct val {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
enan(struct val *v)
|
tonum(struct val *v)
|
||||||
{
|
{
|
||||||
if (!v->str)
|
const char *errstr;
|
||||||
return;
|
long long d = strtonum(v->str, LLONG_MIN, LLONG_MAX, &errstr);
|
||||||
enprintf(2, "syntax error: expected integer, got %s\n", v->str);
|
if (errstr)
|
||||||
|
enprintf(2, "error: expected integer, got %s\n", v->str);
|
||||||
|
v->num = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -37,16 +39,14 @@ static int
|
|||||||
valcmp(struct val *a, struct val *b)
|
valcmp(struct val *a, struct val *b)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char buf[BUFSIZ];
|
const char *err1, *err2;
|
||||||
|
long long d1, d2;
|
||||||
|
|
||||||
if (!a->str && !b->str) {
|
d1 = strtonum(a->str, LLONG_MIN, LLONG_MAX, &err1);
|
||||||
ret = (a->num > b->num) - (a->num < b->num);
|
d2 = strtonum(b->str, LLONG_MIN, LLONG_MAX, &err2);
|
||||||
} else if (a->str && !b->str) {
|
|
||||||
snprintf(buf, sizeof(buf), "%lld", b->num);
|
if (!err1 && !err2) {
|
||||||
ret = strcmp(a->str, buf);
|
ret = (d1 > d2) - (d1 < d2);
|
||||||
} else if (!a->str && b->str) {
|
|
||||||
snprintf(buf, sizeof(buf), "%lld", a->num);
|
|
||||||
ret = strcmp(buf, b->str);
|
|
||||||
} else {
|
} else {
|
||||||
ret = strcmp(a->str, b->str);
|
ret = strcmp(a->str, b->str);
|
||||||
}
|
}
|
||||||
@ -61,24 +61,10 @@ match(struct val *vstr, struct val *vregx, struct val *ret)
|
|||||||
regmatch_t matches[2];
|
regmatch_t matches[2];
|
||||||
long long d;
|
long long d;
|
||||||
size_t anchlen;
|
size_t anchlen;
|
||||||
char strbuf[BUFSIZ], regxbuf[BUFSIZ],
|
char *s, *p, *anchreg;
|
||||||
*s, *p, *anchreg, *str, *regx;
|
char *str = vstr->str, *regx = vregx->str;
|
||||||
const char *errstr;
|
const char *errstr;
|
||||||
|
|
||||||
if (!vstr->str) {
|
|
||||||
snprintf(strbuf, sizeof(strbuf), "%lld", vstr->num);
|
|
||||||
str = strbuf;
|
|
||||||
} else {
|
|
||||||
str = vstr->str;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vregx->str) {
|
|
||||||
snprintf(regxbuf, sizeof(regxbuf), "%lld", vregx->num);
|
|
||||||
regx = regxbuf;
|
|
||||||
} else {
|
|
||||||
regx = vregx->str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* anchored regex */
|
/* anchored regex */
|
||||||
anchlen = strlen(regx) + 1 + 1;
|
anchlen = strlen(regx) + 1 + 1;
|
||||||
anchreg = emalloc(anchlen);
|
anchreg = emalloc(anchlen);
|
||||||
@ -152,11 +138,11 @@ doop(int *ophead, int *opp, struct val *valhead, struct val *valp)
|
|||||||
case LE : ret.num = (valcmp(a, b) <= 0); break;
|
case LE : ret.num = (valcmp(a, b) <= 0); break;
|
||||||
case NE : ret.num = (valcmp(a, b) != 0); break;
|
case NE : ret.num = (valcmp(a, b) != 0); break;
|
||||||
|
|
||||||
case '+': enan(a); enan(b); ret.num = a->num + b->num; break;
|
case '+': tonum(a); tonum(b); ret.num = a->num + b->num; break;
|
||||||
case '-': enan(a); enan(b); ret.num = a->num - b->num; break;
|
case '-': tonum(a); tonum(b); ret.num = a->num - b->num; break;
|
||||||
case '*': enan(a); enan(b); ret.num = a->num * b->num; break;
|
case '*': tonum(a); tonum(b); ret.num = a->num * b->num; break;
|
||||||
case '/': enan(a); enan(b); ezero(b); ret.num = a->num / b->num; break;
|
case '/': tonum(a); tonum(b); ezero(b); ret.num = a->num / b->num; break;
|
||||||
case '%': enan(a); enan(b); ezero(b); ret.num = a->num % b->num; break;
|
case '%': tonum(a); tonum(b); ezero(b); ret.num = a->num % b->num; break;
|
||||||
|
|
||||||
case ':': match(a, b, &ret); break;
|
case ':': match(a, b, &ret); break;
|
||||||
}
|
}
|
||||||
@ -167,25 +153,15 @@ doop(int *ophead, int *opp, struct val *valhead, struct val *valp)
|
|||||||
static int
|
static int
|
||||||
lex(char *s, struct val *v)
|
lex(char *s, struct val *v)
|
||||||
{
|
{
|
||||||
long long d;
|
|
||||||
int type = VAL;
|
int type = VAL;
|
||||||
char *ops = "|&=><+-*/%():";
|
char *ops = "|&=><+-*/%():";
|
||||||
const char *errstr;
|
|
||||||
|
|
||||||
d = strtonum(s, LLONG_MIN, LLONG_MAX, &errstr);
|
if (s[0] && strchr(ops, s[0]) && !s[1]) {
|
||||||
|
|
||||||
if (!errstr) {
|
|
||||||
/* integer */
|
|
||||||
v->num = d;
|
|
||||||
} else if (s[0] && strchr(ops, s[0]) && !s[1]) {
|
|
||||||
/* one-char operand */
|
/* one-char operand */
|
||||||
type = s[0];
|
type = s[0];
|
||||||
} else if (s[0] && strchr("><!", s[0]) && s[1] == '=' && !s[2]) {
|
} else if (s[0] && strchr("><!", s[0]) && s[1] == '=' && !s[2]) {
|
||||||
/* two-char operand */
|
/* two-char operand */
|
||||||
type = (s[0] == '>') ? GE : (s[0] == '<') ? LE : NE;
|
type = (s[0] == '>') ? GE : (s[0] == '<') ? LE : NE;
|
||||||
} else {
|
|
||||||
/* string */
|
|
||||||
v->str = s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
@ -211,8 +187,9 @@ parse(char *expr[], int numexpr)
|
|||||||
for (; *expr; expr++) {
|
for (; *expr; expr++) {
|
||||||
switch ((type = lex(*expr, &v))) {
|
switch ((type = lex(*expr, &v))) {
|
||||||
case VAL:
|
case VAL:
|
||||||
valp->str = v.str;
|
/* treatment of *expr is not known until
|
||||||
valp->num = v.num;
|
* doop(); treat as a string for now */
|
||||||
|
valp->str = *expr;
|
||||||
valp++;
|
valp++;
|
||||||
break;
|
break;
|
||||||
case '(':
|
case '(':
|
||||||
|
Loading…
Reference in New Issue
Block a user