Home | History | Annotate | Line # | Download | only in roken
      1 /*	$NetBSD: parse_units.c,v 1.2 2017/01/28 21:31:50 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 - 2001 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <config.h>
     37 
     38 #include <stdio.h>
     39 #include <ctype.h>
     40 #include <string.h>
     41 #include <krb5/roken.h>
     42 #include <krb5/parse_units.h>
     43 
     44 /*
     45  * Parse string in `s' according to `units' and return value.
     46  * def_unit defines the default unit.
     47  */
     48 
     49 static int
     50 parse_something (const char *s, const struct units *units,
     51 		 const char *def_unit,
     52 		 int (*func)(int res, int val, unsigned mult),
     53 		 int init,
     54 		 int accept_no_val_p)
     55 {
     56     const char *p;
     57     int res = init;
     58     unsigned def_mult = 1;
     59 
     60     if (def_unit != NULL) {
     61 	const struct units *u;
     62 
     63 	for (u = units; u->name; ++u) {
     64 	    if (strcasecmp (u->name, def_unit) == 0) {
     65 		def_mult = u->mult;
     66 		break;
     67 	    }
     68 	}
     69 	if (u->name == NULL)
     70 	    return -1;
     71     }
     72 
     73     p = s;
     74     while (*p) {
     75 	int val;
     76 	char *next;
     77 	const struct units *u, *partial_unit;
     78 	size_t u_len;
     79 	unsigned partial;
     80 	int no_val_p = 0;
     81 
     82 	while(isspace((unsigned char)*p) || *p == ',')
     83 	    ++p;
     84 
     85 	val = strtol(p, &next, 0);
     86 	if (p == next) {
     87 	    val = 0;
     88 	    if(!accept_no_val_p)
     89 		return -1;
     90 	    no_val_p = 1;
     91 	}
     92 	p = next;
     93 	while (isspace((unsigned char)*p))
     94 	    ++p;
     95 	if (*p == '\0') {
     96 	    res = (*func)(res, val, def_mult);
     97 	    if (res < 0)
     98 		return res;
     99 	    break;
    100 	} else if (*p == '+') {
    101 	    ++p;
    102 	    val = 1;
    103 	} else if (*p == '-') {
    104 	    ++p;
    105 	    val = -1;
    106 	}
    107 	if (no_val_p && val == 0)
    108 	    val = 1;
    109 	u_len = strcspn (p, ", \t");
    110 	partial = 0;
    111 	partial_unit = NULL;
    112 	if (u_len > 1 && p[u_len - 1] == 's')
    113 	    --u_len;
    114 	for (u = units; u->name; ++u) {
    115 	    if (strncasecmp (p, u->name, u_len) == 0) {
    116 		if (u_len == strlen (u->name)) {
    117 		    p += u_len;
    118 		    res = (*func)(res, val, u->mult);
    119 		    if (res < 0)
    120 			return res;
    121 		    break;
    122 		} else {
    123 		    ++partial;
    124 		    partial_unit = u;
    125 		}
    126 	    }
    127 	}
    128 	if (u->name == NULL) {
    129 	    if (partial == 1) {
    130 		p += u_len;
    131 		res = (*func)(res, val, partial_unit->mult);
    132 		if (res < 0)
    133 		    return res;
    134 	    } else {
    135 		return -1;
    136 	    }
    137 	}
    138 	if (*p == 's')
    139 	    ++p;
    140     }
    141     return res;
    142 }
    143 
    144 /*
    145  * The string consists of a sequence of `n unit'
    146  */
    147 
    148 static int
    149 acc_units(int res, int val, unsigned mult)
    150 {
    151     return res + val * mult;
    152 }
    153 
    154 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
    155 parse_units (const char *s, const struct units *units,
    156 	     const char *def_unit)
    157 {
    158     return parse_something (s, units, def_unit, acc_units, 0, 0);
    159 }
    160 
    161 /*
    162  * The string consists of a sequence of `[+-]flag'.  `orig' consists
    163  * the original set of flags, those are then modified and returned as
    164  * the function value.
    165  */
    166 
    167 static int
    168 acc_flags(int res, int val, unsigned mult)
    169 {
    170     if(val == 1)
    171 	return res | mult;
    172     else if(val == -1)
    173 	return res & ~mult;
    174     else if (val == 0)
    175 	return mult;
    176     else
    177 	return -1;
    178 }
    179 
    180 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
    181 parse_flags (const char *s, const struct units *units,
    182 	     int orig)
    183 {
    184     return parse_something (s, units, NULL, acc_flags, orig, 1);
    185 }
    186 
    187 /*
    188  * Return a string representation according to `units' of `num' in `s'
    189  * with maximum length `len'.  The actual length is the function value.
    190  */
    191 
    192 static int
    193 unparse_something (int num, const struct units *units, char *s, size_t len,
    194 		   int (*print) (char *, size_t, int, const char *, int),
    195 		   int (*update) (int, unsigned),
    196 		   const char *zero_string)
    197 {
    198     const struct units *u;
    199     int ret = 0, tmp;
    200 
    201     if (num == 0)
    202 	return snprintf (s, len, "%s", zero_string);
    203 
    204     for (u = units; num > 0 && u->name; ++u) {
    205 	int divisor;
    206 
    207 	divisor = num / u->mult;
    208 	if (divisor) {
    209 	    num = (*update) (num, u->mult);
    210 	    tmp = (*print) (s, len, divisor, u->name, num);
    211 	    if (tmp < 0)
    212 		return tmp;
    213 	    if (tmp > (int) len) {
    214 		len = 0;
    215 		s = NULL;
    216 	    } else {
    217 		len -= tmp;
    218 		s += tmp;
    219 	    }
    220 	    ret += tmp;
    221 	}
    222     }
    223     return ret;
    224 }
    225 
    226 static int
    227 print_unit (char *s, size_t len, int divisor, const char *name, int rem)
    228 {
    229     return snprintf (s, len, "%u %s%s%s",
    230 		     divisor, name,
    231 		     divisor == 1 ? "" : "s",
    232 		     rem > 0 ? " " : "");
    233 }
    234 
    235 static int
    236 update_unit (int in, unsigned mult)
    237 {
    238     return in % mult;
    239 }
    240 
    241 static int
    242 update_unit_approx (int in, unsigned mult)
    243 {
    244     if (in / mult > 0)
    245 	return 0;
    246     else
    247 	return update_unit (in, mult);
    248 }
    249 
    250 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
    251 unparse_units (int num, const struct units *units, char *s, size_t len)
    252 {
    253     return unparse_something (num, units, s, len,
    254 			      print_unit,
    255 			      update_unit,
    256 			      "0");
    257 }
    258 
    259 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
    260 unparse_units_approx (int num, const struct units *units, char *s, size_t len)
    261 {
    262     return unparse_something (num, units, s, len,
    263 			      print_unit,
    264 			      update_unit_approx,
    265 			      "0");
    266 }
    267 
    268 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    269 print_units_table (const struct units *units, FILE *f)
    270 {
    271     const struct units *u, *u2;
    272     size_t max_sz = 0;
    273 
    274     for (u = units; u->name; ++u) {
    275 	max_sz = max(max_sz, strlen(u->name));
    276     }
    277 
    278     for (u = units; u->name;) {
    279 	char buf[1024];
    280 	const struct units *next;
    281 
    282 	for (next = u + 1; next->name && next->mult == u->mult; ++next)
    283 	    ;
    284 
    285 	if (next->name) {
    286 	    for (u2 = next;
    287 		 u2->name && u->mult % u2->mult != 0;
    288 		 ++u2)
    289 		;
    290 	    if (u2->name == NULL)
    291 		--u2;
    292 	    unparse_units (u->mult, u2, buf, sizeof(buf));
    293 	    fprintf (f, "1 %*s = %s\n", (int)max_sz, u->name, buf);
    294 	} else {
    295 	    fprintf (f, "1 %s\n", u->name);
    296 	}
    297 	u = next;
    298     }
    299 }
    300 
    301 static int
    302 print_flag (char *s, size_t len, int divisor, const char *name, int rem)
    303 {
    304     return snprintf (s, len, "%s%s", name, rem > 0 ? ", " : "");
    305 }
    306 
    307 static int
    308 update_flag (int in, unsigned mult)
    309 {
    310     return in - mult;
    311 }
    312 
    313 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
    314 unparse_flags (int num, const struct units *units, char *s, size_t len)
    315 {
    316     return unparse_something (num, units, s, len,
    317 			      print_flag,
    318 			      update_flag,
    319 			      "");
    320 }
    321 
    322 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    323 print_flags_table (const struct units *units, FILE *f)
    324 {
    325     const struct units *u;
    326 
    327     for(u = units; u->name; ++u)
    328 	fprintf(f, "%s%s", u->name, (u+1)->name ? ", " : "\n");
    329 }
    330