parse_units.c revision 233294
11839Swollman/*
21839Swollman * Copyright (c) 1997 - 2001 Kungliga Tekniska H��gskolan
31839Swollman * (Royal Institute of Technology, Stockholm, Sweden).
41839Swollman * All rights reserved.
51839Swollman *
61839Swollman * Redistribution and use in source and binary forms, with or without
71839Swollman * modification, are permitted provided that the following conditions
81839Swollman * are met:
91839Swollman *
101839Swollman * 1. Redistributions of source code must retain the above copyright
111839Swollman *    notice, this list of conditions and the following disclaimer.
121839Swollman *
131839Swollman * 2. Redistributions in binary form must reproduce the above copyright
141839Swollman *    notice, this list of conditions and the following disclaimer in the
151839Swollman *    documentation and/or other materials provided with the distribution.
161839Swollman *
171839Swollman * 3. Neither the name of the Institute nor the names of its contributors
181839Swollman *    may be used to endorse or promote products derived from this software
191839Swollman *    without specific prior written permission.
201839Swollman *
211839Swollman * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
221839Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231839Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241839Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
251839Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261839Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271839Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281903Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291903Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301903Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311903Swollman * SUCH DAMAGE.
321839Swollman */
331839Swollman
341839Swollman#include <config.h>
351839Swollman
361839Swollman#include <stdio.h>
371839Swollman#include <ctype.h>
381839Swollman#include <string.h>
391839Swollman#include "roken.h"
401839Swollman#include "parse_units.h"
411903Swollman
421903Swollman/*
431903Swollman * Parse string in `s' according to `units' and return value.
441839Swollman * def_unit defines the default unit.
451839Swollman */
461839Swollman
471839Swollmanstatic int
481839Swollmanparse_something (const char *s, const struct units *units,
491839Swollman		 const char *def_unit,
501839Swollman		 int (*func)(int res, int val, unsigned mult),
511839Swollman		 int init,
521839Swollman		 int accept_no_val_p)
531839Swollman{
541839Swollman    const char *p;
551839Swollman    int res = init;
561839Swollman    unsigned def_mult = 1;
571839Swollman
581839Swollman    if (def_unit != NULL) {
591839Swollman	const struct units *u;
601839Swollman
611839Swollman	for (u = units; u->name; ++u) {
621839Swollman	    if (strcasecmp (u->name, def_unit) == 0) {
631839Swollman		def_mult = u->mult;
641839Swollman		break;
651839Swollman	    }
661839Swollman	}
671839Swollman	if (u->name == NULL)
681839Swollman	    return -1;
691839Swollman    }
701839Swollman
711839Swollman    p = s;
721839Swollman    while (*p) {
731839Swollman	int val;
741839Swollman	char *next;
751839Swollman	const struct units *u, *partial_unit;
761839Swollman	size_t u_len;
771839Swollman	unsigned partial;
781839Swollman	int no_val_p = 0;
791839Swollman
801839Swollman	while(isspace((unsigned char)*p) || *p == ',')
811839Swollman	    ++p;
821839Swollman
831839Swollman	val = strtol(p, &next, 0);
841839Swollman	if (p == next) {
851839Swollman	    val = 0;
861839Swollman	    if(!accept_no_val_p)
871839Swollman		return -1;
881839Swollman	    no_val_p = 1;
891839Swollman	}
901839Swollman	p = next;
911839Swollman	while (isspace((unsigned char)*p))
921839Swollman	    ++p;
931839Swollman	if (*p == '\0') {
941839Swollman	    res = (*func)(res, val, def_mult);
951839Swollman	    if (res < 0)
961839Swollman		return res;
971839Swollman	    break;
981839Swollman	} else if (*p == '+') {
991839Swollman	    ++p;
1001839Swollman	    val = 1;
1011839Swollman	} else if (*p == '-') {
1021839Swollman	    ++p;
1031839Swollman	    val = -1;
1041839Swollman	}
1051839Swollman	if (no_val_p && val == 0)
1061839Swollman	    val = 1;
1071839Swollman	u_len = strcspn (p, ", \t");
1081839Swollman	partial = 0;
1091839Swollman	partial_unit = NULL;
1101839Swollman	if (u_len > 1 && p[u_len - 1] == 's')
1111839Swollman	    --u_len;
1121839Swollman	for (u = units; u->name; ++u) {
1131839Swollman	    if (strncasecmp (p, u->name, u_len) == 0) {
1141839Swollman		if (u_len == strlen (u->name)) {
1151839Swollman		    p += u_len;
1161839Swollman		    res = (*func)(res, val, u->mult);
1171839Swollman		    if (res < 0)
1181839Swollman			return res;
1191839Swollman		    break;
1201839Swollman		} else {
1211839Swollman		    ++partial;
1221839Swollman		    partial_unit = u;
1231839Swollman		}
1241839Swollman	    }
1251839Swollman	}
1261839Swollman	if (u->name == NULL) {
1271839Swollman	    if (partial == 1) {
1281839Swollman		p += u_len;
1291839Swollman		res = (*func)(res, val, partial_unit->mult);
1301839Swollman		if (res < 0)
1311839Swollman		    return res;
1321839Swollman	    } else {
1331839Swollman		return -1;
1341839Swollman	    }
1351839Swollman	}
1361839Swollman	if (*p == 's')
1371839Swollman	    ++p;
1381839Swollman    }
1391839Swollman    return res;
1401839Swollman}
1411839Swollman
1421839Swollman/*
1431839Swollman * The string consists of a sequence of `n unit'
1441839Swollman */
1451839Swollman
1461839Swollmanstatic int
1471839Swollmanacc_units(int res, int val, unsigned mult)
1481839Swollman{
1491839Swollman    return res + val * mult;
1501839Swollman}
1511839Swollman
1521839SwollmanROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
1531839Swollmanparse_units (const char *s, const struct units *units,
1541839Swollman	     const char *def_unit)
1551839Swollman{
1561839Swollman    return parse_something (s, units, def_unit, acc_units, 0, 0);
1571839Swollman}
1581839Swollman
1591839Swollman/*
1601839Swollman * The string consists of a sequence of `[+-]flag'.  `orig' consists
1611903Swollman * the original set of flags, those are then modified and returned as
1621839Swollman * the function value.
1631839Swollman */
1641839Swollman
1651839Swollmanstatic int
1661839Swollmanacc_flags(int res, int val, unsigned mult)
1671839Swollman{
1681903Swollman    if(val == 1)
1691839Swollman	return res | mult;
1701839Swollman    else if(val == -1)
1711839Swollman	return res & ~mult;
1721839Swollman    else if (val == 0)
1731839Swollman	return mult;
1741839Swollman    else
1751839Swollman	return -1;
1761903Swollman}
1771839Swollman
1781839SwollmanROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
1791839Swollmanparse_flags (const char *s, const struct units *units,
1801839Swollman	     int orig)
1811839Swollman{
1821839Swollman    return parse_something (s, units, NULL, acc_flags, orig, 1);
1831839Swollman}
1841903Swollman
1851839Swollman/*
1861839Swollman * Return a string representation according to `units' of `num' in `s'
1871839Swollman * with maximum length `len'.  The actual length is the function value.
1881839Swollman */
1891839Swollman
1901839Swollmanstatic int
1911839Swollmanunparse_something (int num, const struct units *units, char *s, size_t len,
1921903Swollman		   int (*print) (char *, size_t, int, const char *, int),
1931903Swollman		   int (*update) (int, unsigned),
1941903Swollman		   const char *zero_string)
1951903Swollman{
196    const struct units *u;
197    int ret = 0, tmp;
198
199    if (num == 0)
200	return snprintf (s, len, "%s", zero_string);
201
202    for (u = units; num > 0 && u->name; ++u) {
203	int divisor;
204
205	divisor = num / u->mult;
206	if (divisor) {
207	    num = (*update) (num, u->mult);
208	    tmp = (*print) (s, len, divisor, u->name, num);
209	    if (tmp < 0)
210		return tmp;
211	    if (tmp > (int) len) {
212		len = 0;
213		s = NULL;
214	    } else {
215		len -= tmp;
216		s += tmp;
217	    }
218	    ret += tmp;
219	}
220    }
221    return ret;
222}
223
224static int
225print_unit (char *s, size_t len, int divisor, const char *name, int rem)
226{
227    return snprintf (s, len, "%u %s%s%s",
228		     divisor, name,
229		     divisor == 1 ? "" : "s",
230		     rem > 0 ? " " : "");
231}
232
233static int
234update_unit (int in, unsigned mult)
235{
236    return in % mult;
237}
238
239static int
240update_unit_approx (int in, unsigned mult)
241{
242    if (in / mult > 0)
243	return 0;
244    else
245	return update_unit (in, mult);
246}
247
248ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
249unparse_units (int num, const struct units *units, char *s, size_t len)
250{
251    return unparse_something (num, units, s, len,
252			      print_unit,
253			      update_unit,
254			      "0");
255}
256
257ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
258unparse_units_approx (int num, const struct units *units, char *s, size_t len)
259{
260    return unparse_something (num, units, s, len,
261			      print_unit,
262			      update_unit_approx,
263			      "0");
264}
265
266ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
267print_units_table (const struct units *units, FILE *f)
268{
269    const struct units *u, *u2;
270    size_t max_sz = 0;
271
272    for (u = units; u->name; ++u) {
273	max_sz = max(max_sz, strlen(u->name));
274    }
275
276    for (u = units; u->name;) {
277	char buf[1024];
278	const struct units *next;
279
280	for (next = u + 1; next->name && next->mult == u->mult; ++next)
281	    ;
282
283	if (next->name) {
284	    for (u2 = next;
285		 u2->name && u->mult % u2->mult != 0;
286		 ++u2)
287		;
288	    if (u2->name == NULL)
289		--u2;
290	    unparse_units (u->mult, u2, buf, sizeof(buf));
291	    fprintf (f, "1 %*s = %s\n", (int)max_sz, u->name, buf);
292	} else {
293	    fprintf (f, "1 %s\n", u->name);
294	}
295	u = next;
296    }
297}
298
299static int
300print_flag (char *s, size_t len, int divisor, const char *name, int rem)
301{
302    return snprintf (s, len, "%s%s", name, rem > 0 ? ", " : "");
303}
304
305static int
306update_flag (int in, unsigned mult)
307{
308    return in - mult;
309}
310
311ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
312unparse_flags (int num, const struct units *units, char *s, size_t len)
313{
314    return unparse_something (num, units, s, len,
315			      print_flag,
316			      update_flag,
317			      "");
318}
319
320ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
321print_flags_table (const struct units *units, FILE *f)
322{
323    const struct units *u;
324
325    for(u = units; u->name; ++u)
326	fprintf(f, "%s%s", u->name, (u+1)->name ? ", " : "\n");
327}
328