charset.c 16 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8
/* Copyright (C) 2000 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
unknown's avatar
unknown committed
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
unknown's avatar
unknown committed
10 11 12 13 14 15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
unknown's avatar
unknown committed
16 17 18 19 20 21

#include "mysys_priv.h"
#include "mysys_err.h"
#include <m_ctype.h>
#include <m_string.h>
#include <my_dir.h>
unknown's avatar
unknown committed
22
#include <my_xml.h>
unknown's avatar
unknown committed
23

unknown's avatar
unknown committed
24

unknown's avatar
unknown committed
25 26 27 28 29 30 31
/*

  The code below implements this functionality:
  
    - Initializing charset related structures
    - Loading dynamic charsets
    - Searching for a proper CHARSET_INFO 
32
      using charset name, collation name or collation ID
unknown's avatar
unknown committed
33 34 35
    - Setting server default character set
*/

unknown's avatar
unknown committed
36 37 38 39
my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2)
{
  return ((cs1 == cs2) || !strcmp(cs1->csname,cs2->csname));
}
unknown's avatar
unknown committed
40

41 42 43 44 45 46 47 48 49
static void set_max_sort_char(CHARSET_INFO *cs)
{
  uchar max_char;
  uint  i;
  
  if (!cs->sort_order)
    return;
  
  max_char=cs->sort_order[(uchar) cs->max_sort_char];
unknown's avatar
unknown committed
50
  for (i= 0; i < 256; i++)
51 52 53 54 55 56 57 58
  {
    if ((uchar) cs->sort_order[i] > max_char)
    {
      max_char=(uchar) cs->sort_order[i];
      cs->max_sort_char= (char) i;
    }
  }
}
unknown's avatar
unknown committed
59

unknown's avatar
unknown committed
60

61 62 63 64 65
static void init_state_maps(CHARSET_INFO *cs)
{
  uint i;
  uchar *state_map= cs->state_map;
  uchar *ident_map= cs->ident_map;
66

67 68 69 70 71 72 73 74
  /* Fill state_map with states to get a faster parser */
  for (i=0; i < 256 ; i++)
  {
    if (my_isalpha(cs,i))
      state_map[i]=(uchar) MY_LEX_IDENT;
    else if (my_isdigit(cs,i))
      state_map[i]=(uchar) MY_LEX_NUMBER_IDENT;
#if defined(USE_MB) && defined(USE_MB_IDENT)
75
    else if (use_mb(cs) && (my_mbcharlen(cs, i)>1))
76 77 78
      state_map[i]=(uchar) MY_LEX_IDENT;
#endif
    else if (!my_isgraph(cs,i))
79
      state_map[i]=(uchar) MY_LEX_SKIP;
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    else
      state_map[i]=(uchar) MY_LEX_CHAR;
  }
  state_map[(uchar)'_']=state_map[(uchar)'$']=(uchar) MY_LEX_IDENT;
  state_map[(uchar)'\'']=(uchar) MY_LEX_STRING;
  state_map[(uchar)'.']=(uchar) MY_LEX_REAL_OR_POINT;
  state_map[(uchar)'>']=state_map[(uchar)'=']=state_map[(uchar)'!']= (uchar) MY_LEX_CMP_OP;
  state_map[(uchar)'<']= (uchar) MY_LEX_LONG_CMP_OP;
  state_map[(uchar)'&']=state_map[(uchar)'|']=(uchar) MY_LEX_BOOL;
  state_map[(uchar)'#']=(uchar) MY_LEX_COMMENT;
  state_map[(uchar)';']=(uchar) MY_LEX_COLON;
  state_map[(uchar)':']=(uchar) MY_LEX_SET_VAR;
  state_map[0]=(uchar) MY_LEX_EOL;
  state_map[(uchar)'\\']= (uchar) MY_LEX_ESCAPE;
  state_map[(uchar)'/']= (uchar) MY_LEX_LONG_COMMENT;
  state_map[(uchar)'*']= (uchar) MY_LEX_END_LONG_COMMENT;
  state_map[(uchar)'@']= (uchar) MY_LEX_USER_END;
  state_map[(uchar) '`']= (uchar) MY_LEX_USER_VARIABLE_DELIMITER;
  state_map[(uchar)'"']= (uchar) MY_LEX_STRING_OR_DELIMITER;

  /*
    Create a second map to make it faster to find identifiers
  */
  for (i=0; i < 256 ; i++)
  {
    ident_map[i]= (uchar) (state_map[i] == MY_LEX_IDENT ||
			   state_map[i] == MY_LEX_NUMBER_IDENT);
  }

  /* Special handling of hex and binary strings */
  state_map[(uchar)'x']= state_map[(uchar)'X']= (uchar) MY_LEX_IDENT_OR_HEX;
  state_map[(uchar)'b']= state_map[(uchar)'b']= (uchar) MY_LEX_IDENT_OR_BIN;
unknown's avatar
unknown committed
112
  state_map[(uchar)'n']= state_map[(uchar)'N']= (uchar) MY_LEX_IDENT_OR_NCHAR;
113 114 115 116


}

