Chat (Lingr.com)
Informaiton
Daily
Column
- MySQL日本語の旅(5/1)
- アクセス向上秘伝(5/9)
- 一風変ったHaskellλ門(6/13)
- SICP Answer Book (5/31) 問題3.26追加
Zope Solution
Extra
アーカイブ
OSS案内所
Site Info
関連リンク
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)()
フィードバック:
There is no comment.