Drizzled Public API Documentation

ctype-simple.cc
00001 /* Copyright (C) 2002 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 
00018 #include <drizzled/internal/m_string.h>
00019 #include <drizzled/charset.h>
00020 #include <cerrno>
00021 #include <cstdio>
00022 #include <cstdlib>
00023 
00024 #include <stdarg.h>
00025 
00026 #include <algorithm>
00027 
00028 using namespace std;
00029 
00030 namespace drizzled {
00031 
00032 /*
00033   Returns the number of bytes required for strnxfrm().
00034 */
00035 
00036 size_t my_strnxfrmlen_simple(const charset_info_st * const cs, size_t len)
00037 {
00038   return len * (cs->strxfrm_multiply ? cs->strxfrm_multiply : 1);
00039 }
00040 
00041 
00042 /*
00043    We can't use vsprintf here as it's not guaranteed to return
00044    the length on all operating systems.
00045    This function is also not called in a safe environment, so the
00046    end buffer must be checked.
00047 */
00048 
00049 size_t my_snprintf_8bit(const charset_info_st * const,
00050                         char* to, size_t n,
00051          const char* fmt, ...)
00052 {
00053   va_list args;
00054   int result;
00055   va_start(args,fmt);
00056   result= vsnprintf(to, n, fmt, args);
00057   va_end(args);
00058   return result;
00059 }
00060 
00061 
00062 long my_strntol_8bit(const charset_info_st * const cs,
00063          const char *nptr, size_t l, int base,
00064          char **endptr, int *err)
00065 {
00066   int negative;
00067   uint32_t cutoff;
00068   uint32_t cutlim;
00069   uint32_t i;
00070   const char *s;
00071   unsigned char c;
00072   const char *save, *e;
00073   int overflow;
00074 
00075   *err= 0;        /* Initialize error indicator */
00076 #ifdef NOT_USED
00077   if (base < 0 || base == 1 || base > 36)
00078     base = 10;
00079 #endif
00080 
00081   s = nptr;
00082   e = nptr+l;
00083 
00084   for ( ; s<e && cs->isspace(*s) ; s++) {}
00085 
00086   if (s == e)
00087   {
00088     goto noconv;
00089   }
00090 
00091   /* Check for a sign.  */
00092   if (*s == '-')
00093   {
00094     negative = 1;
00095     ++s;
00096   }
00097   else if (*s == '+')
00098   {
00099     negative = 0;
00100     ++s;
00101   }
00102   else
00103     negative = 0;
00104 
00105 #ifdef NOT_USED
00106   if (base == 16 && s[0] == '0' && (s[1]=='X' || s[1]=='x'))
00107     s += 2;
00108 #endif
00109 
00110 #ifdef NOT_USED
00111   if (base == 0)
00112   {
00113     if (*s == '0')
00114     {
00115       if (s[1]=='X' || s[1]=='x')
00116       {
00117   s += 2;
00118   base = 16;
00119       }
00120       else
00121   base = 8;
00122     }
00123     else
00124       base = 10;
00125   }
00126 #endif
00127 
00128   save = s;
00129   cutoff = (UINT32_MAX) / (uint32_t) base;
00130   cutlim = (uint32_t) ((UINT32_MAX) % (uint32_t) base);
00131 
00132   overflow = 0;
00133   i = 0;
00134   for (c = *s; s != e; c = *++s)
00135   {
00136     if (c>='0' && c<='9')
00137       c -= '0';
00138     else if (c>='A' && c<='Z')
00139       c = c - 'A' + 10;
00140     else if (c>='a' && c<='z')
00141       c = c - 'a' + 10;
00142     else
00143       break;
00144     if (c >= base)
00145       break;
00146     if (i > cutoff || (i == cutoff && c > cutlim))
00147       overflow = 1;
00148     else
00149     {
00150       i *= (uint32_t) base;
00151       i += c;
00152     }
00153   }
00154 
00155   if (s == save)
00156     goto noconv;
00157 
00158   if (endptr != NULL)
00159     *endptr = (char *) s;
00160 
00161   if (negative)
00162   {
00163     if (i  > (uint32_t) INT32_MIN)
00164       overflow = 1;
00165   }
00166   else if (i > INT32_MAX)
00167     overflow = 1;
00168 
00169   if (overflow)
00170   {
00171     err[0]= ERANGE;
00172     return negative ? INT32_MIN : INT32_MAX;
00173   }
00174 
00175   return (negative ? -((long) i) : (long) i);
00176 
00177 noconv:
00178   err[0]= EDOM;
00179   if (endptr != NULL)
00180     *endptr = (char *) nptr;
00181   return 0L;
00182 }
00183 
00184 
00185 ulong my_strntoul_8bit(const charset_info_st * const cs,
00186            const char *nptr, size_t l, int base,
00187            char **endptr, int *err)
00188 {
00189   int negative;
00190   uint32_t cutoff;
00191   uint32_t cutlim;
00192   uint32_t i;
00193   const char *s;
00194   unsigned char c;
00195   const char *save, *e;
00196   int overflow;
00197 
00198   *err= 0;        /* Initialize error indicator */
00199 #ifdef NOT_USED
00200   if (base < 0 || base == 1 || base > 36)
00201     base = 10;
00202 #endif
00203 
00204   s = nptr;
00205   e = nptr+l;
00206 
00207   for( ; s<e && cs->isspace(*s); s++) {}
00208 
00209   if (s==e)
00210   {
00211     goto noconv;
00212   }
00213 
00214   if (*s == '-')
00215   {
00216     negative = 1;
00217     ++s;
00218   }
00219   else if (*s == '+')
00220   {
00221     negative = 0;
00222     ++s;
00223   }
00224   else
00225     negative = 0;
00226 
00227 #ifdef NOT_USED
00228   if (base == 16 && s[0] == '0' && (s[1]=='X' || s[1]=='x'))
00229     s += 2;
00230 #endif
00231 
00232 #ifdef NOT_USED
00233   if (base == 0)
00234   {
00235     if (*s == '0')
00236     {
00237       if (s[1]=='X' || s[1]=='x')
00238       {
00239   s += 2;
00240   base = 16;
00241       }
00242       else
00243   base = 8;
00244     }
00245     else
00246       base = 10;
00247   }
00248 #endif
00249 
00250   save = s;
00251   cutoff = (UINT32_MAX) / (uint32_t) base;
00252   cutlim = (uint32_t) ((UINT32_MAX) % (uint32_t) base);
00253   overflow = 0;
00254   i = 0;
00255 
00256   for (c = *s; s != e; c = *++s)
00257   {
00258     if (c>='0' && c<='9')
00259       c -= '0';
00260     else if (c>='A' && c<='Z')
00261       c = c - 'A' + 10;
00262     else if (c>='a' && c<='z')
00263       c = c - 'a' + 10;
00264     else
00265       break;
00266     if (c >= base)
00267       break;
00268     if (i > cutoff || (i == cutoff && c > cutlim))
00269       overflow = 1;
00270     else
00271     {
00272       i *= (uint32_t) base;
00273       i += c;
00274     }
00275   }
00276 
00277   if (s == save)
00278     goto noconv;
00279 
00280   if (endptr != NULL)
00281     *endptr = (char *) s;
00282 
00283   if (overflow)
00284   {
00285     err[0]= ERANGE;
00286     return UINT32_MAX;
00287   }
00288 
00289   return (negative ? -((long) i) : (long) i);
00290 
00291 noconv:
00292   err[0]= EDOM;
00293   if (endptr != NULL)
00294     *endptr = (char *) nptr;
00295   return 0L;
00296 }
00297 
00298 
00299 int64_t my_strntoll_8bit(const charset_info_st * const cs,
00300         const char *nptr, size_t l, int base,
00301         char **endptr,int *err)
00302 {
00303   int negative;
00304   uint64_t cutoff;
00305   uint32_t cutlim;
00306   uint64_t i;
00307   const char *s, *e;
00308   const char *save;
00309   int overflow;
00310 
00311   *err= 0;        /* Initialize error indicator */
00312 #ifdef NOT_USED
00313   if (base < 0 || base == 1 || base > 36)
00314     base = 10;
00315 #endif
00316 
00317   s = nptr;
00318   e = nptr+l;
00319 
00320   for(; s<e && cs->isspace(*s); s++) {}
00321 
00322   if (s == e)
00323   {
00324     goto noconv;
00325   }
00326 
00327   if (*s == '-')
00328   {
00329     negative = 1;
00330     ++s;
00331   }
00332   else if (*s == '+')
00333   {
00334     negative = 0;
00335     ++s;
00336   }
00337   else
00338     negative = 0;
00339 
00340 #ifdef NOT_USED
00341   if (base == 16 && s[0] == '0' && (s[1]=='X'|| s[1]=='x'))
00342     s += 2;
00343 #endif
00344 
00345 #ifdef NOT_USED
00346   if (base == 0)
00347   {
00348     if (*s == '0')
00349     {
00350       if (s[1]=='X' || s[1]=='x')
00351       {
00352   s += 2;
00353   base = 16;
00354       }
00355       else
00356   base = 8;
00357     }
00358     else
00359       base = 10;
00360   }
00361 #endif
00362 
00363   save = s;
00364 
00365   cutoff = (~(uint64_t) 0) / (unsigned long int) base;
00366   cutlim = (uint32_t) ((~(uint64_t) 0) % (unsigned long int) base);
00367 
00368   overflow = 0;
00369   i = 0;
00370   for ( ; s != e; s++)
00371   {
00372     unsigned char c= *s;
00373     if (c>='0' && c<='9')
00374       c -= '0';
00375     else if (c>='A' && c<='Z')
00376       c = c - 'A' + 10;
00377     else if (c>='a' && c<='z')
00378       c = c - 'a' + 10;
00379     else
00380       break;
00381     if (c >= base)
00382       break;
00383     if (i > cutoff || (i == cutoff && c > cutlim))
00384       overflow = 1;
00385     else
00386     {
00387       i *= (uint64_t) base;
00388       i += c;
00389     }
00390   }
00391 
00392   if (s == save)
00393     goto noconv;
00394 
00395   if (endptr != NULL)
00396     *endptr = (char *) s;
00397 
00398   if (negative)
00399   {
00400     if (i  > (uint64_t) INT64_MIN)
00401       overflow = 1;
00402   }
00403   else if (i > (uint64_t) INT64_MAX)
00404     overflow = 1;
00405 
00406   if (overflow)
00407   {
00408     err[0]= ERANGE;
00409     return negative ? INT64_MIN : INT64_MAX;
00410   }
00411 
00412   return (negative ? -((int64_t) i) : (int64_t) i);
00413 
00414 noconv:
00415   err[0]= EDOM;
00416   if (endptr != NULL)
00417     *endptr = (char *) nptr;
00418   return 0L;
00419 }
00420 
00421 
00422 uint64_t my_strntoull_8bit(const charset_info_st * const cs,
00423          const char *nptr, size_t l, int base,
00424          char **endptr, int *err)
00425 {
00426   int negative;
00427   uint64_t cutoff;
00428   uint32_t cutlim;
00429   uint64_t i;
00430   const char *s, *e;
00431   const char *save;
00432   int overflow;
00433 
00434   *err= 0;        /* Initialize error indicator */
00435 #ifdef NOT_USED
00436   if (base < 0 || base == 1 || base > 36)
00437     base = 10;
00438 #endif
00439 
00440   s = nptr;
00441   e = nptr+l;
00442 
00443   for(; s<e && cs->isspace(*s); s++) {}
00444 
00445   if (s == e)
00446   {
00447     goto noconv;
00448   }
00449 
00450   if (*s == '-')
00451   {
00452     negative = 1;
00453     ++s;
00454   }
00455   else if (*s == '+')
00456   {
00457     negative = 0;
00458     ++s;
00459   }
00460   else
00461     negative = 0;
00462 
00463 #ifdef NOT_USED
00464   if (base == 16 && s[0] == '0' && (s[1]=='X' || s[1]=='x'))
00465     s += 2;
00466 #endif
00467 
00468 #ifdef NOT_USED
00469   if (base == 0)
00470   {
00471     if (*s == '0')
00472     {
00473       if (s[1]=='X' || s[1]=='x')
00474       {
00475   s += 2;
00476   base = 16;
00477       }
00478       else
00479   base = 8;
00480     }
00481     else
00482       base = 10;
00483   }
00484 #endif
00485 
00486   save = s;
00487 
00488   cutoff = (~(uint64_t) 0) / (unsigned long int) base;
00489   cutlim = (uint32_t) ((~(uint64_t) 0) % (unsigned long int) base);
00490 
00491   overflow = 0;
00492   i = 0;
00493   for ( ; s != e; s++)
00494   {
00495     unsigned char c= *s;
00496 
00497     if (c>='0' && c<='9')
00498       c -= '0';
00499     else if (c>='A' && c<='Z')
00500       c = c - 'A' + 10;
00501     else if (c>='a' && c<='z')
00502       c = c - 'a' + 10;
00503     else
00504       break;
00505     if (c >= base)
00506       break;
00507     if (i > cutoff || (i == cutoff && c > cutlim))
00508       overflow = 1;
00509     else
00510     {
00511       i *= (uint64_t) base;
00512       i += c;
00513     }
00514   }
00515 
00516   if (s == save)
00517     goto noconv;
00518 
00519   if (endptr != NULL)
00520     *endptr = (char *) s;
00521 
00522   if (overflow)
00523   {
00524     err[0]= ERANGE;
00525     return (~(uint64_t) 0);
00526   }
00527 
00528   return (negative ? -((int64_t) i) : (int64_t) i);
00529 
00530 noconv:
00531   err[0]= EDOM;
00532   if (endptr != NULL)
00533     *endptr = (char *) nptr;
00534   return 0L;
00535 }
00536 
00537 
00538 /*
00539   Read double from string
00540 
00541   SYNOPSIS:
00542     my_strntod_8bit()
00543     cs    Character set information
00544     str   String to convert to double
00545     length  Optional length for string.
00546     end   result pointer to end of converted string
00547     err   Error number if failed conversion
00548 
00549   NOTES:
00550     If length is not INT32_MAX or str[length] != 0 then the given str must
00551     be writeable
00552     If length == INT32_MAX the str must be \0 terminated.
00553 
00554     It's implemented this way to save a buffer allocation and a memory copy.
00555 
00556   RETURN
00557     Value of number in string
00558 */
00559 
00560 
00561 double my_strntod_8bit(const charset_info_st * const,
00562            char *str, size_t length,
00563            char **end, int *err)
00564 {
00565   if (length == INT32_MAX)
00566     length= 65535;                          /* Should be big enough */
00567   *end= str + length;
00568   return internal::my_strtod(str, end, err);
00569 }
00570 
00571 
00572 /*
00573   This is a fast version optimized for the case of radix 10 / -10
00574 
00575   Assume len >= 1
00576 */
00577 
00578 size_t my_long10_to_str_8bit(const charset_info_st * const,
00579                              char *dst, size_t len, int radix, long int val)
00580 {
00581   char buffer[66];
00582   char *p, *e;
00583   long int new_val;
00584   uint32_t sign=0;
00585   unsigned long int uval = (unsigned long int) val;
00586 
00587   e = p = &buffer[sizeof(buffer)-1];
00588   *p= 0;
00589 
00590   if (radix < 0)
00591   {
00592     if (val < 0)
00593     {
00594       /* Avoid integer overflow in (-val) for INT64_MIN (BUG#31799). */
00595       uval= (unsigned long int)0 - uval;
00596       *dst++= '-';
00597       len--;
00598       sign= 1;
00599     }
00600   }
00601 
00602   new_val = (long) (uval / 10);
00603   *--p    = '0'+ (char) (uval - (unsigned long) new_val * 10);
00604   val     = new_val;
00605 
00606   while (val != 0)
00607   {
00608     new_val=val/10;
00609     *--p = '0' + (char) (val-new_val*10);
00610     val= new_val;
00611   }
00612 
00613   len= min(len, (size_t) (e-p));
00614   memcpy(dst, p, len);
00615   return len+sign;
00616 }
00617 
00618 
00619 size_t my_int64_t10_to_str_8bit(const charset_info_st * const,
00620                                 char *dst, size_t len, int radix,
00621                                 int64_t val)
00622 {
00623   char buffer[65];
00624   char *p, *e;
00625   long long_val;
00626   uint32_t sign= 0;
00627   uint64_t uval = (uint64_t)val;
00628 
00629   if (radix < 0)
00630   {
00631     if (val < 0)
00632     {
00633       /* Avoid integer overflow in (-val) for INT64_MIN (BUG#31799). */
00634       uval = (uint64_t)0 - uval;
00635       *dst++= '-';
00636       len--;
00637       sign= 1;
00638     }
00639   }
00640 
00641   e = p = &buffer[sizeof(buffer)-1];
00642   *p= 0;
00643 
00644   if (uval == 0)
00645   {
00646     *--p= '0';
00647     len= 1;
00648     goto cnv;
00649   }
00650 
00651   while (uval > (uint64_t) LONG_MAX)
00652   {
00653     uint64_t quo= uval/(uint32_t) 10;
00654     uint32_t rem= (uint32_t) (uval- quo* (uint32_t) 10);
00655     *--p = '0' + rem;
00656     uval= quo;
00657   }
00658 
00659   long_val= (long) uval;
00660   while (long_val != 0)
00661   {
00662     long quo= long_val/10;
00663     *--p = (char) ('0' + (long_val - quo*10));
00664     long_val= quo;
00665   }
00666 
00667   len= min(len, (size_t) (e-p));
00668 cnv:
00669   memcpy(dst, p, len);
00670   return len+sign;
00671 }
00672 
00673 
00674 /*
00675 ** Compare string against string with wildcard
00676 **  0 if matched
00677 **  -1 if not matched with wildcard
00678 **   1 if matched with wildcard
00679 */
00680 
00681 inline static int likeconv(const charset_info_st *cs, const char c) 
00682 {
00683 #ifdef LIKE_CMP_TOUPPER
00684   return (unsigned char) cs->toupper(c);
00685 #else
00686   return cs->sort_order[(unsigned char)c];
00687 #endif    
00688 }
00689 
00690 
00691 inline static const char* inc_ptr(const charset_info_st *cs, const char *str, const char *str_end)
00692 {
00693   // (Strange this macro have been used. If str_end would actually
00694   // have been used it would have made sense. /Gustaf)
00695   (void)cs;
00696   (void)str_end;
00697   return str++; 
00698 }
00699 
00700 int my_wildcmp_8bit(const charset_info_st * const cs,
00701         const char *str,const char *str_end,
00702         const char *wildstr,const char *wildend,
00703         int escape, int w_one, int w_many)
00704 {
00705   int result= -1;     /* Not found, using wildcards */
00706 
00707   while (wildstr != wildend)
00708   {
00709     while (*wildstr != w_many && *wildstr != w_one)
00710     {
00711       if (*wildstr == escape && wildstr+1 != wildend)
00712   wildstr++;
00713 
00714       if (str == str_end || likeconv(cs,*wildstr++) != likeconv(cs,*str++))
00715   return 1;       /* No match */
00716       if (wildstr == wildend)
00717   return(str != str_end);   /* Match if both are at end */
00718       result=1;         /* Found an anchor char     */
00719     }
00720     if (*wildstr == w_one)
00721     {
00722       do
00723       {
00724   if (str == str_end)     /* Skip one char if possible */
00725     return(result);
00726   inc_ptr(cs,str,str_end);
00727       } while (++wildstr < wildend && *wildstr == w_one);
00728       if (wildstr == wildend)
00729   break;
00730     }
00731     if (*wildstr == w_many)
00732     {           /* Found w_many */
00733       unsigned char cmp;
00734 
00735       wildstr++;
00736       /* Remove any '%' and '_' from the wild search string */
00737       for (; wildstr != wildend ; wildstr++)
00738       {
00739   if (*wildstr == w_many)
00740     continue;
00741   if (*wildstr == w_one)
00742   {
00743     if (str == str_end)
00744       return(-1);
00745     inc_ptr(cs,str,str_end);
00746     continue;
00747   }
00748   break;          /* Not a wild character */
00749       }
00750       if (wildstr == wildend)
00751   return 0;       /* Ok if w_many is last */
00752       if (str == str_end)
00753   return(-1);
00754 
00755       if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
00756   cmp= *++wildstr;
00757 
00758       inc_ptr(cs,wildstr,wildend);  /* This is compared trough cmp */
00759       cmp=likeconv(cs,cmp);
00760       do
00761       {
00762   while (str != str_end && (unsigned char) likeconv(cs,*str) != cmp)
00763     str++;
00764   if (str++ == str_end) return(-1);
00765   {
00766     int tmp=my_wildcmp_8bit(cs,str,str_end,wildstr,wildend,escape,w_one,
00767           w_many);
00768     if (tmp <= 0)
00769       return(tmp);
00770   }
00771       } while (str != str_end && wildstr[0] != w_many);
00772       return(-1);
00773     }
00774   }
00775   return(str != str_end ? 1 : 0);
00776 }
00777 
00778 
00779 /*
00780 ** Calculate min_str and max_str that ranges a LIKE string.
00781 ** Arguments:
00782 ** ptr    Pointer to LIKE string.
00783 ** ptr_length Length of LIKE string.
00784 ** escape Escape character in LIKE.  (Normally '\').
00785 **    All escape characters should be removed from
00786 **              min_str and max_str
00787 ** res_length Length of min_str and max_str.
00788 ** min_str  Smallest case sensitive string that ranges LIKE.
00789 **    Should be space padded to res_length.
00790 ** max_str  Largest case sensitive string that ranges LIKE.
00791 **    Normally padded with the biggest character sort value.
00792 **
00793 ** The function should return 0 if ok and 1 if the LIKE string can't be
00794 ** optimized !
00795 */
00796 
00797 bool my_like_range_simple(const charset_info_st * const cs,
00798                              const char *ptr, size_t ptr_length,
00799                              char escape, char w_one, char w_many,
00800                              size_t res_length,
00801                              char *min_str,char *max_str,
00802                              size_t *min_length, size_t *max_length)
00803 {
00804   const char *end= ptr + ptr_length;
00805   char *min_org=min_str;
00806   char *min_end=min_str+res_length;
00807   size_t charlen= res_length / cs->mbmaxlen;
00808 
00809   for (; ptr != end && min_str != min_end && charlen > 0 ; ptr++, charlen--)
00810   {
00811     if (*ptr == escape && ptr+1 != end)
00812     {
00813       ptr++;          /* Skip escape */
00814       *min_str++= *max_str++ = *ptr;
00815       continue;
00816     }
00817     if (*ptr == w_one)        /* '_' in SQL */
00818     {
00819       *min_str++='\0';        /* This should be min char */
00820       *max_str++= (char) cs->max_sort_char;
00821       continue;
00822     }
00823     if (*ptr == w_many)       /* '%' in SQL */
00824     {
00825       /* Calculate length of keys */
00826       *min_length= ((cs->state & MY_CS_BINSORT) ?
00827                     (size_t) (min_str - min_org) :
00828                     res_length);
00829       *max_length= res_length;
00830       do
00831       {
00832   *min_str++= 0;
00833   *max_str++= (char) cs->max_sort_char;
00834       } while (min_str != min_end);
00835       return 0;
00836     }
00837     *min_str++= *max_str++ = *ptr;
00838   }
00839 
00840  *min_length= *max_length = (size_t) (min_str - min_org);
00841   while (min_str != min_end)
00842     *min_str++= *max_str++ = ' ';      /* Because if key compression */
00843   return 0;
00844 }
00845 
00846 
00847 size_t my_scan_8bit(const charset_info_st * const cs, const char *str, const char *end, int sq)
00848 {
00849   const char *str0= str;
00850   switch (sq)
00851   {
00852   case MY_SEQ_INTTAIL:
00853     if (*str == '.')
00854     {
00855       for(str++ ; str != end && *str == '0' ; str++) {}
00856       return (size_t) (str - str0);
00857     }
00858     return 0;
00859 
00860   case MY_SEQ_SPACES:
00861     for ( ; str < end ; str++)
00862     {
00863       if (!cs->isspace(*str))
00864         break;
00865     }
00866     return (size_t) (str - str0);
00867   default:
00868     return 0;
00869   }
00870 }
00871 
00872 
00873 void my_fill_8bit(const charset_info_st * const, char *s, size_t l, int fill)
00874 {
00875   memset(s, fill, l);
00876 }
00877 
00878 
00879 size_t my_numchars_8bit(const charset_info_st * const, const char *b, const char *e)
00880 {
00881   return (size_t) (e - b);
00882 }
00883 
00884 
00885 size_t my_numcells_8bit(const charset_info_st * const, const char *b, const char *e)
00886 {
00887   return (size_t) (e - b);
00888 }
00889 
00890 
00891 size_t my_charpos_8bit(const charset_info_st * const, const char *, const char *, size_t pos)
00892 {
00893   return pos;
00894 }
00895 
00896 
00897 size_t my_well_formed_len_8bit(const charset_info_st&, str_ref str, size_t nchars, int *error)
00898 {
00899   *error= 0;
00900   return min(str.size(), nchars);
00901 }
00902 
00903 
00904 size_t my_lengthsp_8bit(const charset_info_st * const,
00905                         const char *ptr, size_t length)
00906 {
00907   const char *end;
00908   end= (const char *) internal::skip_trailing_space((const unsigned char *)ptr, length);
00909   return (size_t) (end-ptr);
00910 }
00911 
00912 
00913 uint32_t my_instr_simple(const charset_info_st * const cs,
00914                      const char *b, size_t b_length,
00915                      const char *s, size_t s_length,
00916                      my_match_t *match, uint32_t nmatch)
00917 {
00918   const unsigned char *str, *search, *end, *search_end;
00919 
00920   if (s_length <= b_length)
00921   {
00922     if (!s_length)
00923     {
00924       if (nmatch)
00925       {
00926         match->beg= 0;
00927         match->end= 0;
00928         match->mb_len= 0;
00929       }
00930       return 1;   /* Empty string is always found */
00931     }
00932 
00933     str= (const unsigned char*) b;
00934     search= (const unsigned char*) s;
00935     end= (const unsigned char*) b+b_length-s_length+1;
00936     search_end= (const unsigned char*) s + s_length;
00937 
00938 skip:
00939     while (str != end)
00940     {
00941       if (cs->sort_order[*str++] == cs->sort_order[*search])
00942       {
00943   const unsigned char *i,*j;
00944 
00945   i= str;
00946   j= search+1;
00947 
00948   while (j != search_end)
00949     if (cs->sort_order[*i++] != cs->sort_order[*j++])
00950             goto skip;
00951 
00952   if (nmatch > 0)
00953   {
00954     match[0].beg= 0;
00955     match[0].end= (size_t) (str- (const unsigned char*)b-1);
00956     match[0].mb_len= match[0].end;
00957 
00958     if (nmatch > 1)
00959     {
00960       match[1].beg= match[0].end;
00961       match[1].end= match[0].end+s_length;
00962       match[1].mb_len= match[1].end-match[1].beg;
00963     }
00964   }
00965   return 2;
00966       }
00967     }
00968   }
00969   return 0;
00970 }
00971 
00972 
00973 typedef struct
00974 {
00975   int   nchars;
00976   MY_UNI_IDX  uidx;
00977 } uni_idx;
00978 
00979 #define PLANE_SIZE  0x100
00980 #define PLANE_NUM 0x100
00981 inline static int plane_number(uint16_t x)
00982 {
00983   return ((x >> 8) % PLANE_NUM);
00984 }
00985 
00986 static int pcmp(const void * f, const void * s)
00987 {
00988   const uni_idx *F= (const uni_idx*) f;
00989   const uni_idx *S= (const uni_idx*) s;
00990   int res;
00991 
00992   if (!(res=((S->nchars)-(F->nchars))))
00993     res=((F->uidx.from)-(S->uidx.to));
00994   return res;
00995 }
00996 
00997 static bool create_fromuni(charset_info_st *cs, cs_alloc_func alloc)
00998 {
00999   uni_idx idx[PLANE_NUM];
01000   int   i,n;
01001 
01002   /*
01003     Check that Unicode map is loaded.
01004     It can be not loaded when the collation is
01005     listed in Index.xml but not specified
01006     in the character set specific XML file.
01007   */
01008   if (!cs->tab_to_uni)
01009     return true;
01010 
01011   /* Clear plane statistics */
01012   memset(idx, 0, sizeof(idx));
01013 
01014   /* Count number of characters in each plane */
01015   for (i=0; i< 0x100; i++)
01016   {
01017     uint16_t wc=cs->tab_to_uni[i];
01018     int pl= plane_number(wc);
01019 
01020     if (wc || !i)
01021     {
01022       if (!idx[pl].nchars)
01023       {
01024         idx[pl].uidx.from=wc;
01025         idx[pl].uidx.to=wc;
01026       }else
01027       {
01028         idx[pl].uidx.from=wc<idx[pl].uidx.from?wc:idx[pl].uidx.from;
01029         idx[pl].uidx.to=wc>idx[pl].uidx.to?wc:idx[pl].uidx.to;
01030       }
01031       idx[pl].nchars++;
01032     }
01033   }
01034 
01035   /* Sort planes in descending order */
01036   qsort(&idx,PLANE_NUM,sizeof(uni_idx),&pcmp);
01037 
01038   for (i=0; i < PLANE_NUM; i++)
01039   {
01040     int ch,numchars;
01041 
01042     /* Skip empty plane */
01043     if (!idx[i].nchars)
01044       break;
01045 
01046     numchars=idx[i].uidx.to-idx[i].uidx.from+1;
01047     if (!(idx[i].uidx.tab=(unsigned char*) alloc(numchars * sizeof(*idx[i].uidx.tab))))
01048       return true;
01049 
01050     memset(idx[i].uidx.tab, 0, numchars*sizeof(*idx[i].uidx.tab));
01051 
01052     for (ch=1; ch < PLANE_SIZE; ch++)
01053     {
01054       uint16_t wc=cs->tab_to_uni[ch];
01055       if (wc >= idx[i].uidx.from && wc <= idx[i].uidx.to && wc)
01056       {
01057         int ofs= wc - idx[i].uidx.from;
01058         idx[i].uidx.tab[ofs]= ch;
01059       }
01060     }
01061   }
01062 
01063   /* Allocate and fill reverse table for each plane */
01064   n=i;
01065   if (!(cs->tab_from_uni= (MY_UNI_IDX*) alloc(sizeof(MY_UNI_IDX)*(n+1))))
01066     return true;
01067 
01068   for (i=0; i< n; i++)
01069     cs->tab_from_uni[i]= idx[i].uidx;
01070 
01071   /* Set end-of-list marker */
01072   memset(&cs->tab_from_uni[i], 0, sizeof(MY_UNI_IDX));
01073   return false;
01074 }
01075 
01076 bool my_cset_init_8bit(charset_info_st *cs, cs_alloc_func alloc)
01077 {
01078   cs->caseup_multiply= 1;
01079   cs->casedn_multiply= 1;
01080   cs->pad_char= ' ';
01081   return create_fromuni(cs, alloc);
01082 }
01083 
01084 static void set_max_sort_char(charset_info_st *cs)
01085 {
01086   unsigned char max_char;
01087   uint32_t  i;
01088 
01089   if (!cs->sort_order)
01090     return;
01091 
01092   max_char=cs->sort_order[(unsigned char) cs->max_sort_char];
01093   for (i= 0; i < 256; i++)
01094   {
01095     if ((unsigned char) cs->sort_order[i] > max_char)
01096     {
01097       max_char=(unsigned char) cs->sort_order[i];
01098       cs->max_sort_char= i;
01099     }
01100   }
01101 }
01102 
01103 bool my_coll_init_simple(charset_info_st *cs, cs_alloc_func)
01104 {
01105   set_max_sort_char(cs);
01106   return false;
01107 }
01108 
01109 
01110 int64_t my_strtoll10_8bit(const charset_info_st * const,
01111                           const char *nptr, char **endptr, int *error)
01112 {
01113   return internal::my_strtoll10(nptr, endptr, error);
01114 }
01115 
01116 
01117 int my_mb_ctype_8bit(const charset_info_st * const cs, int *ctype,
01118                    const unsigned char *s, const unsigned char *e)
01119 {
01120   if (s >= e)
01121   {
01122     *ctype= 0;
01123     return MY_CS_TOOSMALL;
01124   }
01125   *ctype= cs->ctype[*s + 1];
01126   return 1;
01127 }
01128 
01129 
01130 #undef  UINT64_MAX
01131 #define UINT64_MAX           (~(uint64_t) 0)
01132 
01133 #define CUTOFF  (UINT64_MAX / 10)
01134 #define CUTLIM  (UINT64_MAX % 10)
01135 #define DIGITS_IN_ULONGLONG 20
01136 
01137 static uint64_t d10[DIGITS_IN_ULONGLONG]=
01138 {
01139   1,
01140   10,
01141   100,
01142   1000,
01143   10000,
01144   100000,
01145   1000000,
01146   10000000,
01147   100000000,
01148   1000000000,
01149   10000000000ULL,
01150   100000000000ULL,
01151   1000000000000ULL,
01152   10000000000000ULL,
01153   100000000000000ULL,
01154   1000000000000000ULL,
01155   10000000000000000ULL,
01156   100000000000000000ULL,
01157   1000000000000000000ULL,
01158   10000000000000000000ULL
01159 };
01160 
01161 
01162 /*
01163 
01164   Convert a string to uint64_t integer value
01165   with rounding.
01166 
01167   SYNOPSYS
01168     my_strntoull10_8bit()
01169       cs              in      pointer to character set
01170       str             in      pointer to the string to be converted
01171       length          in      string length
01172       unsigned_flag   in      whether the number is unsigned
01173       endptr          out     pointer to the stop character
01174       error           out     returned error code
01175 
01176   DESCRIPTION
01177     This function takes the decimal representation of integer number
01178     from string str and converts it to an signed or unsigned
01179     int64_t value.
01180     Space characters and tab are ignored.
01181     A sign character might precede the digit characters.
01182     The number may have any number of pre-zero digits.
01183     The number may have decimal point and exponent.
01184     Rounding is always done in "away from zero" style:
01185       0.5  ->   1
01186      -0.5  ->  -1
01187 
01188     The function stops reading the string str after "length" bytes
01189     or at the first character that is not a part of correct number syntax:
01190 
01191     <signed numeric literal> ::=
01192       [ <sign> ] <exact numeric literal> [ E [ <sign> ] <unsigned integer> ]
01193 
01194     <exact numeric literal> ::=
01195                         <unsigned integer> [ <period> [ <unsigned integer> ] ]
01196                       | <period> <unsigned integer>
01197     <unsigned integer>   ::= <digit>...
01198 
01199   RETURN VALUES
01200     Value of string as a signed/unsigned int64_t integer
01201 
01202     endptr cannot be NULL. The function will store the end pointer
01203     to the stop character here.
01204 
01205     The error parameter contains information how things went:
01206     0      ok
01207     ERANGE   If the the value of the converted number is out of range
01208     In this case the return value is:
01209     - UINT64_MAX if unsigned_flag and the number was too big
01210     - 0 if unsigned_flag and the number was negative
01211     - INT64_MAX if no unsigned_flag and the number is too big
01212     - INT64_MIN if no unsigned_flag and the number it too big negative
01213 
01214     EDOM If the string didn't contain any digits.
01215     In this case the return value is 0.
01216 */
01217 
01218 uint64_t
01219 my_strntoull10rnd_8bit(const charset_info_st * const,
01220                        const char *str, size_t length, int unsigned_flag,
01221                        char **endptr, int *error)
01222 {
01223   const char *dot, *end9, *beg, *end= str + length;
01224   uint64_t ull;
01225   ulong ul;
01226   unsigned char ch;
01227   int shift= 0, digits= 0, negative, addon;
01228 
01229   /* Skip leading spaces and tabs */
01230   for ( ; str < end && (*str == ' ' || *str == '\t') ; str++) {}
01231 
01232   if (str >= end)
01233     goto ret_edom;
01234 
01235   if ((negative= (*str == '-')) || *str=='+') /* optional sign */
01236   {
01237     if (++str == end)
01238       goto ret_edom;
01239   }
01240 
01241   beg= str;
01242   end9= (str + 9) > end ? end : (str + 9);
01243   /* Accumulate small number into ulong, for performance purposes */
01244   for (ul= 0 ; str < end9 && (ch= (unsigned char) (*str - '0')) < 10; str++)
01245   {
01246     ul= ul * 10 + ch;
01247   }
01248 
01249   if (str >= end) /* Small number without dots and expanents */
01250   {
01251     *endptr= (char*) str;
01252     if (negative)
01253     {
01254       if (unsigned_flag)
01255       {
01256         *error= ul ? ERANGE : 0;
01257         return 0;
01258       }
01259       else
01260       {
01261         *error= 0;
01262         return (uint64_t) (int64_t) -(long) ul;
01263       }
01264     }
01265     else
01266     {
01267       *error=0;
01268       return (uint64_t) ul;
01269     }
01270   }
01271 
01272   digits= str - beg;
01273 
01274   /* Continue to accumulate into uint64_t */
01275   for (dot= NULL, ull= ul; str < end; str++)
01276   {
01277     if ((ch= (unsigned char) (*str - '0')) < 10)
01278     {
01279       if (ull < CUTOFF || (ull == CUTOFF && ch <= CUTLIM))
01280       {
01281         ull= ull * 10 + ch;
01282         digits++;
01283         continue;
01284       }
01285       /*
01286         Adding the next digit would overflow.
01287         Remember the next digit in "addon", for rounding.
01288         Scan all digits with an optional single dot.
01289       */
01290       if (ull == CUTOFF)
01291       {
01292         ull= UINT64_MAX;
01293         addon= 1;
01294         str++;
01295       }
01296       else
01297         addon= (*str >= '5');
01298       if (!dot)
01299       {
01300         for ( ; str < end && (ch= (unsigned char) (*str - '0')) < 10; shift++, str++) {}
01301         if (str < end && *str == '.')
01302         {
01303           str++;
01304           for ( ; str < end && (ch= (unsigned char) (*str - '0')) < 10; str++) {}
01305         }
01306       }
01307       else
01308       {
01309         shift= dot - str;
01310         for ( ; str < end && (ch= (unsigned char) (*str - '0')) < 10; str++) {}
01311       }
01312       goto exp;
01313     }
01314 
01315     if (*str == '.')
01316     {
01317       if (dot)
01318       {
01319         /* The second dot character */
01320         addon= 0;
01321         goto exp;
01322       }
01323       else
01324       {
01325         dot= str + 1;
01326       }
01327       continue;
01328     }
01329 
01330     /* Unknown character, exit the loop */
01331     break;
01332   }
01333   shift= dot ? dot - str : 0; /* Right shift */
01334   addon= 0;
01335 
01336 exp:    /* [ E [ <sign> ] <unsigned integer> ] */
01337 
01338   if (!digits)
01339   {
01340     str= beg;
01341     goto ret_edom;
01342   }
01343 
01344   if (str < end && (*str == 'e' || *str == 'E'))
01345   {
01346     str++;
01347     if (str < end)
01348     {
01349       int negative_exp, exponent;
01350       if ((negative_exp= (*str == '-')) || *str=='+')
01351       {
01352         if (++str == end)
01353           goto ret_sign;
01354       }
01355       for (exponent= 0 ;
01356            str < end && (ch= (unsigned char) (*str - '0')) < 10;
01357            str++)
01358       {
01359         exponent= exponent * 10 + ch;
01360       }
01361       shift+= negative_exp ? -exponent : exponent;
01362     }
01363   }
01364 
01365   if (shift == 0) /* No shift, check addon digit */
01366   {
01367     if (addon)
01368     {
01369       if (ull == UINT64_MAX)
01370         goto ret_too_big;
01371       ull++;
01372     }
01373     goto ret_sign;
01374   }
01375 
01376   if (shift < 0) /* Right shift */
01377   {
01378     uint64_t d, r;
01379 
01380     if (-shift >= DIGITS_IN_ULONGLONG)
01381       goto ret_zero; /* Exponent is a big negative number, return 0 */
01382 
01383     d= d10[-shift];
01384     r= (ull % d) * 2;
01385     ull /= d;
01386     if (r >= d)
01387       ull++;
01388     goto ret_sign;
01389   }
01390 
01391   if (shift > DIGITS_IN_ULONGLONG) /* Huge left shift */
01392   {
01393     if (!ull)
01394       goto ret_sign;
01395     goto ret_too_big;
01396   }
01397 
01398   for ( ; shift > 0; shift--, ull*= 10) /* Left shift */
01399   {
01400     if (ull > CUTOFF)
01401       goto ret_too_big; /* Overflow, number too big */
01402   }
01403 
01404 ret_sign:
01405   *endptr= (char*) str;
01406 
01407   if (!unsigned_flag)
01408   {
01409     if (negative)
01410     {
01411       if (ull > (uint64_t) INT64_MIN)
01412       {
01413         *error= ERANGE;
01414         return (uint64_t) INT64_MIN;
01415       }
01416       *error= 0;
01417       return (uint64_t) -(int64_t) ull;
01418     }
01419     else
01420     {
01421       if (ull > (uint64_t) INT64_MAX)
01422       {
01423         *error= ERANGE;
01424         return (uint64_t) INT64_MAX;
01425       }
01426       *error= 0;
01427       return ull;
01428     }
01429   }
01430 
01431   /* Unsigned number */
01432   if (negative && ull)
01433   {
01434     *error= ERANGE;
01435     return 0;
01436   }
01437   *error= 0;
01438   return ull;
01439 
01440 ret_zero:
01441   *endptr= (char*) str;
01442   *error= 0;
01443   return 0;
01444 
01445 ret_edom:
01446   *endptr= (char*) str;
01447   *error= EDOM;
01448   return 0;
01449 
01450 ret_too_big:
01451   *endptr= (char*) str;
01452   *error= ERANGE;
01453   return unsigned_flag ?
01454          UINT64_MAX :
01455          negative ? (uint64_t) INT64_MIN : (uint64_t) INT64_MAX;
01456 }
01457 
01458 
01459 /*
01460   Check if a constant can be propagated
01461 
01462   SYNOPSIS:
01463     my_propagate_simple()
01464     cs    Character set information
01465     str   String to convert to double
01466     length  Optional length for string.
01467 
01468   NOTES:
01469    Takes the string in the given charset and check
01470    if it can be safely propagated in the optimizer.
01471 
01472    create table t1 (
01473      s char(5) character set latin1 collate latin1_german2_ci);
01474    insert into t1 values (0xf6); -- o-umlaut
01475    select * from t1 where length(s)=1 and s='oe';
01476 
01477    The above query should return one row.
01478    We cannot convert this query into:
01479    select * from t1 where length('oe')=1 and s='oe';
01480 
01481    Currently we don't check the constant itself,
01482    and decide not to propagate a constant
01483    just if the collation itself allows tricky things
01484    like expansions and contractions. In the future
01485    we can write a more sophisticated functions to
01486    check the constants. For example, 'oa' can always
01487    be safety propagated in German2 because unlike
01488    'oe' it does not have any special meaning.
01489 
01490   RETURN
01491     1 if constant can be safely propagated
01492     0 if it is not safe to propagate the constant
01493 */
01494 
01495 
01496 
01497 bool my_propagate_simple()
01498 {
01499   return 1;
01500 }
01501 
01502 bool my_propagate_complex()
01503 {
01504   return 0;
01505 }
01506 
01507 /*
01508   Apply DESC and REVERSE collation rules.
01509 
01510   SYNOPSIS:
01511     my_strxfrm_desc_and_reverse()
01512     str      - pointer to string
01513     strend   - end of string
01514     flags    - flags
01515     level    - which level, starting from 0.
01516 
01517   NOTES:
01518     Apply DESC or REVERSE or both flags.
01519 
01520     If DESC flag is given, then the weights
01521     come out NOTed or negated for that level.
01522 
01523     If REVERSE flags is given, then the weights come out in
01524     reverse order for that level, that is, starting with
01525     the last character and ending with the first character.
01526 
01527     If nether DESC nor REVERSE flags are give,
01528     the string is not changed.
01529 
01530 */
01531 void my_strxfrm_desc_and_reverse(unsigned char *str, unsigned char *strend,
01532                                  uint32_t flags, uint32_t level)
01533 {
01534   if (flags & (MY_STRXFRM_DESC_LEVEL1 << level))
01535   {
01536     if (flags & (MY_STRXFRM_REVERSE_LEVEL1 << level))
01537     {
01538       for (strend--; str <= strend;)
01539       {
01540         unsigned char tmp= *str;
01541         *str++= ~*strend;
01542         *strend--= ~tmp;
01543       }
01544     }
01545     else
01546     {
01547       for (; str < strend; str++)
01548         *str= ~*str;
01549     }
01550   }
01551   else if (flags & (MY_STRXFRM_REVERSE_LEVEL1 << level))
01552   {
01553     for (strend--; str < strend;)
01554     {
01555       unsigned char tmp= *str;
01556       *str++= *strend;
01557       *strend--= tmp;
01558     }
01559   }
01560 }
01561 
01562 
01563 size_t
01564 my_strxfrm_pad_desc_and_reverse(const charset_info_st * const cs,
01565                                 unsigned char *str, unsigned char *frmend, unsigned char *strend,
01566                                 uint32_t nweights, uint32_t flags, uint32_t level)
01567 {
01568   if (nweights && frmend < strend && (flags & MY_STRXFRM_PAD_WITH_SPACE))
01569   {
01570     uint32_t fill_length= min((uint32_t) (strend - frmend), nweights * cs->mbminlen);
01571     cs->cset->fill(cs, (char*) frmend, fill_length, cs->pad_char);
01572     frmend+= fill_length;
01573   }
01574   my_strxfrm_desc_and_reverse(str, frmend, flags, level);
01575   return frmend - str;
01576 }
01577 
01578 } /* namespace drizzled */