117
static void simple_cs_init_functions(CHARSET_INFO *cs)
unknown's avatar
unknown committed
118
{
unknown's avatar
unknown committed
119
  
120 121
  if (cs->state & MY_CS_BINSORT)
  {
122
    cs->coll= &my_collation_bin_handler;
123 124 125
  }
  else
  {
126
    cs->coll= &my_collation_8bit_simple_ci_handler;
127 128
  }
  
129
  cs->cset= &my_charset_8bit_handler;
130
  cs->mbmaxlen    = 1;
unknown's avatar
unknown committed
131 132
}

unknown's avatar
unknown committed
133 134 135 136 137

typedef struct
{
  int		nchars;
  MY_UNI_IDX	uidx;
138 139 140 141 142 143 144 145
} uni_idx;

#define PLANE_SIZE	0x100
#define PLANE_NUM	0x100
#define PLANE_NUMBER(x)	(((x)>>8) % PLANE_NUM)

static int pcmp(const void * f, const void * s)
{
unknown's avatar
unknown committed
146 147
  const uni_idx *F= (const uni_idx*) f;
  const uni_idx *S= (const uni_idx*) s;
148 149
  int res;

unknown's avatar
unknown committed
150
  if (!(res=((S->nchars)-(F->nchars))))
151 152 153 154
    res=((F->uidx.from)-(S->uidx.to));
  return res;
}

unknown's avatar
unknown committed
155 156 157

static my_bool create_fromuni(CHARSET_INFO *cs)
{
158 159 160 161 162 163 164
  uni_idx	idx[PLANE_NUM];
  int		i,n;
  
  /* Clear plane statistics */
  bzero(idx,sizeof(idx));
  
  /* Count number of characters in each plane */
unknown's avatar
unknown committed
165
  for (i=0; i< 0x100; i++)
166 167 168 169
  {
    uint16 wc=cs->tab_to_uni[i];
    int pl= PLANE_NUMBER(wc);
    
unknown's avatar
unknown committed
170
    if (wc || !i)
171
    {
unknown's avatar
unknown committed
172
      if (!idx[pl].nchars)
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
      {
        idx[pl].uidx.from=wc;
        idx[pl].uidx.to=wc;
      }else
      {
        idx[pl].uidx.from=wc<idx[pl].uidx.from?wc:idx[pl].uidx.from;
        idx[pl].uidx.to=wc>idx[pl].uidx.to?wc:idx[pl].uidx.to;
      }
      idx[pl].nchars++;
    }
  }
  
  /* Sort planes in descending order */
  qsort(&idx,PLANE_NUM,sizeof(uni_idx),&pcmp);
  
unknown's avatar
unknown committed
188
  for (i=0; i < PLANE_NUM; i++)
189 190 191 192
  {
    int ch,numchars;
    
    /* Skip empty plane */
unknown's avatar
unknown committed
193
    if (!idx[i].nchars)
194 195 196
      break;
    
    numchars=idx[i].uidx.to-idx[i].uidx.from+1;
unknown's avatar
unknown committed
197 198 199
    idx[i].uidx.tab=(unsigned char*)my_once_alloc(numchars *
						  sizeof(*idx[i].uidx.tab),
						  MYF(MY_WME));
200 201
    bzero(idx[i].uidx.tab,numchars*sizeof(*idx[i].uidx.tab));
    
unknown's avatar
unknown committed
202
    for (ch=1; ch < PLANE_SIZE; ch++)
203 204
    {
      uint16 wc=cs->tab_to_uni[ch];
unknown's avatar
unknown committed
205
      if (wc >= idx[i].uidx.from && wc <= idx[i].uidx.to && wc)
206
      {
unknown's avatar
unknown committed
207 208
        int ofs= wc - idx[i].uidx.from;
        idx[i].uidx.tab[ofs]= ch;
209 210 211 212 213 214
      }
    }
  }
  
  /* Allocate and fill reverse table for each plane */
  n=i;
unknown's avatar
unknown committed
215 216 217 218
  cs->tab_from_uni= (MY_UNI_IDX*) my_once_alloc(sizeof(MY_UNI_IDX)*(n+1),
					       MYF(MY_WME));
  for (i=0; i< n; i++)
    cs->tab_from_uni[i]= idx[i].uidx;
219 220 221 222 223 224
  
  /* Set end-of-list marker */
  bzero(&cs->tab_from_uni[i],sizeof(MY_UNI_IDX));
  return FALSE;
}

