]> granicus.if.org Git - postgresql/blob - src/port/strtol.c
2689efdd4682475ed6ef4acd4763a097e4563a97
[postgresql] / src / port / strtol.c
1 /*
2  * src/port/strtol.c
3  *
4  *
5  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
6  * Portions Copyright (c) 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *        notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *        notice, this list of conditions and the following disclaimer in the
16  *        documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *        may be used to endorse or promote products derived from this software
19  *        without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.      IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static char sccsid[] = "@(#)strtol.c    5.4 (Berkeley) 2/23/91";
36 #endif   /* LIBC_SCCS and not lint */
37
38 #include "c.h"
39
40 #include <limits.h>
41 #include <ctype.h>
42
43
44 #define const
45
46 /*
47  *      Usage Tip:
48  *
49  *      strtol() doesn't give a unique return value to indicate that errno
50  *      should be consulted, so in most cases it is best to set errno = 0
51  *      before calling this function, and then errno != 0 can be tested
52  *      after the function completes.
53  */
54
55 /*
56  * Convert a string to a long integer.
57  *
58  * Ignores `locale' stuff.  Assumes that the upper and lower case
59  * alphabets and digits are each contiguous.
60  */
61 long
62 strtol(nptr, endptr, base)
63 const char *nptr;
64 char      **endptr;
65 int                     base;
66 {
67         const char *s = nptr;
68         unsigned long acc;
69         unsigned char c;
70         unsigned long cutoff;
71         int                     neg = 0,
72                                 any,
73                                 cutlim;
74
75         /*
76          * Skip white space and pick up leading +/- sign if any. If base is 0,
77          * allow 0x for hex and 0 for octal, else assume decimal; if base is
78          * already 16, allow 0x.
79          */
80         do
81         {
82                 c = *s++;
83         } while (isspace(c));
84         if (c == '-')
85         {
86                 neg = 1;
87                 c = *s++;
88         }
89         else if (c == '+')
90                 c = *s++;
91         if ((base == 0 || base == 16) &&
92                 c == '0' && (*s == 'x' || *s == 'X'))
93         {
94                 c = s[1];
95                 s += 2;
96                 base = 16;
97         }
98         if (base == 0)
99                 base = c == '0' ? 8 : 10;
100
101         /*
102          * Compute the cutoff value between legal numbers and illegal numbers.
103          * That is the largest legal value, divided by the base.  An input number
104          * that is greater than this value, if followed by a legal input
105          * character, is too big.  One that is equal to this value may be valid or
106          * not; the limit between valid and invalid numbers is then based on the
107          * last digit.  For instance, if the range for longs is
108          * [-2147483648..2147483647] and the input base is 10, cutoff will be set
109          * to 214748364 and cutlim to either 7 (neg==0) or 8 (neg==1), meaning
110          * that if we have accumulated a value > 214748364, or equal but the next
111          * digit is > 7 (or 8), the number is too big, and we will return a range
112          * error.
113          *
114          * Set any if any `digits' consumed; make it negative to indicate
115          * overflow.
116          */
117         cutoff = neg ? -(unsigned long) LONG_MIN : LONG_MAX;
118         cutlim = cutoff % (unsigned long) base;
119         cutoff /= (unsigned long) base;
120         for (acc = 0, any = 0;; c = *s++)
121         {
122                 if (isdigit(c))
123                         c -= '0';
124                 else if (isalpha(c))
125                         c -= isupper(c) ? 'A' - 10 : 'a' - 10;
126                 else
127                         break;
128                 if ((int) c >= base)
129                         break;
130                 if (any < 0 || acc > cutoff || acc == cutoff && (int) c > cutlim)
131                         any = -1;
132                 else
133                 {
134                         any = 1;
135                         acc *= base;
136                         acc += c;
137                 }
138         }
139         if (any < 0)
140         {
141                 acc = neg ? LONG_MIN : LONG_MAX;
142                 errno = ERANGE;
143         }
144         else if (neg)
145                 acc = -acc;
146         if (endptr != 0)
147                 *endptr = any ? s - 1 : (char *) nptr;
148         return acc;
149 }