Drizzled Public API Documentation

ctype-mb.cc
00001 /* Copyright (C) 2000 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 
00021 #include <algorithm>
00022 
00023 using namespace std;
00024 
00025 namespace drizzled {
00026 
00027 /*
00028   my_strcasecmp_mb() returns 0 if strings are equal, non-zero otherwise.
00029  */
00030 
00031 int my_strcasecmp_mb(const charset_info_st * const  cs,const char *s, const char *t)
00032 {
00033   uint32_t l;
00034   unsigned char *map=cs->to_upper;
00035 
00036   while (*s && *t)
00037   {
00038     /* Pointing after the '\0' is safe here. */
00039     if ((l=my_ismbchar(cs, s, s + cs->mbmaxlen)))
00040     {
00041       while (l--)
00042         if (*s++ != *t++)
00043           return 1;
00044     }
00045     else if (my_mbcharlen(cs, *t) > 1)
00046       return 1;
00047     else if (map[(unsigned char) *s++] != map[(unsigned char) *t++])
00048       return 1;
00049   }
00050   /* At least one of '*s' and '*t' is zero here. */
00051   return (*t != *s);
00052 }
00053 
00054 /*
00055 ** Compare string against string with wildcard
00056 **  0 if matched
00057 **  -1 if not matched with wildcard
00058 **   1 if matched with wildcard
00059 */
00060 
00061 inline static const char* inc_ptr(const charset_info_st *cs, const char *str, const char* str_end)
00062 {
00063   return str + (my_ismbchar(cs, str, str_end) ? my_ismbchar(cs, str, str_end) : 1);
00064 }
00065 
00066 inline static int likeconv(const charset_info_st *cs, const char c) 
00067 {
00068   return (unsigned char) cs->sort_order[(unsigned char) c];
00069 }
00070     
00071 int my_wildcmp_mb(const charset_info_st * const cs,
00072       const char *str,const char *str_end,
00073       const char *wildstr,const char *wildend,
00074       int escape, int w_one, int w_many)
00075 {
00076   int result= -1;       /* Not found, using wildcards */
00077 
00078   while (wildstr != wildend)
00079   {
00080     while (*wildstr != w_many && *wildstr != w_one)
00081     {
00082       int l;
00083       if (*wildstr == escape && wildstr+1 != wildend)
00084   wildstr++;
00085       if ((l = my_ismbchar(cs, wildstr, wildend)))
00086       {
00087     if (str+l > str_end || memcmp(str, wildstr, l) != 0)
00088         return 1;
00089     str += l;
00090     wildstr += l;
00091       }
00092       else
00093       if (str == str_end || likeconv(cs,*wildstr++) != likeconv(cs,*str++))
00094   return 1;       /* No match */
00095       if (wildstr == wildend)
00096   return (str != str_end);    /* Match if both are at end */
00097       result=1;         /* Found an anchor char */
00098     }
00099     if (*wildstr == w_one)
00100     {
00101       do
00102       {
00103   if (str == str_end)     /* Skip one char if possible */
00104     return (result);
00105   inc_ptr(cs,str,str_end);
00106       } while (++wildstr < wildend && *wildstr == w_one);
00107       if (wildstr == wildend)
00108   break;
00109     }
00110     if (*wildstr == w_many)
00111     {           /* Found w_many */
00112       unsigned char cmp;
00113       const char* mb = wildstr;
00114       int mb_len=0;
00115 
00116       wildstr++;
00117       /* Remove any '%' and '_' from the wild search string */
00118       for (; wildstr != wildend ; wildstr++)
00119       {
00120   if (*wildstr == w_many)
00121     continue;
00122   if (*wildstr == w_one)
00123   {
00124     if (str == str_end)
00125       return (-1);
00126     inc_ptr(cs,str,str_end);
00127     continue;
00128   }
00129   break;          /* Not a wild character */
00130       }
00131       if (wildstr == wildend)
00132   return 0;       /* Ok if w_many is last */
00133       if (str == str_end)
00134   return -1;
00135 
00136       if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
00137   cmp= *++wildstr;
00138 
00139       mb=wildstr;
00140       mb_len= my_ismbchar(cs, wildstr, wildend);
00141       inc_ptr(cs,wildstr,wildend);    /* This is compared trough cmp */
00142       cmp=likeconv(cs,cmp);
00143       do
00144       {
00145         for (;;)
00146         {
00147           if (str >= str_end)
00148             return -1;
00149           if (mb_len)
00150           {
00151             if (str+mb_len <= str_end && memcmp(str, mb, mb_len) == 0)
00152             {
00153               str += mb_len;
00154               break;
00155             }
00156           }
00157           else if (!my_ismbchar(cs, str, str_end) &&
00158                    likeconv(cs,*str) == cmp)
00159           {
00160             str++;
00161             break;
00162           }
00163           inc_ptr(cs,str, str_end);
00164         }
00165   {
00166     int tmp=my_wildcmp_mb(cs,str,str_end,wildstr,wildend,escape,w_one,
00167                                 w_many);
00168     if (tmp <= 0)
00169       return (tmp);
00170   }
00171       } while (str != str_end && wildstr[0] != w_many);
00172       return(-1);
00173     }
00174   }
00175   return (str != str_end ? 1 : 0);
00176 }
00177 
00178 
00179 size_t my_numchars_mb(const charset_info_st * const cs,
00180           const char *pos, const char *end)
00181 {
00182   size_t count= 0;
00183   while (pos < end)
00184   {
00185     uint32_t mb_len;
00186     pos+= (mb_len= my_ismbchar(cs,pos,end)) ? mb_len : 1;
00187     count++;
00188   }
00189   return count;
00190 }
00191 
00192 
00193 size_t my_charpos_mb(const charset_info_st * const cs, const char *pos, const char *end, size_t length)
00194 {
00195   const char *start= pos;
00196 
00197   while (length && pos < end)
00198   {
00199     uint32_t mb_len;
00200     pos+= (mb_len= my_ismbchar(cs, pos, end)) ? mb_len : 1;
00201     length--;
00202   }
00203   return (size_t) (length ? end+2-start : pos-start);
00204 }
00205 
00206 
00207 size_t my_well_formed_len_mb(const charset_info_st& cs, str_ref str, size_t pos, int *error)
00208 {
00209   const char *b= str.begin();
00210   const char *e= str.end();
00211   const char *b_start= b;
00212   *error= 0;
00213   while (pos)
00214   {
00215     my_wc_t wc;
00216     int mb_len= cs.cset->mb_wc(&cs, &wc, (const unsigned char*) b, (const unsigned char*) e);
00217     if (mb_len <= 0)
00218     {
00219       *error= b < e ? 1 : 0;
00220       break;
00221     }
00222     b+= mb_len;
00223     pos--;
00224   }
00225   return (size_t) (b - b_start);
00226 }
00227 
00228 
00229 uint32_t my_instr_mb(const charset_info_st * const cs,
00230                  const char *b, size_t b_length,
00231                  const char *s, size_t s_length,
00232                  my_match_t *match, uint32_t nmatch)
00233 {
00234   const char *end, *b0;
00235   int res= 0;
00236 
00237   if (s_length <= b_length)
00238   {
00239     if (!s_length)
00240     {
00241       if (nmatch)
00242       {
00243         match->beg= 0;
00244         match->end= 0;
00245         match->mb_len= 0;
00246       }
00247       return 1;   /* Empty string is always found */
00248     }
00249 
00250     b0= b;
00251     end= b+b_length-s_length+1;
00252 
00253     while (b < end)
00254     {
00255       int mb_len;
00256 
00257       if (!cs->coll->strnncoll(cs, (const unsigned char*) b, s_length,
00258                                    (const unsigned char*) s, s_length, 0))
00259       {
00260         if (nmatch)
00261         {
00262           match[0].beg= 0;
00263           match[0].end= (size_t) (b-b0);
00264           match[0].mb_len= res;
00265           if (nmatch > 1)
00266           {
00267             match[1].beg= match[0].end;
00268             match[1].end= match[0].end+s_length;
00269             match[1].mb_len= 0; /* Not computed */
00270           }
00271         }
00272         return 2;
00273       }
00274       mb_len= (mb_len= my_ismbchar(cs, b, end)) ? mb_len : 1;
00275       b+= mb_len;
00276       b_length-= mb_len;
00277       res++;
00278     }
00279   }
00280   return 0;
00281 }
00282 
00283 
00284 /* BINARY collations handlers for MB charsets */
00285 
00286 int my_strnncoll_mb_bin(const charset_info_st * const,
00287                         const unsigned char *s, size_t slen,
00288                         const unsigned char *t, size_t tlen,
00289                         bool t_is_prefix)
00290 {
00291   size_t len= min(slen,tlen);
00292   int cmp= memcmp(s,t,len);
00293   return cmp ? cmp : (int) ((t_is_prefix ? len : slen) - tlen);
00294 }
00295 
00296 
00297 /*
00298   Compare two strings.
00299 
00300   SYNOPSIS
00301     my_strnncollsp_mb_bin()
00302     cs      Chararacter set
00303     s     String to compare
00304     slen    Length of 's'
00305     t     String to compare
00306     tlen    Length of 't'
00307     diff_if_only_endspace_difference
00308             Set to 1 if the strings should be regarded as different
00309                         if they only difference in end space
00310 
00311   NOTE
00312    This function is used for character strings with binary collations.
00313    The shorter string is extended with end space to be as long as the longer
00314    one.
00315 
00316   RETURN
00317     A negative number if s < t
00318     A positive number if s > t
00319     0 if strings are equal
00320 */
00321 
00322 int my_strnncollsp_mb_bin(const charset_info_st * const,
00323                           const unsigned char *a, size_t a_length,
00324                           const unsigned char *b, size_t b_length,
00325                           bool diff_if_only_endspace_difference)
00326 {
00327   const unsigned char *end;
00328   size_t length;
00329   int res;
00330 
00331 #ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
00332   diff_if_only_endspace_difference= 0;
00333 #endif
00334 
00335   end= a + (length= min(a_length, b_length));
00336   while (a < end)
00337   {
00338     if (*a++ != *b++)
00339       return ((int) a[-1] - (int) b[-1]);
00340   }
00341   res= 0;
00342   if (a_length != b_length)
00343   {
00344     int swap= 1;
00345     if (diff_if_only_endspace_difference)
00346       res= 1;                                   /* Assume 'a' is bigger */
00347     /*
00348       Check the next not space character of the longer key. If it's < ' ',
00349       then it's smaller than the other key.
00350     */
00351     if (a_length < b_length)
00352     {
00353       /* put shorter key in s */
00354       a_length= b_length;
00355       a= b;
00356       swap= -1;         /* swap sign of result */
00357       res= -res;
00358     }
00359     for (end= a + a_length-length; a < end ; a++)
00360     {
00361       if (*a != ' ')
00362   return (*a < ' ') ? -swap : swap;
00363     }
00364   }
00365   return res;
00366 }
00367 
00368 
00369 /*
00370   Copy one non-ascii character.
00371   "dst" must have enough room for the character.
00372   Note, we don't use sort_order[] in this macros.
00373   This is correct even for case insensitive collations:
00374   - basic Latin letters are processed outside this macros;
00375   - for other characters sort_order[x] is equal to x.
00376 */
00377 #define my_strnxfrm_mb_non_ascii_char(cs, dst, src, se)                  \
00378 {                                                                        \
00379   switch (cs->cset->ismbchar(cs, (const char*) src, (const char*) se)) { \
00380   case 4:                                                                \
00381     *dst++= *src++;                                                      \
00382     /* fall through */                                                   \
00383   case 3:                                                                \
00384     *dst++= *src++;                                                      \
00385     /* fall through */                                                   \
00386   case 2:                                                                \
00387     *dst++= *src++;                                                      \
00388     /* fall through */                                                   \
00389   case 0:                                                                \
00390     *dst++= *src++; /* byte in range 0x80..0xFF which is not MB head */  \
00391   }                                                                      \
00392 }
00393 
00394 
00395 /*
00396   For character sets with two or three byte multi-byte
00397   characters having multibyte weights *equal* to their codes:
00398   cp932, euckr, gb2312, sjis, eucjpms, ujis.
00399 */
00400 size_t
00401 my_strnxfrm_mb(const charset_info_st * const cs,
00402                unsigned char *dst, size_t dstlen, uint32_t nweights,
00403                const unsigned char *src, size_t srclen, uint32_t flags)
00404 {
00405   unsigned char *d0= dst;
00406   unsigned char *de= dst + dstlen;
00407   const unsigned char *se= src + srclen;
00408   const unsigned char *sort_order= cs->sort_order;
00409 
00410   assert(cs->mbmaxlen <= 4);
00411 
00412   /*
00413     If "srclen" is smaller than both "dstlen" and "nweights"
00414     then we can run a simplified loop -
00415     without checking "nweights" and "de".
00416   */
00417   if (dstlen >= srclen && nweights >= srclen)
00418   {
00419     if (sort_order)
00420     {
00421       /* Optimized version for a case insensitive collation */
00422       for (; src < se; nweights--)
00423       {
00424         if (*src < 128) /* quickly catch ASCII characters */
00425           *dst++= sort_order[*src++];
00426         else
00427           my_strnxfrm_mb_non_ascii_char(cs, dst, src, se);
00428       }
00429     }
00430     else
00431     {
00432       /* Optimized version for a case sensitive collation (no sort_order) */
00433       for (; src < se; nweights--)
00434       {
00435         if (*src < 128) /* quickly catch ASCII characters */
00436           *dst++= *src++;
00437         else
00438           my_strnxfrm_mb_non_ascii_char(cs, dst, src, se);
00439       }
00440     }
00441     goto pad;
00442   }
00443 
00444   /*
00445     A thourough loop, checking all possible limits:
00446     "se", "nweights" and "de".
00447   */
00448   for (; src < se && nweights; nweights--)
00449   {
00450     int chlen;
00451     if (*src < 128 ||
00452         !(chlen= cs->cset->ismbchar(cs, (const char*) src, (const char*) se)))
00453     {
00454       /* Single byte character */
00455       if (dst >= de)
00456         break;
00457       *dst++= sort_order ? sort_order[*src++] : *src++;
00458     }
00459     else
00460     {
00461       /* Multi-byte character */
00462       if (dst + chlen > de)
00463         break;
00464       *dst++= *src++;
00465       *dst++= *src++;
00466       if (chlen == 3)
00467         *dst++= *src++;
00468     }
00469   }
00470 
00471 pad:
00472   return my_strxfrm_pad_desc_and_reverse(cs, d0, dst, de, nweights, flags, 0);
00473 }
00474 
00475 
00476 int my_strcasecmp_mb_bin(const charset_info_st * const,
00477                          const char *s, const char *t)
00478 {
00479   return strcmp(s,t);
00480 }
00481 
00482 
00483 void my_hash_sort_mb_bin(const charset_info_st * const,
00484                          const unsigned char *key, size_t len,
00485                          uint32_t *nr1, uint32_t *nr2)
00486 {
00487   const unsigned char *pos = key;
00488 
00489   /*
00490      Remove trailing spaces. We have to do this to be able to compare
00491     'A ' and 'A' as identical
00492   */
00493   key= internal::skip_trailing_space(key, len);
00494 
00495   for (; pos < (const unsigned char*) key ; pos++)
00496   {
00497     nr1[0]^=(ulong) ((((uint32_t) nr1[0] & 63)+nr2[0]) *
00498        ((uint32_t)*pos)) + (nr1[0] << 8);
00499     nr2[0]+=3;
00500   }
00501 }
00502 
00503 
00504 /*
00505   Fill the given buffer with 'maximum character' for given charset
00506   SYNOPSIS
00507       pad_max_char()
00508       cs   Character set
00509       str  Start of buffer to fill
00510       end  End of buffer to fill
00511 
00512   DESCRIPTION
00513       Write max key:
00514       - for non-Unicode character sets:
00515         just set to 255.
00516       - for Unicode character set (utf-8):
00517         create a buffer with multibyte representation of the max_sort_char
00518         character, and copy it into max_str in a loop.
00519 */
00520 static void pad_max_char(const charset_info_st * const cs, char *str, char *end)
00521 {
00522   char buf[10];
00523   char buflen;
00524 
00525   if (!(cs->state & MY_CS_UNICODE))
00526   {
00527     memset(str, 255, end - str);
00528     return;
00529   }
00530 
00531   buflen= cs->cset->wc_mb(cs, cs->max_sort_char, (unsigned char*) buf,
00532                           (unsigned char*) buf + sizeof(buf));
00533 
00534   assert(buflen > 0);
00535   do
00536   {
00537     if ((str + buflen) < end)
00538     {
00539       /* Enough space for the characer */
00540       memcpy(str, buf, buflen);
00541       str+= buflen;
00542     }
00543     else
00544     {
00545       /*
00546         There is no space for whole multibyte
00547         character, then add trailing spaces.
00548       */
00549       *str++= ' ';
00550     }
00551   } while (str < end);
00552 }
00553 
00554 /*
00555 ** Calculate min_str and max_str that ranges a LIKE string.
00556 ** Arguments:
00557 ** ptr    Pointer to LIKE string.
00558 ** ptr_length Length of LIKE string.
00559 ** escape Escape character in LIKE.  (Normally '\').
00560 **    All escape characters should be removed from
00561 **              min_str and max_str
00562 ** w_one        Single char matching char in LIKE (Normally '_')
00563 ** w_many       Multiple char matching char in LIKE (Normally '%')
00564 ** res_length Length of min_str and max_str.
00565 ** min_str  Smallest case sensitive string that ranges LIKE.
00566 **    Should be space padded to res_length.
00567 ** max_str  Largest case sensitive string that ranges LIKE.
00568 **    Normally padded with the biggest character sort value.
00569 **
00570 ** The function should return 0 if ok and 1 if the LIKE string can't be
00571 ** optimized !
00572 */
00573 
00574 bool my_like_range_mb(const charset_info_st * const cs,
00575                          const char *ptr,size_t ptr_length,
00576                          char escape, char w_one, char w_many,
00577                          size_t res_length,
00578                          char *min_str,char *max_str,
00579                          size_t *min_length,size_t *max_length)
00580 {
00581   uint32_t mb_len;
00582   const char *end= ptr + ptr_length;
00583   char *min_org= min_str;
00584   char *min_end= min_str + res_length;
00585   char *max_end= max_str + res_length;
00586   size_t maxcharlen= res_length / cs->mbmaxlen;
00587   const char *contraction_flags= cs->contractions ?
00588               ((const char*) cs->contractions) + 0x40*0x40 : NULL;
00589 
00590   for (; ptr != end && min_str != min_end && maxcharlen ; maxcharlen--)
00591   {
00592     /* We assume here that escape, w_any, w_namy are one-byte characters */
00593     if (*ptr == escape && ptr+1 != end)
00594       ptr++;                                    /* Skip escape */
00595     else if (*ptr == w_one || *ptr == w_many)   /* '_' and '%' in SQL */
00596     {
00597 fill_max_and_min:
00598       /*
00599         Calculate length of keys:
00600         'a\0\0... is the smallest possible string when we have space expand
00601         a\ff\ff... is the biggest possible string
00602       */
00603       *min_length= ((cs->state & MY_CS_BINSORT) ? (size_t) (min_str - min_org) :
00604                     res_length);
00605       *max_length= res_length;
00606       /* Create min key  */
00607       do
00608       {
00609   *min_str++= (char) cs->min_sort_char;
00610       } while (min_str != min_end);
00611 
00612       /*
00613         Write max key: create a buffer with multibyte
00614         representation of the max_sort_char character,
00615         and copy it into max_str in a loop.
00616       */
00617       *max_length= res_length;
00618       pad_max_char(cs, max_str, max_end);
00619       return 0;
00620     }
00621     if ((mb_len= my_ismbchar(cs, ptr, end)) > 1)
00622     {
00623       if (ptr+mb_len > end || min_str+mb_len > min_end)
00624         break;
00625       while (mb_len--)
00626        *min_str++= *max_str++= *ptr++;
00627     }
00628     else
00629     {
00630       /*
00631         Special case for collations with contractions.
00632         For example, in Chezh, 'ch' is a separate letter
00633         which is sorted between 'h' and 'i'.
00634         If the pattern 'abc%', 'c' at the end can mean:
00635         - letter 'c' itself,
00636         - beginning of the contraction 'ch'.
00637 
00638         If we simply return this LIKE range:
00639 
00640          'abc\min\min\min' and 'abc\max\max\max'
00641 
00642         then this query: SELECT * FROM t1 WHERE a LIKE 'abc%'
00643         will only find values starting from 'abc[^h]',
00644         but won't find values starting from 'abch'.
00645 
00646         We must ignore contraction heads followed by w_one or w_many.
00647         ('Contraction head' means any letter which can be the first
00648         letter in a contraction)
00649 
00650         For example, for Czech 'abc%', we will return LIKE range,
00651         which is equal to LIKE range for 'ab%':
00652 
00653         'ab\min\min\min\min' and 'ab\max\max\max\max'.
00654 
00655       */
00656       if (contraction_flags && ptr + 1 < end &&
00657           contraction_flags[(unsigned char) *ptr])
00658       {
00659         /* Ptr[0] is a contraction head. */
00660 
00661         if (ptr[1] == w_one || ptr[1] == w_many)
00662         {
00663           /* Contraction head followed by a wildcard, quit. */
00664           goto fill_max_and_min;
00665         }
00666 
00667         /*
00668           Some letters can be both contraction heads and contraction tails.
00669           For example, in Danish 'aa' is a separate single letter which
00670           is sorted after 'z'. So 'a' can be both head and tail.
00671 
00672           If ptr[0]+ptr[1] is a contraction,
00673           then put both letters together.
00674 
00675           If ptr[1] can be a contraction part, but ptr[0]+ptr[1]
00676           is not a contraction, then we put only ptr[0],
00677           and continue with ptr[1] on the next loop.
00678         */
00679         if (contraction_flags[(unsigned char) ptr[1]] &&
00680             cs->contractions[(*ptr-0x40)*0x40 + ptr[1] - 0x40])
00681         {
00682           /* Contraction found */
00683           if (maxcharlen == 1 || min_str + 1 >= min_end)
00684           {
00685             /* Both contraction parts don't fit, quit */
00686             goto fill_max_and_min;
00687           }
00688 
00689           /* Put contraction head */
00690           *min_str++= *max_str++= *ptr++;
00691           maxcharlen--;
00692         }
00693       }
00694       /* Put contraction tail, or a single character */
00695       *min_str++= *max_str++= *ptr++;
00696     }
00697   }
00698 
00699   *min_length= *max_length = (size_t) (min_str - min_org);
00700   while (min_str != min_end)
00701     *min_str++= *max_str++= ' ';           /* Because if key compression */
00702   return 0;
00703 }
00704 
00705 
00706 int my_wildcmp_mb_bin(const charset_info_st * const cs,
00707                       const char *str,const char *str_end,
00708                       const char *wildstr,const char *wildend,
00709                       int escape, int w_one, int w_many)
00710 {
00711   int result= -1;       /* Not found, using wildcards */
00712 
00713   while (wildstr != wildend)
00714   {
00715     while (*wildstr != w_many && *wildstr != w_one)
00716     {
00717       int l;
00718       if (*wildstr == escape && wildstr+1 != wildend)
00719   wildstr++;
00720       if ((l = my_ismbchar(cs, wildstr, wildend)))
00721       {
00722     if (str+l > str_end || memcmp(str, wildstr, l) != 0)
00723         return 1;
00724     str += l;
00725     wildstr += l;
00726       }
00727       else
00728       if (str == str_end || *wildstr++ != *str++)
00729   return 1;       /* No match */
00730       if (wildstr == wildend)
00731   return (str != str_end);    /* Match if both are at end */
00732       result=1;         /* Found an anchor char */
00733     }
00734     if (*wildstr == w_one)
00735     {
00736       do
00737       {
00738   if (str == str_end)     /* Skip one char if possible */
00739     return (result);
00740   inc_ptr(cs,str,str_end);
00741       } while (++wildstr < wildend && *wildstr == w_one);
00742       if (wildstr == wildend)
00743   break;
00744     }
00745     if (*wildstr == w_many)
00746     {           /* Found w_many */
00747       unsigned char cmp;
00748       const char* mb = wildstr;
00749       int mb_len=0;
00750 
00751       wildstr++;
00752       /* Remove any '%' and '_' from the wild search string */
00753       for (; wildstr != wildend ; wildstr++)
00754       {
00755   if (*wildstr == w_many)
00756     continue;
00757   if (*wildstr == w_one)
00758   {
00759     if (str == str_end)
00760       return (-1);
00761     inc_ptr(cs,str,str_end);
00762     continue;
00763   }
00764   break;          /* Not a wild character */
00765       }
00766       if (wildstr == wildend)
00767   return 0;       /* Ok if w_many is last */
00768       if (str == str_end)
00769   return -1;
00770 
00771       if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
00772   cmp= *++wildstr;
00773 
00774       mb=wildstr;
00775       mb_len= my_ismbchar(cs, wildstr, wildend);
00776       inc_ptr(cs,wildstr,wildend);    /* This is compared trough cmp */
00777       do
00778       {
00779         for (;;)
00780         {
00781           if (str >= str_end)
00782             return -1;
00783           if (mb_len)
00784           {
00785             if (str+mb_len <= str_end && memcmp(str, mb, mb_len) == 0)
00786             {
00787               str += mb_len;
00788               break;
00789             }
00790           }
00791           else if (!my_ismbchar(cs, str, str_end) && *str == cmp)
00792           {
00793             str++;
00794             break;
00795           }
00796           inc_ptr(cs,str, str_end);
00797         }
00798   {
00799     int tmp=my_wildcmp_mb_bin(cs,str,str_end,wildstr,wildend,escape,w_one,w_many);
00800     if (tmp <= 0)
00801       return (tmp);
00802   }
00803       } while (str != str_end && wildstr[0] != w_many);
00804       return(-1);
00805     }
00806   }
00807   return (str != str_end ? 1 : 0);
00808 }
00809 
00810 
00811 /*
00812   Data was produced from EastAsianWidth.txt
00813   using utt11-dump utility.
00814 */
00815 static char pg11[256]=
00816 {
00817 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00818 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00819 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,
00820 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00821 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00822 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00823 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00824 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
00825 };
00826 
00827 static char pg23[256]=
00828 {
00829 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00830 0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00831 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00832 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00833 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00834 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00835 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00836 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
00837 };
00838 
00839 static char pg2E[256]=
00840 {
00841 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00842 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00843 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00844 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00845 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,
00846 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00847 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00848 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0
00849 };
00850 
00851 static char pg2F[256]=
00852 {
00853 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00854 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00855 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00856 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00857 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00858 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00859 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
00860 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0
00861 };
00862 
00863 static char pg30[256]=
00864 {
00865 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00866 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
00867 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00868 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00869 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,
00870 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00871 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00872 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
00873 };
00874 
00875 static char pg31[256]=
00876 {
00877 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00878 1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00879 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00880 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00881 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00882 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
00883 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00884 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
00885 };
00886 
00887 static char pg32[256]=
00888 {
00889 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
00890 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00891 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00892 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,
00893 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00894 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00895 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00896 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
00897 };
00898 
00899 static char pg4D[256]=
00900 {
00901 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00902 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00903 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00904 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00905 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00906 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
00907 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00908 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
00909 };
00910 
00911 static char pg9F[256]=
00912 {
00913 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00914 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00915 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00916 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00917 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00918 1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00919 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00920 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
00921 };
00922 
00923 static char pgA4[256]=
00924 {
00925 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00926 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00927 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00928 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00929 1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00930 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00931 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00932 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
00933 };
00934 
00935 static char pgD7[256]=
00936 {
00937 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00938 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00939 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00940 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00941 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00942 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00943 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00944 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
00945 };
00946 
00947 static char pgFA[256]=
00948 {
00949 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00950 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00951 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00952 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00953 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00954 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00955 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00956 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
00957 };
00958 
00959 static char pgFE[256]=
00960 {
00961 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00962 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00963 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,
00964 1,1,1,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00965 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00966 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00967 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00968 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
00969 };
00970 
00971 static char pgFF[256]=
00972 {
00973 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00974 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00975 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00976 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00977 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00978 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00979 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00980 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
00981 };
00982 
00983 static class {
00984 public:
00985   int page; 
00986   char *p;
00987 } 
00988   utr11_data[256]=
00989 {
00990 {0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},
00991 {0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},
00992 {0,NULL},{0,pg11},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},
00993 {0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},
00994 {0,NULL},{0,NULL},{0,NULL},{0,pg23},{0,NULL},{0,NULL},{0,NULL},{0,NULL},
00995 {0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,pg2E},{0,pg2F},
00996 {0,pg30},{0,pg31},{0,pg32},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
00997 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
00998 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
00999 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{0,pg4D},{1,NULL},{1,NULL},
01000 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01001 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01002 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01003 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01004 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01005 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01006 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01007 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01008 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01009 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{0,pg9F},
01010 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{0,pgA4},{0,NULL},{0,NULL},{0,NULL},
01011 {0,NULL},{0,NULL},{0,NULL},{0,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01012 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01013 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01014 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01015 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},
01016 {1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{1,NULL},{0,pgD7},
01017 {0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},
01018 {0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},
01019 {0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},
01020 {0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},{0,NULL},
01021 {0,NULL},{1,NULL},{0,pgFA},{0,NULL},{0,NULL},{0,NULL},{0,pgFE},{0,pgFF}
01022 };
01023 
01024 
01025 size_t my_numcells_mb(const charset_info_st * const cs, const char *b, const char *e)
01026 {
01027   my_wc_t wc;
01028   size_t clen= 0;
01029 
01030   while (b < e)
01031   {
01032     int mb_len;
01033     uint32_t pg;
01034     if ((mb_len= cs->cset->mb_wc(cs, &wc, (unsigned char*) b, (unsigned char*) e)) <= 0 ||
01035         wc > 0xFFFF)
01036     {
01037       /*
01038         Let's think a wrong sequence takes 1 dysplay cell.
01039         Also, consider supplementary characters as taking one cell.
01040       */
01041       mb_len= 1;
01042       b++;
01043       continue;
01044     }
01045     b+= mb_len;
01046     pg= (wc >> 8) & 0xFF;
01047     clen+= utr11_data[pg].p ? utr11_data[pg].p[wc & 0xFF] : utr11_data[pg].page;
01048     clen++;
01049   }
01050   return clen;
01051 }
01052 
01053 
01054 
01055 int my_mb_ctype_mb(const charset_info_st * const cs, int *ctype,
01056                    const unsigned char *s, const unsigned char *e)
01057 {
01058   my_wc_t wc;
01059   int res= cs->cset->mb_wc(cs, &wc, s, e);
01060   if (res <= 0 || wc > 0xFFFF)
01061     *ctype= 0;
01062   else
01063     *ctype= my_uni_ctype[wc>>8].ctype ? my_uni_ctype[wc>>8].ctype[wc&0xFF] : my_uni_ctype[wc>>8].pctype;
01064   return res;
01065 }
01066 
01067 } /* namespace drizzled */