charset.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:15k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either
  6.    version 2 of the License, or (at your option) any later version.
  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. #include "mysys_priv.h"
  18. #include "mysys_err.h"
  19. #include <m_ctype.h>
  20. #include <m_string.h>
  21. #include <my_dir.h>
  22. typedef struct cs_id_st {
  23.   char *name;
  24.   uint number;
  25. } CS_ID;
  26. const char *charsets_dir = NULL;
  27. static DYNAMIC_ARRAY cs_info_table;
  28. static CS_ID **available_charsets;
  29. static int charset_initialized=0;
  30. #define MAX_LINE  1024
  31. #define CTYPE_TABLE_SIZE      257
  32. #define TO_LOWER_TABLE_SIZE   256
  33. #define TO_UPPER_TABLE_SIZE   256
  34. #define SORT_ORDER_TABLE_SIZE 256
  35. struct simpleconfig_buf_st {
  36.   FILE *f;
  37.   char  buf[MAX_LINE];
  38.   char *p;
  39. };
  40. /* Defined in strings/ctype.c */
  41. CHARSET_INFO *find_compiled_charset(uint cs_number);
  42. uint compiled_charset_number(const char *name);
  43. const char *compiled_charset_name(uint charset_number);
  44. static uint num_from_csname(CS_ID **cs, const char *name)
  45. {
  46.   CS_ID **c;
  47.   for (c = cs; *c; ++c)
  48.     if (!strcmp((*c)->name, name))
  49.       return (*c)->number;
  50.   return 0;   /* this mimics find_type() */
  51. }
  52. static char *name_from_csnum(CS_ID **cs, uint number)
  53. {
  54.   CS_ID **c;
  55.   if(cs)
  56.     for (c = cs; *c; ++c)
  57.       if ((*c)->number == number)
  58. return (*c)->name;
  59.   return (char*) "?";   /* this mimics find_type() */
  60. }
  61. static my_bool get_word(struct simpleconfig_buf_st *fb, char *buf)
  62. {
  63.   char *endptr=fb->p;
  64.   for (;;)
  65.   {
  66.     while (isspace(*endptr))
  67.       ++endptr;
  68.     if (*endptr && *endptr != '#') /* Not comment */
  69.       break; /* Found something */
  70.     if ((fgets(fb->buf, sizeof(fb->buf), fb->f)) == NULL)
  71.       return TRUE; /* end of file */
  72.     endptr = fb->buf;
  73.   }
  74.   while (!isspace(*endptr))
  75.     *buf++= *endptr++;
  76.   *buf=0;
  77.   fb->p = endptr;
  78.   return FALSE;
  79. }
  80. char *get_charsets_dir(char *buf)
  81. {
  82.   const char *sharedir = SHAREDIR;
  83.   DBUG_ENTER("get_charsets_dir");
  84.   if (charsets_dir != NULL)
  85.     strmake(buf, charsets_dir, FN_REFLEN-1);
  86.   else
  87.   {
  88.     if (test_if_hard_path(sharedir) ||
  89. is_prefix(sharedir, DEFAULT_CHARSET_HOME))
  90.       strxmov(buf, sharedir, "/", CHARSET_DIR, NullS);
  91.     else
  92.       strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
  93.       NullS);
  94.   }
  95.   convert_dirname(buf);
  96.   DBUG_PRINT("info",("charsets dir='%s'", buf));
  97.   DBUG_RETURN(strend(buf));
  98. }
  99. static my_bool read_charset_index(CS_ID ***charsets, myf myflags)
  100. {
  101.   struct simpleconfig_buf_st fb;
  102.   char buf[MAX_LINE], num_buf[MAX_LINE];
  103.   DYNAMIC_ARRAY cs;
  104.   CS_ID *csid;
  105.   strmov(get_charsets_dir(buf), "Index");
  106.   if ((fb.f = my_fopen(buf, O_RDONLY, myflags)) == NULL)
  107.     return TRUE;
  108.   fb.buf[0] = '';
  109.   fb.p = fb.buf;
  110.   if (init_dynamic_array(&cs, sizeof(CS_ID *), 32, 32))
  111.     return TRUE;
  112.   while (!get_word(&fb, buf) && !get_word(&fb, num_buf))
  113.   {
  114.     uint csnum;
  115.     uint length;
  116.     if (!(csnum = atoi(num_buf)))
  117.     {
  118.       /* corrupt Index file */
  119.       my_fclose(fb.f,myflags);
  120.       return TRUE;
  121.     }
  122.     if (!(csid = (CS_ID*) my_once_alloc(sizeof(CS_ID), myflags)) ||
  123.         !(csid->name=
  124.            (char*) my_once_alloc(length= (uint) strlen(buf)+1, myflags)))
  125.     {
  126.       my_fclose(fb.f,myflags);
  127.       return TRUE;
  128.     }
  129.     memcpy(csid->name,buf,length);
  130.     csid->number = csnum;
  131.     insert_dynamic(&cs, (gptr) &csid);
  132.   }
  133.   my_fclose(fb.f,myflags);
  134.   if (!(*charsets =
  135.       (CS_ID **) my_once_alloc((cs.elements + 1) * sizeof(CS_ID *), myflags)))
  136.     return TRUE;
  137.   /* unwarranted chumminess with dynamic_array implementation? */
  138.   memcpy((byte *) *charsets, cs.buffer, cs.elements * sizeof(CS_ID *));
  139.   (*charsets)[cs.elements] = NULL;
  140.   delete_dynamic(&cs);  
  141.   return FALSE;
  142. }
  143. static my_bool init_available_charsets(myf myflags)
  144. {
  145.   my_bool error=0;
  146.   /*
  147.     We have to use charset_initialized to not lock on THR_LOCK_charset
  148.     inside get_internal_charset...
  149.    */
  150.   if (!charset_initialized)
  151.   {
  152.   /*
  153.     To make things thread safe we are not allowing other threads to interfere
  154.     while we may changing the cs_info_table
  155.   */
  156.     pthread_mutex_lock(&THR_LOCK_charset);
  157.     if (!cs_info_table.buffer) /* If not initialized */
  158.     {
  159.       init_dynamic_array(&cs_info_table, sizeof(CHARSET_INFO*), 16, 8);
  160.       error = read_charset_index(&available_charsets, myflags);
  161.     }
  162.     charset_initialized=1;
  163.     pthread_mutex_unlock(&THR_LOCK_charset);
  164.   }
  165.   if(!available_charsets || !available_charsets[0])
  166.     error = TRUE;
  167.   return error;
  168. }
  169. void free_charsets(void)
  170. {
  171.   delete_dynamic(&cs_info_table);
  172. }
  173. static my_bool fill_array(uchar *array, int sz, struct simpleconfig_buf_st *fb)
  174. {
  175.   char buf[MAX_LINE];
  176.   while (sz--)
  177.   {
  178.     if (get_word(fb, buf))
  179.     {
  180.       DBUG_PRINT("error",("get_word failed, expecting %d more words", sz + 1));
  181.       return 1;
  182.     }
  183.     *array++ = (uchar) strtol(buf, NULL, 16);
  184.   }
  185.   return 0;
  186. }
  187. static void get_charset_conf_name(uint cs_number, char *buf)
  188. {
  189.   strxmov(get_charsets_dir(buf),
  190.           name_from_csnum(available_charsets, cs_number), ".conf", NullS);
  191. }
  192. static my_bool read_charset_file(uint cs_number, CHARSET_INFO *set,
  193.  myf myflags)
  194. {
  195.   struct simpleconfig_buf_st fb;
  196.   char buf[FN_REFLEN];
  197.   my_bool result;
  198.   DBUG_ENTER("read_charset_file");
  199.   DBUG_PRINT("enter",("cs_number: %d", cs_number));
  200.   if (cs_number <= 0)
  201.     DBUG_RETURN(TRUE);
  202.   get_charset_conf_name(cs_number, buf);
  203.   DBUG_PRINT("info",("file name: %s", buf));
  204.   if ((fb.f = my_fopen(buf, O_RDONLY, myflags)) == NULL)
  205.     DBUG_RETURN(TRUE);
  206.   fb.buf[0] = ''; /* Init for get_word */
  207.   fb.p = fb.buf;
  208.   result=FALSE;
  209.   if (fill_array(set->ctype,      CTYPE_TABLE_SIZE,      &fb) ||
  210.       fill_array(set->to_lower,   TO_LOWER_TABLE_SIZE,   &fb) ||
  211.       fill_array(set->to_upper,   TO_UPPER_TABLE_SIZE,   &fb) ||
  212.       fill_array(set->sort_order, SORT_ORDER_TABLE_SIZE, &fb))
  213.     result=TRUE;
  214.   my_fclose(fb.f, MYF(0));
  215.   DBUG_RETURN(result);
  216. }
  217. uint get_charset_number(const char *charset_name)
  218. {
  219.   my_bool error;
  220.   error = init_available_charsets(MYF(0)); /* If it isn't initialized */
  221.   if (error)
  222.     return compiled_charset_number(charset_name);
  223.   else
  224.     return num_from_csname(available_charsets, charset_name);
  225. }
  226. const char *get_charset_name(uint charset_number)
  227. {
  228.   my_bool error;
  229.   error = init_available_charsets(MYF(0)); /* If it isn't initialized */
  230.   if (error)
  231.     return compiled_charset_name(charset_number);
  232.   else
  233.     return name_from_csnum(available_charsets, charset_number);
  234. }
  235. static CHARSET_INFO *find_charset(CHARSET_INFO **table, uint cs_number,
  236.                                   size_t tablesz)
  237. {
  238.   uint i;
  239.   for (i = 0; i < tablesz; ++i)
  240.     if (table[i]->number == cs_number)
  241.       return table[i];
  242.   return NULL;
  243. }
  244. static CHARSET_INFO *find_charset_by_name(CHARSET_INFO **table, const char *name,
  245.   size_t tablesz)
  246. {
  247.   uint i;
  248.   for (i = 0; i < tablesz; ++i)
  249.     if (!strcmp(table[i]->name,name))
  250.       return table[i];
  251.   return NULL;
  252. }
  253. static CHARSET_INFO *add_charset(uint cs_number, const char *cs_name)
  254. {
  255.   CHARSET_INFO tmp_cs,*cs;
  256.   uchar tmp_ctype[CTYPE_TABLE_SIZE];
  257.   uchar tmp_to_lower[TO_LOWER_TABLE_SIZE];
  258.   uchar tmp_to_upper[TO_UPPER_TABLE_SIZE];
  259.   uchar tmp_sort_order[SORT_ORDER_TABLE_SIZE];
  260.   /* Don't allocate memory if we are not sure we can find the char set */
  261.   cs= &tmp_cs;
  262.   bzero((char*) cs, sizeof(*cs));
  263.   cs->ctype=tmp_ctype;
  264.   cs->to_lower=tmp_to_lower;
  265.   cs->to_upper=tmp_to_upper;
  266.   cs->sort_order=tmp_sort_order;
  267.   if (read_charset_file(cs_number, cs, MYF(MY_WME)))
  268.     return NULL;
  269.   cs           = (CHARSET_INFO*) my_once_alloc(sizeof(CHARSET_INFO),
  270.        MYF(MY_WME));
  271.   *cs=tmp_cs;
  272.   cs->name     = (char *) my_once_alloc((uint) strlen(cs_name)+1, MYF(MY_WME));
  273.   cs->ctype    = (uchar*) my_once_alloc(CTYPE_TABLE_SIZE,      MYF(MY_WME));
  274.   cs->to_lower = (uchar*) my_once_alloc(TO_LOWER_TABLE_SIZE,   MYF(MY_WME));
  275.   cs->to_upper = (uchar*) my_once_alloc(TO_UPPER_TABLE_SIZE,   MYF(MY_WME));
  276.   cs->sort_order=(uchar*) my_once_alloc(SORT_ORDER_TABLE_SIZE, MYF(MY_WME));
  277.   cs->number   = cs_number;
  278.   memcpy((char*) cs->name,  (char*) cs_name, strlen(cs_name) + 1);
  279.   memcpy((char*) cs->ctype,  (char*) tmp_ctype, sizeof(tmp_ctype));
  280.   memcpy((char*) cs->to_lower, (char*) tmp_to_lower, sizeof(tmp_to_lower));
  281.   memcpy((char*) cs->to_upper, (char*) tmp_to_upper, sizeof(tmp_to_upper));
  282.   memcpy((char*) cs->sort_order, (char*) tmp_sort_order,
  283.  sizeof(tmp_sort_order));
  284.   insert_dynamic(&cs_info_table, (gptr) &cs);
  285.   return cs;
  286. }
  287. static CHARSET_INFO *get_internal_charset(uint cs_number)
  288. {
  289.   CHARSET_INFO *cs;
  290.   /*
  291.     To make things thread safe we are not allowing other threads to interfere
  292.     while we may changing the cs_info_table
  293.   */
  294.   pthread_mutex_lock(&THR_LOCK_charset);
  295.   if (!(cs = find_charset((CHARSET_INFO**) cs_info_table.buffer, cs_number,
  296.   cs_info_table.elements)))
  297.     if (!(cs = find_compiled_charset(cs_number)))
  298.       cs=add_charset(cs_number, get_charset_name(cs_number));
  299.   pthread_mutex_unlock(&THR_LOCK_charset);
  300.   return cs;
  301. }
  302. static CHARSET_INFO *get_internal_charset_by_name(const char *name)
  303. {
  304.   CHARSET_INFO *cs;
  305.   /*
  306.     To make things thread safe we are not allowing other threads to interfere
  307.     while we may changing the cs_info_table
  308.   */
  309.   pthread_mutex_lock(&THR_LOCK_charset);
  310.   if (!(cs = find_charset_by_name((CHARSET_INFO**) cs_info_table.buffer, name,
  311.  cs_info_table.elements)))
  312.     if (!(cs = find_compiled_charset_by_name(name)))
  313.       cs=add_charset(get_charset_number(name), name);
  314.   pthread_mutex_unlock(&THR_LOCK_charset);
  315.   return cs;
  316. }
  317. CHARSET_INFO *get_charset(uint cs_number, myf flags)
  318. {
  319.   CHARSET_INFO *cs;
  320.   (void) init_available_charsets(MYF(0)); /* If it isn't initialized */
  321.   cs=get_internal_charset(cs_number);
  322.   if (!cs && (flags & MY_WME))
  323.   {
  324.     char index_file[FN_REFLEN], cs_string[23];
  325.     strmov(get_charsets_dir(index_file), "Index");
  326.     cs_string[0]='#';
  327.     int10_to_str(cs_number, cs_string+1, 10);
  328.     my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file);
  329.   }
  330.   return cs;
  331. }
  332. my_bool set_default_charset(uint cs, myf flags)
  333. {
  334.   CHARSET_INFO *new;
  335.   DBUG_ENTER("set_default_charset");
  336.   DBUG_PRINT("enter",("character set: %d",(int) cs));
  337.   new = get_charset(cs, flags);
  338.   if (!new)
  339.   {
  340.     DBUG_PRINT("error",("Couldn't set default character set"));
  341.     DBUG_RETURN(TRUE);   /* error */
  342.   }
  343.   default_charset_info = new;
  344.   DBUG_RETURN(FALSE);
  345. }
  346. CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
  347. {
  348.   CHARSET_INFO *cs;
  349.   (void) init_available_charsets(MYF(0)); /* If it isn't initialized */
  350.   cs=get_internal_charset_by_name(cs_name);
  351.   if (!cs && (flags & MY_WME))
  352.   {
  353.     char index_file[FN_REFLEN];
  354.     strmov(get_charsets_dir(index_file), "Index");
  355.     my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
  356.   }
  357.   return cs;
  358. }
  359. my_bool set_default_charset_by_name(const char *cs_name, myf flags)
  360. {
  361.   CHARSET_INFO *new;
  362.   DBUG_ENTER("set_default_charset_by_name");
  363.   DBUG_PRINT("enter",("character set: %s", cs_name));
  364.   new = get_charset_by_name(cs_name, flags);
  365.   if (!new)
  366.   {
  367.     DBUG_PRINT("error",("Couldn't set default character set"));
  368.     DBUG_RETURN(TRUE);   /* error */
  369.   }
  370.   default_charset_info = new;
  371.   DBUG_RETURN(FALSE);
  372. }
  373. /* Only append name if it doesn't exist from before */
  374. static my_bool charset_in_string(const char *name, DYNAMIC_STRING *s)
  375. {
  376.   uint length= (uint) strlen(name);
  377.   const char *pos;
  378.   for (pos=s->str ; (pos=strstr(pos,name)) ; pos++)
  379.   {
  380.     if (! pos[length] || pos[length] == ' ')
  381.       return TRUE; /* Already existed */
  382.   }
  383.   return FALSE;
  384. }
  385. static void charset_append(DYNAMIC_STRING *s, const char *name)
  386. {
  387.   if (!charset_in_string(name, s)) {
  388.     dynstr_append(s, name);
  389.     dynstr_append(s, " ");
  390.   }
  391. }
  392. /* Returns a dynamically-allocated string listing the character sets
  393.    requested.  The caller is responsible for freeing the memory. */
  394. char * list_charsets(myf want_flags)
  395. {
  396.   DYNAMIC_STRING s;
  397.   char *p;
  398.   (void)init_available_charsets(MYF(0));
  399.   init_dynamic_string(&s, NullS, 256, 1024);
  400.   if (want_flags & MY_COMPILED_SETS)
  401.   {
  402.     CHARSET_INFO *cs;
  403.     for (cs = compiled_charsets; cs->number > 0; cs++)
  404.     {
  405.       dynstr_append(&s, cs->name);
  406.       dynstr_append(&s, " ");
  407.     }
  408.   }
  409.   if (want_flags & MY_CONFIG_SETS)
  410.   {
  411.     CS_ID **c;
  412.     char buf[FN_REFLEN];
  413.     MY_STAT status;
  414.     if((c=available_charsets))
  415.       for (; *c; ++c)
  416. {
  417.   if (charset_in_string((*c)->name, &s))
  418.     continue;
  419.   get_charset_conf_name((*c)->number, buf);
  420.   if (!my_stat(buf, &status, MYF(0)))
  421.     continue;       /* conf file doesn't exist */
  422.   dynstr_append(&s, (*c)->name);
  423.   dynstr_append(&s, " ");
  424. }
  425.   }
  426.   if (want_flags & MY_INDEX_SETS)
  427.   {
  428.     CS_ID **c;
  429.     for (c = available_charsets; *c; ++c)
  430.       charset_append(&s, (*c)->name);
  431.   }
  432.   if (want_flags & MY_LOADED_SETS)
  433.   {
  434.     uint i;
  435.     for (i = 0; i < cs_info_table.elements; i++)
  436.       charset_append(&s, 
  437.      dynamic_element(&cs_info_table, i, CHARSET_INFO *)->name);
  438.   }
  439.   s.str[s.length - 1] = '';   /* chop trailing space */
  440.   p = my_strdup(s.str, MYF(MY_WME));
  441.   dynstr_free(&s);
  442.   return p;
  443. }
  444. /****************************************************************************
  445. * Code for debugging.
  446. ****************************************************************************/
  447. static void _print_array(uint8 *data, uint size)
  448. {
  449.   uint i;
  450.   for (i = 0; i < size; ++i)
  451.   {
  452.     if (i == 0 || i % 16 == size % 16) printf("  ");
  453.     printf(" %02x", data[i]);
  454.     if ((i+1) % 16 == size % 16) printf("n");
  455.   }
  456. }
  457. /* _print_csinfo is called from test_charset.c */
  458. void _print_csinfo(CHARSET_INFO *cs)
  459. {
  460.   printf("%s #%dn", cs->name, cs->number);
  461.   printf("ctype:n"); _print_array(cs->ctype, 257);
  462.   printf("to_lower:n"); _print_array(cs->to_lower, 256);
  463.   printf("to_upper:n"); _print_array(cs->to_upper, 256);
  464.   printf("sort_order:n"); _print_array(cs->sort_order, 256);
  465.   printf("collate:    %3s (%d, %p, %p, %p, %p, %p)n",
  466.          cs->strxfrm_multiply ? "yes" : "no",
  467.          cs->strxfrm_multiply,
  468.          cs->strcoll,
  469.          cs->strxfrm,
  470.          cs->strnncoll,
  471.          cs->strnxfrm,
  472.          cs->like_range);
  473.   printf("multi-byte: %3s (%d, %p, %p, %p)n",
  474.          cs->mbmaxlen ? "yes" : "no",
  475.          cs->mbmaxlen,
  476.          cs->ismbchar,
  477.          cs->ismbhead,
  478.          cs->mbcharlen);
  479. }