1/* $NetBSD: parse_units.c,v 1.1.1.1 2011/04/13 18:15:42 elric Exp $ */ 2 3/* 4 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan 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 49static int 50parse_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 148static int 149acc_units(int res, int val, unsigned mult) 150{ 151 return res + val * mult; 152} 153 154ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 155parse_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 167static int 168acc_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 180ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 181parse_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 192static int 193unparse_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 226static int 227print_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 235static int 236update_unit (int in, unsigned mult) 237{ 238 return in % mult; 239} 240 241static int 242update_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 250ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 251unparse_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 259ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 260unparse_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 268ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 269print_units_table (const struct units *units, FILE *f) 270{ 271 const struct units *u, *u2; 272 int 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", max_sz, u->name, buf); 294 } else { 295 fprintf (f, "1 %s\n", u->name); 296 } 297 u = next; 298 } 299} 300 301static int 302print_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 307static int 308update_flag (int in, unsigned mult) 309{ 310 return in - mult; 311} 312 313ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 314unparse_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 322ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 323print_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