(root)/
findutils-4.9.0/
gl/
lib/
xstrtol.c
       1  /* A more useful interface to strtol.
       2  
       3     Copyright (C) 1995-1996, 1998-2001, 2003-2007, 2009-2022 Free Software
       4     Foundation, Inc.
       5  
       6     This program is free software: you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation, either version 3 of the License, or
       9     (at your option) any later version.
      10  
      11     This program is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      18  
      19  /* Written by Jim Meyering. */
      20  
      21  #ifndef __strtol
      22  # define __strtol strtol
      23  # define __strtol_t long int
      24  # define __xstrtol xstrtol
      25  # define STRTOL_T_MINIMUM LONG_MIN
      26  # define STRTOL_T_MAXIMUM LONG_MAX
      27  #endif
      28  
      29  #include <config.h>
      30  
      31  #include "xstrtol.h"
      32  
      33  /* Some pre-ANSI implementations (e.g. SunOS 4)
      34     need stderr defined if assertion checking is enabled.  */
      35  #include <stdio.h>
      36  
      37  #include <ctype.h>
      38  #include <errno.h>
      39  #include <limits.h>
      40  #include <stdlib.h>
      41  #include <string.h>
      42  
      43  #if XSTRTOL_INCLUDE_INTTYPES_H
      44  # include <inttypes.h>
      45  #endif
      46  
      47  #include "assure.h"
      48  #include "intprops.h"
      49  
      50  static strtol_error
      51  bkm_scale (__strtol_t *x, int scale_factor)
      52  {
      53    __strtol_t scaled;
      54    if (INT_MULTIPLY_WRAPV (*x, scale_factor, &scaled))
      55      {
      56        *x = *x < 0 ? TYPE_MINIMUM (__strtol_t) : TYPE_MAXIMUM (__strtol_t);
      57        return LONGINT_OVERFLOW;
      58      }
      59  
      60    *x = scaled;
      61  
      62    return LONGINT_OK;
      63  }
      64  
      65  static strtol_error
      66  bkm_scale_by_power (__strtol_t *x, int base, int power)
      67  {
      68    strtol_error err = LONGINT_OK;
      69    while (power--)
      70      err |= bkm_scale (x, base);
      71    return err;
      72  }
      73  
      74  /* FIXME: comment.  */
      75  
      76  strtol_error
      77  __xstrtol (const char *s, char **ptr, int strtol_base,
      78             __strtol_t *val, const char *valid_suffixes)
      79  {
      80    char *t_ptr;
      81    char **p;
      82    __strtol_t tmp;
      83    strtol_error err = LONGINT_OK;
      84  
      85    assure (0 <= strtol_base && strtol_base <= 36);
      86  
      87    p = (ptr ? ptr : &t_ptr);
      88  
      89    errno = 0;
      90  
      91    if (! TYPE_SIGNED (__strtol_t))
      92      {
      93        const char *q = s;
      94        unsigned char ch = *q;
      95        while (isspace (ch))
      96          ch = *++q;
      97        if (ch == '-')
      98          return LONGINT_INVALID;
      99      }
     100  
     101    tmp = __strtol (s, p, strtol_base);
     102  
     103    if (*p == s)
     104      {
     105        /* If there is no number but there is a valid suffix, assume the
     106           number is 1.  The string is invalid otherwise.  */
     107        if (valid_suffixes && **p && strchr (valid_suffixes, **p))
     108          tmp = 1;
     109        else
     110          return LONGINT_INVALID;
     111      }
     112    else if (errno != 0)
     113      {
     114        if (errno != ERANGE)
     115          return LONGINT_INVALID;
     116        err = LONGINT_OVERFLOW;
     117      }
     118  
     119    /* Let valid_suffixes == NULL mean "allow any suffix".  */
     120    /* FIXME: update all callers except the ones that allow suffixes
     121       after the number, changing last parameter NULL to "".  */
     122    if (!valid_suffixes)
     123      {
     124        *val = tmp;
     125        return err;
     126      }
     127  
     128    if (**p != '\0')
     129      {
     130        int base = 1024;
     131        int suffixes = 1;
     132        strtol_error overflow;
     133  
     134        if (!strchr (valid_suffixes, **p))
     135          {
     136            *val = tmp;
     137            return err | LONGINT_INVALID_SUFFIX_CHAR;
     138          }
     139  
     140        switch (**p)
     141          {
     142          case 'E': case 'G': case 'g': case 'k': case 'K': case 'M': case 'm':
     143          case 'P': case 'T': case 't': case 'Y': case 'Z':
     144  
     145            /* The "valid suffix" '0' is a special flag meaning that
     146               an optional second suffix is allowed, which can change
     147               the base.  A suffix "B" (e.g. "100MB") stands for a power
     148               of 1000, whereas a suffix "iB" (e.g. "100MiB") stands for
     149               a power of 1024.  If no suffix (e.g. "100M"), assume
     150               power-of-1024.  */
     151  
     152            if (strchr (valid_suffixes, '0'))
     153              switch (p[0][1])
     154                {
     155                case 'i':
     156                  if (p[0][2] == 'B')
     157                    suffixes += 2;
     158                  break;
     159  
     160                case 'B':
     161                case 'D': /* 'D' is obsolescent */
     162                  base = 1000;
     163                  suffixes++;
     164                  break;
     165                }
     166          }
     167  
     168        switch (**p)
     169          {
     170          case 'b':
     171            overflow = bkm_scale (&tmp, 512);
     172            break;
     173  
     174          case 'B':
     175            /* This obsolescent first suffix is distinct from the 'B'
     176               second suffix above.  E.g., 'tar -L 1000B' means change
     177               the tape after writing 1000 KiB of data.  */
     178            overflow = bkm_scale (&tmp, 1024);
     179            break;
     180  
     181          case 'c':
     182            overflow = LONGINT_OK;
     183            break;
     184  
     185          case 'E': /* exa or exbi */
     186            overflow = bkm_scale_by_power (&tmp, base, 6);
     187            break;
     188  
     189          case 'G': /* giga or gibi */
     190          case 'g': /* 'g' is undocumented; for compatibility only */
     191            overflow = bkm_scale_by_power (&tmp, base, 3);
     192            break;
     193  
     194          case 'k': /* kilo */
     195          case 'K': /* kibi */
     196            overflow = bkm_scale_by_power (&tmp, base, 1);
     197            break;
     198  
     199          case 'M': /* mega or mebi */
     200          case 'm': /* 'm' is undocumented; for compatibility only */
     201            overflow = bkm_scale_by_power (&tmp, base, 2);
     202            break;
     203  
     204          case 'P': /* peta or pebi */
     205            overflow = bkm_scale_by_power (&tmp, base, 5);
     206            break;
     207  
     208          case 'T': /* tera or tebi */
     209          case 't': /* 't' is undocumented; for compatibility only */
     210            overflow = bkm_scale_by_power (&tmp, base, 4);
     211            break;
     212  
     213          case 'w':
     214            overflow = bkm_scale (&tmp, 2);
     215            break;
     216  
     217          case 'Y': /* yotta or 2**80 */
     218            overflow = bkm_scale_by_power (&tmp, base, 8);
     219            break;
     220  
     221          case 'Z': /* zetta or 2**70 */
     222            overflow = bkm_scale_by_power (&tmp, base, 7);
     223            break;
     224  
     225          default:
     226            *val = tmp;
     227            return err | LONGINT_INVALID_SUFFIX_CHAR;
     228          }
     229  
     230        err |= overflow;
     231        *p += suffixes;
     232        if (**p)
     233          err |= LONGINT_INVALID_SUFFIX_CHAR;
     234      }
     235  
     236    *val = tmp;
     237    return err;
     238  }