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