1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*	Copyright (c) 1988 AT&T	*/
28/*	  All Rights Reserved	*/
29
30#if	defined(_KERNEL) && !defined(_BOOT)
31#include <sys/null.h>
32#include <sys/errno.h>
33#else	/* _KERNEL && !_BOOT */
34#if	!defined(_BOOT) && !defined(_KMDB) && !defined(_STANDALONE)
35#include "lint.h"
36#endif	/* !_BOOT && !_KMDB && !_STANDALONE */
37#if	defined(_STANDALONE)
38#include <sys/cdefs.h>
39#include <stand.h>
40#include <limits.h>
41
42typedef long long longlong_t;
43#else
44#include <errno.h>
45#include <ctype.h>
46#include <limits.h>
47#include <stdlib.h>
48#endif	/* _STANDALONE */
49#endif	/* _KERNEL && !_BOOT */
50#include "strtolctype.h"
51#include <sys/types.h>
52
53#if	defined(_KERNEL) && !defined(_BOOT)
54int
55ddi_strtoll(const char *str, char **nptr, int base, longlong_t *result)
56#else	/* _KERNEL && !_BOOT */
57longlong_t
58strtoll(const char *str, char **nptr, int base)
59#endif	/* _KERNEL && !_BOOT */
60{
61	longlong_t val;
62	int c;
63	int xx;
64	int neg = 0;
65	longlong_t multmin;
66	longlong_t limit;
67	const char **ptr = (const char **)nptr;
68	const unsigned char *ustr = (const unsigned char *)str;
69
70	if (ptr != NULL)
71		*ptr = (char *)ustr; /* in case no number is formed */
72	if (base < 0 || base > MBASE || base == 1) {
73		/* base is invalid -- should be a fatal error */
74#if	defined(_KERNEL) && !defined(_BOOT)
75		return (EINVAL);
76#else	/* _KERNEL && !_BOOT */
77		errno = EINVAL;
78		return (0);
79#endif	/* _KERNEL && !_BOOT */
80	}
81	if (!isalnum(c = *ustr)) {
82		while (isspace(c))
83			c = *++ustr;
84		switch (c) {
85		case '-':
86			neg++;
87			/* FALLTHROUGH */
88		case '+':
89			c = *++ustr;
90		}
91	}
92	if (base == 0) {
93		if (c != '0')
94			base = 10;
95		else if (ustr[1] == 'x' || ustr[1] == 'X')
96			base = 16;
97		else
98			base = 8;
99	}
100	/*
101	 * for any base > 10, the digits incrementally following
102	 *	9 are assumed to be "abc...z" or "ABC...Z"
103	 */
104	if (!lisalnum(c) || (xx = DIGIT(c)) >= base) {
105		/* no number formed */
106#if	defined(_KERNEL) && !defined(_BOOT)
107		return (EINVAL);
108#else	/* _KERNEL && !_BOOT */
109		return (0);
110#endif	/* _KERNEL && !_BOOT */
111	}
112	if (base == 16 && c == '0' && (ustr[1] == 'x' || ustr[1] == 'X') &&
113	    isxdigit(ustr[2]))
114		c = *(ustr += 2); /* skip over leading "0x" or "0X" */
115
116	/* this code assumes that abs(LLONG_MIN) >= abs(LLONG_MAX) */
117	if (neg)
118		limit = LLONG_MIN;
119	else
120		limit = -LLONG_MAX;
121	multmin = limit / (longlong_t)base;
122	val = -DIGIT(c);
123	for (c = *++ustr; lisalnum(c) && (xx = DIGIT(c)) < base; ) {
124		/* accumulate neg avoids surprises near LLONG_MAX */
125		if (val < multmin)
126			goto overflow;
127		val *= base;
128		if (val < limit + xx)
129			goto overflow;
130		val -= xx;
131		c = *++ustr;
132	}
133	if (ptr != NULL)
134		*ptr = (char *)ustr;
135#if	defined(_KERNEL) && !defined(_BOOT)
136	*result = neg ? val : -val;
137	return (0);
138#else	/* _KERNEL && !_BOOT */
139	return (neg ? val : -val);
140#endif	/* _KERNEL && !_BOOT */
141
142overflow:
143	for (c = *++ustr; lisalnum(c) && (xx = DIGIT(c)) < base; (c = *++ustr))
144		;
145	if (ptr != NULL)
146		*ptr = (char *)ustr;
147#if	defined(_KERNEL) && !defined(_BOOT)
148	return (ERANGE);
149#else	/* _KERNEL && !_BOOT */
150	errno = ERANGE;
151	return (neg ? LLONG_MIN : LLONG_MAX);
152#endif	/* _KERNEL && !_BOOT */
153}
154