unknown's avatar
unknown committed
225

226 227 228 229 230 231 232 233 234 235 236
static void simple_cs_copy_data(CHARSET_INFO *to, CHARSET_INFO *from)
{
  to->number= from->number ? from->number : to->number;
  to->state|= from->state;

  if (from->csname)
    to->csname= my_once_strdup(from->csname,MYF(MY_WME));
  
  if (from->name)
    to->name= my_once_strdup(from->name,MYF(MY_WME));
  
237 238 239
  if (from->comment)
    to->comment= my_once_strdup(from->comment,MYF(MY_WME));
  
240
  if (from->ctype)
241
  {
242
    to->ctype= (uchar*) my_once_memdup((char*) from->ctype,
243
				       MY_CS_CTYPE_TABLE_SIZE, MYF(MY_WME));
244 245
    init_state_maps(to);
  }
246 247
  if (from->to_lower)
    to->to_lower= (uchar*) my_once_memdup((char*) from->to_lower,
248
					  MY_CS_TO_LOWER_TABLE_SIZE, MYF(MY_WME));
249 250
  if (from->to_upper)
    to->to_upper= (uchar*) my_once_memdup((char*) from->to_upper,
251
					  MY_CS_TO_UPPER_TABLE_SIZE, MYF(MY_WME));
252 253 254
  if (from->sort_order)
  {
    to->sort_order= (uchar*) my_once_memdup((char*) from->sort_order,
255
					    MY_CS_SORT_ORDER_TABLE_SIZE,
256 257 258 259 260
					    MYF(MY_WME));
    set_max_sort_char(to);
  }
  if (from->tab_to_uni)
  {
261
    uint sz= MY_CS_TO_UNI_TABLE_SIZE*sizeof(uint16);
262 263 264 265
    to->tab_to_uni= (uint16*)  my_once_memdup((char*)from->tab_to_uni, sz,
					     MYF(MY_WME));
    create_fromuni(to);
  }
unknown's avatar
unknown committed
266
  to->mbmaxlen= 1;
267 268 269 270 271 272 273
}


static my_bool simple_cs_is_full(CHARSET_INFO *cs)
{
  return ((cs->csname && cs->tab_to_uni && cs->ctype && cs->to_upper &&
	   cs->to_lower) &&
274 275
	  (cs->number && cs->name &&
	  (cs->sort_order || (cs->state & MY_CS_BINSORT) )));
276 277 278 279 280
}


