/* * eval.c - String to parameter * * Copyright 2012 by Werner Almesberger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include "bitset.h" #include "param.h" int eval_name(const struct format *fmt, const char *s, struct value *res) { res->u.name = s; return 1; } static int lookup_name(const struct names *name, const char *s) { const struct equiv *eq; int n; for (n = 0; name; n++) { for (eq = name->equiv; eq; eq = eq->next) if (eq->name == s) return n; name = name->next; } return -1; } int eval_set(const struct format *fmt, const char *s, struct value *res) { int n; bitset_zero(&res->u.set); n = lookup_name(fmt->u.set, s); if (n < 0) return 0; bitset_set(&res->u.set, n); return 1; } static int decode_mult(char c, double *mult) { switch (c) { case 'f': *mult = 1e-15; return 1; case 'p': *mult = 1e-12; return 1; case 'n': *mult = 1e-9; return 1; case 'u': *mult = 1e-6; return 1; case 'm': *mult = 1e-3; return 1; case 'k': *mult = 1e3; return 1; case 'M': *mult = 1e6; return 1; default: return 0; } } static int strip_unit(const char *s, const char **stop, const char *unit, double *mult) { int n; n = strlen(unit); if (*stop-n < s) return 0; if (!strcmp(*stop-n, unit)) *stop -= n; if (*stop > s) { if (decode_mult((*stop)[-1], mult)) (*stop)--; else *mult = 1; } else { *mult = 1; } return 1; } int eval_abs(const struct format *fmt, const char *s, struct value *res) { const char *slash, *stop; char *end; double mult, a, b; stop = strchr(s, 0); if (!strip_unit(s, &stop, fmt->u.abs, &mult)) return 0; slash = strchr(s, '/'); if (!slash) { res->u.abs = strtod(s, &end)*mult; return end == stop; } a = strtod(s, &end); if (end != slash) return 0; b = strtod(slash+1, &end); if (end != stop) return 0; res->u.abs = a/b*mult; return 1; } static int plusminus(const char *s, const char *slash, const char *stop, double *plus, double *minus) { char *end; if (s == slash || slash == stop) return 0; /* -M/+P */ if (*s == '-') { if (slash[1] != '+') return 0; *minus = strtod(s+1, &end); if (end != slash) return 0; *plus = strtod(slash+2, &end); return end == stop; } /* +P/-M */ if (*s == '+') { if (slash[1] != '-') return 0; *plus = strtod(s+1, &end); if (end != slash) return 0; *minus = strtod(slash+2, &end); return end == stop; } /* M/P */ *minus = strtod(s, &end); if (end != slash) return 0; *plus = strtod(slash+1, &end); return end == stop; } static int relative(const char *s, const char *stop, double *plus, double *minus) { const char *slash; char *end; slash = strchr(s, '/'); if (slash >= stop) return 0; if (slash) return plusminus(s, slash, stop, plus, minus); *plus = *minus = strtod(s, &end); return *plus >= 0 && end == stop; } int eval_rel(const struct format *fmt, const char *s, struct value *res) { const char *perc, *stop; double mult = 1; perc = strchr(s, '%'); res->u.rel.fract = !!perc; if (perc) { if (perc[1]) return 0; return relative(s, perc, &res->u.rel.plus, &res->u.rel.minus); } assert(fmt->u.rel->ops == ¶m_ops_abs); stop = strchr(s, 0); if (!strip_unit(s, &stop, fmt->u.rel->u.abs, &mult)) return 0; if (!relative(s, perc, &res->u.rel.plus, &res->u.rel.minus)) return 0; res->u.rel.plus *= mult; res->u.rel.minus *= mult; return 1; } int evaluate(const struct format *fmt, const char *s, struct value *res) { return fmt->ops->eval(fmt, s, res); }