~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to strings/ctype-ucs2.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000 MySQL AB
 
2
   
 
3
   This library is free software; you can redistribute it and/or
 
4
   modify it under the terms of the GNU Library General Public
 
5
   License as published by the Free Software Foundation; version 2
 
6
   of the License.
 
7
   
 
8
   This library is distributed in the hope that it will be useful,
 
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11
   Library General Public License for more details.
 
12
   
 
13
   You should have received a copy of the GNU Library General Public
 
14
   License along with this library; if not, write to the Free
 
15
   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 
16
   MA 02111-1307, USA */
 
17
 
 
18
/* UCS2 support. Written by Alexander Barkov <bar@mysql.com> */
 
19
 
 
20
#include <my_global.h>
 
21
#include <my_sys.h>
 
22
#include "m_string.h"
 
23
#include "m_ctype.h"
 
24
#include <errno.h>
 
25
#include <stdarg.h>
 
26
 
 
27
 
 
28
#ifdef HAVE_CHARSET_ucs2
 
29
 
 
30
#ifndef EILSEQ
 
31
#define EILSEQ ENOENT
 
32
#endif
 
33
 
 
34
 
 
35
static uchar ctype_ucs2[] = {
 
36
    0,
 
37
   32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 32, 32,
 
38
   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
 
39
   72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
 
40
  132,132,132,132,132,132,132,132,132,132, 16, 16, 16, 16, 16, 16,
 
41
   16,129,129,129,129,129,129,  1,  1,  1,  1,  1,  1,  1,  1,  1,
 
42
    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 16, 16, 16, 16, 16,
 
43
   16,130,130,130,130,130,130,  2,  2,  2,  2,  2,  2,  2,  2,  2,
 
44
    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 16, 16, 16, 16, 32,
 
45
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
46
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
47
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
48
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
49
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
50
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
51
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
52
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
 
53
};
 
54
 
 
55
static uchar to_lower_ucs2[] = {
 
56
    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
 
57
   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 
58
   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
 
59
   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
 
60
   64, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
 
61
  112,113,114,115,116,117,118,119,120,121,122, 91, 92, 93, 94, 95,
 
62
   96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
 
63
  112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
 
64
  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
 
65
  144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
 
66
  160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
 
67
  176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
 
68
  192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
 
69
  208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
 
70
  224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
 
71
  240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
 
72
};
 
73
 
 
74
static uchar to_upper_ucs2[] = {
 
75
    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
 
76
   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 
77
   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
 
78
   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
 
79
   64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
 
80
   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
 
81
   96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
 
82
   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127,
 
83
  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
 
84
  144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
 
85
  160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
 
86
  176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
 
87
  192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
 
88
  208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
 
89
  224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
 
90
  240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
 
91
};
 
92
 
 
93
 
 
94
static int my_ucs2_uni(CHARSET_INFO *cs __attribute__((unused)),
 
95
                       my_wc_t * pwc, const uchar *s, const uchar *e)
 
96
{
 
97
  if (s+2 > e) /* Need 2 characters */
 
98
    return MY_CS_TOOSMALL2;
 
99
  
 
100
  *pwc= ((uchar)s[0]) * 256  + ((uchar)s[1]);
 
101
  return 2;
 
102
}
 
103
 
 
104
static int my_uni_ucs2(CHARSET_INFO *cs __attribute__((unused)) ,
 
105
                       my_wc_t wc, uchar *r, uchar *e)
 
106
{
 
107
  if ( r+2 > e ) 
 
108
    return MY_CS_TOOSMALL2;
 
109
  
 
110
  r[0]= (uchar) (wc >> 8);
 
111
  r[1]= (uchar) (wc & 0xFF);
 
112
  return 2;
 
113
}
 
114
 
 
115
 
 
116
static size_t my_caseup_ucs2(CHARSET_INFO *cs, char *src, size_t srclen,
 
117
                           char *dst __attribute__((unused)),
 
118
                           size_t dstlen __attribute__((unused)))
 
119
{
 
120
  my_wc_t wc;
 
121
  int res;
 
122
  char *srcend= src + srclen;
 
123
  MY_UNICASE_INFO **uni_plane= cs->caseinfo;
 
124
  DBUG_ASSERT(src == dst && srclen == dstlen);
 
125
  
 
126
  while ((src < srcend) &&
 
127
         (res= my_ucs2_uni(cs, &wc, (uchar *)src, (uchar*) srcend)) > 0)
 
128
  {
 
129
    int plane= (wc>>8) & 0xFF;
 
130
    wc= uni_plane[plane] ? uni_plane[plane][wc & 0xFF].toupper : wc;
 
131
    if (res != my_uni_ucs2(cs, wc, (uchar*) src, (uchar*) srcend))
 
132
      break;
 
133
    src+= res;
 
134
  }
 
135
  return srclen;
 
136
}
 
137
 
 
138
 
 
139
static void my_hash_sort_ucs2(CHARSET_INFO *cs, const uchar *s, size_t slen,
 
140
                              ulong *n1, ulong *n2)
 
141
{
 
142
  my_wc_t wc;
 
143
  int res;
 
144
  const uchar *e=s+slen;
 
145
  MY_UNICASE_INFO **uni_plane= cs->caseinfo;
 
146
 
 
147
  while (e > s+1 && e[-1] == ' ' && e[-2] == '\0')
 
148
    e-= 2;
 
149
 
 
150
  while ((s < e) && (res=my_ucs2_uni(cs,&wc, (uchar *)s, (uchar*)e)) >0)
 
151
  {
 
152
    int plane = (wc>>8) & 0xFF;
 
153
    wc = uni_plane[plane] ? uni_plane[plane][wc & 0xFF].sort : wc;
 
154
    n1[0]^= (((n1[0] & 63)+n2[0])*(wc & 0xFF))+ (n1[0] << 8);
 
155
    n2[0]+=3;
 
156
    n1[0]^= (((n1[0] & 63)+n2[0])*(wc >> 8))+ (n1[0] << 8);
 
157
    n2[0]+=3;
 
158
    s+=res;
 
159
  }
 
160
}
 
161
 
 
162
 
 
163
static size_t my_caseup_str_ucs2(CHARSET_INFO * cs  __attribute__((unused)), 
 
164
                               char * s __attribute__((unused)))
 
165
{
 
166
  return 0;
 
167
}
 
168
 
 
169
 
 
170
static size_t my_casedn_ucs2(CHARSET_INFO *cs, char *src, size_t srclen,
 
171
                           char *dst __attribute__((unused)),
 
172
                           size_t dstlen __attribute__((unused)))
 
173
{
 
174
  my_wc_t wc;
 
175
  int res;
 
176
  char *srcend= src + srclen;
 
177
  MY_UNICASE_INFO **uni_plane= cs->caseinfo;
 
178
  DBUG_ASSERT(src == dst && srclen == dstlen);
 
179
 
 
180
  while ((src < srcend) &&
 
181
         (res= my_ucs2_uni(cs, &wc, (uchar*) src, (uchar*) srcend)) > 0)
 
182
  {
 
183
    int plane= (wc>>8) & 0xFF;
 
184
    wc= uni_plane[plane] ? uni_plane[plane][wc & 0xFF].tolower : wc;
 
185
    if (res != my_uni_ucs2(cs, wc, (uchar*) src, (uchar*) srcend))
 
186
      break;
 
187
    src+= res;
 
188
  }
 
189
  return srclen;
 
190
}
 
191
 
 
192
 
 
193
static size_t my_casedn_str_ucs2(CHARSET_INFO *cs __attribute__((unused)), 
 
194
                               char * s __attribute__((unused)))
 
195
{
 
196
  return 0;
 
197
}
 
198
 
 
199
 
 
200
static int my_strnncoll_ucs2(CHARSET_INFO *cs, 
 
201
                             const uchar *s, size_t slen, 
 
202
                             const uchar *t, size_t tlen,
 
203
                             my_bool t_is_prefix)
 
204
{
 
205
  int s_res,t_res;
 
206
  my_wc_t UNINIT_VAR(s_wc),t_wc;
 
207
  const uchar *se=s+slen;
 
208
  const uchar *te=t+tlen;
 
209
  MY_UNICASE_INFO **uni_plane= cs->caseinfo;
 
210
 
 
211
  while ( s < se && t < te )
 
212
  {
 
213
    int plane;
 
214
    s_res=my_ucs2_uni(cs,&s_wc, s, se);
 
215
    t_res=my_ucs2_uni(cs,&t_wc, t, te);
 
216
    
 
217
    if ( s_res <= 0 || t_res <= 0 )
 
218
    {
 
219
      /* Incorrect string, compare by char value */
 
220
      return ((int)s[0]-(int)t[0]); 
 
221
    }
 
222
    
 
223
    plane=(s_wc>>8) & 0xFF;
 
224
    s_wc = uni_plane[plane] ? uni_plane[plane][s_wc & 0xFF].sort : s_wc;
 
225
    plane=(t_wc>>8) & 0xFF;
 
226
    t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].sort : t_wc;
 
227
    if ( s_wc != t_wc )
 
228
    {
 
229
      return  s_wc > t_wc ? 1 : -1;
 
230
    }
 
231
    
 
232
    s+=s_res;
 
233
    t+=t_res;
 
234
  }
 
