Drizzled Public API Documentation

my_strtoll10.cc

00001 /* Copyright (C) 2003 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 #include <config.h>
00017 #include <drizzled/internal/m_string.h>
00018 #include <errno.h>
00019 
00020 namespace drizzled
00021 {
00022 namespace internal
00023 {
00024 
00025 #define MAX_NEGATIVE_NUMBER ((uint64_t) 0x8000000000000000LL)
00026 #define INIT_CNT  9
00027 #define LFACTOR   1000000000ULL
00028 #define LFACTOR1  10000000000ULL
00029 #define LFACTOR2  100000000000ULL
00030 
00031 static uint64_t lfactor[9]=
00032 {
00033   1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L
00034 };
00035 
00036 /*
00037   Convert a string to an to uint64_t integer value
00038 
00039   SYNOPSYS
00040     my_strtoll10()
00041       nptr     in       pointer to the string to be converted
00042       endptr   in/out   pointer to the end of the string/
00043                         pointer to the stop character
00044       error    out      returned error code
00045 
00046   DESCRIPTION
00047     This function takes the decimal representation of integer number
00048     from string nptr and converts it to an signed or unsigned
00049     int64_t value.
00050     Space characters and tab are ignored.
00051     A sign character might precede the digit characters. The number
00052     may have any number of pre-zero digits.
00053 
00054     The function stops reading the string nptr at the first character
00055     that is not a decimal digit. If endptr is not NULL then the function
00056     will not read characters after *endptr.
00057 
00058   RETURN VALUES
00059     Value of string as a signed/unsigned int64_t integer
00060 
00061     if no error and endptr != NULL, it will be set to point at the character
00062     after the number
00063 
00064     The error parameter contains information how things went:
00065     -1    Number was an ok negative number
00066     0   ok
00067     ERANGE  If the the value of the converted number exceeded the
00068           maximum negative/uint64_t integer.
00069     In this case the return value is UINT64_MAX if value was
00070     positive and UINT64_MIN if value was negative.
00071     EDOM  If the string didn't contain any digits. In this case
00072         the return value is 0.
00073 
00074     If endptr is not NULL the function will store the end pointer to
00075     the stop character here.
00076 */
00077 
00078 
00079 int64_t my_strtoll10(const char *nptr, char **endptr, int *error)
00080 {
00081   const char *s, *end, *start, *n_end, *true_end;
00082   char *dummy;
00083   unsigned char c;
00084   unsigned long i, j, k;
00085   uint64_t li;
00086   int negative;
00087   uint64_t cutoff, cutoff2, cutoff3;
00088 
00089   s= nptr;
00090   /* If fixed length string */
00091   if (endptr)
00092   {
00093     end= *endptr;
00094     while (s != end && (*s == ' ' || *s == '\t'))
00095       s++;
00096     if (s == end)
00097       goto no_conv;
00098   }
00099   else
00100   {
00101     endptr= &dummy;       /* Easier end test */
00102     while (*s == ' ' || *s == '\t')
00103       s++;
00104     if (!*s)
00105       goto no_conv;
00106     /* This number must be big to guard against a lot of pre-zeros */
00107     end= s+65535;       /* Can't be longer than this */
00108   }
00109 
00110   /* Check for a sign.  */
00111   negative= 0;
00112   if (*s == '-')
00113   {
00114     *error= -1;         /* Mark as negative number */
00115     negative= 1;
00116     if (++s == end)
00117       goto no_conv;
00118     cutoff=  MAX_NEGATIVE_NUMBER / LFACTOR2;
00119     cutoff2= (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100;
00120     cutoff3=  MAX_NEGATIVE_NUMBER % 100;
00121   }
00122   else
00123   {
00124     *error= 0;
00125     if (*s == '+')
00126     {
00127       if (++s == end)
00128   goto no_conv;
00129     }
00130     cutoff=  UINT64_MAX / LFACTOR2;
00131     cutoff2= UINT64_MAX % LFACTOR2 / 100;
00132     cutoff3=  UINT64_MAX % 100;
00133   }
00134 
00135   /* Handle case where we have a lot of pre-zero */
00136   if (*s == '0')
00137   {
00138     i= 0;
00139     do
00140     {
00141       if (++s == end)
00142   goto end_i;       /* Return 0 */
00143     }
00144     while (*s == '0');
00145     n_end= s+ INIT_CNT;
00146   }
00147   else
00148   {
00149     /* Read first digit to check that it's a valid number */
00150     if ((c= (*s-'0')) > 9)
00151       goto no_conv;
00152     i= c;
00153     n_end= ++s+ INIT_CNT-1;
00154   }
00155 
00156   /* Handle first 9 digits and store them in i */
00157   if (n_end > end)
00158     n_end= end;
00159   for (; s != n_end ; s++)
00160   {
00161     if ((c= (*s-'0')) > 9)
00162       goto end_i;
00163     i= i*10+c;
00164   }
00165   if (s == end)
00166     goto end_i;
00167 
00168   /* Handle next 9 digits and store them in j */
00169   j= 0;
00170   start= s;       /* Used to know how much to shift i */
00171   n_end= true_end= s + INIT_CNT;
00172   if (n_end > end)
00173     n_end= end;
00174   do
00175   {
00176     if ((c= (*s-'0')) > 9)
00177       goto end_i_and_j;
00178     j= j*10+c;
00179   } while (++s != n_end);
00180   if (s == end)
00181   {
00182     if (s != true_end)
00183       goto end_i_and_j;
00184     goto end3;
00185   }
00186   if ((c= (*s-'0')) > 9)
00187     goto end3;
00188 
00189   /* Handle the next 1 or 2 digits and store them in k */
00190   k=c;
00191   if (++s == end || (c= (*s-'0')) > 9)
00192     goto end4;
00193   k= k*10+c;
00194   *endptr= (char*) ++s;
00195 
00196   /* number string should have ended here */
00197   if (s != end && (c= (*s-'0')) <= 9)
00198     goto overflow;
00199 
00200   /* Check that we didn't get an overflow with the last digit */
00201   if (i > cutoff || (i == cutoff && ((j > cutoff2 || j == cutoff2) &&
00202                                      k > cutoff3)))
00203     goto overflow;
00204   li=i*LFACTOR2+ (uint64_t) j*100 + k;
00205   return (int64_t) li;
00206 
00207 overflow:         /* *endptr is set here */
00208   *error= ERANGE;
00209   return negative ? INT64_MIN: INT64_MAX;
00210 
00211 end_i:
00212   *endptr= (char*) s;
00213   return (negative ? ((int64_t) -(long) i) : (int64_t) i);
00214 
00215 end_i_and_j:
00216   li= (uint64_t) i * lfactor[(unsigned int) (s-start)] + j;
00217   *endptr= (char*) s;
00218   return (negative ? -((int64_t) li) : (int64_t) li);
00219 
00220 end3:
00221   li=(uint64_t) i*LFACTOR+ (uint64_t) j;
00222   *endptr= (char*) s;
00223   return (negative ? -((int64_t) li) : (int64_t) li);
00224 
00225 end4:
00226   li=(uint64_t) i*LFACTOR1+ (uint64_t) j * 10 + k;
00227   *endptr= (char*) s;
00228   if (negative)
00229   {
00230    if (li > MAX_NEGATIVE_NUMBER)
00231      goto overflow;
00232    return -((int64_t) li);
00233   }
00234   return (int64_t) li;
00235 
00236 no_conv:
00237   /* There was no number to convert.  */
00238   *error= EDOM;
00239   *endptr= (char *) nptr;
00240   return 0;
00241 }
00242 
00243 } /* namespace internal */
00244 } /* namespace drizzled */