Coverage Report

Created: 2024-06-18 07:03

/src/server/strings/my_strtoll10.c
Line
Count
Source (jump to first uncovered line)
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
0
#define MAX_NEGATIVE_NUMBER ((ulonglong) 0x8000000000000000ULL)
33
0
#define INIT_CNT  9
34
0
#define LFACTOR   1000000000ULL
35
0
#define LFACTOR1  10000000000ULL
36
0
#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
0
{
88
0
  const char *s, *end, *start, *n_end, *true_end;
89
0
  char *dummy;
90
0
  uchar c;
91
0
  unsigned long i, j, k;
92
0
  ulonglong li;
93
0
  int negative;
94
0
  ulong cutoff, cutoff2, cutoff3;
95
96
0
  s= nptr;
97
  /* If fixed length string */
98
0
  if (endptr)
99
0
  {
100
0
    end= *endptr;
101
    /* Skip leading spaces */
102
0
    for ( ; s < end && my_isspace(&my_charset_latin1, *s) ; )
103
0
      s++;
104
105
0
    if (s == end)
106
0
      goto no_conv;
107
0
  }
108
0
  else
109
0
  {
110
0
    endptr= &dummy;       /* Easier end test */
111
    /* Skip leading spaces */
112
0
    for ( ; ; s++)
113
0
    {
114
0
      if (!*s)
115
0
        goto no_conv;
116
0
      if (!my_isspace(&my_charset_latin1, *s))
117
0
        break;
118
0
    }
119
120
    /* This number must be big to guard against a lot of pre-zeros */
121
0
    end= s+65535;       /* Can't be longer than this */
122
0
  }
123
124
  /* Check for a sign.  */
125
0
  negative= 0;
126
0
  if (*s == '-')
127
0
  {
128
0
    *error= -1;         /* Mark as negative number */
129
0
    negative= 1;
130
0
    if (++s == end)
131
0
      goto no_conv;
132
0
    cutoff=  MAX_NEGATIVE_NUMBER / LFACTOR2;
133
0
    cutoff2= (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100;
134
0
    cutoff3=  MAX_NEGATIVE_NUMBER % 100;
135
0
  }
136
0
  else
137
0
  {
138
0
    *error= 0;
139
0
    if (*s == '+')
140
0
    {
141
0
      if (++s == end)
142
0
  goto no_conv;
143
0
    }
144
0
    cutoff=  ULONGLONG_MAX / LFACTOR2;
145
0
    cutoff2= ULONGLONG_MAX % LFACTOR2 / 100;
146
0
    cutoff3=  ULONGLONG_MAX % 100;
147
0
  }
148
149
  /* Handle case where we have a lot of pre-zero */
150
0
  if (*s == '0')
151
0
  {
152
0
    i= 0;
153
0
    do
154
0
    {
155
0
      if (++s == end)
156
0
  goto end_i;       /* Return 0 */
157
0
    }
158
0
    while (*s == '0');
159
0
    n_end= s+ INIT_CNT;
160
0
  }
161
0
  else
162
0
  {
163
    /* Read first digit to check that it's a valid number */
164
0
    if ((c= (*s-'0')) > 9)
165
0
      goto no_conv;
166
0
    i= c;
167
0
    n_end= ++s+ INIT_CNT-1;
168
0
  }
169
170
  /* Handle first 9 digits and store them in i */
171
0
  if (n_end > end)
172
0
    n_end= end;
173
0
  for (; s != n_end ; s++)
174
0
  {
175
0
    if ((c= (*s-'0')) > 9)
176
0
      goto end_i;
177
0
    i= i*10+c;
178
0
  }
179
0
  if (s == end)
180
0
    goto end_i;
181
182
  /* Handle next 9 digits and store them in j */
183
0
  j= 0;
184
0
  start= s;       /* Used to know how much to shift i */
185
0
  n_end= true_end= s + INIT_CNT;
186
0
  if (n_end > end)
187
0
    n_end= end;
188
0
  do
189
0
  {
190
0
    if ((c= (*s-'0')) > 9)
191
0
      goto end_i_and_j;
192
0
    j= j*10+c;
193
0
  } while (++s != n_end);
194
0
  if (s == end)
195
0
  {
196
0
    if (s != true_end)
197
0
      goto end_i_and_j;
198
0
    goto end3;
199
0
  }
200
0
  if ((c= (*s-'0')) > 9)
201
0
    goto end3;
202
203
  /* Handle the next 1 or 2 digits and store them in k */
204
0
  k=c;
205
0
  if (++s == end || (c= (*s-'0')) > 9)
206
0
    goto end4;
207
0
  k= k*10+c;
208
0
  *endptr= (char*) ++s;
209
210
  /* number string should have ended here */
211
0
  if (s != end && (c= (*s-'0')) <= 9)
212
0
    goto overflow;
213
214
  /* Check that we didn't get an overflow with the last digit */
215
0
  if (i > cutoff || (i == cutoff && (j > cutoff2 || (j == cutoff2 &&
216
0
                                     k > cutoff3))))
217
0
    goto overflow;
218
0
  li=i*LFACTOR2+ (ulonglong) j*100 + k;
219
0
  return (longlong) li;
220
221
0
overflow:         /* *endptr is set here */
222
0
  *error= MY_ERRNO_ERANGE;
223
0
  return negative ? LONGLONG_MIN : (longlong) ULONGLONG_MAX;
224
225
0
end_i:
226
0
  *endptr= (char*) s;
227
0
  return (negative ? ((longlong) -(long) i) : (longlong) i);
228
229
0
end_i_and_j:
230
0
  li= (ulonglong) i * lfactor[(uint) (s-start)] + j;
231
0
  *endptr= (char*) s;
232
0
  return (negative ? -((longlong) li) : (longlong) li);
233
234
0
end3:
235
0
  li=(ulonglong) i*LFACTOR+ (ulonglong) j;
236
0
  *endptr= (char*) s;
237
0
  return (negative ? -((longlong) li) : (longlong) li);
238
239
0
end4:
240
0
  li=(ulonglong) i*LFACTOR1+ (ulonglong) j * 10 + k;
241
0
  *endptr= (char*) s;
242
0
  if (negative)
243
0
  {
244
0
   if (li > MAX_NEGATIVE_NUMBER)
245
0
     goto overflow;
246
0
   return -((longlong) li);
247
0
  }
248
0
  return (longlong) li;
249
250
0
no_conv:
251
  /* There was no number to convert.  */
252
0
  *error= MY_ERRNO_EDOM;
253
0
  *endptr= (char *) nptr;
254
0
  return 0;
255
0
}