235
  return (int) (t_is_prefix ? t-te : ((se-s) - (te-t)));
 
236
}
 
237
 
 
238
/*
 
239
  Compare strings, discarding end space
 
240
 
 
241
  SYNOPSIS
 
242
    my_strnncollsp_ucs2()
 
243
    cs                  character set handler
 
244
    a                   First string to compare
 
245
    a_length            Length of 'a'
 
246
    b                   Second string to compare
 
247
    b_length            Length of 'b'
 
248
 
 
249
  IMPLEMENTATION
 
250
    If one string is shorter as the other, then we space extend the other
 
251
    so that the strings have equal length.
 
252
 
 
253
    This will ensure that the following things hold:
 
254
 
 
255
    "a"  == "a "
 
256
    "a\0" < "a"
 
257
    "a\0" < "a "
 
258
 
 
259
  RETURN
 
260
    < 0  a <  b
 
261
    = 0  a == b
 
262
    > 0  a > b
 
263
*/
 
264
 
 
265
static int my_strnncollsp_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
266
                               const uchar *s, size_t slen,
 
267
                               const uchar *t, size_t tlen,
 
268
                               my_bool diff_if_only_endspace_difference
 
269
                               __attribute__((unused)))
 
270
{
 
271
  const uchar *se, *te;
 
272
  size_t minlen;
 
273
  MY_UNICASE_INFO **uni_plane= cs->caseinfo;
 
274
 
 
275
  /* extra safety to make sure the lengths are even numbers */
 
276
  slen&= ~1;
 
277
  tlen&= ~1;
 
278
 
 
279
  se= s + slen;
 
280
  te= t + tlen;
 
281
 
 
282
  for (minlen= min(slen, tlen); minlen; minlen-= 2)
 
283
  {
 
284
    int s_wc = uni_plane[s[0]] ? (int) uni_plane[s[0]][s[1]].sort :
 
285
                                 (((int) s[0]) << 8) + (int) s[1];
 
286
 
 
287
    int t_wc = uni_plane[t[0]] ? (int) uni_plane[t[0]][t[1]].sort : 
 
288
                                 (((int) t[0]) << 8) + (int) t[1];
 
289
    if ( s_wc != t_wc )
 
290
      return  s_wc > t_wc ? 1 : -1;
 
291
 
 
292
    s+= 2;
 
293
    t+= 2;
 
294
  }
 
295
 
 
296
  if (slen != tlen)
 
297
  {
 
298
    int swap= 1;
 
299
    if (slen < tlen)
 
300
    {
 
301
      s= t;
 
302
      se= te;
 
303
      swap= -1;
 
304
    }
 
305
 
 
306
    for ( ; s < se ; s+= 2)
 
307
    {
 
308
      if (s[0] || s[1] != ' ')
 
309
        return (s[0] == 0 && s[1] < ' ') ? -swap : swap;
 
310
    }
 
311
  }
 
312
  return 0;
 
313
}
 
314
 
 
315
 
 
316
static int my_strncasecmp_ucs2(CHARSET_INFO *cs,
 
317
                               const char *s, const char *t,  size_t len)
 
318
{
 
319
  int s_res,t_res;
 
320
  my_wc_t UNINIT_VAR(s_wc),t_wc;
 
321
  const char *se=s+len;
 
322
  const char *te=t+len;
 
323
  MY_UNICASE_INFO **uni_plane= cs->caseinfo;
 
324
 
 
325
  while ( s < se && t < te )
 
326
  {
 
327
    int plane;
 
328
    
 
329
    s_res=my_ucs2_uni(cs,&s_wc, (const uchar*)s, (const uchar*)se);
 
330
    t_res=my_ucs2_uni(cs,&t_wc, (const uchar*)t, (const uchar*)te);
 
331
    
 
332
    if ( s_res <= 0 || t_res <= 0 )
 
333
    {
 
334
      /* Incorrect string, compare by char value */
 
335
      return ((int)s[0]-(int)t[0]); 
 
336
    }
 
337
    
 
338
    plane=(s_wc>>8) & 0xFF;
 
339
    s_wc = uni_plane[plane] ? uni_plane[plane][s_wc & 0xFF].tolower : s_wc;
 
340
 
 
341
    plane=(t_wc>>8) & 0xFF;
 
342
    t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].tolower : t_wc;
 
343
    
 
344
    if ( s_wc != t_wc )
 
345
      return  ((int) s_wc) - ((int) t_wc);
 
346
    
 
347
    s+=s_res;
 
348
    t+=t_res;
 
349
  }
 
350
  return (int) ( (se-s) - (te-t) );
 
351
}
 
352
 
 
353
 
 
354
static int my_strcasecmp_ucs2(CHARSET_INFO *cs, const char *s, const char *t)
 
355
{
 
356
  size_t s_len= strlen(s);
 
357
  size_t t_len= strlen(t);
 
358
  size_t len = (s_len > t_len) ? s_len : t_len;
 
359
  return my_strncasecmp_ucs2(cs, s, t, len);
 
360
}
 
361
 
 
362
 
 
363
static size_t my_strnxfrm_ucs2(CHARSET_INFO *cs, 
 
364
                               uchar *dst, size_t dstlen, const uchar *src,
 
365
                               size_t srclen)
 
366
{
 
367
  my_wc_t wc;
 
368
  int res;
 
369
  int plane;
 
370
  uchar *de = dst + dstlen;
 
371
  const uchar *se = src + srclen;
 
372
  MY_UNICASE_INFO **uni_plane= cs->caseinfo;
 
373
 
 
374
  while( src < se && dst < de )
 
375
  {
 
376
    if ((res=my_ucs2_uni(cs,&wc, src, se))<0)
 
377
    {
 
378
      break;
 
379
    }
 
380
    src+=res;
 
381
    srclen-=res;
 
382
    
 
383
    plane=(wc>>8) & 0xFF;
 
384
    wc = uni_plane[plane] ? uni_plane[plane][wc & 0xFF].sort : wc;
 
385
    
 
386
    if ((res=my_uni_ucs2(cs,wc,dst,de)) <0)
 
387
    {
 
388
      break;
 
389
    }
 
390
    dst+=res;
 
391
  }
 
392
  if (dst < de)
 
393
    cs->cset->fill(cs, (char*) dst, (size_t) (de - dst), ' ');
 
394
  return dstlen;
 
395
}
 
396
 
 
397
 
 
398
static uint my_ismbchar_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
399
                             const char *b __attribute__((unused)),
 
400
                             const char *e __attribute__((unused)))
 
401
{
 
402
  return 2;
 
403
}
 
404
 
 
405
 
 
406
static uint my_mbcharlen_ucs2(CHARSET_INFO *cs  __attribute__((unused)) , 
 
407
                              uint c __attribute__((unused)))
 
408
{
 
409
  return 2;
 
410
}
 
411
 
 
412
 
 
413
static int my_vsnprintf_ucs2(char *dst, size_t n, const char* fmt, va_list ap)
 
