Open Source WEB

MySQL文字列処理ライブラリ

mysql-5.0.7-beta/strings というディレクトリの下に、 mysql文字処理ライブラリとして、 標準ライブラリとは異なる処理をまとめてある。

詳しくは、 README があるので読めば良いが、ここは先を急ごう。

mysql-5.0.7-beta/strings  mysql文字列処理ライブラリ

さて、このディレクトリで、MY_CHARSET_HANDLER という文字列が含まれている ファイルが存在するかどうか調べてみよう。

$ grep MY_CHARSET_HANDLER *.c
ctype-big5.c:static MY_CHARSET_HANDLER my_charset_big5_handler=
ctype-bin.c:static MY_CHARSET_HANDLER my_charset_handler=
ctype-cp932.c:static MY_CHARSET_HANDLER my_charset_handler=
ctype-euc_kr.c:static MY_CHARSET_HANDLER my_charset_handler=
ctype-eucjpms.c:static MY_CHARSET_HANDLER my_charset_handler=
ctype-gb2312.c:static MY_CHARSET_HANDLER my_charset_handler=
ctype-gbk.c:static MY_CHARSET_HANDLER my_charset_handler=
ctype-latin1.c:static MY_CHARSET_HANDLER my_charset_handler=
ctype-simple.c:MY_CHARSET_HANDLER my_charset_8bit_handler=
ctype-sjis.c:static MY_CHARSET_HANDLER my_charset_handler=
ctype-tis620.c:static MY_CHARSET_HANDLER my_charset_handler=
ctype-uca.c:extern MY_CHARSET_HANDLER my_charset_utf8_handler;
ctype-ucs2.c:MY_CHARSET_HANDLER my_charset_ucs2_handler=
ctype-ujis.c:static MY_CHARSET_HANDLER my_charset_handler=
ctype-utf8.c:MY_CHARSET_HANDLER my_charset_utf8_handler=

キャラクタセット毎にCのソースが用意されているようだ。 いずれもctype-で始まり、その後にキャラクタセットを示す文字列が続く。

strings/ctype-キャラクタセット.c  個別キャラクタセット対応プログラム

EUC-JP(eucjpms)で色々調べていたので、ctype-eucjpms.c を調べることにしよう。

  8654  static MY_CHARSET_HANDLER my_charset_handler=
  8655  {
  8656      NULL,               /* init */
  8657      ismbchar_eucjpms,
  8658      mbcharlen_eucjpms,
  8659      my_numchars_mb,
  8660      my_charpos_mb,
  8661      my_well_formed_len_eucjpms,
  8662      my_lengthsp_8bit,
  8663      my_numcells_eucjp,
  8664      my_mb_wc_euc_jp,    /* mb_wc       */
  8665      my_wc_mb_euc_jp,    /* wc_mb       */
  8666      my_caseup_str_mb,
  8667      my_casedn_str_mb,
  8668      my_caseup_mb,
  8669      my_casedn_mb,
  8670      my_snprintf_8bit,
  8671      my_long10_to_str_8bit,
  8672      my_longlong10_to_str_8bit,
  8673      my_fill_8bit,
  8674      my_strntol_8bit,
  8675      my_strntoul_8bit,
  8676      my_strntoll_8bit,
  8677      my_strntoull_8bit,
  8678      my_strntod_8bit,
  8679      my_strtoll10_8bit,
  8680      my_scan_8bit
  8681  };

この中で

include/m_ctype.h

   159    uint    (*numcells)(struct charset_info_st *, const char *b, const char *e);

に対応しているのは8番目なので

  8663      my_numcells_eucjp,

である。数えなくても、名前から多分そうである。

my_numcells_eucjp は関数で、このファイル(ctype-eucjpms.c)中に存在する。


関数 my_numcells_eucjp()

さて、この関数は何をしているのだろうか。

strings/ctype-eucjpms.c

  8436  static
  8437  uint my_numcells_eucjp(CHARSET_INFO *cs __attribute__((unused)),
  8438                         const char *str, const char *strend)
  8439  {
  8440    uint clen= 0;
  8441    const unsigned char *b= (const unsigned char *) str;
  8442    const unsigned char *e= (const unsigned char *) strend;
  8443
  8444    for (clen= 0; b < e; )
  8445    {
  8446      if (*b == 0x8E)
  8447      {
  8448        clen++;
  8449        b+= 2;
  8450      }
  8451      else if (*b == 0x8F)
  8452      {
  8453        clen+= 2;
  8454        b+= 3;
  8455      }
  8456      else if (*b & 0x80)
  8457      {
  8458        clen+= 2;
  8459        b+= 2;
  8460      }
  8461      else
  8462      {
  8463        clen++;
  8464        b++;
  8465      }
  8466    }
  8467    return clen;
  8468  }

2番目の引数は文字列であるが、C言語の文字列は最後が \0 というので判定 するのではなく、最後の文字の次のアドレスを strend で与えている。

変数 b が文字列をなめていき、clen が それに伴なって増加している。 *b の内容により、clen と b のインクリメント量が異なる。 clen は文字幅(cell幅)のことだと思われる。

*b == 0x8E

0x8E は2バイトの半角カタカナの1バイト目である。 したがって、文字幅clenは +1 され、 2バイト文字なので、bは +2 される。

*b == 0x8F

0x8F は、JIS X 0212(補助漢字)の1バイト目である。 補助漢字は3バイトで、文字幅は普通の漢字と同じ全角である。 したがって、文字幅clenは +2 され、bは +3 される。

*b & 0x80

0x8Eでも 0x8Fでもなくて最上位ビットが立っている場合には、 普通の漢字 JIS X 0208 の1バイト目となる。 したがって、文字幅clenは +2 され、bも +2 される。

その他

最上位ビットが立っていない場合には、全てASCII文字とみなされる。 したがって、文字幅clenは +1 され、bも +1 される。

最上位ビットが立っていないと文字幅が1、つまり半角とみなしてしまうのは、 ちょっと大胆ではないかと思う。制御文字だって文字幅が1になるのだから、 バックスペースだって +1 される訳だ。

でも、そんなことは些細なことで、通常考える必要はないかも知れないので、 深入りはよそう。

ということで、当初の予測通り、

client/mysql.cc

 2210          uint numcells= charset_info->cset->numcells(charset_info,
 2211                                              str, str + currlength);

は文字列の幅(表示幅)を半角を1として求めているところであった。

文字列の表示幅を、毎回ちゃんと計算しているのに、 うまく縦線が揃わないのは何故だろうか?


戻る:文字幅を求める関数へのポインタ(*numcells)()

次へ:charset_infoはいつ変更されるか


フィードバック:

Name:
Comment:

There is no comment.

このサイトは、 IPA の「平成15年度オープンソフトウエア活用基盤整備事業」 の委託事業として開発されたKahuaで試験的に運用しております。

Copyright (c) 2004-2007 株式会社タイムインターメディア About Us