155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2001 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include <config.h> 3555682Smarkm 3655682Smarkm#include <stdio.h> 3755682Smarkm#include <ctype.h> 3855682Smarkm#include <string.h> 39178825Sdfr#include "roken.h" 4055682Smarkm#include "parse_units.h" 4155682Smarkm 4255682Smarkm/* 4355682Smarkm * Parse string in `s' according to `units' and return value. 4455682Smarkm * def_unit defines the default unit. 4555682Smarkm */ 4655682Smarkm 4755682Smarkmstatic int 4855682Smarkmparse_something (const char *s, const struct units *units, 4955682Smarkm const char *def_unit, 5055682Smarkm int (*func)(int res, int val, unsigned mult), 5155682Smarkm int init, 5255682Smarkm int accept_no_val_p) 5355682Smarkm{ 5455682Smarkm const char *p; 5555682Smarkm int res = init; 5655682Smarkm unsigned def_mult = 1; 5755682Smarkm 5855682Smarkm if (def_unit != NULL) { 5955682Smarkm const struct units *u; 6055682Smarkm 6155682Smarkm for (u = units; u->name; ++u) { 6255682Smarkm if (strcasecmp (u->name, def_unit) == 0) { 6355682Smarkm def_mult = u->mult; 6455682Smarkm break; 6555682Smarkm } 6655682Smarkm } 6755682Smarkm if (u->name == NULL) 6855682Smarkm return -1; 6955682Smarkm } 7055682Smarkm 7155682Smarkm p = s; 7255682Smarkm while (*p) { 73233294Sstas int val; 7455682Smarkm char *next; 7555682Smarkm const struct units *u, *partial_unit; 7655682Smarkm size_t u_len; 7755682Smarkm unsigned partial; 7855682Smarkm int no_val_p = 0; 7955682Smarkm 8055682Smarkm while(isspace((unsigned char)*p) || *p == ',') 8155682Smarkm ++p; 8255682Smarkm 83233294Sstas val = strtol(p, &next, 0); 8478527Sassar if (p == next) { 8578527Sassar val = 0; 8655682Smarkm if(!accept_no_val_p) 8755682Smarkm return -1; 8855682Smarkm no_val_p = 1; 8955682Smarkm } 9055682Smarkm p = next; 9155682Smarkm while (isspace((unsigned char)*p)) 9255682Smarkm ++p; 9355682Smarkm if (*p == '\0') { 9455682Smarkm res = (*func)(res, val, def_mult); 9555682Smarkm if (res < 0) 9655682Smarkm return res; 9755682Smarkm break; 9855682Smarkm } else if (*p == '+') { 9955682Smarkm ++p; 10055682Smarkm val = 1; 10155682Smarkm } else if (*p == '-') { 10255682Smarkm ++p; 10355682Smarkm val = -1; 10455682Smarkm } 10555682Smarkm if (no_val_p && val == 0) 10655682Smarkm val = 1; 10755682Smarkm u_len = strcspn (p, ", \t"); 10855682Smarkm partial = 0; 10955682Smarkm partial_unit = NULL; 11055682Smarkm if (u_len > 1 && p[u_len - 1] == 's') 11155682Smarkm --u_len; 11255682Smarkm for (u = units; u->name; ++u) { 11355682Smarkm if (strncasecmp (p, u->name, u_len) == 0) { 11455682Smarkm if (u_len == strlen (u->name)) { 11555682Smarkm p += u_len; 11655682Smarkm res = (*func)(res, val, u->mult); 11755682Smarkm if (res < 0) 11855682Smarkm return res; 11955682Smarkm break; 12055682Smarkm } else { 12155682Smarkm ++partial; 12255682Smarkm partial_unit = u; 12355682Smarkm } 12455682Smarkm } 12555682Smarkm } 12655682Smarkm if (u->name == NULL) { 12755682Smarkm if (partial == 1) { 12855682Smarkm p += u_len; 12955682Smarkm res = (*func)(res, val, partial_unit->mult); 13055682Smarkm if (res < 0) 13155682Smarkm return res; 13255682Smarkm } else { 13355682Smarkm return -1; 13455682Smarkm } 13555682Smarkm } 13655682Smarkm if (*p == 's') 13755682Smarkm ++p; 13855682Smarkm } 13955682Smarkm return res; 14055682Smarkm} 14155682Smarkm 14255682Smarkm/* 14355682Smarkm * The string consists of a sequence of `n unit' 14455682Smarkm */ 14555682Smarkm 14655682Smarkmstatic int 14755682Smarkmacc_units(int res, int val, unsigned mult) 14855682Smarkm{ 14955682Smarkm return res + val * mult; 15055682Smarkm} 15155682Smarkm 152233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 15355682Smarkmparse_units (const char *s, const struct units *units, 15455682Smarkm const char *def_unit) 15555682Smarkm{ 15655682Smarkm return parse_something (s, units, def_unit, acc_units, 0, 0); 15755682Smarkm} 15855682Smarkm 15955682Smarkm/* 16055682Smarkm * The string consists of a sequence of `[+-]flag'. `orig' consists 16155682Smarkm * the original set of flags, those are then modified and returned as 16255682Smarkm * the function value. 16355682Smarkm */ 16455682Smarkm 16555682Smarkmstatic int 16655682Smarkmacc_flags(int res, int val, unsigned mult) 16755682Smarkm{ 16855682Smarkm if(val == 1) 16955682Smarkm return res | mult; 17055682Smarkm else if(val == -1) 17155682Smarkm return res & ~mult; 17255682Smarkm else if (val == 0) 17355682Smarkm return mult; 17455682Smarkm else 17555682Smarkm return -1; 17655682Smarkm} 17755682Smarkm 178233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 17955682Smarkmparse_flags (const char *s, const struct units *units, 18055682Smarkm int orig) 18155682Smarkm{ 18255682Smarkm return parse_something (s, units, NULL, acc_flags, orig, 1); 18355682Smarkm} 18455682Smarkm 18555682Smarkm/* 18655682Smarkm * Return a string representation according to `units' of `num' in `s' 18755682Smarkm * with maximum length `len'. The actual length is the function value. 18855682Smarkm */ 18955682Smarkm 19090926Snectarstatic int 19155682Smarkmunparse_something (int num, const struct units *units, char *s, size_t len, 192178825Sdfr int (*print) (char *, size_t, int, const char *, int), 193178825Sdfr int (*update) (int, unsigned), 19455682Smarkm const char *zero_string) 19555682Smarkm{ 19655682Smarkm const struct units *u; 19790926Snectar int ret = 0, tmp; 19855682Smarkm 19955682Smarkm if (num == 0) 20055682Smarkm return snprintf (s, len, "%s", zero_string); 20155682Smarkm 20255682Smarkm for (u = units; num > 0 && u->name; ++u) { 203178825Sdfr int divisor; 20455682Smarkm 205178825Sdfr divisor = num / u->mult; 206178825Sdfr if (divisor) { 20755682Smarkm num = (*update) (num, u->mult); 208178825Sdfr tmp = (*print) (s, len, divisor, u->name, num); 20990926Snectar if (tmp < 0) 21090926Snectar return tmp; 211233294Sstas if (tmp > (int) len) { 212178825Sdfr len = 0; 213178825Sdfr s = NULL; 214178825Sdfr } else { 215178825Sdfr len -= tmp; 216178825Sdfr s += tmp; 217178825Sdfr } 21855682Smarkm ret += tmp; 21955682Smarkm } 22055682Smarkm } 22155682Smarkm return ret; 22255682Smarkm} 22355682Smarkm 22455682Smarkmstatic int 225178825Sdfrprint_unit (char *s, size_t len, int divisor, const char *name, int rem) 22655682Smarkm{ 22755682Smarkm return snprintf (s, len, "%u %s%s%s", 228178825Sdfr divisor, name, 229178825Sdfr divisor == 1 ? "" : "s", 23055682Smarkm rem > 0 ? " " : ""); 23155682Smarkm} 23255682Smarkm 23355682Smarkmstatic int 23455682Smarkmupdate_unit (int in, unsigned mult) 23555682Smarkm{ 23655682Smarkm return in % mult; 23755682Smarkm} 23855682Smarkm 23955682Smarkmstatic int 24055682Smarkmupdate_unit_approx (int in, unsigned mult) 24155682Smarkm{ 24255682Smarkm if (in / mult > 0) 24355682Smarkm return 0; 24455682Smarkm else 24555682Smarkm return update_unit (in, mult); 24655682Smarkm} 24755682Smarkm 248233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 24955682Smarkmunparse_units (int num, const struct units *units, char *s, size_t len) 25055682Smarkm{ 25155682Smarkm return unparse_something (num, units, s, len, 25255682Smarkm print_unit, 25355682Smarkm update_unit, 25455682Smarkm "0"); 25555682Smarkm} 25655682Smarkm 257233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 25855682Smarkmunparse_units_approx (int num, const struct units *units, char *s, size_t len) 25955682Smarkm{ 26055682Smarkm return unparse_something (num, units, s, len, 26155682Smarkm print_unit, 26255682Smarkm update_unit_approx, 26355682Smarkm "0"); 26455682Smarkm} 26555682Smarkm 266233294SstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 26755682Smarkmprint_units_table (const struct units *units, FILE *f) 26855682Smarkm{ 26955682Smarkm const struct units *u, *u2; 270233294Sstas size_t max_sz = 0; 27155682Smarkm 27255682Smarkm for (u = units; u->name; ++u) { 27355682Smarkm max_sz = max(max_sz, strlen(u->name)); 27455682Smarkm } 27555682Smarkm 27655682Smarkm for (u = units; u->name;) { 27755682Smarkm char buf[1024]; 27855682Smarkm const struct units *next; 27955682Smarkm 28055682Smarkm for (next = u + 1; next->name && next->mult == u->mult; ++next) 28155682Smarkm ; 28255682Smarkm 28355682Smarkm if (next->name) { 28455682Smarkm for (u2 = next; 28555682Smarkm u2->name && u->mult % u2->mult != 0; 28655682Smarkm ++u2) 28755682Smarkm ; 28855682Smarkm if (u2->name == NULL) 28955682Smarkm --u2; 29055682Smarkm unparse_units (u->mult, u2, buf, sizeof(buf)); 291233294Sstas fprintf (f, "1 %*s = %s\n", (int)max_sz, u->name, buf); 29255682Smarkm } else { 29355682Smarkm fprintf (f, "1 %s\n", u->name); 29455682Smarkm } 29555682Smarkm u = next; 29655682Smarkm } 29755682Smarkm} 29855682Smarkm 29955682Smarkmstatic int 300178825Sdfrprint_flag (char *s, size_t len, int divisor, const char *name, int rem) 30155682Smarkm{ 30255682Smarkm return snprintf (s, len, "%s%s", name, rem > 0 ? ", " : ""); 30355682Smarkm} 30455682Smarkm 30555682Smarkmstatic int 30655682Smarkmupdate_flag (int in, unsigned mult) 30755682Smarkm{ 30855682Smarkm return in - mult; 30955682Smarkm} 31055682Smarkm 311233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 31255682Smarkmunparse_flags (int num, const struct units *units, char *s, size_t len) 31355682Smarkm{ 31455682Smarkm return unparse_something (num, units, s, len, 31555682Smarkm print_flag, 31655682Smarkm update_flag, 31755682Smarkm ""); 31855682Smarkm} 31955682Smarkm 320233294SstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 32155682Smarkmprint_flags_table (const struct units *units, FILE *f) 32255682Smarkm{ 32355682Smarkm const struct units *u; 32455682Smarkm 32555682Smarkm for(u = units; u->name; ++u) 32655682Smarkm fprintf(f, "%s%s", u->name, (u+1)->name ? ", " : "\n"); 32755682Smarkm} 328