414
{
 
415
  char *start=dst, *end=dst+n-1;
 
416
  for (; *fmt ; fmt++)
 
417
  {
 
418
    if (fmt[0] != '%')
 
419
    {
 
420
      if (dst == end)                   /* End of buffer */
 
421
        break;
 
422
      
 
423
      *dst++='\0'; *dst++= *fmt;        /* Copy ordinary char */
 
424
      continue;
 
425
    }
 
426
    
 
427
    fmt++;
 
428
    
 
429
    /* Skip if max size is used (to be compatible with printf) */
 
430
    while ( (*fmt>='0' && *fmt<='9') || *fmt == '.' || *fmt == '-')
 
431
      fmt++;
 
432
    
 
433
    if (*fmt == 'l')
 
434
      fmt++;
 
435
    
 
436
    if (*fmt == 's')                            /* String parameter */
 
437
    {
 
438
      reg2 char *par = va_arg(ap, char *);
 
439
      size_t plen;
 
440
      size_t left_len = (size_t)(end-dst);
 
441
      if (!par) par = (char*)"(null)";
 
442
      plen= strlen(par);
 
443
      if (left_len <= plen*2)
 
444
        plen = left_len/2 - 1;
 
445
 
 
446
      for ( ; plen ; plen--, dst+=2, par++)
 
447
      {
 
448
        dst[0]='\0';
 
449
        dst[1]=par[0];
 
450
      }
 
451
      continue;
 
452
    }
 
453
    else if (*fmt == 'd' || *fmt == 'u')        /* Integer parameter */
 
454
    {
 
455
      register int iarg;
 
456
      char nbuf[16];
 
457
      char *pbuf=nbuf;
 
458
      
 
459
      if ((size_t) (end-dst) < 32)
 
460
        break;
 
461
      iarg = va_arg(ap, int);
 
462
      if (*fmt == 'd')
 
463
        int10_to_str((long) iarg, nbuf, -10);
 
464
      else
 
465
        int10_to_str((long) (uint) iarg,nbuf,10);
 
466
 
 
467
      for (; pbuf[0]; pbuf++)
 
468
      {
 
469
        *dst++='\0';
 
470
        *dst++=*pbuf;
 
471
      }
 
472
      continue;
 
473
    }
 
474
    
 
475
    /* We come here on '%%', unknown code or too long parameter */
 
476
    if (dst == end)
 
477
      break;
 
478
    *dst++='\0';
 
479
    *dst++='%';                         /* % used as % or unknown code */
 
480
  }
 
481
  
 
482
  DBUG_ASSERT(dst <= end);
 
483
  *dst='\0';                            /* End of errmessage */
 
484
  return (size_t) (dst - start);
 
485
}
 
486
 
 
487
static size_t my_snprintf_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
488
                               char* to, size_t n, const char* fmt, ...)
 
489
{
 
490
  va_list args;
 
491
  va_start(args,fmt);
 
492
  return my_vsnprintf_ucs2(to, n, fmt, args);
 
493
}
 
494
 
 
495
 
 
496
long my_strntol_ucs2(CHARSET_INFO *cs,
 
497
                     const char *nptr, size_t l, int base,
 
498
                     char **endptr, int *err)
 