static int add_collation(CHARSET_INFO *cs)
{
281
  if (cs->name && (cs->number || (cs->number=get_collation_number(cs->name))))
282 283 284
  {
    if (!all_charsets[cs->number])
    {
285
      if (cs->state & MY_CS_COMPILED)
unknown's avatar
unknown committed
286
        goto clear;
287 288 289 290 291
      if (!(all_charsets[cs->number]=
         (CHARSET_INFO*) my_once_alloc(sizeof(CHARSET_INFO),MYF(0))))
        return MY_XML_ERROR;
      bzero((void*)all_charsets[cs->number],sizeof(CHARSET_INFO));
    }
292 293 294
    
    if (cs->primary_number == cs->number)
      cs->state |= MY_CS_PRIMARY;
295
      
unknown's avatar
unknown committed
296
    if (cs->binary_number == cs->number)
297 298
      cs->state |= MY_CS_BINSORT;
    
299 300
    if (!(all_charsets[cs->number]->state & MY_CS_COMPILED))
    {
301
      simple_cs_init_functions(all_charsets[cs->number]);
302 303 304 305 306 307
      simple_cs_copy_data(all_charsets[cs->number],cs);
      if (simple_cs_is_full(all_charsets[cs->number]))
      {
        all_charsets[cs->number]->state |= MY_CS_LOADED;
      }
    }
308 309
    else
    {
310 311 312 313
      CHARSET_INFO *dst= all_charsets[cs->number];
      dst->state |= cs->state;
      if (cs->comment)
	dst->comment= my_once_strdup(cs->comment,MYF(MY_WME));
314
    }
unknown's avatar
unknown committed
315
clear:
316
    cs->number= 0;
317 318
    cs->primary_number= 0;
    cs->binary_number= 0;
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
    cs->name= NULL;
    cs->state= 0;
    cs->sort_order= NULL;
    cs->state= 0;
  }
  return MY_XML_OK;
}


#define MAX_BUF 1024*16
#define MY_CHARSET_INDEX "Index.xml"

const char *charsets_dir= NULL;
static int charset_initialized=0;


static my_bool my_read_charset_file(const char *filename, myf myflags)
{
  char *buf;
  int  fd;
  uint len;
  
  if (!(buf= (char *)my_malloc(MAX_BUF,myflags)))
    return FALSE;
  
  if ((fd=my_open(filename,O_RDONLY,myflags)) < 0)
  {
    my_free(buf,myflags);
    return TRUE;
  }
  len=read(fd,buf,MAX_BUF);
  my_close(fd,myflags);
  
352
  if (my_parse_charset_xml(buf,len,add_collation))
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
  {
#ifdef NOT_YET
    printf("ERROR at line %d pos %d '%s'\n",
	   my_xml_error_lineno(&p)+1,
	   my_xml_error_pos(&p),
	   my_xml_error_string(&p));
#endif
  }
  
  my_free(buf, myflags);  
  return FALSE;
}


char *get_charsets_dir(char *buf)
{
  const char *sharedir= SHAREDIR;
370
  char *res;
371 372 373 374 375 376 377 378 379 380 381 382 383
  DBUG_ENTER("get_charsets_dir");

  if (charsets_dir != NULL)
    strmake(buf, charsets_dir, FN_REFLEN-1);
  else
  {
    if (test_if_hard_path(sharedir) ||
	is_prefix(sharedir, DEFAULT_CHARSET_HOME))
      strxmov(buf, sharedir, "/", CHARSET_DIR, NullS);
    else
      strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
	      NullS);
  }
384
  res= convert_dirname(buf,buf,NullS);
385
  DBUG_PRINT("info",("charsets dir: '%s'", buf));
386
  DBUG_RETURN(res);
387 388
}

389
CHARSET_INFO *all_charsets[256];
unknown's avatar
unknown committed
390
CHARSET_INFO *default_charset_info = &my_charset_latin1;
391 392 393 394

#define MY_ADD_CHARSET(x)	all_charsets[(x)->number]=(x)


