CCP4iのタスクリストを日本語対応にする  

2011-05-18 -- 最近のCCP4では使えないかも・・・

概要  

CCP4iを使っていてふと思いました。

タスクのタイトルに日本語が使いたい!!

なぜなら英語が苦手だから(全然よくない [sad])。
そんなわけで日本語対応を試みてみました。
ここで言うタスクのタイトルとはREFMACだとRigid body refinementなどとプログラム名の右側に表示される文字列のことです。ここでのハックはUTF-8を使っているのでひょっとしたら日本語以外のマルチバイト文字にも対応できてるかもしれません(もちろん未確認)。
なお、公開している結果はどぶおが独自に検討したものであり、十分に実用に耐えるものであるという保証は全くありません。従って試そうという方はその辺を理解した上、自己責任で楽しんで下さい。もし実際に試して、何かあればメッセージを書いていただけると検証するかもしれません。

読み方  

将来、自分でもう一度解析できるようにやや冗長にまとめているかもしれませんが、ご容赦下さい。私がたまに行うソースの追跡はこんな感じで行っています。

以上のように読み替えて下さい。

検証  

検証その1  

とりあえずは標準の状態で日本語タイトルを入れてみました。タイトルのところに「てすと」と。
すると結果は「___(伏せ字じゃありません、アンダースコアです [huh])」となりました・・・(試したことある人もいると思いますが)
で、これをいろいろ検証するために、先日まとめたHappy Scripting/CCP4iのAPIを使うのdbCCP4iに行き着くわけです。慣れないtclのソースを追いかけていくと、まず一つ怪しいところに行き着きます。

怪しいところその1
$CCP4I_TOP/src/utils.tcl 857行目付近 RemoveMetaChars関数

この関数では文字列からメタキャラクタを取り除くためにa-z0-9といくつかの記号以外は全てアンダースコアに変換しています(888行目付近)。これを見るとタイトルに使える記号は_- ()/.,ということがわかりますね。検証のため、まずはこれを無効にします。メタキャラクタを取り除くためのルーチンなので無効にしてしまうとあまりよくないので、一通りの検証が済んだら整理することにします。

   886   set name "[string trim $namein]"
   887   if {$title} {
   888   # while { [regsub -nocase {[^a-z^0-9^_^-^ ^(^)^/^.^,]} $name _ name1] > 0 } {
   889   #   set changed 1
   890   #   set name $name1
   891   # }
   892   } elseif {$nospace} {

このソースの888から891行目をコメントアウトしてみました(実は内部関数のdbccp4_set_dataを使えばこのチェックはパスできます)。で、再度実行。
通るかな、と思ったらそんなに甘くありません。応答が帰ってこず、しばらくフリーズしたようになりました [huh]。そんなわけでさらに検証を進めます。

検証その2  

ソースを追いかけていくうちにdbCCP4iのアクセスログが$HOME/.CCP4/dbclientapi.logに書き込まれていることがわかりました。これで相当追跡がはかどりそうです。で、応答が返ってこなかった部分を見てみると、

db_handler_processResponse: from server: "<db_response><status>ERROR</status><result>not well form request</result><response_id>#</response_id></db_response>" msg: 115

というようなメッセージがDBから返ってきています。not well form requestということなのでXMLフォーマットがおかしいということだと推測できます(CCP4iとdbCCP4iはXMLでメッセージ交換しています)。何も考えていませんでしたがVine Linuxでは日本語エンコードがEUC-JPなのでXMLのパースに失敗したのだと思われます(正式にはUTF-8を使わなければならない)。この時につまずいているため、応答のタイムアウト待ちでフリーズしたようになっていたようです。ひょっとしたらCentOSなど標準のエンコーディングがUTF-8のシステムではこのエラーは出ないかもしれません。

怪しいところその2
dbCCP4iへのメッセージ送受信時

この部分を追跡します。ソースを読んでいくとメッセージ送信には::dbClientAPI::db_handler_requestが使われているようで、この部分を追いかけます。ファイルは$CCP4/share/dbccp4i/ClientAPI/dbClientAPI.tclの1940行目付近です。
ここで試行錯誤があったのですが、結局dbCCP4iのソケットにメッセージを書き込む時にUTF-8で行うという手段をとることにしました。どうやらtclにはfconfigureというファイルハンドル書き込み時(読み込み時)に文字エンコーディングを指定できる関数があるようなのでそれを使います。2002行目付近にputs...とあります。そこに追加してみました。

  2001   # Send the request to the server
  2002   ##puts "db_handler_request: request \"$request\""
  2003   fconfigure $client -encoding utf-8               <-- 書き込みをUTF-8で行う
  2004   if { ![catch { puts $client $request } msg] } {
  2005     fconfigure $client -encoding [encoding system] <-- 読み込みはシステムのエンコーディング
  2006     db_client_report 1 "db_handler_request: request sent ok"

これでUTF-8で送信されるはずです。ここでテスト。

検証その3  

結構いい線行ったと思ったのですがまたもや失敗。dbclientapi.logを確認すると、

db_handler_processResponse: from server: "<db_response><status>ERROR</status><result>Handler exception: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)</result><response_id>request#15</response_id></db_response>" msg: 202

となりました。どうやらPythonのディフォルトエンコーディングがASCIIなのでマルチバイト文字列を受け入れられないようです。
今度はPython側を検証します。dbCCP4iはPythonで書かれているのです。
調べてみるとディフォルトエンコーディングはsite.pyをいじればよいということでしたが、あまりシステムファイルをいじりたくないのでもう少し調べると、site-packages/sitecustomize.pyを作成すればいいと言うことがわかりました。

$CCP4_MASTER/Python-2.4.5/lib/python2.4/site-packages/sitecustomize.py
import sys
import locale
sys.setdefaultencoding(locale.getdefaultlocale()[1])

というように作成します。
テストすると、ようやく反映されました!

最終調整  

ようやくメドがついたので細かい部分を調整します。 検証1でコメントアウトした部分をきちんと作成しておきます。

   886   set name "[string trim $namein]"
   887   if {$title} {
   888     while { [regsub -nocase {[^a-z^0-9^_^-^ ^(^)^/^.^,^\x80-\xFD]} [encoding convertto utf-8 $name] _ name1] > 0 } {
   889       set changed 1
   890       set name [encoding convertfrom $name1]
   891     }
   892   } elseif {$nospace} {

888行目、890行目を修正してあります。メタキャラクタの処理に使用されている正規表現中で、UTF-8で使用される0x80-0xBFおよび0xC0-0xFDを合わせて0x80-0xFDは除去しないようにします。少々煩雑なのですが、UTF-8にコンバートした後、日本語部分は置換せずに処理するような流れです。

以上でようやく日本語タイトルが使えるようになりました!
最終的に修正したファイルは、

の3つです。とりあえずこの状態でしばらく使ってみて(ちょうど今、構造解析中なので)、検討を続けたいと思います。
dbCCP4i側までいじらずに対応できてよかったー [smile]

パッチ  

パッチを作成してみました。当然のことながら適用は自己責任でお願いします。

適用方法  

rootになって行います。

# cd /usr/local/ccp4-6.1.1
# patch -p1 < ccp4i-2.0.4_japanize20090415.patch
patching file Python-2.4.5/lib/python2.4/site-packages/sitecustomize.py
patching file ccp4-6.1.1/ccp4i/src/utils.tcl
patching file ccp4-6.1.1/share/dbccp4i/ClientAPI/dbClientAPI.tcl

ディスカッション  

試してみたよ報告などありましたらお願いします。

添付ファイル: fileccp4i-2.0.4_japanize20090415.patch 2156件 [詳細]