Root/b2/eval.c

1/*
2 * eval.c - String to parameter
3 *
4 * Copyright 2012 by Werner Almesberger
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12
13#include <stdlib.h>
14#include <string.h>
15#include <assert.h>
16
17#include "bitset.h"
18#include "param.h"
19
20
21int eval_name(const struct format *fmt, const char *s, struct value *res)
22{
23    (void) fmt;
24    res->u.s = s;
25    return 1;
26}
27
28
29static int lookup_name(const struct names *name, const char *s)
30{
31    const struct equiv *eq;
32    int n;
33
34    for (n = 0; name; n++) {
35        for (eq = name->equiv; eq; eq = eq->next)
36            if (eq->name == s)
37                return n;
38        name = name->next;
39    }
40    return -1;
41}
42
43
44int eval_set(const struct format *fmt, const char *s, struct value *res)
45{
46    int n;
47
48    bitset_zero(&res->u.set);
49    n = lookup_name(fmt->u.set, s);
50    if (n < 0)
51        return 0;
52    bitset_set(&res->u.set, n);
53    return 1;
54}
55
56
57static int decode_mult(char c, double *mult)
58{
59    switch (c) {
60    case 'f':
61        *mult = 1e-15;
62        return 1;
63    case 'p':
64        *mult = 1e-12;
65        return 1;
66    case 'n':
67        *mult = 1e-9;
68        return 1;
69    case 'u':
70        *mult = 1e-6;
71        return 1;
72    case 'm':
73        *mult = 1e-3;
74        return 1;
75    case 'k':
76        *mult = 1e3;
77        return 1;
78    case 'M':
79        *mult = 1e6;
80        return 1;
81    case 'G':
82        *mult = 1e9;
83        return 1;
84    default:
85        return 0;
86    }
87}
88
89
90static int strip_unit(const char *s, const char **stop, const char *unit,
91    double *mult)
92{
93    int n;
94
95    if (unit) {
96        n = strlen(unit);
97        if (*stop-n < s)
98            return 0;
99        if (!strcmp(*stop-n, unit))
100            *stop -= n;
101    }
102    if (*stop > s) {
103        if (decode_mult((*stop)[-1], mult))
104            (*stop)--;
105        else
106            *mult = 1;
107    } else {
108        *mult = 1;
109    }
110    return 1;
111}
112
113
114int eval_abs(const struct format *fmt, const char *s,
115    struct value *res)
116{
117    const char *slash, *stop;
118    char *end;
119    double mult, a, b;
120
121    stop = strchr(s, 0);
122    if (!strip_unit(s, &stop, fmt->u.abs, &mult))
123        return 0;
124    slash = strchr(s, '/');
125    if (!slash) {
126        res->u.abs = strtod(s, &end)*mult;
127        return end == stop;
128    }
129    a = strtod(s, &end);
130    if (end != slash)
131        return 0;
132    b = strtod(slash+1, &end);
133    if (end != stop)
134        return 0;
135    res->u.abs = a/b*mult;
136    return 1;
137}
138
139
140static int plusminus(const char *s, const char *slash, const char *stop,
141    double *plus, double *minus)
142{
143    char *end;
144
145    if (s == slash || slash == stop)
146        return 0;
147
148    /* -M/+P */
149    if (*s == '-') {
150        if (slash[1] != '+')
151            return 0;
152        *minus = strtod(s+1, &end);
153        if (end != slash)
154            return 0;
155        *plus = strtod(slash+2, &end);
156        return end == stop;
157    }
158
159    /* +P/-M */
160    if (*s == '+') {
161        if (slash[1] != '-')
162            return 0;
163        *plus = strtod(s+1, &end);
164        if (end != slash)
165            return 0;
166        *minus = strtod(slash+2, &end);
167        return end == stop;
168    }
169
170    /* M/P */
171    *minus = strtod(s, &end);
172    if (end != slash)
173        return 0;
174    *plus = strtod(slash+1, &end);
175    return end == stop;
176}
177
178
179static int relative(const char *s, const char *stop, double *plus,
180    double *minus)
181{
182    const char *slash;
183    char *end;
184
185    slash = strchr(s, '/');
186    if (slash >= stop)
187        return 0;
188    if (slash)
189        return plusminus(s, slash, stop, plus, minus);
190    *plus = *minus = strtod(s, &end);
191    return *plus >= 0 && end == stop;
192}
193
194
195int eval_rel(const struct format *fmt, const char *s,
196    struct value *res)
197{
198    const char *perc, *stop;
199    double mult = 1;
200
201    perc = strchr(s, '%');
202    res->u.rel.fract = !!perc;
203    if (perc) {
204        if (perc[1])
205            return 0;
206        if (!relative(s, perc, &res->u.rel.plus, &res->u.rel.minus))
207            return 0;
208        res->u.rel.plus /= 100;
209        res->u.rel.minus /= 100;
210        return 1;
211    }
212    assert(fmt->u.rel->ops == &param_ops_abs);
213    stop = strchr(s, 0);
214    if (!strip_unit(s, &stop, fmt->u.rel->u.abs, &mult))
215        return 0;
216    if (!relative(s, stop, &res->u.rel.plus, &res->u.rel.minus))
217        return 0;
218    res->u.rel.plus *= mult;
219    res->u.rel.minus *= mult;
220    return 1;
221}
222
223
224int evaluate(const struct format *fmt, const char *s, struct value *res)
225{
226    return fmt->ops->eval(fmt, s, res);
227}
228

Archive Download this file

Branches:
master



interactive