499
{
 
500
  int      negative=0;
 
501
  int      overflow;
 
502
  int      cnv;
 
503
  my_wc_t  wc;
 
504
  register unsigned int cutlim;
 
505
  register uint32 cutoff;
 
506
  register uint32 res;
 
507
  register const uchar *s= (const uchar*) nptr;
 
508
  register const uchar *e= (const uchar*) nptr+l;
 
509
  const uchar *save;
 
510
  
 
511
  *err= 0;
 
512
  do
 
513
  {
 
514
    if ((cnv=cs->cset->mb_wc(cs,&wc,s,e))>0)
 
515
    {
 
516
      switch (wc)
 
517
      {
 
518
        case ' ' : break;
 
519
        case '\t': break;
 
520
        case '-' : negative= !negative; break;
 
521
        case '+' : break;
 
522
        default  : goto bs;
 
523
      }
 
524
    } 
 
525
    else /* No more characters or bad multibyte sequence */
 
526
    {
 
527
      if (endptr !=NULL )
 
528
        *endptr = (char*)s;
 
529
      err[0] = (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM;
 
530
      return 0;
 
531
    } 
 
532
    s+=cnv;
 
533
  } while (1);
 
534
  
 
535
bs:
 
536
 
 
537
#ifdef NOT_USED  
 
538
  if (base <= 0 || base == 1 || base > 36)
 
539
    base = 10;
 
540
#endif
 
541
  
 
542
  overflow = 0;
 
543
  res = 0;
 
544
  save = s;
 
545
  cutoff = ((uint32)~0L) / (uint32) base;
 
546
  cutlim = (uint) (((uint32)~0L) % (uint32) base);
 
547
  
 
548
  do {
 
549
    if ((cnv=cs->cset->mb_wc(cs,&wc,s,e))>0)
 
550
    {
 
551
      s+=cnv;
 
552
      if ( wc>='0' && wc<='9')
 
553
        wc -= '0';
 
554
      else if ( wc>='A' && wc<='Z')
 
555
        wc = wc - 'A' + 10;
 
556
      else if ( wc>='a' && wc<='z')
 
557
        wc = wc - 'a' + 10;
 
558
      else
 
559
        break;
 
560
      if ((int)wc >= base)
 
561
        break;
 
562
      if (res > cutoff || (res == cutoff && wc > cutlim))
 
563
        overflow = 1;
 
564
      else
 
565
      {
 
566
        res *= (uint32) base;
 
567
        res += wc;
 
568
      }
 
569
    }
 
570
    else if (cnv==MY_CS_ILSEQ)
 
571
    {
 
572
      if (endptr !=NULL )
 
573
        *endptr = (char*)s;
 
574
      err[0]=EILSEQ;
 
575
      return 0;
 
576
    } 
 
577
    else
 
578
    {
 
579
      /* No more characters */
 
580
      break;
 
581
    }
 
582
  } while(1);
 
583
  
 
584
  if (endptr != NULL)
 
585
    *endptr = (char *) s;
 
586
  
 
587
  if (s == save)
 
588
  {
 
589
    err[0]=EDOM;
 
590
    return 0L;
 
591
  }
 
592
  
 
593
  if (negative)
 
594
  {
 
595
    if (res > (uint32) INT_MIN32)
 
596
      overflow = 1;
 
597
  }
 
598
  else if (res > INT_MAX32)
 
599
    overflow = 1;
 
600
  
 
601
  if (overflow)
 
602
  {
 
603
    err[0]=ERANGE;
 
604
    return negative ? INT_MIN32 : INT_MAX32;
 
605
  }
 
606
  
 
607
  return (negative ? -((long) res) : (long) res);
 
608
}
 
609
 
 
610
 
 
611
ulong my_strntoul_ucs2(CHARSET_INFO *cs,
 
612
                       const char *nptr, size_t l, int base, 
 
613
                       char **endptr, int *err)
 
614
{
 
615
  int      negative=0;
 
616
  int      overflow;
 
617
  int      cnv;
 
618
  my_wc_t  wc;
 
619
  register unsigned int cutlim;
 
620
  register uint32 cutoff;
 
621
  register uint32 res;
 
622
  register const uchar *s= (const uchar*) nptr;
 
623
  register const uchar *e= (const uchar*) nptr+l;
 
624
  const uchar *save;
 
625
  
 
626
  *err= 0;
 
627
  do
 
628
  {
 
629
    if ((cnv=cs->cset->mb_wc(cs,&wc,s,e))>0)
 
630
    {
 
631
      switch (wc)
 
632
      {
 
633
        case ' ' : break;
 
634
        case '\t': break;
 
635
        case '-' : negative= !negative; break;
 
636
        case '+' : break;
 
637
        default  : goto bs;
 
638
      }
 
639
    } 
 
640
    else /* No more characters or bad multibyte sequence */
 
641
    {
 
642
      if (endptr !=NULL )
 
643
        *endptr = (char*)s;
 
644
      err[0] = (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM;
 
645
      return 0;
 
646
    } 
 
647
    s+=cnv;
 
648
  } while (1);
 
649
  
 
650
bs:
 
651
 
 
652
#ifdef NOT_USED
 
653
  if (base <= 0 || base == 1 || base > 36)
 
654
    base = 10;
 
655
#endif
 
656
 
 
657
  overflow = 0;
 
658
  res = 0;
 
659
  save = s;
 
660
  cutoff = ((uint32)~0L) / (uint32) base;
 
661
  cutlim = (uint) (((uint32)~0L) % (uint32) base);
 
662
  
 
663
  do
 
664
  {
 
665
    if ((cnv=cs->cset->mb_wc(cs,&wc,s,e))>0)
 
666
    {
 
667
      s+=cnv;
 
668
      if ( wc>='0' && wc<='9')
 
669
        wc -= '0';
 
670
      else if ( wc>='A' && wc<='Z')
 
671
        wc = wc - 'A' + 10;
 
672
      else if ( wc>='a' && wc<='z')
 
673
        wc = wc - 'a' + 10;
 
674
      else
 
675
        break;
 
676
      if ((int)wc >= base)
 
677
        break;
 
678
      if (res > cutoff || (res == cutoff && wc > cutlim))
 
679
        overflow = 1;
 
680
      else
 
681
      {
 
682
        res *= (uint32) base;
 
683
        res += wc;
 
684
      }
 
685
    }
 
686
    else if (cnv==MY_CS_ILSEQ)
 
687
    {
 
688
      if (endptr !=NULL )
 
689
        *endptr = (char*)s;
 
690
      err[0]=EILSEQ;
 
691
      return 0;
 
692
    } 
 
693
    else
 
694
    {
 
695
      /* No more characters */
 
696
      break;
 
697
    }
 
698
  } while(1);
 
699
  
 
700
  if (endptr != NULL)
 
701
    *endptr = (char *) s;
 
702
  
 
703
  if (s == save)
 
704
  {
 
705
    err[0]=EDOM;
 
706
    return 0L;
 
707
  }
 
708
  
 
709
  if (overflow)
 
710
  {
 
711
    err[0]=(ERANGE);
 
712
    return (~(uint32) 0);
 
713
  }
 
714
  
 
715
  return (negative ? -((long) res) : (long) res);
 
716
}
 
717
 
 
718
 
 
719
 
 
720
longlong  my_strntoll_ucs2(CHARSET_INFO *cs,
 
721
                           const char *nptr, size_t l, int base,
 
722
                           char **endptr, int *err)
 
723
{
 
724
  int      negative=0;
 
725
  int      overflow;
 
726
  int      cnv;
 
727
  my_wc_t  wc;
 
728
  register ulonglong    cutoff;
 
729
  register unsigned int cutlim;
 
730
  register ulonglong    res;
 
731
  register const uchar *s= (const uchar*) nptr;
 
732
  register const uchar *e= (const uchar*) nptr+l;
 
733
  const uchar *save;
 
734
  
 
735
  *err= 0;
 
736
  do
 
737
  {
 
738
    if ((cnv=cs->cset->mb_wc(cs,&wc,s,e))>0)
 
739
    {
 
740
      switch (wc)
 
741
      {
 
742
        case ' ' : break;
 
743
        case '\t': break;
 
744
        case '-' : negative= !negative; break;
 
745
        case '+' : break;
 
746
        default  : goto bs;
 
747
      }
 
748
    } 
 
749
    else /* No more characters or bad multibyte sequence */
 
750
    {
 
751
      if (endptr !=NULL )
 
752
        *endptr = (char*)s;
 
753
      err[0] = (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM;
 
754
      return 0;
 
755
    } 
 
756
    s+=cnv;
 
757
  } while (1);
 
758
  
 
759
bs:
 
760
 
 
761
#ifdef NOT_USED  
 
762
  if (base <= 0 || base == 1 || base > 36)
 
763
    base = 10;
 
764
#endif
 
765
 
 
766
  overflow = 0;
 
767
  res = 0;
 
768
  save = s;
 
769
  cutoff = (~(ulonglong) 0) / (unsigned long int) base;
 
770
  cutlim = (uint) ((~(ulonglong) 0) % (unsigned long int) base);
 
771
 
 
772
  do {
 
773
    if ((cnv=cs->cset->mb_wc(cs,&wc,s,e))>0)
 
774
    {
 
775
      s+=cnv;
 
776
      if ( wc>='0' && wc<='9')
 
777
        wc -= '0';
 
778
      else if ( wc>='A' && wc<='Z')
 
779
        wc = wc - 'A' + 10;
 
780
      else if ( wc>='a' && wc<='z')
 
781
        wc = wc - 'a' + 10;
 
782
      else
 
783
        break;
 
784
      if ((int)wc >= base)
 
785
        break;
 
786
      if (res > cutoff || (res == cutoff && wc > cutlim))
 
787
        overflow = 1;
 
788
      else
 
789
      {
 
790
        res *= (ulonglong) base;
 
791
        res += wc;
 
792
      }
 
793
    }
 
794
    else if (cnv==MY_CS_ILSEQ)
 
795
    {
 
796
      if (endptr !=NULL )
 
797
        *endptr = (char*)s;
 
798
      err[0]=EILSEQ;
 
799
      return 0;
 
800
    } 
 
801
    else
 
802
    {
 
803
      /* No more characters */
 
804
      break;
 
805
    }
 
806
  } while(1);
 
807
  
 
808
  if (endptr != NULL)
 
809
    *endptr = (char *) s;
 
810
  
 
811
  if (s == save)
 
812
  {
 
813
    err[0]=EDOM;
 
814
    return 0L;
 
815
  }
 
816
  
 
817
  if (negative)
 
818
  {
 
819
    if (res  > (ulonglong) LONGLONG_MIN)
 
820
      overflow = 1;
 
821
  }
 
822
  else if (res > (ulonglong) LONGLONG_MAX)
 
823
    overflow = 1;
 
824
  
 
825
  if (overflow)
 
826
  {
 
827
    err[0]=ERANGE;
 
828
    return negative ? LONGLONG_MIN : LONGLONG_MAX;
 
829
  }
 
830
  
 
831
  return (negative ? -((longlong)res) : (longlong)res);
 
832
}
 
833
 
 
834
 
 
835
 
 
836
 
 
837
ulonglong  my_strntoull_ucs2(CHARSET_INFO *cs,
 
838
                           const char *nptr, size_t l, int base,
 
839
                           char **endptr, int *err)
 
840
{
 
841
  int      negative=0;
 
842
  int      overflow;
 
843
  int      cnv;
 
844
  my_wc_t  wc;
 
845
  register ulonglong    cutoff;
 
846
  register unsigned int cutlim;
 
847
  register ulonglong    res;
 
848
  register const uchar *s= (const uchar*) nptr;
 
849
  register const uchar *e= (const uchar*) nptr+l;
 
850
  const uchar *save;
 
851
  
 
852
  *err= 0;
 
853
  do
 
854
  {
 
855
    if ((cnv=cs->cset->mb_wc(cs,&wc,s,e))>0)
 
856
    {
 
857
      switch (wc)
 
858
      {
 
859
        case ' ' : break;
 
860
        case '\t': break;
 
861
        case '-' : negative= !negative; break;
 
862
        case '+' : break;
 
863
        default  : goto bs;
 
864
      }
 
865
    } 
 
866
    else /* No more characters or bad multibyte sequence */
 
867
    {
 
868
      if (endptr !=NULL )
 
869
        *endptr = (char*)s;
 
870
      err[0]= (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM;
 
871
      return 0;
 
872
    } 
 
873
    s+=cnv;
 
874
  } while (1);
 
875
  
 
876
bs:
 
877
  
 
878
#ifdef NOT_USED
 
879
  if (base <= 0 || base == 1 || base > 36)
 
880
    base = 10;
 
881
#endif
 
882
 
 
883
  overflow = 0;
 
884
  res = 0;
 
885
  save = s;
 
886
  cutoff = (~(ulonglong) 0) / (unsigned long int) base;
 
887
  cutlim = (uint) ((~(ulonglong) 0) % (unsigned long int) base);
 
888
 
 
889
  do
 
890
  {
 
891
    if ((cnv=cs->cset->mb_wc(cs,&wc,s,e))>0)
 
892
    {
 
893
      s+=cnv;
 
894
      if ( wc>='0' && wc<='9')
 
895
        wc -= '0';
 
896
      else if ( wc>='A' && wc<='Z')
 
897
        wc = wc - 'A' + 10;
 
898
      else if ( wc>='a' && wc<='z')
 
899
        wc = wc - 'a' + 10;
 
900
      else
 
901
        break;
 
902
      if ((int)wc >= base)
 
903
        break;
 
904
      if (res > cutoff || (res == cutoff && wc > cutlim))
 
905
        overflow = 1;
 
906
      else
 
907
      {
 
908
        res *= (ulonglong) base;
 
909
        res += wc;
 
910
      }
 
911
    }
 
912
    else if (cnv==MY_CS_ILSEQ)
 
913
    {
 
914
      if (endptr !=NULL )
 
915
        *endptr = (char*)s;
 
916
      err[0]= EILSEQ;
 
917
      return 0;
 
918
    } 
 
919
    else
 
920
    {
 
921
      /* No more characters */
 
922
      break;
 
923
    }
 
924
  } while(1);
 
925
  
 
926
  if (endptr != NULL)
 
927
    *endptr = (char *) s;
 
928
  
 
929
  if (s == save)
 
930
  {
 
931
    err[0]= EDOM;
 
932
    return 0L;
 
933
  }
 
934
  
 
935
  if (overflow)
 
936
  {
 
937
    err[0]= ERANGE;
 
938
    return (~(ulonglong) 0);
 
939
  }
 
940
 
 
941
  return (negative ? -((longlong) res) : (longlong) res);
 
942
}
 
943
 
 
944
 
 
945
double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
946
                       char *nptr, size_t length, 
 
947
                       char **endptr, int *err)
 
948
{
 
949
  char     buf[256];
 
950
  double   res;
 
951
  register char *b=buf;
 
952
  register const uchar *s= (const uchar*) nptr;
 
953
  const uchar *end;
 
954
  my_wc_t  wc;
 
955
  int      cnv;
 
956
 
 
957
  *err= 0;
 
958
  /* Cut too long strings */
 
959
  if (length >= sizeof(buf))
 
960
    length= sizeof(buf)-1;
 
961
  end= s+length;
 
962
 
 
963
  while ((cnv=cs->cset->mb_wc(cs,&wc,s,end)) > 0)
 
964
  {
 
965
    s+=cnv;
 
966
    if (wc > (int) (uchar) 'e' || !wc)
 
967
      break;                                    /* Can't be part of double */
 
968
    *b++= (char) wc;
 
969
  }
 
970
 
 
971
  *endptr= b;
 
972
  res= my_strtod(buf, endptr, err);
 
973
  *endptr= nptr + (size_t) (*endptr- buf);
 
974
  return res;
 
975
}
 
976
 
 
977
 
 
978
ulonglong my_strntoull10rnd_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
979
                                 const char *nptr, size_t length,
 
980
                                 int unsign_fl,
 
981
                                 char **endptr, int *err)
 
982
{
 
983
  char     buf[256], *b= buf;
 
984
  ulonglong res;
 
985
  const uchar *end, *s= (const uchar*) nptr;
 
986
  my_wc_t  wc;
 
987
  int      cnv;
 
988
 
 
989
  /* Cut too long strings */
 
990
  if (length >= sizeof(buf))
 
991
    length= sizeof(buf)-1;
 
992
  end= s + length;
 
993
 
 
994
  while ((cnv= cs->cset->mb_wc(cs,&wc,s,end)) > 0)
 
995
  {
 
996
    s+= cnv;
 
997
    if (wc > (int) (uchar) 'e' || !wc)
 
998
      break;                            /* Can't be a number part */
 
999
    *b++= (char) wc;
 
1000
  }
 
1001
 
 
1002
  res= my_strntoull10rnd_8bit(cs, buf, b - buf, unsign_fl, endptr, err);
 
1003
  *endptr= (char*) nptr + 2 * (size_t) (*endptr- buf);
 
1004
  return res;
 
1005
}
 
1006
 
 
1007
 
 
1008
/*
 
1009
  This is a fast version optimized for the case of radix 10 / -10
 
1010
*/
 
1011
 
 
1012
size_t my_l10tostr_ucs2(CHARSET_INFO *cs,
 
1013
                        char *dst, size_t len, int radix, long int val)
 
1014
{
 
1015
  char buffer[66];
 
1016
  register char *p, *db, *de;
 
1017
  long int new_val;
 
1018
  int  sl=0;
 
1019
  unsigned long int uval = (unsigned long int) val;
 
1020
  
 
1021
  p = &buffer[sizeof(buffer)-1];
 
1022
  *p='\0';
 
1023
  
 
1024
  if (radix < 0)
 
1025
  {
 
1026
    if (val < 0)
 
1027
    {
 
1028
      sl   = 1;
 
1029
      /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */
 
1030
      uval  = (unsigned long int)0 - uval;
 
1031
    }
 
1032
  }
 
1033
  
 
1034
  new_val = (long) (uval / 10);
 
1035
  *--p    = '0'+ (char) (uval - (unsigned long) new_val * 10);
 
1036
  val     = new_val;
 
1037
  
 
1038
  while (val != 0)
 
1039
  {
 
1040
    new_val=val/10;
 
1041
    *--p = '0' + (char) (val-new_val*10);
 
1042
    val= new_val;
 
1043
  }
 
1044
  
 
1045
  if (sl)
 
1046
  {
 
1047
    *--p='-';
 
1048
  }
 
1049
  
 
1050
  for ( db=dst, de=dst+len ; (dst<de) && *p ; p++)
 
1051
  {
 
1052
    int cnvres=cs->cset->wc_mb(cs,(my_wc_t)p[0],(uchar*) dst, (uchar*) de);
 
1053
    if (cnvres>0)
 
1054
      dst+=cnvres;
 
1055
    else
 
1056
      break;
 
1057
  }
 
1058
  return (int) (dst-db);
 
1059
}
 
1060
 
 
1061
 
 
1062
size_t my_ll10tostr_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
1063
                         char *dst, size_t len, int radix, longlong val)
 
1064
{
 
1065
  char buffer[65];
 
1066
  register char *p, *db, *de;
 
1067
  long long_val;
 
1068
  int  sl=0;
 
1069
  ulonglong uval= (ulonglong) val;
 
1070
  
 
1071
  if (radix < 0)
 
1072
  {
 
1073
    if (val < 0)
 
1074
    {
 
1075
      sl=1;
 
1076
      /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */
 
1077
      uval = (ulonglong)0 - uval;
 
1078
    }
 
1079
  }
 
1080
  
 
1081
  p = &buffer[sizeof(buffer)-1];
 
1082
  *p='\0';
 
1083
  
 
1084
  if (uval == 0)
 
1085
  {
 
1086
    *--p='0';
 
1087
    goto cnv;
 
1088
  }
 
1089
  
 
1090
  while (uval > (ulonglong) LONG_MAX)
 
1091
  {
 
1092
    ulonglong quo= uval/(uint) 10;
 
1093
    uint rem= (uint) (uval- quo* (uint) 10);
 
1094
    *--p = '0' + rem;
 
1095
    uval= quo;
 
1096
  }
 
1097
  
 
1098
  long_val= (long) uval;
 
1099
  while (long_val != 0)
 
1100
  {
 
1101
    long quo= long_val/10;
 
1102
    *--p = (char) ('0' + (long_val - quo*10));
 
1103
    long_val= quo;
 
1104
  }
 
1105
  
 
1106
cnv:
 
1107
  if (sl)
 
1108
  {
 
1109
    *--p='-';
 
1110
  }
 
1111
  
 
1112
  for ( db=dst, de=dst+len ; (dst<de) && *p ; p++)
 
1113
  {
 
1114
    int cnvres=cs->cset->wc_mb(cs, (my_wc_t) p[0], (uchar*) dst, (uchar*) de);
 
1115
    if (cnvres>0)
 
1116
      dst+=cnvres;
 
1117
    else
 
1118
      break;
 
1119
  }
 
1120
  return (int) (dst-db);
 
1121
}
 
1122
 
 
1123
 
 
1124
#undef  ULONGLONG_MAX
 
1125
#define ULONGLONG_MAX           (~(ulonglong) 0)
 
1126
#define MAX_NEGATIVE_NUMBER     ((ulonglong) LL(0x8000000000000000))
 
1127
#define INIT_CNT  9
 
1128
#define LFACTOR   ULL(1000000000)
 
1129
#define LFACTOR1  ULL(10000000000)
 
1130
#define LFACTOR2  ULL(100000000000)
 
1131
 
 
1132
static unsigned long lfactor[9]=
 
1133
{
 
1134
  1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L
 
1135
};
 
1136
 
 
1137
 
 
1138
longlong my_strtoll10_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
1139
                           const char *nptr, char **endptr, int *error)
 
