155682Smarkm/* 278527Sassar * Copyright (c) 1997 - 2001 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#ifdef HAVE_CONFIG_H 3555682Smarkm#include <config.h> 36178825SdfrRCSID("$Id: parse_units.c 21005 2007-06-08 01:54:35Z lha $"); 3755682Smarkm#endif 3855682Smarkm 3955682Smarkm#include <stdio.h> 4055682Smarkm#include <ctype.h> 4155682Smarkm#include <string.h> 42178825Sdfr#include "roken.h" 4355682Smarkm#include "parse_units.h" 4455682Smarkm 4555682Smarkm/* 4655682Smarkm * Parse string in `s' according to `units' and return value. 4755682Smarkm * def_unit defines the default unit. 4855682Smarkm */ 4955682Smarkm 5055682Smarkmstatic int 5155682Smarkmparse_something (const char *s, const struct units *units, 5255682Smarkm const char *def_unit, 5355682Smarkm int (*func)(int res, int val, unsigned mult), 5455682Smarkm int init, 5555682Smarkm int accept_no_val_p) 5655682Smarkm{ 5755682Smarkm const char *p; 5855682Smarkm int res = init; 5955682Smarkm unsigned def_mult = 1; 6055682Smarkm 6155682Smarkm if (def_unit != NULL) { 6255682Smarkm const struct units *u; 6355682Smarkm 6455682Smarkm for (u = units; u->name; ++u) { 6555682Smarkm if (strcasecmp (u->name, def_unit) == 0) { 6655682Smarkm def_mult = u->mult; 6755682Smarkm break; 6855682Smarkm } 6955682Smarkm } 7055682Smarkm if (u->name == NULL) 7155682Smarkm return -1; 7255682Smarkm } 7355682Smarkm 7455682Smarkm p = s; 7555682Smarkm while (*p) { 7655682Smarkm double val; 7755682Smarkm char *next; 7855682Smarkm const struct units *u, *partial_unit; 7955682Smarkm size_t u_len; 8055682Smarkm unsigned partial; 8155682Smarkm int no_val_p = 0; 8255682Smarkm 8355682Smarkm while(isspace((unsigned char)*p) || *p == ',') 8455682Smarkm ++p; 8555682Smarkm 8655682Smarkm val = strtod (p, &next); /* strtol(p, &next, 0); */ 8778527Sassar if (p == next) { 8878527Sassar val = 0; 8955682Smarkm if(!accept_no_val_p) 9055682Smarkm return -1; 9155682Smarkm no_val_p = 1; 9255682Smarkm } 9355682Smarkm p = next; 9455682Smarkm while (isspace((unsigned char)*p)) 9555682Smarkm ++p; 9655682Smarkm if (*p == '\0') { 9755682Smarkm res = (*func)(res, val, def_mult); 9855682Smarkm if (res < 0) 9955682Smarkm return res; 10055682Smarkm break; 10155682Smarkm } else if (*p == '+') { 10255682Smarkm ++p; 10355682Smarkm val = 1; 10455682Smarkm } else if (*p == '-') { 10555682Smarkm ++p; 10655682Smarkm val = -1; 10755682Smarkm } 10855682Smarkm if (no_val_p && val == 0) 10955682Smarkm val = 1; 11055682Smarkm u_len = strcspn (p, ", \t"); 11155682Smarkm partial = 0; 11255682Smarkm partial_unit = NULL; 11355682Smarkm if (u_len > 1 && p[u_len - 1] == 's') 11455682Smarkm --u_len; 11555682Smarkm for (u = units; u->name; ++u) { 11655682Smarkm if (strncasecmp (p, u->name, u_len) == 0) { 11755682Smarkm if (u_len == strlen (u->name)) { 11855682Smarkm p += u_len; 11955682Smarkm res = (*func)(res, val, u->mult); 12055682Smarkm if (res < 0) 12155682Smarkm return res; 12255682Smarkm break; 12355682Smarkm } else { 12455682Smarkm ++partial; 12555682Smarkm partial_unit = u; 12655682Smarkm } 12755682Smarkm } 12855682Smarkm } 12955682Smarkm if (u->name == NULL) { 13055682Smarkm if (partial == 1) { 13155682Smarkm p += u_len; 13255682Smarkm res = (*func)(res, val, partial_unit->mult); 13355682Smarkm if (res < 0) 13455682Smarkm return res; 13555682Smarkm } else { 13655682Smarkm return -1; 13755682Smarkm } 13855682Smarkm } 13955682Smarkm if (*p == 's') 14055682Smarkm ++p; 14155682Smarkm } 14255682Smarkm return res; 14355682Smarkm} 14455682Smarkm 14555682Smarkm/* 14655682Smarkm * The string consists of a sequence of `n unit' 14755682Smarkm */ 14855682Smarkm 14955682Smarkmstatic int 15055682Smarkmacc_units(int res, int val, unsigned mult) 15155682Smarkm{ 15255682Smarkm return res + val * mult; 15355682Smarkm} 15455682Smarkm 155178825Sdfrint ROKEN_LIB_FUNCTION 15655682Smarkmparse_units (const char *s, const struct units *units, 15755682Smarkm const char *def_unit) 15855682Smarkm{ 15955682Smarkm return parse_something (s, units, def_unit, acc_units, 0, 0); 16055682Smarkm} 16155682Smarkm 16255682Smarkm/* 16355682Smarkm * The string consists of a sequence of `[+-]flag'. `orig' consists 16455682Smarkm * the original set of flags, those are then modified and returned as 16555682Smarkm * the function value. 16655682Smarkm */ 16755682Smarkm 16855682Smarkmstatic int 16955682Smarkmacc_flags(int res, int val, unsigned mult) 17055682Smarkm{ 17155682Smarkm if(val == 1) 17255682Smarkm return res | mult; 17355682Smarkm else if(val == -1) 17455682Smarkm return res & ~mult; 17555682Smarkm else if (val == 0) 17655682Smarkm return mult; 17755682Smarkm else 17855682Smarkm return -1; 17955682Smarkm} 18055682Smarkm 181178825Sdfrint ROKEN_LIB_FUNCTION 18255682Smarkmparse_flags (const char *s, const struct units *units, 18355682Smarkm int orig) 18455682Smarkm{ 18555682Smarkm return parse_something (s, units, NULL, acc_flags, orig, 1); 18655682Smarkm} 18755682Smarkm 18855682Smarkm/* 18955682Smarkm * Return a string representation according to `units' of `num' in `s' 19055682Smarkm * with maximum length `len'. The actual length is the function value. 19155682Smarkm */ 19255682Smarkm 19390926Snectarstatic int 19455682Smarkmunparse_something (int num, const struct units *units, char *s, size_t len, 195178825Sdfr int (*print) (char *, size_t, int, const char *, int), 196178825Sdfr int (*update) (int, unsigned), 19755682Smarkm const char *zero_string) 19855682Smarkm{ 19955682Smarkm const struct units *u; 20090926Snectar int ret = 0, tmp; 20155682Smarkm 20255682Smarkm if (num == 0) 20355682Smarkm return snprintf (s, len, "%s", zero_string); 20455682Smarkm 20555682Smarkm for (u = units; num > 0 && u->name; ++u) { 206178825Sdfr int divisor; 20755682Smarkm 208178825Sdfr divisor = num / u->mult; 209178825Sdfr if (divisor) { 21055682Smarkm num = (*update) (num, u->mult); 211178825Sdfr tmp = (*print) (s, len, divisor, u->name, num); 21290926Snectar if (tmp < 0) 21390926Snectar return tmp; 214178825Sdfr if (tmp > len) { 215178825Sdfr len = 0; 216178825Sdfr s = NULL; 217178825Sdfr } else { 218178825Sdfr len -= tmp; 219178825Sdfr s += tmp; 220178825Sdfr } 22155682Smarkm ret += tmp; 22255682Smarkm } 22355682Smarkm } 22455682Smarkm return ret; 22555682Smarkm} 22655682Smarkm 22755682Smarkmstatic int 228178825Sdfrprint_unit (char *s, size_t len, int divisor, const char *name, int rem) 22955682Smarkm{ 23055682Smarkm return snprintf (s, len, "%u %s%s%s", 231178825Sdfr divisor, name, 232178825Sdfr divisor == 1 ? "" : "s", 23355682Smarkm rem > 0 ? " " : ""); 23455682Smarkm} 23555682Smarkm 23655682Smarkmstatic int 23755682Smarkmupdate_unit (int in, unsigned mult) 23855682Smarkm{ 23955682Smarkm return in % mult; 24055682Smarkm} 24155682Smarkm 24255682Smarkmstatic int 24355682Smarkmupdate_unit_approx (int in, unsigned mult) 24455682Smarkm{ 24555682Smarkm if (in / mult > 0) 24655682Smarkm return 0; 24755682Smarkm else 24855682Smarkm return update_unit (in, mult); 24955682Smarkm} 25055682Smarkm 251178825Sdfrint ROKEN_LIB_FUNCTION 25255682Smarkmunparse_units (int num, const struct units *units, char *s, size_t len) 25355682Smarkm{ 25455682Smarkm return unparse_something (num, units, s, len, 25555682Smarkm print_unit, 25655682Smarkm update_unit, 25755682Smarkm "0"); 25855682Smarkm} 25955682Smarkm 260178825Sdfrint ROKEN_LIB_FUNCTION 26155682Smarkmunparse_units_approx (int num, const struct units *units, char *s, size_t len) 26255682Smarkm{ 26355682Smarkm return unparse_something (num, units, s, len, 26455682Smarkm print_unit, 26555682Smarkm update_unit_approx, 26655682Smarkm "0"); 26755682Smarkm} 26855682Smarkm 269178825Sdfrvoid ROKEN_LIB_FUNCTION 27055682Smarkmprint_units_table (const struct units *units, FILE *f) 27155682Smarkm{ 27255682Smarkm const struct units *u, *u2; 27355682Smarkm unsigned max_sz = 0; 27455682Smarkm 27555682Smarkm for (u = units; u->name; ++u) { 27655682Smarkm max_sz = max(max_sz, strlen(u->name)); 27755682Smarkm } 27855682Smarkm 27955682Smarkm for (u = units; u->name;) { 28055682Smarkm char buf[1024]; 28155682Smarkm const struct units *next; 28255682Smarkm 28355682Smarkm for (next = u + 1; next->name && next->mult == u->mult; ++next) 28455682Smarkm ; 28555682Smarkm 28655682Smarkm if (next->name) { 28755682Smarkm for (u2 = next; 28855682Smarkm u2->name && u->mult % u2->mult != 0; 28955682Smarkm ++u2) 29055682Smarkm ; 29155682Smarkm if (u2->name == NULL) 29255682Smarkm --u2; 29355682Smarkm unparse_units (u->mult, u2, buf, sizeof(buf)); 29455682Smarkm fprintf (f, "1 %*s = %s\n", max_sz, u->name, buf); 29555682Smarkm } else { 29655682Smarkm fprintf (f, "1 %s\n", u->name); 29755682Smarkm } 29855682Smarkm u = next; 29955682Smarkm } 30055682Smarkm} 30155682Smarkm 30255682Smarkmstatic int 303178825Sdfrprint_flag (char *s, size_t len, int divisor, const char *name, int rem) 30455682Smarkm{ 30555682Smarkm return snprintf (s, len, "%s%s", name, rem > 0 ? ", " : ""); 30655682Smarkm} 30755682Smarkm 30855682Smarkmstatic int 30955682Smarkmupdate_flag (int in, unsigned mult) 31055682Smarkm{ 31155682Smarkm return in - mult; 31255682Smarkm} 31355682Smarkm 314178825Sdfrint ROKEN_LIB_FUNCTION 31555682Smarkmunparse_flags (int num, const struct units *units, char *s, size_t len) 31655682Smarkm{ 31755682Smarkm return unparse_something (num, units, s, len, 31855682Smarkm print_flag, 31955682Smarkm update_flag, 32055682Smarkm ""); 32155682Smarkm} 32255682Smarkm 323178825Sdfrvoid ROKEN_LIB_FUNCTION 32455682Smarkmprint_flags_table (const struct units *units, FILE *f) 32555682Smarkm{ 32655682Smarkm const struct units *u; 32755682Smarkm 32855682Smarkm for(u = units; u->name; ++u) 32955682Smarkm fprintf(f, "%s%s", u->name, (u+1)->name ? ", " : "\n"); 33055682Smarkm} 331