xref: /onnv-gate/usr/src/lib/libast/common/string/strtoi.h (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin /*
234887Schin  * AT&T Research
244887Schin  * Glenn Fowler
254887Schin  * Phong Vo
264887Schin  *
274887Schin  * common header and implementation for
284887Schin  *
294887Schin  *	strtol		strtoul		strton
304887Schin  *	strtoll		strtoull	strtonll
314887Schin  *	strntol		strntoul	strnton
324887Schin  *	strntoll	strntoull	strntonll
334887Schin  *
344887Schin  * define these macros to instantiate an implementation:
354887Schin  *
364887Schin  *	S2I_function	the function name
374887Schin  *	S2I_number	the signed number type
384887Schin  *	S2I_unumber	the unsigned number type
394887Schin  *	S2I_unsigned	1 for unsigned, 0 for signed
4010898Sroland.mainz@nrubsig.org  *	S2I_qualifier	1 for optional qualifier suffix, 0 otherwise
414887Schin  *	S2I_multiplier	1 for optional multiplier suffix, 0 otherwise
424887Schin  *	S2I_size	the second argument is the input string size
434887Schin  *
444887Schin  * convert string to number
454887Schin  * errno=ERANGE on overflow (LONG_MAX) or underflow (LONG_MIN)
464887Schin  * if non-null e will point to first unrecognized char in s
474887Schin  * if basep!=0 it points to the default base on input and
484887Schin  * will point to the explicit base on return
494887Schin  * a default base of 0 will determine the base from the input
504887Schin  * a default base of 1 will determine the base from the input using bb#*
514887Schin  * a base prefix in the string overrides *b
524887Schin  * *b will not be set if the string has no base prefix
534887Schin  * if m>1 and no multipler was specified then the result is multiplied by m
544887Schin  * if m<0 then multipliers are not consumed
554887Schin  * if a base arg or prefix is specified then multiplier is not consumed
564887Schin  *
574887Schin  * integer numbers are of the form:
584887Schin  *
594887Schin  *	[sign][base][number[qualifier]][multiplier]
604887Schin  *
614887Schin  *	base:		nnn#		base nnn
624887Schin  *			0[xX]		hex
634887Schin  *			0		octal
644887Schin  *			[1-9]		decimal
654887Schin  *
664887Schin  *	number:		[0-9a-zA-Z]*
674887Schin  *
684887Schin  *	qualifier:	[lL]
694887Schin  *			[uU]
704887Schin  *			[uU][lL]
714887Schin  *			[lL][uU]
724887Schin  *			[lL][lL][uU]
734887Schin  *			[uU][lL][lL]
744887Schin  *
754887Schin  *	multiplier:	.		pseudo-float if m>1
764887Schin  *			[bB]		block (512)
774887Schin  *			[cC]		char (1)
784887Schin  *			[gG]		giga (1024*1024*1024)
794887Schin  *			[kK]		kilo (1024)
804887Schin  *			[mM]		mega (1024*1024)
814887Schin  */
824887Schin 
834887Schin #include <ast.h>
844887Schin #include <ctype.h>
854887Schin 
864887Schin #include "sfhdr.h"
874887Schin 
884887Schin #if !__STD_C && !defined(const)
894887Schin #define const
904887Schin #endif
914887Schin 
924887Schin #ifndef ERANGE
934887Schin #define ERANGE		EINVAL
944887Schin #endif
954887Schin 
964887Schin #define QL		01
974887Schin #define QU		02
984887Schin 
994887Schin #define S2I_umax	(~((S2I_unumber)0))
1004887Schin 
1014887Schin #if S2I_unsigned
1024887Schin #define S2I_type	S2I_unumber
1034887Schin #define S2I_min		0
1044887Schin #define S2I_max		S2I_umax
1054887Schin #else
1064887Schin #define S2I_type	S2I_number
1074887Schin #define S2I_min		(-S2I_max-1)
1084887Schin #define S2I_max		(S2I_umax>>1)
1094887Schin #endif
1104887Schin 
1114887Schin #if S2I_size
1124887Schin #define S2I_valid(s)	((s)<(z))
1134887Schin #else
1144887Schin #define S2I_valid(s)	1
1154887Schin #endif
1164887Schin 
1174887Schin #define ADDOVER(n,c,s)	((S2I_umax-(n))<((S2I_unumber)((c)+(s))))
1184887Schin #define MPYOVER(n,c)	(((S2I_unumber)(n))>(S2I_umax/(c)))
1194887Schin 
1204887Schin static const S2I_unumber	mm[] =
1214887Schin {
1224887Schin 	0,
1234887Schin 	S2I_umax /  1,
1244887Schin 	S2I_umax /  2,
1254887Schin 	S2I_umax /  3,
1264887Schin 	S2I_umax /  4,
1274887Schin 	S2I_umax /  5,
1284887Schin 	S2I_umax /  6,
1294887Schin 	S2I_umax /  7,
1304887Schin 	S2I_umax /  8,
1314887Schin 	S2I_umax /  9,
1324887Schin 	S2I_umax / 10,
1334887Schin 	S2I_umax / 11,
1344887Schin 	S2I_umax / 12,
1354887Schin 	S2I_umax / 13,
1364887Schin 	S2I_umax / 14,
1374887Schin 	S2I_umax / 15,
1384887Schin 	S2I_umax / 16,
1394887Schin 	S2I_umax / 17,
1404887Schin 	S2I_umax / 18,
1414887Schin 	S2I_umax / 19,
1424887Schin 	S2I_umax / 20,
1434887Schin 	S2I_umax / 21,
1444887Schin 	S2I_umax / 22,
1454887Schin 	S2I_umax / 23,
1464887Schin 	S2I_umax / 24,
1474887Schin 	S2I_umax / 25,
1484887Schin 	S2I_umax / 26,
1494887Schin 	S2I_umax / 27,
1504887Schin 	S2I_umax / 28,
1514887Schin 	S2I_umax / 29,
1524887Schin 	S2I_umax / 30,
1534887Schin 	S2I_umax / 31,
1544887Schin 	S2I_umax / 32,
1554887Schin 	S2I_umax / 33,
1564887Schin 	S2I_umax / 34,
1574887Schin 	S2I_umax / 35,
1584887Schin 	S2I_umax / 36,
1594887Schin 	S2I_umax / 37,
1604887Schin 	S2I_umax / 38,
1614887Schin 	S2I_umax / 39,
1624887Schin 	S2I_umax / 40,
1634887Schin 	S2I_umax / 41,
1644887Schin 	S2I_umax / 42,
1654887Schin 	S2I_umax / 43,
1664887Schin 	S2I_umax / 44,
1674887Schin 	S2I_umax / 45,
1684887Schin 	S2I_umax / 46,
1694887Schin 	S2I_umax / 47,
1704887Schin 	S2I_umax / 48,
1714887Schin 	S2I_umax / 49,
1724887Schin 	S2I_umax / 50,
1734887Schin 	S2I_umax / 51,
1744887Schin 	S2I_umax / 52,
1754887Schin 	S2I_umax / 53,
1764887Schin 	S2I_umax / 54,
1774887Schin 	S2I_umax / 55,
1784887Schin 	S2I_umax / 56,
1794887Schin 	S2I_umax / 57,
1804887Schin 	S2I_umax / 58,
1814887Schin 	S2I_umax / 59,
1824887Schin 	S2I_umax / 60,
1834887Schin 	S2I_umax / 61,
1844887Schin 	S2I_umax / 62,
1854887Schin 	S2I_umax / 63,
1864887Schin 	S2I_umax / 64,
1874887Schin };
1884887Schin 
1894887Schin #if defined(__EXPORT__)
1904887Schin #define extern		__EXPORT__
1914887Schin #endif
1924887Schin extern S2I_type
1934887Schin #undef	extern
1944887Schin #if S2I_size
1954887Schin #if S2I_multiplier
1964887Schin #if __STD_C
S2I_function(const char * a,size_t size,char ** e,char * basep,int m)1974887Schin S2I_function(const char* a, size_t size, char** e, char* basep, int m)
1984887Schin #else
1994887Schin S2I_function(a, size, e, basep, m) const char* a; size_t size; char** e; char* basep; int m;
2004887Schin #endif
2014887Schin #else
2024887Schin #if __STD_C
2034887Schin S2I_function(const char* a, size_t size, char** e, int base)
2044887Schin #else
2054887Schin S2I_function(a, size, e, base) const char* a; size_t size; char** e; int base;
2064887Schin #endif
2074887Schin #endif
2084887Schin #else
2094887Schin #if S2I_multiplier
2104887Schin #if __STD_C
2114887Schin S2I_function(const char* a, char** e, char* basep, int m)
2124887Schin #else
2134887Schin S2I_function(a, e, basep, m) const char* a; char** e; char* basep; int m;
2144887Schin #endif
2154887Schin #else
2164887Schin #if __STD_C
2174887Schin S2I_function(const char* a, char** e, int base)
2184887Schin #else
2194887Schin S2I_function(a, e, base) const char* a; char** e; int base;
2204887Schin #endif
2214887Schin #endif
2224887Schin #endif
2234887Schin {
2244887Schin 	register unsigned char*	s = (unsigned char*)a;
2254887Schin #if S2I_size
2264887Schin 	register unsigned char*	z = s + size;
2274887Schin #endif
2284887Schin 	register S2I_unumber	n;
2294887Schin 	register S2I_unumber	x;
2304887Schin 	register int		c;
2314887Schin 	register int		shift;
2324887Schin 	register unsigned char*	p;
2334887Schin 	register unsigned char*	cv;
2344887Schin 	unsigned char*		b;
2354887Schin 	unsigned char*		k;
2364887Schin 	S2I_unumber		v;
2374887Schin #if S2I_multiplier
2384887Schin 	register int		base;
2394887Schin #endif
2404887Schin 	int			negative;
2414887Schin 	int			overflow = 0;
2424887Schin 	int			decimal = 0;
2434887Schin 	int			thousand = 0;
2444887Schin #if !S2I_unsigned
2454887Schin 	int			qualifier = 0;
2464887Schin #endif
2474887Schin 
2484887Schin #if S2I_multiplier
2494887Schin 	base = basep ? *((unsigned char*)basep) : 0;
2504887Schin #else
2514887Schin 	if (base > 36 && base <= SF_RADIX)
2524887Schin 	{
2534887Schin 		static int	conformance = -1;
2544887Schin 
2554887Schin 		if (conformance < 0)
2564887Schin 			conformance = !strcmp(astconf("CONFORMANCE", NiL, NiL), "standard");
2574887Schin 		if (conformance)
2584887Schin 			base = 1;
2594887Schin 	}
2604887Schin #endif
2614887Schin 	if (base && (base < 2 || base > SF_RADIX))
2624887Schin 	{
2634887Schin 		errno = EINVAL;
2644887Schin 		return 0;
2654887Schin 	}
2664887Schin 	while (S2I_valid(s) && isspace(*s))
2674887Schin 		s++;
2684887Schin 	if ((negative = S2I_valid(s) && (*s == '-')) || S2I_valid(s) && *s == '+')
2694887Schin 		k = ++s;
2704887Schin 	else
2714887Schin 		k = 0;
2724887Schin 	p = s;
2734887Schin 	if (!base)
2744887Schin 	{
2754887Schin 		if (S2I_valid(p) && (c = *p++) >= '0' && c <= '9')
2764887Schin 		{
2774887Schin 			n = c - '0';
2784887Schin 			if (S2I_valid(p) && (c = *p) >= '0' && c <= '9')
2794887Schin 			{
2804887Schin 				n = (n << 3) + (n << 1) + c - '0';
2814887Schin 				p++;
2824887Schin 			}
2834887Schin 			if (S2I_valid(p) && *p == '#')
2844887Schin 			{
2854887Schin 				if (n >= 2 && n <= 64)
2864887Schin 				{
2874887Schin 					k = s = p + 1;
2884887Schin 					base = n;
2894887Schin 				}
2904887Schin 			}
2914887Schin 			else if (base)
2924887Schin 				base = 0;
2934887Schin 			else if (S2I_valid(s) && *s == '0' && S2I_valid(s + 1))
2944887Schin 			{
2954887Schin 				if ((c = *(s + 1)) == 'x' || c == 'X')
2964887Schin 				{
2974887Schin 					k = s += 2;
2984887Schin 					base = 16;
2994887Schin 				}
3004887Schin 				else if (c >= '0' && c <= '7')
3014887Schin 				{
3024887Schin 					s++;
3034887Schin 					base = 8;
3044887Schin 				}
3054887Schin 			}
3064887Schin 		}
3074887Schin 		if (!base)
3084887Schin 			base = 10;
3094887Schin 		else if (base < 2 || base > SF_RADIX)
3104887Schin 		{
3114887Schin 			errno = EINVAL;
3124887Schin 			return 0;
3134887Schin 		}
3144887Schin #if S2I_multiplier
3154887Schin 		else
3164887Schin 		{
3174887Schin 			if (basep)
3184887Schin 				*basep = base;
3194887Schin 			m = -1;
3204887Schin 		}
3214887Schin #endif
3224887Schin 	}
3234887Schin #if S2I_multiplier
3244887Schin 	else
3254887Schin 		m = -1;
3264887Schin #endif
3274887Schin 
3284887Schin 	/*
3294887Schin 	 * this part transcribed from sfvscanf()
3304887Schin 	 */
3314887Schin 
3324887Schin 	SFSETLOCALE(&decimal, &thousand);
3334887Schin 	x = mm[base];
3344887Schin 	n = 0;
3354887Schin 	if (base == 10)
3364887Schin 	{
3374887Schin 		b = s;
3384887Schin 		p = 0;
3394887Schin 		for (;;)
3404887Schin 		{
3414887Schin 			if (S2I_valid(s) && (c = *s++) >= '0' && c <= '9')
3424887Schin 			{
3434887Schin 				if (n > x)
3444887Schin 					overflow = 1;
3454887Schin 				else
3464887Schin 				{
3474887Schin 					n = (n << 3) + (n << 1);
3484887Schin 					c -= '0';
3494887Schin 					if (ADDOVER(n, c, negative))
3504887Schin 						overflow = 1;
3514887Schin 					n += c;
3524887Schin 				}
3534887Schin 			}
3544887Schin 			else if (p && (s - p) != (3 + S2I_valid(s)))
3554887Schin 			{
3564887Schin 				s = p;
3574887Schin 				n = v;
3584887Schin 				c = 0;
3594887Schin 				break;
3604887Schin 			}
3618462SApril.Chin@Sun.COM 			else if (!S2I_valid(s) || c != thousand)
3624887Schin 				break;
3634887Schin 			else if (!p && (s - b) > 4)
3644887Schin 			{
3654887Schin 				if (e)
3664887Schin 					*e = (char*)s - 1;
3674887Schin 				if (overflow)
3684887Schin 				{
3694887Schin 					errno = ERANGE;
3704887Schin #if S2I_unsigned
3714887Schin 					n = S2I_max;
3724887Schin #else
3734887Schin 					n = negative ? S2I_min : S2I_max;
3744887Schin #endif
3754887Schin 				}
3764887Schin 				return n;
3774887Schin 			}
3784887Schin 			else
3794887Schin 			{
3804887Schin 				p = s;
3814887Schin 				v = n;
3824887Schin 			}
3834887Schin 		}
3844887Schin 	}
3854887Schin 	else
3864887Schin 	{
3874887Schin 		SFCVINIT();
3884887Schin 		cv = base <= 36 ? _Sfcv36 : _Sfcv64;
3894887Schin 		if ((base & ~(base - 1)) == base)
3904887Schin 		{
3914887Schin #if !S2I_unsigned
3924887Schin 			qualifier |= QU;
3934887Schin #endif
3944887Schin 			if (base < 8)
3954887Schin 				shift = base <  4 ? 1 : 2;
3964887Schin 			else if (base < 32)
3974887Schin 				shift = base < 16 ? 3 : 4;
3984887Schin 			else
3994887Schin 				shift = base < 64 ? 5 : 6;
4004887Schin 			while (S2I_valid(s) && (c = cv[*s++]) < base)
4014887Schin 			{
4024887Schin 				if (n > x)
4034887Schin 					overflow = 1;
4044887Schin 				else
4054887Schin 				{
4064887Schin 					n <<= shift;
4074887Schin 					if (ADDOVER(n, c, negative))
4084887Schin 						overflow = 1;
4094887Schin 					n += c;
4104887Schin 				}
4114887Schin 			}
4124887Schin 		}
4134887Schin 		else
4144887Schin 			while (S2I_valid(s) && (c = cv[*s++]) < base)
4154887Schin 			{
4164887Schin 				if (n > x)
4174887Schin 					overflow = 1;
4184887Schin 				else
4194887Schin 				{
4204887Schin 					n *= base;
4214887Schin 					if (ADDOVER(n, c, negative))
4224887Schin 						overflow = 1;
4234887Schin 					n += c;
4244887Schin 				}
4254887Schin 			}
4264887Schin 		c = *(s - 1);
4274887Schin 	}
4284887Schin 
42910898Sroland.mainz@nrubsig.org #if S2I_qualifier
43010898Sroland.mainz@nrubsig.org 
4314887Schin 	/*
4324887Schin 	 * optional qualifier suffix
4334887Schin 	 */
4344887Schin 
4354887Schin 	if (S2I_valid(s) && s > (unsigned char*)(a + 1))
4364887Schin 	{
4374887Schin 		base = 0;
4384887Schin 		for (;;)
4394887Schin 		{
4404887Schin 			if (!(base & QL) && (c == 'l' || c == 'L'))
4414887Schin 			{
4424887Schin 				base |= QL;
4434887Schin 				if (!S2I_valid(s))
4444887Schin 					break;
4454887Schin 				c = *s++;
4464887Schin 				if (c == 'l' || c == 'L')
4474887Schin 				{
4484887Schin 					if (!S2I_valid(s))
4494887Schin 						break;
4504887Schin 					c = *s++;
4514887Schin 				}
4524887Schin 			}
4534887Schin 			else if (!(base & QU) && (c == 'u' || c == 'U'))
4544887Schin 			{
4554887Schin 				base |= QU;
4564887Schin #if !S2I_unsigned
4574887Schin 				qualifier |= QU;
4584887Schin #endif
4594887Schin 				if (!S2I_valid(s))
4604887Schin 					break;
4614887Schin 				c = *s++;
4624887Schin 			}
4634887Schin 			else
4644887Schin 				break;
4654887Schin 		}
4664887Schin 	}
46710898Sroland.mainz@nrubsig.org #endif
4684887Schin 	if (S2I_valid(s))
4694887Schin 	{
4704887Schin #if S2I_multiplier
4714887Schin 		/*
4724887Schin 		 * optional multiplier suffix
4734887Schin 		 */
4744887Schin 
4754887Schin 		if (m < 0 || s == (unsigned char*)(a + 1))
4764887Schin 			s--;
4774887Schin 		else
4784887Schin 		{
4794887Schin 			switch (c)
4804887Schin 			{
4814887Schin 			case 'b':
4824887Schin 			case 'B':
4834887Schin 				shift = 9;
4844887Schin 				break;
4854887Schin 			case 'k':
4864887Schin 			case 'K':
4874887Schin 				shift = 10;
4884887Schin 				break;
4894887Schin 			case 'm':
4904887Schin 			case 'M':
4914887Schin 				shift = 20;
4924887Schin 				break;
4934887Schin 			case 'g':
4944887Schin 			case 'G':
4954887Schin 				shift = 30;
4964887Schin 				break;
4974887Schin 			case 't':
4984887Schin 			case 'T':
4994887Schin 				shift = 40;
5004887Schin 				break;
5014887Schin 			case 'p':
5024887Schin 			case 'P':
5034887Schin 				shift = 50;
5044887Schin 				break;
5054887Schin 			case 'e':
5064887Schin 			case 'E':
5074887Schin 				shift = 60;
5084887Schin 				break;
5094887Schin 			default:
5104887Schin 				if (m <= 1)
5114887Schin 					v = 0;
5124887Schin 				else if (c == decimal && S2I_valid(s))
5134887Schin 				{
5144887Schin 					if (MPYOVER(n, m))
5154887Schin 						overflow = 1;
5164887Schin 					n *= m;
5174887Schin 					v = 0;
5184887Schin 					while (S2I_valid(s) && (c = *s++) >= '0' && c <= '9')
5194887Schin 						v += (m /= 10) * (c - '0');
5204887Schin 					if (ADDOVER(n, v, negative))
5214887Schin 						overflow = 1;
5224887Schin 					n += v;
5234887Schin 					v = 0;
5244887Schin 				}
5254887Schin 				else
5264887Schin 					v = m;
5274887Schin 				s--;
5284887Schin 				shift = 0;
5294887Schin 				break;
5304887Schin 			}
5314887Schin 			if (shift)
5324887Schin 			{
5334887Schin 				if (S2I_valid(s))
5344887Schin 					switch (*s)
5354887Schin 					{
5364887Schin 					case 'b':
5374887Schin 					case 'B':
5384887Schin 					case 'i':
5394887Schin 					case 'I':
5404887Schin 						s++;
5414887Schin 						break;
5424887Schin 					}
5434887Schin #if S2I_unsigned
5444887Schin 				if (shift >= (sizeof(S2I_type) * CHAR_BIT))
5454887Schin #else
5464887Schin 				if (shift >= (sizeof(S2I_type) * CHAR_BIT - 1))
5474887Schin #endif
5484887Schin 				{
5494887Schin 					v = 0;
5504887Schin 					overflow = 1;
5514887Schin 				}
5524887Schin 				else
5534887Schin 					v = ((S2I_unumber)1) << shift;
5544887Schin 			}
5554887Schin 			if (v)
5564887Schin 			{
5574887Schin 				if (MPYOVER(n, v))
5584887Schin 					overflow = 1;
5594887Schin 				n *= v;
5604887Schin 			}
5614887Schin 		}
5624887Schin #else
5634887Schin 		s--;
5644887Schin #endif
5654887Schin 	}
5664887Schin 	if (s == k)
5674887Schin 	{
5684887Schin 		s--;
5694887Schin #if S2I_multiplier
5704887Schin 		if (basep)
5714887Schin 			*basep = 10;
5724887Schin #endif
5734887Schin 	}
5744887Schin #if !S2I_unsigned
5754887Schin 	else if (!(qualifier & QU))
5764887Schin 	{
5774887Schin 		if (negative)
5784887Schin 		{
5794887Schin 			if (!n)
5804887Schin 			{
5814887Schin 				b = k;
5824887Schin 				do
5834887Schin 				{
5844887Schin 					if (b >= s)
5854887Schin 					{
5864887Schin 						negative = 0;
5874887Schin 						break;
5884887Schin 					}
5894887Schin 				} while (*b++ == '0');
5904887Schin 			}
5914887Schin 			if (negative && (n - 1) > S2I_max)
5924887Schin 				overflow = 1;
5934887Schin 		}
5944887Schin 		else if (n > S2I_max)
5954887Schin 			overflow = 1;
5964887Schin 	}
5974887Schin #endif
5984887Schin 	if (e)
5994887Schin 		*e = (char*)s;
6004887Schin 	if (overflow)
6014887Schin 	{
6024887Schin #if !S2I_unsigned
6034887Schin 		if (negative)
6044887Schin 		{
6054887Schin 			if (x << 1)
6064887Schin 				errno = ERANGE;
6074887Schin 			return (S2I_type)S2I_min;
6084887Schin 		}
6094887Schin #endif
6104887Schin 		errno = ERANGE;
6114887Schin 		return (S2I_type)S2I_max;
6124887Schin 	}
6134887Schin 	return negative ? -n : n;
6144887Schin }
615