1140
{
 
1141
  const char *s, *end, *start, *n_end, *true_end;
 
1142
  uchar c;
 
1143
  unsigned long i, j, k;
 
1144
  ulonglong li;
 
1145
  int negative;
 
1146
  ulong cutoff, cutoff2, cutoff3;
 
1147
 
 
1148
  s= nptr;
 
1149
  /* If fixed length string */
 
1150
  if (endptr)
 
1151
  {
 
1152
    /* Make sure string length is even */
 
1153
    end= s + ((*endptr - s) / 2) * 2;
 
1154
    while (s < end && !s[0] && (s[1] == ' ' || s[1] == '\t'))
 
1155
      s+= 2;
 
1156
    if (s == end)
 
1157
      goto no_conv;
 
1158
  }
 
1159
  else
 
1160
  {
 
1161
     /* We don't support null terminated strings in UCS2 */
 
1162
     goto no_conv;
 
1163
  }
 
1164
 
 
1165
  /* Check for a sign.  */
 
1166
  negative= 0;
 
1167
  if (!s[0] && s[1] == '-')
 
1168
  {
 
1169
    *error= -1;                                 /* Mark as negative number */
 
1170
    negative= 1;
 
1171
    s+= 2;
 
1172
    if (s == end)
 
1173
      goto no_conv;
 
1174
    cutoff=  MAX_NEGATIVE_NUMBER / LFACTOR2;
 
1175
    cutoff2= (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100;
 
1176
    cutoff3=  MAX_NEGATIVE_NUMBER % 100;
 
1177
  }
 
1178
  else
 
1179
  {
 
1180
    *error= 0;
 
1181
    if (!s[0] && s[1] == '+')
 
1182
    {
 
1183
      s+= 2;
 
1184
      if (s == end)
 
1185
        goto no_conv;
 
1186
    }
 
1187
    cutoff=  ULONGLONG_MAX / LFACTOR2;
 
1188
    cutoff2= ULONGLONG_MAX % LFACTOR2 / 100;
 
1189
    cutoff3=  ULONGLONG_MAX % 100;
 
1190
  }
 
1191
 
 
1192
  /* Handle case where we have a lot of pre-zero */
 
1193
  if (!s[0] && s[1] == '0')
 
1194
  {
 
1195
    i= 0;
 
1196
    do
 
1197
    {
 
1198
      s+= 2;
 
1199
      if (s == end)
 
1200
        goto end_i;                             /* Return 0 */
 
1201
    }
 
1202
    while (!s[0] && s[1] == '0');
 
1203
    n_end= s + 2 * INIT_CNT;
 
1204
  }
 
1205
  else
 
1206
  {
 
1207
    /* Read first digit to check that it's a valid number */
 
1208
    if (s[0] || (c= (s[1]-'0')) > 9)
 
1209
      goto no_conv;
 
1210
    i= c;
 
1211
    s+= 2;
 
1212
    n_end= s + 2 * (INIT_CNT-1);
 
1213
  }
 
1214
 
 
1215
  /* Handle first 9 digits and store them in i */
 
1216
  if (n_end > end)
 
1217
    n_end= end;
 
1218
  for (; s != n_end ; s+= 2)
 
1219
  {
 
1220
    if (s[0] || (c= (s[1]-'0')) > 9)
 
1221
      goto end_i;
 
1222
    i= i*10+c;
 
1223
  }
 
1224
  if (s == end)
 
1225
    goto end_i;
 
1226
 
 
1227
  /* Handle next 9 digits and store them in j */
 
1228
  j= 0;
 
1229
  start= s;                             /* Used to know how much to shift i */
 
1230
  n_end= true_end= s + 2 * INIT_CNT;
 
1231
  if (n_end > end)
 
1232
    n_end= end;
 
1233
  do
 
1234
  {
 
1235
    if (s[0] || (c= (s[1]-'0')) > 9)
 
1236
      goto end_i_and_j;
 
1237
    j= j*10+c;
 
1238
    s+= 2;
 
1239
  } while (s != n_end);
 
1240
  if (s == end)
 
1241
  {
 
1242
    if (s != true_end)
 
1243
      goto end_i_and_j;
 
1244
    goto end3;
 
1245
  }
 
1246
  if (s[0] || (c= (s[1]-'0')) > 9)
 
1247
    goto end3;
 
1248
 
 
1249
  /* Handle the next 1 or 2 digits and store them in k */
 
1250
  k=c;
 
1251
  s+= 2;
 
1252
  if (s == end || s[0] || (c= (s[1]-'0')) > 9)
 
1253
    goto end4;
 
1254
  k= k*10+c;
 
1255
  s+= 2;
 
1256
  *endptr= (char*) s;
 
1257
 
 
1258
  /* number string should have ended here */
 
1259
  if (s != end && !s[0] && (c= (s[1]-'0')) <= 9)
 
1260
    goto overflow;
 
1261
 
 
1262
  /* Check that we didn't get an overflow with the last digit */
 
1263
  if (i > cutoff || (i == cutoff && ((j > cutoff2 || j == cutoff2) &&
 
1264
                                     k > cutoff3)))
 
1265
    goto overflow;
 
1266
  li=i*LFACTOR2+ (ulonglong) j*100 + k;
 
1267
  return (longlong) li;
 
1268
 
 
1269
overflow:                                       /* *endptr is set here */
 
1270
  *error= MY_ERRNO_ERANGE;
 
1271
  return negative ? LONGLONG_MIN : (longlong) ULONGLONG_MAX;
 
1272
 
 
1273
end_i:
 
1274
  *endptr= (char*) s;
 
1275
  return (negative ? ((longlong) -(long) i) : (longlong) i);
 
1276
 
 
1277
end_i_and_j:
 
1278
  li= (ulonglong) i * lfactor[(size_t) (s-start) / 2] + j;
 
1279
  *endptr= (char*) s;
 
1280
  return (negative ? -((longlong) li) : (longlong) li);
 
1281
 
 
1282
end3:
 
1283
  li=(ulonglong) i*LFACTOR+ (ulonglong) j;
 
1284
  *endptr= (char*) s;
 
1285
  return (negative ? -((longlong) li) : (longlong) li);
 
1286
 
 
1287
end4:
 
1288
  li=(ulonglong) i*LFACTOR1+ (ulonglong) j * 10 + k;
 
1289
  *endptr= (char*) s;
 
1290
  if (negative)
 
1291
  {
 
1292
   if (li > MAX_NEGATIVE_NUMBER)
 
1293
     goto overflow;
 
1294
   return -((longlong) li);
 
1295
  }
 
1296
  return (longlong) li;
 
1297
 
 
1298
no_conv:
 
1299
  /* There was no number to convert.  */
 
1300
  *error= MY_ERRNO_EDOM;
 
1301
  *endptr= (char *) nptr;
 
1302
  return 0;
 
1303
}
 
1304
 
 
1305
 
 
1306
static
 
1307
size_t my_numchars_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
1308
                        const char *b, const char *e)
 