395
static my_bool init_compiled_charsets(myf flags __attribute__((unused)))
396 397
{
  CHARSET_INFO *cs;
398 399

  MY_ADD_CHARSET(&my_charset_bin);
unknown's avatar
unknown committed
400
  
401
  MY_ADD_CHARSET(&my_charset_latin1);
402
  MY_ADD_CHARSET(&my_charset_latin1_bin);
403
  MY_ADD_CHARSET(&my_charset_latin1_german2_ci);
404 405

#ifdef HAVE_CHARSET_big5
406
  MY_ADD_CHARSET(&my_charset_big5_chinese_ci);
407
  MY_ADD_CHARSET(&my_charset_big5_bin);
408 409
#endif

unknown's avatar
unknown committed
410 411 412 413 414
#ifdef HAVE_CHARSET_cp1250
  MY_ADD_CHARSET(&my_charset_cp1250_czech_ci);
#endif

#ifdef HAVE_CHARSET_latin2
415
  MY_ADD_CHARSET(&my_charset_latin2_czech_ci);
416 417
#endif

unknown's avatar
unknown committed
418
#ifdef HAVE_CHARSET_euckr
419
  MY_ADD_CHARSET(&my_charset_euckr_korean_ci);
420
  MY_ADD_CHARSET(&my_charset_euckr_bin);
421 422 423
#endif

#ifdef HAVE_CHARSET_gb2312
424
  MY_ADD_CHARSET(&my_charset_gb2312_chinese_ci);
425
  MY_ADD_CHARSET(&my_charset_gb2312_bin);
426 427 428
#endif

#ifdef HAVE_CHARSET_gbk
429
  MY_ADD_CHARSET(&my_charset_gbk_chinese_ci);
430
  MY_ADD_CHARSET(&my_charset_gbk_bin);
431 432 433
#endif

#ifdef HAVE_CHARSET_sjis
434
  MY_ADD_CHARSET(&my_charset_sjis_japanese_ci);
435
  MY_ADD_CHARSET(&my_charset_sjis_bin);
436 437 438
#endif

#ifdef HAVE_CHARSET_tis620
439
  MY_ADD_CHARSET(&my_charset_tis620_thai_ci);
440
  MY_ADD_CHARSET(&my_charset_tis620_bin);
441 442 443
#endif

#ifdef HAVE_CHARSET_ucs2
444
  MY_ADD_CHARSET(&my_charset_ucs2_general_ci);
445
  MY_ADD_CHARSET(&my_charset_ucs2_bin);
446 447 448
#endif

#ifdef HAVE_CHARSET_ujis
449
  MY_ADD_CHARSET(&my_charset_ujis_japanese_ci);
450
  MY_ADD_CHARSET(&my_charset_ujis_bin);
451 452 453
#endif

#ifdef HAVE_CHARSET_utf8
454
  MY_ADD_CHARSET(&my_charset_utf8_general_ci);
455
  MY_ADD_CHARSET(&my_charset_utf8_bin);
456 457 458 459 460 461 462 463 464 465 466
#endif

  /* Copy compiled charsets */
  for (cs=compiled_charsets; cs->name; cs++)
  {
    all_charsets[cs->number]=cs;
  }
  
  return FALSE;
}

unknown's avatar
unknown committed
467 468 469
#ifdef __NETWARE__
my_bool STDCALL init_available_charsets(myf myflags)
#else
470
static my_bool init_available_charsets(myf myflags)
unknown's avatar
unknown committed
471
#endif
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
{
  char fname[FN_REFLEN];
  my_bool error=FALSE;
  /*
    We have to use charset_initialized to not lock on THR_LOCK_charset
    inside get_internal_charset...
  */
  if (!charset_initialized)
  {
    CHARSET_INFO **cs;
    /*
      To make things thread safe we are not allowing other threads to interfere
      while we may changing the cs_info_table
    */
    pthread_mutex_lock(&THR_LOCK_charset);

    bzero(&all_charsets,sizeof(all_charsets));
    init_compiled_charsets(myflags);
    
    /* Copy compiled charsets */
    for (cs=all_charsets; cs < all_charsets+255 ; cs++)
    {
      if (*cs)
495
      {
496
        set_max_sort_char(*cs);
497 498
        init_state_maps(*cs);
      }
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
    }
    
    strmov(get_charsets_dir(fname), MY_CHARSET_INDEX);
    error= my_read_charset_file(fname,myflags);
    charset_initialized=1;
    pthread_mutex_unlock(&THR_LOCK_charset);
  }
  return error;
}


void free_charsets(void)
{
  charset_initialized=0;
}


516
uint get_collation_number(const char *name)
517
{
518
  CHARSET_INFO **cs;
519 520 521
  if (init_available_charsets(MYF(0)))	/* If it isn't initialized */
    return 0;
  
unknown's avatar
unknown committed
522 523
  for (cs= all_charsets; cs < all_charsets+255; ++cs)
  {
524
    if ( cs[0] && cs[0]->name && 
525
         !my_strcasecmp(&my_charset_latin1, cs[0]->name, name))
526
      return cs[0]->number;
unknown's avatar
unknown committed
527
  }  
528 529 530
  return 0;   /* this mimics find_type() */
}

531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
uint get_charset_number(const char *charset_name, uint cs_flags)
{
  CHARSET_INFO **cs;
  if (init_available_charsets(MYF(0)))	/* If it isn't initialized */
    return 0;
  
  for (cs= all_charsets; cs < all_charsets+255; ++cs)
  {
    if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
         !my_strcasecmp(&my_charset_latin1, cs[0]->csname, charset_name))
      return cs[0]->number;
  }  
  return 0;
}

