| 1 | /* Copyright (c) 2003 TXT DataKonsult Ab |
| 2 | Copyright (c) 2009, 2013, Monty Program Ab. |
| 3 | |
| 4 | Redistribution and use in source and binary forms, with or without |
| 5 | modification, are permitted provided that the following conditions are |
| 6 | met: |
| 7 | |
| 8 | 1. Redistributions of source code must retain the above copyright |
| 9 | notice, this list of conditions and the following disclaimer. |
| 10 | |
| 11 | 2. Redistributions in binary form must the following disclaimer in |
| 12 | the documentation and/or other materials provided with the |
| 13 | distribution. |
| 14 | |
| 15 | THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY |
| 16 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 18 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR |
| 19 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| 22 | USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| 25 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 26 | SUCH DAMAGE. |
| 27 | */ |
| 28 | |
| 29 | #include "strings_def.h" |
| 30 | #include <my_sys.h> /* Needed for MY_ERRNO_ERANGE */ |
| 31 | |
| 32 | #define MAX_NEGATIVE_NUMBER ((ulonglong) 0x8000000000000000ULL) |
| 33 | #define INIT_CNT 9 |
| 34 | #define LFACTOR 1000000000ULL |
| 35 | #define LFACTOR1 10000000000ULL |
| 36 | #define LFACTOR2 100000000000ULL |
| 37 | |
| 38 | static unsigned long lfactor[9]= |
| 39 | { |
| 40 | 1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L |
| 41 | }; |
| 42 | |
| 43 | /* |
| 44 | Convert a string to an to unsigned long long integer value |
| 45 | |
| 46 | SYNOPSIS |
| 47 | my_strtoll10() |
| 48 | nptr in pointer to the string to be converted |
| 49 | endptr in/out pointer to the end of the string/ |
| 50 | pointer to the stop character |
| 51 | error out returned error code |
| 52 | |
| 53 | DESCRIPTION |
| 54 | This function takes the decimal representation of integer number |
| 55 | from string nptr and converts it to an signed or unsigned |
| 56 | long long integer value. |
| 57 | Space characters and tab are ignored. |
| 58 | A sign character might precede the digit characters. The number |
| 59 | may have any number of pre-zero digits. |
| 60 | |
| 61 | The function stops reading the string nptr at the first character |
| 62 | that is not a decimal digit. If endptr is not NULL then the function |
| 63 | will not read characters after *endptr. |
| 64 | |
| 65 | RETURN VALUES |
| 66 | Value of string as a signed/unsigned longlong integer |
| 67 | |
| 68 | if no error and endptr != NULL, it will be set to point at the character |
| 69 | after the number |
| 70 | |
| 71 | The error parameter contains information how things went: |
| 72 | -1 Number was an ok negative number |
| 73 | 0 ok |
| 74 | ERANGE If the the value of the converted number exceeded the |
| 75 | maximum negative/unsigned long long integer. |
| 76 | In this case the return value is ~0 if value was |
| 77 | positive and LONGLONG_MIN if value was negative. |
| 78 | EDOM If the string didn't contain any digits. In this case |
| 79 | the return value is 0. |
| 80 | |
| 81 | If endptr is not NULL the function will store the end pointer to |
| 82 | the stop character here. |
| 83 | */ |
| 84 | |
| 85 | |
| 86 | longlong my_strtoll10(const char *nptr, char **endptr, int *error) |
| 87 | { |
| 88 | const char *s, *end, *start, *n_end, *true_end; |
| 89 | char *dummy; |
| 90 | uchar c; |
| 91 | unsigned long i, j, k; |
| 92 | ulonglong li; |
| 93 | int negative; |
| 94 | ulong cutoff, cutoff2, cutoff3; |
| 95 | |
| 96 | s= nptr; |
| 97 | /* If fixed length string */ |
| 98 | if (endptr) |
| 99 | { |
| 100 | end= *endptr; |
| 101 | while (s != end && (*s == ' ' || *s == '\t')) |
| 102 | s++; |
| 103 | if (s == end) |
| 104 | goto no_conv; |
| 105 | } |
| 106 | else |
| 107 | { |
| 108 | endptr= &dummy; /* Easier end test */ |
| 109 | while (*s == ' ' || *s == '\t') |
| 110 | s++; |
| 111 | if (!*s) |
| 112 | goto no_conv; |
| 113 | /* This number must be big to guard against a lot of pre-zeros */ |
| 114 | end= s+65535; /* Can't be longer than this */ |
| 115 | } |
| 116 | |
| 117 | /* Check for a sign. */ |
| 118 | negative= 0; |
| 119 | if (*s == '-') |
| 120 | { |
| 121 | *error= -1; /* Mark as negative number */ |
| 122 | negative= 1; |
| 123 | if (++s == end) |
| 124 | goto no_conv; |
| 125 | cutoff= MAX_NEGATIVE_NUMBER / LFACTOR2; |
| 126 | cutoff2= (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100; |
| 127 | cutoff3= MAX_NEGATIVE_NUMBER % 100; |
| 128 | } |
| 129 | else |
| 130 | { |
| 131 | *error= 0; |
| 132 | if (*s == '+') |
| 133 | { |
| 134 | if (++s == end) |
| 135 | goto no_conv; |
| 136 | } |
| 137 | cutoff= ULONGLONG_MAX / LFACTOR2; |
| 138 | cutoff2= ULONGLONG_MAX % LFACTOR2 / 100; |
| 139 | cutoff3= ULONGLONG_MAX % 100; |
| 140 | } |
| 141 | |
| 142 | /* Handle case where we have a lot of pre-zero */ |
| 143 | if (*s == '0') |
| 144 | { |
| 145 | i= 0; |
| 146 | do |
| 147 | { |
| 148 | if (++s == end) |
| 149 | goto end_i; /* Return 0 */ |
| 150 | } |
| 151 | while (*s == '0'); |
| 152 | n_end= s+ INIT_CNT; |
| 153 | } |
| 154 | else |
| 155 | { |
| 156 | /* Read first digit to check that it's a valid number */ |
| 157 | if ((c= (*s-'0')) > 9) |
| 158 | goto no_conv; |
| 159 | i= c; |
| 160 | n_end= ++s+ INIT_CNT-1; |
| 161 | } |
| 162 | |
| 163 | /* Handle first 9 digits and store them in i */ |
| 164 | if (n_end > end) |
| 165 | n_end= end; |
| 166 | for (; s != n_end ; s++) |
| 167 | { |
| 168 | if ((c= (*s-'0')) > 9) |
| 169 | goto end_i; |
| 170 | i= i*10+c; |
| 171 | } |
| 172 | if (s == end) |
| 173 | goto end_i; |
| 174 | |
| 175 | /* Handle next 9 digits and store them in j */ |
| 176 | j= 0; |
| 177 | start= s; /* Used to know how much to shift i */ |
| 178 | n_end= true_end= s + INIT_CNT; |
| 179 | if (n_end > end) |
| 180 | n_end= end; |
| 181 | do |
| 182 | { |
| 183 | if ((c= (*s-'0')) > 9) |
| 184 | goto end_i_and_j; |
| 185 | j= j*10+c; |
| 186 | } while (++s != n_end); |
| 187 | if (s == end) |
| 188 | { |
| 189 | if (s != true_end) |
| 190 | goto end_i_and_j; |
| 191 | goto end3; |
| 192 | } |
| 193 | if ((c= (*s-'0')) > 9) |
| 194 | goto end3; |
| 195 | |
| 196 | /* Handle the next 1 or 2 digits and store them in k */ |
| 197 | k=c; |
| 198 | if (++s == end || (c= (*s-'0')) > 9) |
| 199 | goto end4; |
| 200 | k= k*10+c; |
| 201 | *endptr= (char*) ++s; |
| 202 | |
| 203 | /* number string should have ended here */ |
| 204 | if (s != end && (c= (*s-'0')) <= 9) |
| 205 | goto overflow; |
| 206 | |
| 207 | /* Check that we didn't get an overflow with the last digit */ |
| 208 | if (i > cutoff || (i == cutoff && (j > cutoff2 || (j == cutoff2 && |
| 209 | k > cutoff3)))) |
| 210 | goto overflow; |
| 211 | li=i*LFACTOR2+ (ulonglong) j*100 + k; |
| 212 | return (longlong) li; |
| 213 | |
| 214 | overflow: /* *endptr is set here */ |
| 215 | *error= MY_ERRNO_ERANGE; |
| 216 | return negative ? LONGLONG_MIN : (longlong) ULONGLONG_MAX; |
| 217 | |
| 218 | end_i: |
| 219 | *endptr= (char*) s; |
| 220 | return (negative ? ((longlong) -(long) i) : (longlong) i); |
| 221 | |
| 222 | end_i_and_j: |
| 223 | li= (ulonglong) i * lfactor[(uint) (s-start)] + j; |
| 224 | *endptr= (char*) s; |
| 225 | return (negative ? -((longlong) li) : (longlong) li); |
| 226 | |
| 227 | end3: |
| 228 | li=(ulonglong) i*LFACTOR+ (ulonglong) j; |
| 229 | *endptr= (char*) s; |
| 230 | return (negative ? -((longlong) li) : (longlong) li); |
| 231 | |
| 232 | end4: |
| 233 | li=(ulonglong) i*LFACTOR1+ (ulonglong) j * 10 + k; |
| 234 | *endptr= (char*) s; |
| 235 | if (negative) |
| 236 | { |
| 237 | if (li > MAX_NEGATIVE_NUMBER) |
| 238 | goto overflow; |
| 239 | return -((longlong) li); |
| 240 | } |
| 241 | return (longlong) li; |
| 242 | |
| 243 | no_conv: |
| 244 | /* There was no number to convert. */ |
| 245 | *error= MY_ERRNO_EDOM; |
| 246 | *endptr= (char *) nptr; |
| 247 | return 0; |
| 248 | } |
| 249 | |