1309
{
 
1310
  return (size_t) (e-b)/2;
 
1311
}
 
1312
 
 
1313
 
 
1314
static
 
1315
size_t my_charpos_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
1316
                       const char *b  __attribute__((unused)),
 
1317
                       const char *e  __attribute__((unused)),
 
1318
                       size_t pos)
 
1319
{
 
1320
  size_t string_length= (size_t) (e - b);
 
1321
  return pos > string_length ? string_length + 2 : pos * 2;
 
1322
}
 
1323
 
 
1324
 
 
1325
static
 
1326
size_t my_well_formed_len_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
1327
                               const char *b, const char *e,
 
1328
                               size_t nchars, int *error)
 
1329
{
 
1330
  /* Ensure string length is dividable with 2 */
 
1331
  size_t nbytes= ((size_t) (e-b)) & ~(size_t) 1;
 
1332
  *error= 0;
 
1333
  nchars*= 2;
 
1334
  return min(nbytes, nchars);
 
1335
}
 
1336
 
 
1337
 
 
1338
static
 
1339
void my_fill_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
1340
                   char *s, size_t l, int fill)
 
1341
{
 
1342
  for ( ; l >= 2; s[0]= 0, s[1]= fill, s+=2, l-=2);
 
1343
}
 
1344
 
 
1345
 
 
1346
static
 
1347
size_t my_lengthsp_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
1348
                      const char *ptr, size_t length)
 
1349
{
 
1350
  const char *end= ptr+length;
 
1351
  while (end > ptr+1 && end[-1] == ' ' && end[-2] == '\0')
 
1352
    end-=2;
 
1353
  return (size_t) (end-ptr);
 
1354
}
 
1355
 
 
1356
 
 
1357
static
 
1358
int my_wildcmp_ucs2_ci(CHARSET_INFO *cs,
 
1359
                    const char *str,const char *str_end,
 
1360
                    const char *wildstr,const char *wildend,
 
1361
                    int escape, int w_one, int w_many)
 
1362
{
 
1363
  MY_UNICASE_INFO **uni_plane= cs->caseinfo;
 
1364
  return my_wildcmp_unicode(cs,str,str_end,wildstr,wildend,
 
1365
                            escape,w_one,w_many,uni_plane); 
 
1366
}
 
1367
 
 
1368
 
 
1369
static
 
1370
int my_wildcmp_ucs2_bin(CHARSET_INFO *cs,
 
1371
                    const char *str,const char *str_end,
 
1372
                    const char *wildstr,const char *wildend,
 
1373
                    int escape, int w_one, int w_many)
 
1374
{
 
1375
  return my_wildcmp_unicode(cs,str,str_end,wildstr,wildend,
 
1376
                            escape,w_one,w_many,NULL); 
 
1377
}
 
1378
 
 
1379
 
 
1380
static
 
1381
int my_strnncoll_ucs2_bin(CHARSET_INFO *cs, 
 
1382
                          const uchar *s, size_t slen,
 
1383
                          const uchar *t, size_t tlen,
 
1384
                          my_bool t_is_prefix)
 