546 547 548 549 550 551 552

const char *get_charset_name(uint charset_number)
{
  CHARSET_INFO *cs;
  if (init_available_charsets(MYF(0)))	/* If it isn't initialized */
    return "?";

553
  cs=all_charsets[charset_number];
unknown's avatar
unknown committed
554
  if (cs && (cs->number == charset_number) && cs->name )
unknown's avatar
unknown committed
555 556
    return (char*) cs->name;
  
557 558 559 560
  return (char*) "?";   /* this mimics find_type() */
}


561
static CHARSET_INFO *get_internal_charset(uint cs_number, myf flags)
unknown's avatar
unknown committed
562
{
unknown's avatar
unknown committed
563
  char  buf[FN_REFLEN];
unknown's avatar
unknown committed
564 565 566 567 568 569
  CHARSET_INFO *cs;
  /*
    To make things thread safe we are not allowing other threads to interfere
    while we may changing the cs_info_table
  */
  pthread_mutex_lock(&THR_LOCK_charset);
570

unknown's avatar
unknown committed
571
  cs= all_charsets[cs_number];
572

unknown's avatar
unknown committed
573 574
  if (cs && !(cs->state & (MY_CS_COMPILED | MY_CS_LOADED)))
  {
575 576
     strxmov(get_charsets_dir(buf), cs->csname, ".xml", NullS);
     my_read_charset_file(buf,flags);
unknown's avatar
unknown committed
577
     cs= (cs->state & MY_CS_LOADED) ? cs : NULL;
unknown's avatar
unknown committed
578
  }
unknown's avatar
unknown committed
579 580 581 582 583 584 585 586 587
  pthread_mutex_unlock(&THR_LOCK_charset);
  return cs;
}


CHARSET_INFO *get_charset(uint cs_number, myf flags)
{
  CHARSET_INFO *cs;
  (void) init_available_charsets(MYF(0));	/* If it isn't initialized */
unknown's avatar
unknown committed
588 589 590 591
  
  if (!cs_number)
    return NULL;
  
592
  cs=get_internal_charset(cs_number, flags);
unknown's avatar
unknown committed
593

unknown's avatar
unknown committed
594
  if (!cs && (flags & MY_WME))
unknown's avatar
unknown committed
595 596
  {
    char index_file[FN_REFLEN], cs_string[23];
unknown's avatar
unknown committed
597
    strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
unknown's avatar
unknown committed
598 599 600 601 602 603 604 605 606
    cs_string[0]='#';
    int10_to_str(cs_number, cs_string+1, 10);
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file);
  }
  return cs;
}

CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
{
607
  uint cs_number;
unknown's avatar
unknown committed
608 609 610
  CHARSET_INFO *cs;
  (void) init_available_charsets(MYF(0));	/* If it isn't initialized */

611
  cs_number=get_collation_number(cs_name);
612 613 614 615 616 617 618 619 620 621 622 623 624
  cs= cs_number ? get_internal_charset(cs_number,flags) : NULL;

  if (!cs && (flags & MY_WME))
  {
    char index_file[FN_REFLEN];
    strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
  }

  return cs;
}


unknown's avatar
unknown committed
625 626 627
CHARSET_INFO *get_charset_by_csname(const char *cs_name,
				    uint cs_flags,
				    myf flags)
628
{
629 630
  uint cs_number;
  CHARSET_INFO *cs;
631 632 633
  DBUG_ENTER("get_charset_by_csname");
  DBUG_PRINT("enter",("name: '%s'", cs_name));

634 635
  (void) init_available_charsets(MYF(0));	/* If it isn't initialized */
  
636 637
  cs_number= get_charset_number(cs_name, cs_flags);
  cs= cs_number ? get_internal_charset(cs_number, flags) : NULL;
638
  
unknown's avatar
unknown committed
639 640 641
  if (!cs && (flags & MY_WME))
  {
    char index_file[FN_REFLEN];
unknown's avatar
unknown committed
642
    strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
unknown's avatar
unknown committed
643 644 645
    my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
  }

646
  DBUG_RETURN(cs);
unknown's avatar
unknown committed
647
}