LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/roken - parse_units.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 73 252 29.0 %
Date: 2024-04-21 15:09:00 Functions: 8 27 29.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include <config.h>
      35             : 
      36             : #include <stdio.h>
      37             : #include <ctype.h>
      38             : #include <string.h>
      39             : #include "roken.h"
      40             : #include "parse_units.h"
      41             : 
      42             : /*
      43             :  * Parse string in `s' according to `units' and return value.
      44             :  * def_unit defines the default unit.
      45             :  */
      46             : 
      47             : static int64_t
      48       12081 : parse_something_signed(const char *s, const struct units *units,
      49             :                        const char *def_unit,
      50             :                        int64_t (*func)(int64_t res, int64_t val, uint64_t mult),
      51             :                        int64_t init,
      52             :                        int accept_no_val_p)
      53             : {
      54         585 :     const char *p;
      55       12081 :     int64_t res = init;
      56       12081 :     unsigned def_mult = 1;
      57             : 
      58       12081 :     if (def_unit != NULL) {
      59             :         const struct units *u;
      60             : 
      61      120810 :         for (u = units; u->name; ++u) {
      62      120810 :             if (strcasecmp (u->name, def_unit) == 0) {
      63       12081 :                 def_mult = u->mult;
      64       12081 :                 break;
      65             :             }
      66             :         }
      67       12081 :         if (u->name == NULL)
      68           0 :             return -1;
      69             :     }
      70             : 
      71       12081 :     p = s;
      72       24162 :     while (*p) {
      73             :         int64_t val;
      74             :         char *next;
      75             :         const struct units *u, *partial_unit;
      76             :         size_t u_len;
      77             :         unsigned partial;
      78       12081 :         int no_val_p = 0;
      79             : 
      80       12081 :         while (isspace((unsigned char)*p) || *p == ',')
      81           0 :             ++p;
      82             : 
      83       12081 :         val = strtoll(p, &next, 0);
      84       12081 :         if (p == next) {
      85           0 :             val = 0;
      86           0 :             if(!accept_no_val_p)
      87           0 :                 return -1;
      88           0 :             no_val_p = 1;
      89             :         }
      90       12081 :         p = next;
      91       12113 :         while (isspace((unsigned char)*p))
      92          32 :             ++p;
      93       12081 :         if (*p == '\0') {
      94           0 :             res = (*func)(res, val, def_mult);
      95           0 :             if (res < 0)
      96           0 :                 return res;
      97           0 :             break;
      98       12081 :         } else if (*p == '+') {
      99           0 :             ++p;
     100           0 :             val = 1;
     101       12081 :         } else if (*p == '-') {
     102           0 :             ++p;
     103           0 :             val = -1;
     104             :         }
     105       12081 :         if (no_val_p && val == 0)
     106           0 :             val = 1;
     107       12081 :         u_len = strcspn (p, ", \t");
     108       12081 :         partial = 0;
     109       12081 :         partial_unit = NULL;
     110       12081 :         if (u_len > 1 && p[u_len - 1] == 's')
     111          32 :             --u_len;
     112       72364 :         for (u = units; u->name; ++u) {
     113       72364 :             if (strncasecmp (p, u->name, u_len) == 0) {
     114       24133 :                 if (u_len == strlen (u->name)) {
     115       12081 :                     p += u_len;
     116       12081 :                     res = (*func)(res, val, u->mult);
     117       12081 :                     if (res < 0)
     118           0 :                         return res;
     119       11496 :                     break;
     120             :                 } else {
     121       12052 :                     ++partial;
     122       12052 :                     partial_unit = u;
     123             :                 }
     124             :             }
     125             :         }
     126       12081 :         if (u->name == NULL) {
     127           0 :             if (partial == 1) {
     128           0 :                 p += u_len;
     129           0 :                 res = (*func)(res, val, partial_unit->mult);
     130           0 :                 if (res < 0)
     131           0 :                     return res;
     132             :             } else {
     133           0 :                 return -1;
     134             :             }
     135             :         }
     136       12081 :         if (*p == 's')
     137          32 :             ++p;
     138       12081 :         while (isspace((unsigned char)*p))
     139           0 :             ++p;
     140             :     }
     141       11496 :     return res;
     142             : }
     143             : 
     144             : static uint64_t
     145           0 : parse_something_unsigned(const char *s, const struct units *units,
     146             :                          const char *def_unit,
     147             :                          uint64_t (*func)(uint64_t res, int64_t val, uint64_t mult),
     148             :                          uint64_t init,
     149             :                          int accept_no_val_p)
     150             : {
     151           0 :     const char *p;
     152           0 :     int64_t res = init;
     153           0 :     unsigned def_mult = 1;
     154             : 
     155           0 :     if (def_unit != NULL) {
     156             :         const struct units *u;
     157             : 
     158           0 :         for (u = units; u->name; ++u) {
     159           0 :             if (strcasecmp (u->name, def_unit) == 0) {
     160           0 :                 def_mult = u->mult;
     161           0 :                 break;
     162             :             }
     163             :         }
     164           0 :         if (u->name == NULL)
     165           0 :             return -1;
     166             :     }
     167             : 
     168           0 :     p = s;
     169           0 :     while (*p) {
     170             :         int64_t val;
     171             :         char *next;
     172             :         const struct units *u, *partial_unit;
     173             :         size_t u_len;
     174             :         unsigned partial;
     175           0 :         int no_val_p = 0;
     176             : 
     177           0 :         while (isspace((unsigned char)*p) || *p == ',')
     178           0 :             ++p;
     179             : 
     180           0 :         val = strtoll(p, &next, 0);
     181           0 :         if (p == next) {
     182           0 :             val = 0;
     183           0 :             if(!accept_no_val_p)
     184           0 :                 return -1;
     185           0 :             no_val_p = 1;
     186             :         }
     187           0 :         p = next;
     188           0 :         while (isspace((unsigned char)*p))
     189           0 :             ++p;
     190           0 :         if (*p == '\0') {
     191           0 :             res = (*func)(res, val, def_mult);
     192           0 :             if (res < 0)
     193           0 :                 return res;
     194           0 :             break;
     195           0 :         } else if (*p == '+') {
     196           0 :             ++p;
     197           0 :             val = 1;
     198           0 :         } else if (*p == '-') {
     199           0 :             ++p;
     200           0 :             val = -1;
     201             :         }
     202           0 :         if (no_val_p && val == 0)
     203           0 :             val = 1;
     204           0 :         u_len = strcspn (p, ", \t");
     205           0 :         partial = 0;
     206           0 :         partial_unit = NULL;
     207           0 :         if (u_len > 1 && p[u_len - 1] == 's')
     208           0 :             --u_len;
     209           0 :         for (u = units; u->name; ++u) {
     210           0 :             if (strncasecmp (p, u->name, u_len) == 0) {
     211           0 :                 if (u_len == strlen (u->name)) {
     212           0 :                     p += u_len;
     213           0 :                     res = (*func)(res, val, u->mult);
     214           0 :                     if (res < 0)
     215           0 :                         return res;
     216           0 :                     break;
     217             :                 } else {
     218           0 :                     ++partial;
     219           0 :                     partial_unit = u;
     220             :                 }
     221             :             }
     222             :         }
     223           0 :         if (u->name == NULL) {
     224           0 :             if (partial == 1) {
     225           0 :                 p += u_len;
     226           0 :                 res = (*func)(res, val, partial_unit->mult);
     227           0 :                 if (res < 0)
     228           0 :                     return res;
     229             :             } else {
     230           0 :                 return -1;
     231             :             }
     232             :         }
     233           0 :         if (*p == 's')
     234           0 :             ++p;
     235           0 :         while (isspace((unsigned char)*p))
     236           0 :             ++p;
     237             :     }
     238           0 :     return res;
     239             : }
     240             : 
     241             : /*
     242             :  * The string consists of a sequence of `n unit'
     243             :  */
     244             : 
     245             : static int64_t
     246       12081 : acc_units(int64_t res, int64_t val, uint64_t mult)
     247             : {
     248       12081 :     return res + val * mult;
     249             : }
     250             : 
     251             : ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
     252       12081 : parse_units (const char *s, const struct units *units,
     253             :              const char *def_unit)
     254             : {
     255       12081 :     return parse_something_signed(s, units, def_unit, acc_units, 0, 0);
     256             : }
     257             : 
     258             : /*
     259             :  * The string consists of a sequence of `[+-]flag'.  `orig' consists
     260             :  * the original set of flags, those are then modified and returned as
     261             :  * the function value.
     262             :  */
     263             : 
     264             : static uint64_t
     265           0 : acc_flags(uint64_t res, int64_t val, uint64_t mult)
     266             : {
     267           0 :     if(val == 1)
     268           0 :         return res | mult;
     269           0 :     else if(val == -1)
     270           0 :         return res & ~mult;
     271           0 :     else if (val == 0)
     272           0 :         return mult;
     273             :     else
     274           0 :         return -1;
     275             : }
     276             : 
     277             : ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL
     278           0 : parse_flags(const char *s, const struct units *units, uint64_t orig)
     279             : {
     280           0 :     return parse_something_unsigned (s, units, NULL, acc_flags, orig, 1);
     281             : }
     282             : 
     283             : /*
     284             :  * Return a string representation according to `units' of `num' in `s'
     285             :  * with maximum length `len'.  The actual length is the function value.
     286             :  */
     287             : 
     288             : static int
     289           0 : unparse_something_signed(int64_t num, const struct units *units, char *s,
     290             :                          size_t len,
     291             :                          int64_t (*get_divisor)(int64_t, uint64_t),
     292             :                          int (*print)(char *, size_t, int64_t, const char *, int64_t),
     293             :                          int64_t (*update)(int64_t, uint64_t),
     294             :                          const char *zero_string)
     295             : {
     296           0 :     const struct units *u;
     297           0 :     int ret = 0, tmp;
     298             : 
     299           0 :     if (num == 0)
     300           0 :         return snprintf (s, len, "%s", zero_string);
     301           0 :     if (len)
     302           0 :         s[0] = '\0';
     303           0 :     if (num < 0)
     304           0 :         return -1;
     305             : 
     306           0 :     for (u = units; num > 0 && u->name; ++u) {
     307           0 :         long long divisor = get_divisor(num, u->mult);
     308             : 
     309           0 :         if (divisor) {
     310           0 :             num = (*update)(num, u->mult);
     311           0 :             tmp = (*print)(s, len, divisor, u->name, num);
     312           0 :             if (tmp < 0)
     313           0 :                 return tmp;
     314           0 :             if ((size_t)tmp > len) {
     315           0 :                 len = 0;
     316           0 :                 s = NULL;
     317             :             } else {
     318           0 :                 len -= tmp;
     319           0 :                 s += tmp;
     320             :             }
     321           0 :             ret += tmp;
     322             :         }
     323             :     }
     324           0 :     return ret;
     325             : }
     326             : 
     327             : static int
     328      130750 : unparse_something_unsigned(uint64_t num, const struct units *units, char *s,
     329             :                            size_t len,
     330             :                            uint64_t (*get_divisor)(uint64_t, uint64_t),
     331             :                            int (*print)(char *, size_t, uint64_t, const char *, uint64_t),
     332             :                            uint64_t (*update)(uint64_t, uint64_t),
     333             :                            const char *zero_string)
     334             : {
     335        4486 :     const struct units *u;
     336        4486 :     int64_t tmp;
     337      130750 :     int ret = 0;
     338             : 
     339      130750 :     if (num == 0)
     340       10649 :         return snprintf (s, len, "%s", zero_string);
     341      120101 :     if (len)
     342      120101 :         s[0] = '\0';
     343             : 
     344     1773351 :     for (u = units; num > 0 && u->name; ++u) {
     345     1653250 :         long long divisor = get_divisor(num, u->mult);
     346             : 
     347     1653250 :         if (divisor) {
     348      209494 :             num = (*update) (num, u->mult);
     349      209494 :             tmp = (*print) (s, len, divisor, u->name, num);
     350      209494 :             if (tmp < 0)
     351           0 :                 return tmp;
     352      209494 :             if ((size_t)tmp > len) {
     353           0 :                 len = 0;
     354           0 :                 s = NULL;
     355             :             } else {
     356      209494 :                 len -= tmp;
     357      209494 :                 s += tmp;
     358             :             }
     359      209494 :             ret += tmp;
     360             :         }
     361             :     }
     362      115615 :     return ret;
     363             : }
     364             : 
     365             : static int
     366           0 : print_unit(char *s, size_t len, int64_t divisor, const char *name, int64_t rem)
     367             : {
     368           0 :     return snprintf(s, len, "%lld %s%s%s", (long long)divisor, name,
     369             :                     divisor == 1 ? "" : "s", rem > 0 ? " " : "");
     370             : }
     371             : 
     372             : static int64_t
     373           0 : get_divisor_unit(int64_t in, uint64_t mult)
     374             : {
     375           0 :     return in / mult;
     376             : }
     377             : 
     378             : static int64_t
     379           0 : update_unit(int64_t in, uint64_t mult)
     380             : {
     381           0 :     return in % mult;
     382             : }
     383             : 
     384             : static int64_t
     385           0 : update_unit_approx(int64_t in, uint64_t mult)
     386             : {
     387           0 :     if (in / mult > 0)
     388           0 :         return 0;
     389             :     else
     390           0 :         return update_unit (in, mult);
     391             : }
     392             : 
     393             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     394           0 : unparse_units(int64_t num, const struct units *units, char *s, size_t len)
     395             : {
     396           0 :     return unparse_something_signed(num, units, s, len,
     397             :                                     get_divisor_unit, print_unit, update_unit,
     398             :                                     "0");
     399             : }
     400             : 
     401             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     402           0 : unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len)
     403             : {
     404           0 :     return unparse_something_signed(num, units, s, len, get_divisor_unit,
     405             :                                     print_unit, update_unit_approx, "0");
     406             : }
     407             : 
     408             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     409           0 : print_units_table (const struct units *units, FILE *f)
     410             : {
     411           0 :     const struct units *u, *u2;
     412           0 :     size_t max_sz = 0;
     413             : 
     414           0 :     for (u = units; u->name; ++u) {
     415           0 :         max_sz = max(max_sz, strlen(u->name));
     416             :     }
     417             : 
     418           0 :     for (u = units; u->name;) {
     419           0 :         char buf[1024];
     420           0 :         const struct units *next;
     421             : 
     422           0 :         for (next = u + 1; next->name && next->mult == u->mult; ++next)
     423             :             ;
     424             : 
     425           0 :         if (next->name) {
     426           0 :             for (u2 = next;
     427           0 :                  u2->name && u->mult % u2->mult != 0;
     428           0 :                  ++u2)
     429             :                 ;
     430           0 :             if (u2->name == NULL)
     431           0 :                 --u2;
     432           0 :             unparse_units (u->mult, u2, buf, sizeof(buf));
     433           0 :             fprintf (f, "1 %*s = %s\n", (int)max_sz, u->name, buf);
     434             :         } else {
     435           0 :             fprintf (f, "1 %s\n", u->name);
     436             :         }
     437           0 :         u = next;
     438             :     }
     439           0 : }
     440             : 
     441             : static uint64_t
     442     1653250 : get_divisor_flag(uint64_t in, uint64_t mult)
     443             : {
     444     1653250 :     return in & mult;
     445             : }
     446             : 
     447             : static int
     448      209494 : print_flag(char *s, size_t len, uint64_t divisor, const char *name, uint64_t rem)
     449             : {
     450      209494 :     return snprintf (s, len, "%s%s", name, rem > 0 ? ", " : "");
     451             : }
     452             : 
     453             : static uint64_t
     454      209494 : update_flag(uint64_t in, uint64_t mult)
     455             : {
     456      209494 :     return in & ~mult;
     457             : }
     458             : 
     459             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     460      130750 : unparse_flags (uint64_t num, const struct units *units, char *s, size_t len)
     461             : {
     462      130750 :     return unparse_something_unsigned(num, units, s, len, get_divisor_flag,
     463             :                                       print_flag, update_flag, "");
     464             : }
     465             : 
     466             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     467           0 : print_flags_table (const struct units *units, FILE *f)
     468             : {
     469           0 :     const struct units *u;
     470             : 
     471           0 :     for(u = units; u->name; ++u)
     472           0 :         fprintf(f, "%s%s", u->name, (u+1)->name ? ", " : "\n");
     473           0 : }
     474             : 
     475             : #undef parse_units
     476             : #undef unparse_units
     477             : #undef unparse_units_approx
     478             : #undef print_units_table
     479             : #undef parse_flags
     480             : #undef unparse_flags
     481             : #undef print_flags_table
     482             : 
     483             : ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
     484           0 : parse_units(const char *s, const struct units *units,
     485             :              const char *def_unit)
     486             : {
     487           0 :     return rk_parse_units(s, units, def_unit);
     488             : }
     489             : 
     490             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     491           0 : unparse_units(int64_t num, const struct units *units, char *s, size_t len)
     492             : {
     493           0 :     return rk_unparse_units(num, units, s, len);
     494             : }
     495             : 
     496             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     497           0 : unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len)
     498             : {
     499           0 :     return rk_unparse_units_approx(num, units, s, len);
     500             : }
     501             : 
     502             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     503           0 : print_units_table(const struct units *units, FILE *f)
     504             : {
     505           0 :     rk_print_units_table(units, f);
     506           0 : }
     507             : 
     508             : ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL
     509           0 : parse_flags(const char *s, const struct units *units, int orig)
     510             : {
     511           0 :     return rk_parse_flags(s, units, orig);
     512             : }
     513             : 
     514             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     515           0 : unparse_flags(uint64_t num, const struct units *units, char *s, size_t len)
     516             : {
     517           0 :     return rk_unparse_flags(num, units, s, len);
     518             : }
     519             : 
     520             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     521           0 : print_flags_table (const struct units *units, FILE *f)
     522             : {
     523           0 :     rk_print_flags_table(units, f);
     524           0 : }

Generated by: LCOV version 1.14