1385
{
 
1386
  int s_res,t_res;
 
1387
  my_wc_t UNINIT_VAR(s_wc),t_wc;
 
1388
  const uchar *se=s+slen;
 
1389
  const uchar *te=t+tlen;
 
1390
 
 
1391
  while ( s < se && t < te )
 
1392
  {
 
1393
    s_res=my_ucs2_uni(cs,&s_wc, s, se);
 
1394
    t_res=my_ucs2_uni(cs,&t_wc, t, te);
 
1395
    
 
1396
    if ( s_res <= 0 || t_res <= 0 )
 
1397
    {
 
1398
      /* Incorrect string, compare by char value */
 
1399
      return ((int)s[0]-(int)t[0]); 
 
1400
    }
 
1401
    if ( s_wc != t_wc )
 
1402
    {
 
1403
      return  s_wc > t_wc ? 1 : -1;
 
1404
    }
 
1405
    
 
1406
    s+=s_res;
 
1407
    t+=t_res;
 
1408
  }
 
1409
  return (int) (t_is_prefix ? t-te : ((se-s) - (te-t)));
 
1410
}
 
1411
 
 
1412
static int my_strnncollsp_ucs2_bin(CHARSET_INFO *cs __attribute__((unused)), 
 
1413
                                   const uchar *s, size_t slen, 
 
1414
                                   const uchar *t, size_t tlen,
 
1415
                                   my_bool diff_if_only_endspace_difference
 
1416
                                   __attribute__((unused)))
 
1417
{
 
1418
  const uchar *se, *te;
 
1419
  size_t minlen;
 
1420
 
 
1421
  /* extra safety to make sure the lengths are even numbers */
 
1422
  slen= (slen >> 1) << 1;
 
1423
  tlen= (tlen >> 1) << 1;
 
1424
 
 
1425
  se= s + slen;
 
1426
  te= t + tlen;
 
1427
 
 
1428
  for (minlen= min(slen, tlen); minlen; minlen-= 2)
 
1429
  {
 
1430
    int s_wc= s[0] * 256 + s[1];
 
1431
    int t_wc= t[0] * 256 + t[1];
 
1432
    if ( s_wc != t_wc )
 
1433
      return  s_wc > t_wc ? 1 : -1;
 
1434
 
 
1435
    s+= 2;
 
1436
    t+= 2;
 
1437
  }
 
1438
 
 
1439
  if (slen != tlen)
 
1440
  {
 
1441
    int swap= 1;
 
1442
    if (slen < tlen)
 
1443
    {
 
1444
      s= t;
 
1445
      se= te;
 
1446
      swap= -1;
 
1447
    }
 
1448
 
 
1449
    for ( ; s < se ; s+= 2)
 
1450
    {
 
1451
      if (s[0] || s[1] != ' ')
 
1452
        return (s[0] == 0 && s[1] < ' ') ? -swap : swap;
 
1453
    }
 
1454
  }
 
1455
  return 0;
 
1456
}
 
1457
 
 
1458
 
 
1459
static
 
1460
int my_strcasecmp_ucs2_bin(CHARSET_INFO *cs, const char *s, const char *t)
 
1461
{
 
1462
  size_t s_len= strlen(s);
 
1463
  size_t t_len= strlen(t);
 
1464
  size_t len = (s_len > t_len) ? s_len : t_len;
 
1465
  return  my_strncasecmp_ucs2(cs, s, t, len);
 
1466
}
 
1467
 
 
1468
 
 
1469
static
 
1470
size_t my_strnxfrm_ucs2_bin(CHARSET_INFO *cs __attribute__((unused)),
 
1471
                            uchar *dst, size_t dstlen,
 
1472
                            const uchar *src, size_t srclen)
 
1473
{
 
1474
  if (dst != src)
 
1475
    memcpy(dst,src,srclen= min(dstlen,srclen));
 
1476
  if (dstlen > srclen)
 
1477
    cs->cset->fill(cs, (char*) dst + srclen, dstlen - srclen, ' ');
 
1478
  return dstlen;
 
1479
}
 
1480
 
 
1481
 
 
1482
static
 
1483
void my_hash_sort_ucs2_bin(CHARSET_INFO *cs __attribute__((unused)),
 
1484
                           const uchar *key, size_t len,ulong *nr1, ulong *nr2)
 
1485
{
 
1486
  const uchar *pos = key;
 
1487
  
 
1488
  key+= len;
 
1489
 
 
1490
  while (key > pos+1 && key[-1] == ' ' && key[-2] == '\0')
 
1491
    key-= 2;
 
1492
 
 
1493
  for (; pos < (uchar*) key ; pos++)
 
1494
  {
 
1495
    nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) * 
 
1496
             ((uint)*pos)) + (nr1[0] << 8);
 
1497
    nr2[0]+=3;
 
1498
  }
 
1499
}
 
1500
 
 
1501
/*
 
1502
** Calculate min_str and max_str that ranges a LIKE string.
 
1503
** Arguments:
 
1504
** ptr          Pointer to LIKE string.
 
1505
** ptr_length   Length of LIKE string.
 
1506
** escape       Escape character in LIKE.  (Normally '\').
 
1507
**              All escape characters should be removed from min_str and max_str
 
1508
** res_length   Length of min_str and max_str.
 
1509
** min_str      Smallest case sensitive string that ranges LIKE.
 
1510
**              Should be space padded to res_length.
 
1511
** max_str      Largest case sensitive string that ranges LIKE.
 
1512
**              Normally padded with the biggest character sort value.
 
1513
**
 
1514
** The function should return 0 if ok and 1 if the LIKE string can't be
 
1515
** optimized !
 
1516
*/
 
1517
 
 
1518
my_bool my_like_range_ucs2(CHARSET_INFO *cs,
 
1519
                           const char *ptr, size_t ptr_length,
 
1520
                           pbool escape, pbool w_one, pbool w_many,
 
1521
                           size_t res_length,
 
1522
                           char *min_str,char *max_str,
 
1523
                           size_t *min_length,size_t *max_length)
 
1524
{
 
1525
  const char *end=ptr+ptr_length;
 
1526
  char *min_org=min_str;
 
1527
  char *min_end=min_str+res_length;
 
1528
  size_t charlen= res_length / cs->mbmaxlen;
 
1529
  const char *contraction_flags= cs->contractions ?
 
1530
             ((const char*) cs->contractions) + 0x40*0x40 : NULL;
 
1531
  
 
1532
  for ( ; ptr + 1 < end && min_str + 1 < min_end && charlen > 0
 
1533
        ; ptr+=2, charlen--)
 
1534
  {
 
1535
    if (ptr[0] == '\0' && ptr[1] == escape && ptr + 1 < end)
 
1536
    {
 
1537
      ptr+=2;                                   /* Skip escape */
 
1538
      *min_str++= *max_str++ = ptr[0];
 
1539
      *min_str++= *max_str++ = ptr[1];
 
1540
      continue;
 
1541
    }
 
1542
    if (ptr[0] == '\0' && ptr[1] == w_one)      /* '_' in SQL */
 
1543
    {
 
1544
      *min_str++= (char) (cs->min_sort_char >> 8);
 
1545
      *min_str++= (char) (cs->min_sort_char & 255);
 
1546
      *max_str++= (char) (cs->max_sort_char >> 8);
 
1547
      *max_str++= (char) (cs->max_sort_char & 255);
 
1548
      continue;
 
1549
    }
 
1550
    if (ptr[0] == '\0' && ptr[1] == w_many)     /* '%' in SQL */
 
1551
    {
 
1552
fill_max_and_min:
 
1553
      /*
 
1554
        Calculate length of keys:
 
1555
        'a\0\0... is the smallest possible string when we have space expand
 
1556
        a\ff\ff... is the biggest possible string
 
1557
      */
 
1558
      *min_length= ((cs->state & MY_CS_BINSORT) ? (size_t) (min_str - min_org) :
 
1559
                    res_length);
 
1560
      *max_length= res_length;
 
1561
      do {
 
1562
        *min_str++ = 0;
 
1563
        *min_str++ = 0;
 
1564
        *max_str++ = (char) (cs->max_sort_char >> 8);
 
1565
        *max_str++ = (char) (cs->max_sort_char & 255);
 
1566
      } while (min_str + 1 < min_end);
 
1567
      return 0;
 
1568
    }
 
1569
 
 
1570
    if (contraction_flags && ptr + 3 < end &&
 
1571
        ptr[0] == '\0' && contraction_flags[(uchar) ptr[1]])
 
1572
    {
 
1573
      /* Contraction head found */
 
1574
      if (ptr[2] == '\0' && (ptr[3] == w_one || ptr[3] == w_many))
 
1575
      {
 
1576
        /* Contraction head followed by a wildcard, quit */
 
1577
        goto fill_max_and_min;
 
1578
      }
 
1579
      
 
1580
      /*
 
1581
        Check if the second letter can be contraction part,
 
1582
        and if two letters really produce a contraction.
 
1583
      */
 
1584
      if (ptr[2] == '\0' && contraction_flags[(uchar) ptr[3]] &&
 
1585
          cs->contractions[(ptr[1]-0x40)*0x40 + ptr[3] - 0x40])
 
1586
      {
 
1587
        /* Contraction found */
 
1588
        if (charlen == 1 || min_str + 2 >= min_end)
 
1589
        {
 
1590
          /* Full contraction doesn't fit, quit */
 
1591
          goto fill_max_and_min;
 
1592
        }
 
1593
        
 
1594
        /* Put contraction head */
 
1595
        *min_str++= *max_str++= *ptr++;
 
1596
        *min_str++= *max_str++= *ptr++;
 
1597
        charlen--;
 
1598
      }
 
1599
    }
 
1600
    /* Put contraction tail, or a single character */
 
1601
    *min_str++= *max_str++ = ptr[0];
 
1602
    *min_str++= *max_str++ = ptr[1];
 
1603
  }
 
1604
 
 
1605
  *min_length= *max_length = (size_t) (min_str - min_org);
 
1606
  while (min_str + 1 < min_end)
 
1607
  {
 
1608
    *min_str++ = *max_str++ = '\0';
 
1609
    *min_str++ = *max_str++ = ' ';      /* Because if key compression */
 
1610
  }
 
1611
  return 0;
 
1612
}
 
