db6684f0aa7d04a77882c9dc720c6be81be1bb11
[tpg/acess2.git] / Usermode / Libraries / libc.so_src / strtoi.c
1 /*
2  * Acess2 C Library
3  * - By John Hodge (thePowersGang)
4  *
5  * strtoi.c
6  * - strto[u][l]l/atoi implimentation
7  */
8 #include <ctype.h>
9 #include <errno.h>
10 #include <limits.h>
11 #include <stddef.h>
12
13 unsigned long long strtoull(const char *str, char **end, int base)
14 {
15         long long       ret = 0;
16         
17         if( !str || base < 0 || base > 36 || base == 1 ) {
18                 if(end)
19                         *end = (char*)str;
20                 errno = EINVAL;
21                 return 0;
22         }
23
24         // Trim leading spaces
25         while( isspace(*str) )
26                 str++;
27         
28         // Handle base detection for hex
29         if( base == 0 || base == 16 ) {
30                 if( *str == '0' && (str[1] == 'x' || str[1] == 'X') && isxdigit(str[2]) ) {
31                         str += 2;
32                         base = 16;
33                 }
34         }
35         
36         // Handle base detection for octal
37         if( base == 0 && *str == '0' ) {
38                 str ++;
39                 base = 8;
40         }
41
42         // Fall back on decimal when unknown
43         if( base == 0 )
44                 base = 10;
45
46         while( *str )
47         {
48                  int    next = -1;
49                 if( base <= 10 ) {
50                         if( '0' <= *str && *str <= '0'+base-1 )
51                                 next = *str - '0';
52                 }
53                 else {
54                         if( '0' <= *str && *str <= '9' )
55                                 next = *str - '0';
56                         if( 'A' <= *str && *str <= 'A'+base-10-1 )
57                                 next = *str - 'A' + 10;
58                         if( 'a' <= *str && *str <= 'a'+base-10-1 )
59                                 next = *str - 'a' + 10;
60                 }
61                 if( next < 0 )
62                         break;
63                 
64                 if( ret == ULLONG_MAX ) {
65                         errno = ERANGE;
66                         str ++;
67                         // Keep eating until first unrecognised character
68                         continue;
69                 }
70                 if( ret > (ULLONG_MAX-next)/base ) {
71                         //_SysDebug("strtoull - Out of range (0x%llx > 0x%llx)", ret, (ULLONG_MAX-next)/base);
72                         //_SysDebug("strtoull -              (%llu > %llu)", ret, (ULLONG_MAX-next)/base);
73                         ret = ULLONG_MAX;
74                         errno = ERANGE;
75                         str ++;
76                         continue;
77                 }
78                 ret *= base;
79                 ret += next;
80                 str ++;
81         }
82
83         if(end)
84                 *end = (char*)str;
85         return ret;
86 }
87
88 unsigned long strtoul(const char *ptr, char **end, int base)
89 {
90         unsigned long long tmp = strtoull(ptr, end, base);
91         
92         if( tmp > ULONG_MAX ) {
93                 errno = ERANGE;
94                 return ULONG_MAX;
95         }
96         
97         return tmp;
98 }
99
100 long long strtoll(const char *str, char **end, int base)
101 {
102          int    neg = 0;
103
104         if( !str ) {
105                 errno = EINVAL;
106                 return 0;
107         }
108         
109         while( isspace(*str) )
110                 str++;
111         
112         // Check for negative (or positive) sign
113         if(*str == '-' || *str == '+')
114         {
115                 //_SysDebug("strtoll - str[0:1] = '%.2s'", str);
116                 if( !isdigit(str[1]) ) {
117                         // Non-digit, invalid string
118                         if(end) *end = (char*)str;
119                         return 0;
120                 }
121                 neg = (*str == '-');
122                 str++;
123         }
124
125         unsigned long long ret = strtoull(str, end, base);      
126         //_SysDebug("strtoll - neg=%i,ret=%llu", neg, ret);
127
128         if( neg ) {
129                 if( -ret < LLONG_MIN ) {
130                         errno = ERANGE;
131                         return LLONG_MIN;
132                 }
133                 return -ret;
134         }
135         else
136         {
137                 if( ret > LLONG_MAX ) {
138                         errno = ERANGE;
139                         return LLONG_MAX;
140                 }
141                 return ret;
142         }
143 }
144
145 long strtol(const char *str, char **end, int base)
146 {
147         long long tmp = strtoll(str, end, base);
148         if( tmp > LONG_MAX || tmp < LONG_MIN ) {
149                 errno = ERANGE;
150                 return (tmp > LONG_MAX) ? LONG_MAX : LONG_MIN;
151         }
152         return tmp;
153 }
154
155 /**
156  * \fn int atoi(const char *str)
157  * \brief Convert a string to an integer
158  */
159 int atoi(const char *str)
160 {
161         long long       tmp = strtoll(str, NULL, 0);
162         if( tmp > INT_MAX || tmp < INT_MIN ) {
163                 errno = ERANGE;
164                 return (tmp > INT_MAX) ? INT_MAX : INT_MIN;
165         }
166         return tmp;
167 }
168
169 long atol(const char *str)
170 {
171         long long       tmp = strtoll(str, NULL, 0);
172         if( tmp > LONG_MAX || tmp < LONG_MIN ) {
173                 errno = ERANGE;
174                 return (tmp > LONG_MAX) ? LONG_MAX : LONG_MIN;
175         }
176         return tmp;
177 }
178
179 long long atoll(const char *str)
180 {
181         long long       tmp = strtoll(str, NULL, 0);
182         return tmp;
183 }

UCC git Repository :: git.ucc.asn.au