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 v4-17-test 1498b464 Lines: 70 243 28.8 %
Date: 2024-06-13 04:01:37 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        7085 : 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             :     const char *p;
      55        7085 :     int64_t res = init;
      56        7085 :     unsigned def_mult = 1;
      57             : 
      58        7085 :     if (def_unit != NULL) {
      59             :         const struct units *u;
      60             : 
      61       70850 :         for (u = units; u->name; ++u) {
      62       70850 :             if (strcasecmp (u->name, def_unit) == 0) {
      63        7085 :                 def_mult = u->mult;
      64        7085 :                 break;
      65             :             }
      66             :         }
      67        7085 :         if (u->name == NULL)
      68           0 :             return -1;
      69             :     }
      70             : 
      71        7085 :     p = s;
      72       21255 :     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        7085 :         int no_val_p = 0;
      79             : 
      80       14170 :         while (isspace((unsigned char)*p) || *p == ',')
      81           0 :             ++p;
      82             : 
      83        7085 :         val = strtoll(p, &next, 0);
      84        7085 :         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        7085 :         p = next;
      91       14179 :         while (isspace((unsigned char)*p))
      92           9 :             ++p;
      93        7085 :         if (*p == '\0') {
      94           0 :             res = (*func)(res, val, def_mult);
      95           0 :             if (res < 0)
      96           0 :                 return res;
      97           0 :             break;
      98        7085 :         } else if (*p == '+') {
      99           0 :             ++p;
     100           0 :             val = 1;
     101        7085 :         } else if (*p == '-') {
     102           0 :             ++p;
     103           0 :             val = -1;
     104             :         }
     105        7085 :         if (no_val_p && val == 0)
     106           0 :             val = 1;
     107        7085 :         u_len = strcspn (p, ", \t");
     108        7085 :         partial = 0;
     109        7085 :         partial_unit = NULL;
     110        7085 :         if (u_len > 1 && p[u_len - 1] == 's')
     111           9 :             --u_len;
     112       42480 :         for (u = units; u->name; ++u) {
     113       42480 :             if (strncasecmp (p, u->name, u_len) == 0) {
     114       14164 :                 if (u_len == strlen (u->name)) {
     115        7085 :                     p += u_len;
     116        7085 :                     res = (*func)(res, val, u->mult);
     117        7085 :                     if (res < 0)
     118           0 :                         return res;
     119        7085 :                     break;
     120             :                 } else {
     121        7079 :                     ++partial;
     122        7079 :                     partial_unit = u;
     123             :                 }
     124             :             }
     125             :         }
     126        7085 :         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        7085 :         if (*p == 's')
     137           9 :             ++p;
     138       14170 :         while (isspace((unsigned char)*p))
     139           0 :             ++p;
     140             :     }
     141        7085 :     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             :     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        7085 : acc_units(int64_t res, int64_t val, uint64_t mult)
     247             : {
     248        7085 :     return res + val * mult;
     249             : }
     250             : 
     251             : ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
     252        7085 : parse_units (const char *s, const struct units *units,
     253             :              const char *def_unit)
     254             : {
     255        7085 :     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,
     279             :              int orig)
     280             : {
     281           0 :     return parse_something_unsigned (s, units, NULL, acc_flags, orig, 1);
     282             : }
     283             : 
     284             : /*
     285             :  * Return a string representation according to `units' of `num' in `s'
     286             :  * with maximum length `len'.  The actual length is the function value.
     287             :  */
     288             : 
     289             : static int
     290           0 : unparse_something_signed(int64_t num, const struct units *units, char *s,
     291             :                          size_t len,
     292             :                          int64_t (*get_divisor)(int64_t, uint64_t),
     293             :                          int (*print)(char *, size_t, int64_t, const char *, int64_t),
     294             :                          int64_t (*update)(int64_t, uint64_t),
     295             :                          const char *zero_string)
     296             : {
     297             :     const struct units *u;
     298           0 :     int ret = 0, tmp;
     299             : 
     300           0 :     if (num == 0)
     301           0 :         return snprintf (s, len, "%s", zero_string);
     302           0 :     if (len)
     303           0 :         s[0] = '\0';
     304           0 :     if (num < 0)
     305           0 :         return -1;
     306             : 
     307           0 :     for (u = units; num > 0 && u->name; ++u) {
     308           0 :         long long divisor = get_divisor(num, u->mult);
     309             : 
     310           0 :         if (divisor) {
     311           0 :             num = (*update)(num, u->mult);
     312           0 :             tmp = (*print)(s, len, divisor, u->name, num);
     313           0 :             if (tmp < 0)
     314           0 :                 return tmp;
     315           0 :             if ((size_t)tmp > len) {
     316           0 :                 len = 0;
     317           0 :                 s = NULL;
     318             :             } else {
     319           0 :                 len -= tmp;
     320           0 :                 s += tmp;
     321             :             }
     322           0 :             ret += tmp;
     323             :         }
     324             :     }
     325           0 :     return ret;
     326             : }
     327             : 
     328             : static int
     329       91297 : unparse_something_unsigned(uint64_t num, const struct units *units, char *s,
     330             :                            size_t len,
     331             :                            uint64_t (*get_divisor)(uint64_t, uint64_t),
     332             :                            int (*print)(char *, size_t, uint64_t, const char *, uint64_t),
     333             :                            uint64_t (*update)(uint64_t, uint64_t),
     334             :                            const char *zero_string)
     335             : {
     336             :     const struct units *u;
     337             :     int64_t tmp;
     338       91297 :     int ret = 0;
     339             : 
     340       91297 :     if (num == 0)
     341        9171 :         return snprintf (s, len, "%s", zero_string);
     342       82126 :     if (len)
     343       82126 :         s[0] = '\0';
     344             : 
     345     1203692 :     for (u = units; num > 0 && u->name; ++u) {
     346     1121566 :         long long divisor = get_divisor(num, u->mult);
     347             : 
     348     1121566 :         if (divisor) {
     349      141289 :             num = (*update) (num, u->mult);
     350      141289 :             tmp = (*print) (s, len, divisor, u->name, num);
     351      141289 :             if (tmp < 0)
     352           0 :                 return tmp;
     353      141289 :             if ((size_t)tmp > len) {
     354           0 :                 len = 0;
     355           0 :                 s = NULL;
     356             :             } else {
     357      141289 :                 len -= tmp;
     358      141289 :                 s += tmp;
     359             :             }
     360      141289 :             ret += tmp;
     361             :         }
     362             :     }
     363       82126 :     return ret;
     364             : }
     365             : 
     366             : static int
     367           0 : print_unit(char *s, size_t len, int64_t divisor, const char *name, int64_t rem)
     368             : {
     369           0 :     return snprintf(s, len, "%lld %s%s%s", (long long)divisor, name,
     370             :                     divisor == 1 ? "" : "s", rem > 0 ? " " : "");
     371             : }
     372             : 
     373             : static int64_t
     374           0 : get_divisor_unit(int64_t in, uint64_t mult)
     375             : {
     376           0 :     return in / mult;
     377             : }
     378             : 
     379             : static int64_t
     380           0 : update_unit(int64_t in, uint64_t mult)
     381             : {
     382           0 :     return in % mult;
     383             : }
     384             : 
     385             : static int64_t
     386           0 : update_unit_approx(int64_t in, uint64_t mult)
     387             : {
     388           0 :     if (in / mult > 0)
     389           0 :         return 0;
     390             :     else
     391           0 :         return update_unit (in, mult);
     392             : }
     393             : 
     394             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     395           0 : unparse_units(int64_t num, const struct units *units, char *s, size_t len)
     396             : {
     397           0 :     return unparse_something_signed(num, units, s, len,
     398             :                                     get_divisor_unit, print_unit, update_unit,
     399             :                                     "0");
     400             : }
     401             : 
     402             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     403           0 : unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len)
     404             : {
     405           0 :     return unparse_something_signed(num, units, s, len, get_divisor_unit,
     406             :                                     print_unit, update_unit_approx, "0");
     407             : }
     408             : 
     409             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     410           0 : print_units_table (const struct units *units, FILE *f)
     411             : {
     412             :     const struct units *u, *u2;
     413           0 :     size_t max_sz = 0;
     414             : 
     415           0 :     for (u = units; u->name; ++u) {
     416           0 :         max_sz = max(max_sz, strlen(u->name));
     417             :     }
     418             : 
     419           0 :     for (u = units; u->name;) {
     420             :         char buf[1024];
     421             :         const struct units *next;
     422             : 
     423           0 :         for (next = u + 1; next->name && next->mult == u->mult; ++next)
     424             :             ;
     425             : 
     426           0 :         if (next->name) {
     427           0 :             for (u2 = next;
     428           0 :                  u2->name && u->mult % u2->mult != 0;
     429           0 :                  ++u2)
     430             :                 ;
     431           0 :             if (u2->name == NULL)
     432           0 :                 --u2;
     433           0 :             unparse_units (u->mult, u2, buf, sizeof(buf));
     434           0 :             fprintf (f, "1 %*s = %s\n", (int)max_sz, u->name, buf);
     435             :         } else {
     436           0 :             fprintf (f, "1 %s\n", u->name);
     437             :         }
     438           0 :         u = next;
     439             :     }
     440           0 : }
     441             : 
     442             : static uint64_t
     443     1121566 : get_divisor_flag(uint64_t in, uint64_t mult)
     444             : {
     445     1121566 :     return in & mult;
     446             : }
     447             : 
     448             : static int
     449      141289 : print_flag(char *s, size_t len, uint64_t divisor, const char *name, uint64_t rem)
     450             : {
     451      141289 :     return snprintf (s, len, "%s%s", name, rem > 0 ? ", " : "");
     452             : }
     453             : 
     454             : static uint64_t
     455      141289 : update_flag(uint64_t in, uint64_t mult)
     456             : {
     457      141289 :     return in & ~mult;
     458             : }
     459             : 
     460             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     461       91297 : unparse_flags (uint64_t num, const struct units *units, char *s, size_t len)
     462             : {
     463       91297 :     return unparse_something_unsigned(num, units, s, len, get_divisor_flag,
     464             :                                       print_flag, update_flag, "");
     465             : }
     466             : 
     467             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     468           0 : print_flags_table (const struct units *units, FILE *f)
     469             : {
     470             :     const struct units *u;
     471             : 
     472           0 :     for(u = units; u->name; ++u)
     473           0 :         fprintf(f, "%s%s", u->name, (u+1)->name ? ", " : "\n");
     474           0 : }
     475             : 
     476             : #undef parse_units
     477             : #undef unparse_units
     478             : #undef unparse_units_approx
     479             : #undef print_units_table
     480             : #undef parse_flags
     481             : #undef unparse_flags
     482             : #undef print_flags_table
     483             : 
     484             : ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
     485           0 : parse_units(const char *s, const struct units *units,
     486             :              const char *def_unit)
     487             : {
     488           0 :     return rk_parse_units(s, units, def_unit);
     489             : }
     490             : 
     491             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     492           0 : unparse_units(int64_t num, const struct units *units, char *s, size_t len)
     493             : {
     494           0 :     return rk_unparse_units(num, units, s, len);
     495             : }
     496             : 
     497             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     498           0 : unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len)
     499             : {
     500           0 :     return rk_unparse_units_approx(num, units, s, len);
     501             : }
     502             : 
     503             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     504           0 : print_units_table(const struct units *units, FILE *f)
     505             : {
     506           0 :     rk_print_units_table(units, f);
     507           0 : }
     508             : 
     509             : ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL
     510           0 : parse_flags(const char *s, const struct units *units, int orig)
     511             : {
     512           0 :     return rk_parse_flags(s, units, orig);
     513             : }
     514             : 
     515             : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
     516           0 : unparse_flags(uint64_t num, const struct units *units, char *s, size_t len)
     517             : {
     518           0 :     return rk_unparse_flags(num, units, s, len);
     519             : }
     520             : 
     521             : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     522           0 : print_flags_table (const struct units *units, FILE *f)
     523             : {
     524           0 :     rk_print_flags_table(units, f);
     525           0 : }

Generated by: LCOV version 1.13