1613
 
 
1614
 
 
1615
 
 
1616
size_t my_scan_ucs2(CHARSET_INFO *cs __attribute__((unused)),
 
1617
                    const char *str, const char *end, int sequence_type)
 
1618
{
 
1619
  const char *str0= str;
 
1620
  end--; /* for easier loop condition, because of two bytes per character */
 
1621
  
 
1622
  switch (sequence_type)
 
1623
  {
 
1624
  case MY_SEQ_SPACES:
 
1625
    for ( ; str < end; str+= 2)
 
1626
    {
 
1627
      if (str[0] != '\0' || str[1] != ' ')
 
1628
        break;
 
1629
    }
 
1630
    return (size_t) (str - str0);
 
1631
  default:
 
1632
    return 0;
 
1633
  }
 
1634
}
 
1635
 
 
1636
 
 
1637
 
 
1638
static MY_COLLATION_HANDLER my_collation_ucs2_general_ci_handler =
 
1639
{
 
1640
    NULL,               /* init */
 
1641
    my_strnncoll_ucs2,
 
1642
    my_strnncollsp_ucs2,
 
1643
    my_strnxfrm_ucs2,
 
1644
    my_strnxfrmlen_simple,
 
1645
    my_like_range_ucs2,
 
1646
    my_wildcmp_ucs2_ci,
 
1647
    my_strcasecmp_ucs2,
 
1648
    my_instr_mb,
 
1649
    my_hash_sort_ucs2,
 
1650
    my_propagate_simple
 
1651
};
 
1652
 
 
1653
 
 
1654
static MY_COLLATION_HANDLER my_collation_ucs2_bin_handler =
 
1655
{
 
1656
    NULL,               /* init */
 
1657
    my_strnncoll_ucs2_bin,
 
1658
    my_strnncollsp_ucs2_bin,
 
1659
    my_strnxfrm_ucs2_bin,
 
1660
    my_strnxfrmlen_simple,
 
1661
    my_like_range_ucs2,
 
1662
    my_wildcmp_ucs2_bin,
 
1663
    my_strcasecmp_ucs2_bin,
 
1664
    my_instr_mb,
 
1665
    my_hash_sort_ucs2_bin,
 
1666
    my_propagate_simple
 
1667
};
 
1668
 
 
1669
 
 
1670
MY_CHARSET_HANDLER my_charset_ucs2_handler=
 
1671
{
 
1672
    NULL,               /* init */
 
1673
    my_ismbchar_ucs2,   /* ismbchar     */
 
1674
    my_mbcharlen_ucs2,  /* mbcharlen    */
 
1675
    my_numchars_ucs2,
 
1676
    my_charpos_ucs2,
 
1677
    my_well_formed_len_ucs2,
 
1678
    my_lengthsp_ucs2,
 
1679
    my_numcells_mb,
 
1680
    my_ucs2_uni,        /* mb_wc        */
 
1681
    my_uni_ucs2,        /* wc_mb        */
 
1682
    my_mb_ctype_mb,
 
1683
    my_caseup_str_ucs2,
 
1684
    my_casedn_str_ucs2,
 
1685
    my_caseup_ucs2,
 
1686
    my_casedn_ucs2,
 
1687
    my_snprintf_ucs2,
 
1688
    my_l10tostr_ucs2,
 
1689
    my_ll10tostr_ucs2,
 
1690
    my_fill_ucs2,
 
1691
    my_strntol_ucs2,
 
1692
    my_strntoul_ucs2,
 
1693
    my_strntoll_ucs2,
 
1694
    my_strntoull_ucs2,
 
1695
    my_strntod_ucs2,
 
1696
    my_strtoll10_ucs2,
 
1697
    my_strntoull10rnd_ucs2,
 
1698
    my_scan_ucs2
 
1699
};
 
1700
 
 
1701
 
 
1702
CHARSET_INFO my_charset_ucs2_general_ci=
 
1703
{
 
1704
    35,0,0,             /* number       */
 
1705
    MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM|MY_CS_UNICODE,
 
1706
    "ucs2",             /* cs name    */
 
1707
    "ucs2_general_ci",  /* name         */
 
1708
    "",                 /* comment      */
 
1709
    NULL,               /* tailoring    */
 
1710
    ctype_ucs2,         /* ctype        */
 
1711
    to_lower_ucs2,      /* to_lower     */
 
1712
    to_upper_ucs2,      /* to_upper     */
 
1713
    to_upper_ucs2,      /* sort_order   */
 
1714
    NULL,               /* contractions */
 
1715
    NULL,               /* sort_order_big*/
 
1716
    NULL,               /* tab_to_uni   */
 
1717
    NULL,               /* tab_from_uni */
 
1718
    my_unicase_default, /* caseinfo     */
 
1719
    NULL,               /* state_map    */
 
1720
    NULL,               /* ident_map    */
 
1721
    1,                  /* strxfrm_multiply */
 
1722
    1,                  /* caseup_multiply  */
 
1723
    1,                  /* casedn_multiply  */
 
1724
    2,                  /* mbminlen     */
 
1725
    2,                  /* mbmaxlen     */
 
1726
    0,                  /* min_sort_char */
 
1727
    0xFFFF,             /* max_sort_char */
 
1728
    ' ',                /* pad char      */
 
1729
    0,                  /* escape_with_backslash_is_dangerous */
 
1730
    &my_charset_ucs2_handler,
 
1731
    &my_collation_ucs2_general_ci_handler
 
1732
};
 
1733
 
 
1734
CHARSET_INFO my_charset_ucs2_bin=
 
1735
{
 
1736
    90,0,0,             /* number       */
 
1737
    MY_CS_COMPILED|MY_CS_BINSORT|MY_CS_UNICODE,
 
1738
    "ucs2",             /* cs name    */
 
1739
    "ucs2_bin",         /* name         */
 
1740
    "",                 /* comment      */
 
1741
    NULL,               /* tailoring    */
 
1742
    ctype_ucs2,         /* ctype        */
 
1743
    to_lower_ucs2,      /* to_lower     */
 
1744
    to_upper_ucs2,      /* to_upper     */
 
1745
    NULL,               /* sort_order   */
 
1746
    NULL,               /* contractions */
 
1747
    NULL,               /* sort_order_big*/
 
1748
    NULL,               /* tab_to_uni   */
 
1749
    NULL,               /* tab_from_uni */
 
1750
    my_unicase_default, /* caseinfo     */
 
1751
    NULL,               /* state_map    */
 
1752
    NULL,               /* ident_map    */
 
1753
    1,                  /* strxfrm_multiply */
 
1754
    1,                  /* caseup_multiply  */
 
1755
    1,                  /* casedn_multiply  */
 
1756
    2,                  /* mbminlen     */
 
1757
    2,                  /* mbmaxlen     */
 
1758
    0,                  /* min_sort_char */
 
1759
    0xFFFF,             /* max_sort_char */
 
1760
    ' ',                /* pad char      */
 
1761
    0,                  /* escape_with_backslash_is_dangerous */
 
1762
    &my_charset_ucs2_handler,
 
1763
    &my_collation_ucs2_bin_handler
 
1764
};
 
1765
 
 
1766
 
 
1767
#endif