xref: /dflybsd-src/contrib/grep/lib/xstrtol.c (revision 91b9ed38d3db6a8a8ac5b66da1d43e6e331e259a)
195b7b453SJohn Marino /* A more useful interface to strtol.
295b7b453SJohn Marino 
3*09d4459fSDaniel Fojt    Copyright (C) 1995-1996, 1998-2001, 2003-2007, 2009-2020 Free Software
495b7b453SJohn Marino    Foundation, Inc.
595b7b453SJohn Marino 
695b7b453SJohn Marino    This program is free software: you can redistribute it and/or modify
795b7b453SJohn Marino    it under the terms of the GNU General Public License as published by
895b7b453SJohn Marino    the Free Software Foundation; either version 3 of the License, or
995b7b453SJohn Marino    (at your option) any later version.
1095b7b453SJohn Marino 
1195b7b453SJohn Marino    This program is distributed in the hope that it will be useful,
1295b7b453SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
1395b7b453SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1495b7b453SJohn Marino    GNU General Public License for more details.
1595b7b453SJohn Marino 
1695b7b453SJohn Marino    You should have received a copy of the GNU General Public License
17*09d4459fSDaniel Fojt    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
1895b7b453SJohn Marino 
1995b7b453SJohn Marino /* Written by Jim Meyering. */
2095b7b453SJohn Marino 
2195b7b453SJohn Marino #ifndef __strtol
2295b7b453SJohn Marino # define __strtol strtol
2395b7b453SJohn Marino # define __strtol_t long int
2495b7b453SJohn Marino # define __xstrtol xstrtol
2595b7b453SJohn Marino # define STRTOL_T_MINIMUM LONG_MIN
2695b7b453SJohn Marino # define STRTOL_T_MAXIMUM LONG_MAX
2795b7b453SJohn Marino #endif
2895b7b453SJohn Marino 
2995b7b453SJohn Marino #include <config.h>
3095b7b453SJohn Marino 
3195b7b453SJohn Marino #include "xstrtol.h"
3295b7b453SJohn Marino 
3395b7b453SJohn Marino /* Some pre-ANSI implementations (e.g. SunOS 4)
3495b7b453SJohn Marino    need stderr defined if assertion checking is enabled.  */
3595b7b453SJohn Marino #include <stdio.h>
3695b7b453SJohn Marino 
3795b7b453SJohn Marino #include <ctype.h>
3895b7b453SJohn Marino #include <errno.h>
3995b7b453SJohn Marino #include <limits.h>
4095b7b453SJohn Marino #include <stdlib.h>
4195b7b453SJohn Marino #include <string.h>
4295b7b453SJohn Marino 
43dc7c36e4SJohn Marino #include "assure.h"
4495b7b453SJohn Marino 
45*09d4459fSDaniel Fojt #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
46cf28ed85SJohn Marino 
4795b7b453SJohn Marino static strtol_error
bkm_scale(__strtol_t * x,int scale_factor)4895b7b453SJohn Marino bkm_scale (__strtol_t *x, int scale_factor)
4995b7b453SJohn Marino {
5095b7b453SJohn Marino   if (TYPE_SIGNED (__strtol_t) && *x < STRTOL_T_MINIMUM / scale_factor)
5195b7b453SJohn Marino     {
5295b7b453SJohn Marino       *x = STRTOL_T_MINIMUM;
5395b7b453SJohn Marino       return LONGINT_OVERFLOW;
5495b7b453SJohn Marino     }
5595b7b453SJohn Marino   if (STRTOL_T_MAXIMUM / scale_factor < *x)
5695b7b453SJohn Marino     {
5795b7b453SJohn Marino       *x = STRTOL_T_MAXIMUM;
5895b7b453SJohn Marino       return LONGINT_OVERFLOW;
5995b7b453SJohn Marino     }
6095b7b453SJohn Marino   *x *= scale_factor;
6195b7b453SJohn Marino   return LONGINT_OK;
6295b7b453SJohn Marino }
6395b7b453SJohn Marino 
6495b7b453SJohn Marino static strtol_error
bkm_scale_by_power(__strtol_t * x,int base,int power)6595b7b453SJohn Marino bkm_scale_by_power (__strtol_t *x, int base, int power)
6695b7b453SJohn Marino {
6795b7b453SJohn Marino   strtol_error err = LONGINT_OK;
6895b7b453SJohn Marino   while (power--)
6995b7b453SJohn Marino     err |= bkm_scale (x, base);
7095b7b453SJohn Marino   return err;
7195b7b453SJohn Marino }
7295b7b453SJohn Marino 
7395b7b453SJohn Marino /* FIXME: comment.  */
7495b7b453SJohn Marino 
7595b7b453SJohn Marino strtol_error
__xstrtol(const char * s,char ** ptr,int strtol_base,__strtol_t * val,const char * valid_suffixes)7695b7b453SJohn Marino __xstrtol (const char *s, char **ptr, int strtol_base,
7795b7b453SJohn Marino            __strtol_t *val, const char *valid_suffixes)
7895b7b453SJohn Marino {
7995b7b453SJohn Marino   char *t_ptr;
8095b7b453SJohn Marino   char **p;
8195b7b453SJohn Marino   __strtol_t tmp;
8295b7b453SJohn Marino   strtol_error err = LONGINT_OK;
8395b7b453SJohn Marino 
84dc7c36e4SJohn Marino   assure (0 <= strtol_base && strtol_base <= 36);
8595b7b453SJohn Marino 
8695b7b453SJohn Marino   p = (ptr ? ptr : &t_ptr);
8795b7b453SJohn Marino 
88dc7c36e4SJohn Marino   errno = 0;
89dc7c36e4SJohn Marino 
9095b7b453SJohn Marino   if (! TYPE_SIGNED (__strtol_t))
9195b7b453SJohn Marino     {
9295b7b453SJohn Marino       const char *q = s;
9395b7b453SJohn Marino       unsigned char ch = *q;
9495b7b453SJohn Marino       while (isspace (ch))
9595b7b453SJohn Marino         ch = *++q;
9695b7b453SJohn Marino       if (ch == '-')
9795b7b453SJohn Marino         return LONGINT_INVALID;
9895b7b453SJohn Marino     }
9995b7b453SJohn Marino 
10095b7b453SJohn Marino   tmp = __strtol (s, p, strtol_base);
10195b7b453SJohn Marino 
10295b7b453SJohn Marino   if (*p == s)
10395b7b453SJohn Marino     {
10495b7b453SJohn Marino       /* If there is no number but there is a valid suffix, assume the
10595b7b453SJohn Marino          number is 1.  The string is invalid otherwise.  */
10695b7b453SJohn Marino       if (valid_suffixes && **p && strchr (valid_suffixes, **p))
10795b7b453SJohn Marino         tmp = 1;
10895b7b453SJohn Marino       else
10995b7b453SJohn Marino         return LONGINT_INVALID;
11095b7b453SJohn Marino     }
11195b7b453SJohn Marino   else if (errno != 0)
11295b7b453SJohn Marino     {
11395b7b453SJohn Marino       if (errno != ERANGE)
11495b7b453SJohn Marino         return LONGINT_INVALID;
11595b7b453SJohn Marino       err = LONGINT_OVERFLOW;
11695b7b453SJohn Marino     }
11795b7b453SJohn Marino 
118cf28ed85SJohn Marino   /* Let valid_suffixes == NULL mean "allow any suffix".  */
11995b7b453SJohn Marino   /* FIXME: update all callers except the ones that allow suffixes
120cf28ed85SJohn Marino      after the number, changing last parameter NULL to "".  */
12195b7b453SJohn Marino   if (!valid_suffixes)
12295b7b453SJohn Marino     {
12395b7b453SJohn Marino       *val = tmp;
12495b7b453SJohn Marino       return err;
12595b7b453SJohn Marino     }
12695b7b453SJohn Marino 
12795b7b453SJohn Marino   if (**p != '\0')
12895b7b453SJohn Marino     {
12995b7b453SJohn Marino       int base = 1024;
13095b7b453SJohn Marino       int suffixes = 1;
13195b7b453SJohn Marino       strtol_error overflow;
13295b7b453SJohn Marino 
13395b7b453SJohn Marino       if (!strchr (valid_suffixes, **p))
13495b7b453SJohn Marino         {
13595b7b453SJohn Marino           *val = tmp;
13695b7b453SJohn Marino           return err | LONGINT_INVALID_SUFFIX_CHAR;
13795b7b453SJohn Marino         }
13895b7b453SJohn Marino 
139*09d4459fSDaniel Fojt       switch (**p)
14095b7b453SJohn Marino         {
141*09d4459fSDaniel Fojt         case 'E': case 'G': case 'g': case 'k': case 'K': case 'M': case 'm':
142*09d4459fSDaniel Fojt         case 'P': case 'T': case 't': case 'Y': case 'Z':
143*09d4459fSDaniel Fojt 
144cf28ed85SJohn Marino           /* The "valid suffix" '0' is a special flag meaning that
14595b7b453SJohn Marino              an optional second suffix is allowed, which can change
14695b7b453SJohn Marino              the base.  A suffix "B" (e.g. "100MB") stands for a power
14795b7b453SJohn Marino              of 1000, whereas a suffix "iB" (e.g. "100MiB") stands for
14895b7b453SJohn Marino              a power of 1024.  If no suffix (e.g. "100M"), assume
14995b7b453SJohn Marino              power-of-1024.  */
15095b7b453SJohn Marino 
151*09d4459fSDaniel Fojt           if (strchr (valid_suffixes, '0'))
15295b7b453SJohn Marino             switch (p[0][1])
15395b7b453SJohn Marino               {
15495b7b453SJohn Marino               case 'i':
15595b7b453SJohn Marino                 if (p[0][2] == 'B')
15695b7b453SJohn Marino                   suffixes += 2;
15795b7b453SJohn Marino                 break;
15895b7b453SJohn Marino 
15995b7b453SJohn Marino               case 'B':
16095b7b453SJohn Marino               case 'D': /* 'D' is obsolescent */
16195b7b453SJohn Marino                 base = 1000;
16295b7b453SJohn Marino                 suffixes++;
16395b7b453SJohn Marino                 break;
16495b7b453SJohn Marino               }
16595b7b453SJohn Marino         }
16695b7b453SJohn Marino 
16795b7b453SJohn Marino       switch (**p)
16895b7b453SJohn Marino         {
16995b7b453SJohn Marino         case 'b':
17095b7b453SJohn Marino           overflow = bkm_scale (&tmp, 512);
17195b7b453SJohn Marino           break;
17295b7b453SJohn Marino 
17395b7b453SJohn Marino         case 'B':
174*09d4459fSDaniel Fojt           /* This obsolescent first suffix is distinct from the 'B'
175*09d4459fSDaniel Fojt              second suffix above.  E.g., 'tar -L 1000B' means change
176*09d4459fSDaniel Fojt              the tape after writing 1000 KiB of data.  */
17795b7b453SJohn Marino           overflow = bkm_scale (&tmp, 1024);
17895b7b453SJohn Marino           break;
17995b7b453SJohn Marino 
18095b7b453SJohn Marino         case 'c':
181680a9cb8SJohn Marino           overflow = LONGINT_OK;
18295b7b453SJohn Marino           break;
18395b7b453SJohn Marino 
18495b7b453SJohn Marino         case 'E': /* exa or exbi */
18595b7b453SJohn Marino           overflow = bkm_scale_by_power (&tmp, base, 6);
18695b7b453SJohn Marino           break;
18795b7b453SJohn Marino 
18895b7b453SJohn Marino         case 'G': /* giga or gibi */
18995b7b453SJohn Marino         case 'g': /* 'g' is undocumented; for compatibility only */
19095b7b453SJohn Marino           overflow = bkm_scale_by_power (&tmp, base, 3);
19195b7b453SJohn Marino           break;
19295b7b453SJohn Marino 
19395b7b453SJohn Marino         case 'k': /* kilo */
19495b7b453SJohn Marino         case 'K': /* kibi */
19595b7b453SJohn Marino           overflow = bkm_scale_by_power (&tmp, base, 1);
19695b7b453SJohn Marino           break;
19795b7b453SJohn Marino 
19895b7b453SJohn Marino         case 'M': /* mega or mebi */
19995b7b453SJohn Marino         case 'm': /* 'm' is undocumented; for compatibility only */
20095b7b453SJohn Marino           overflow = bkm_scale_by_power (&tmp, base, 2);
20195b7b453SJohn Marino           break;
20295b7b453SJohn Marino 
20395b7b453SJohn Marino         case 'P': /* peta or pebi */
20495b7b453SJohn Marino           overflow = bkm_scale_by_power (&tmp, base, 5);
20595b7b453SJohn Marino           break;
20695b7b453SJohn Marino 
20795b7b453SJohn Marino         case 'T': /* tera or tebi */
20895b7b453SJohn Marino         case 't': /* 't' is undocumented; for compatibility only */
20995b7b453SJohn Marino           overflow = bkm_scale_by_power (&tmp, base, 4);
21095b7b453SJohn Marino           break;
21195b7b453SJohn Marino 
21295b7b453SJohn Marino         case 'w':
21395b7b453SJohn Marino           overflow = bkm_scale (&tmp, 2);
21495b7b453SJohn Marino           break;
21595b7b453SJohn Marino 
21695b7b453SJohn Marino         case 'Y': /* yotta or 2**80 */
21795b7b453SJohn Marino           overflow = bkm_scale_by_power (&tmp, base, 8);
21895b7b453SJohn Marino           break;
21995b7b453SJohn Marino 
22095b7b453SJohn Marino         case 'Z': /* zetta or 2**70 */
22195b7b453SJohn Marino           overflow = bkm_scale_by_power (&tmp, base, 7);
22295b7b453SJohn Marino           break;
22395b7b453SJohn Marino 
22495b7b453SJohn Marino         default:
22595b7b453SJohn Marino           *val = tmp;
22695b7b453SJohn Marino           return err | LONGINT_INVALID_SUFFIX_CHAR;
22795b7b453SJohn Marino         }
22895b7b453SJohn Marino 
22995b7b453SJohn Marino       err |= overflow;
23095b7b453SJohn Marino       *p += suffixes;
23195b7b453SJohn Marino       if (**p)
23295b7b453SJohn Marino         err |= LONGINT_INVALID_SUFFIX_CHAR;
23395b7b453SJohn Marino     }
23495b7b453SJohn Marino 
23595b7b453SJohn Marino   *val = tmp;
23695b7b453SJohn Marino   return err;
23795b7b453SJohn Marino }
238