(簡易版)pTeX を UTF-8 入力に対応させる試み(3)

UTF-8対応(2) から小さな拡張を行います。 UTF-8 の処理には直接は影響しませんが、 文字コードを切替えやすくして、使い勝手をよくします。

ロケール対応 (libkanji-0.85)

"--kanji=" オプションでの文字コード指定は、 入出力ファイルにとどまらず、メッセージ出力にも影響しました。 そのため、platex-euc と platex-sjis の両方とも文字化けしない ターミナルの設定は存在しませんでした。

Unix の作法では、ターミナル出力の文字コードは、 環境変数 LANG などの設定に従って切替えることになっていますので、 ptex などもこれに従って切替えるようにしてみました。 改造は libkanji のみで行い、 個々のツールには全く手を加える必要はありませんでした。

出力ファイルの文字コードについて

結論から書くと、出力ファイルは、 以前とまったく同じものになるようにしました。

ptex が出力する *.aux などのファイルは、 再び入力としても用いられるので、 出力ファイルの文字コードもよく考えないといけません。

  1. 入力ファイルと同じにする
  2. どのような状況でも正しく読み込める JIS にする

この二つの方法が考えられます。 以前から 1. を採用してきて、今回も引き継ぎました。 2. でもそれほど問題はないと思いますが、 "*.log" などをエディタで眺める人がいるかもしれないので、 JIS 決め打ちよりかは入力ファイルと同じ方が安全であろうという気がします。

参照する環境変数

どの環境変数を見ればよいのか、よくわからなかったのですが、 man のソースを見てまねしてみました。

LC_ALL
LC_MESSAGES
LANG
LANGUAGE

この順番で最初に見つかった設定を採用します。 見つかった環境変数は、次のように処理します。

  • "." を含んでいれば "." 以前を捨ててる
  • 大文字小文字を同一視して、次の文字列と比較する
    euc
    eucJP
    ujis
    sjis
    utf8
    UTF-8
    jis
    ISO-2022-JP

環境変数がどれも設定されてなかったり、 設定されてても比較した文字列のどれとも一致しなければ、 これまでのように "--kanji" オプションの設定に従います。

プログラム開始後、putc2()/fputs2() 経由で 最初に stdout または stderr に出力しようとしたときに、 以上の処理で文字コードを決定し、その結果を記憶します。 プログラム実行中に環境変数が変更されることは想定していません。

文字コードの独立 (libkanji-0.86)

以前は、内部バッファの文字コードが EUC であれば、 SJIS に変換して出力することはありませんでしたが、 ターミナルには SJIS に変換して出力する必要が生じました。

そこで、処理は少し冗長になるのですが、 内部バッファ、ターミナル出力、入出力ファイルの 3つの文字コードをすべてばらばらに設定しても 大丈夫なように改めました。 SJIS と EUC の場合分けが対称になり、 ソースが読みやすくなったと思います。

更にこれを利用して、各ツールでの文字コードの扱いを以下のようにしました。 platex も含めて --kanji オプションで切替えられます。 また、W32TeX と同様に環境変数 PTEX_KANJI_ENC も使えるようにしてみました。

ツール入力
ファイル
内部
バッファ
出力ファイル使用関数
ptex初期固定JIS (DVI)input_line2() toJIS() putc2()
pltotfE/SJIS (tfm)input_line2() toJIS()
tftoplJIS (tfm)E/SfromJIS() putc2()
pdvitypeJIS (DVI)E/SfromJIS() putc2()
jbibtexEUC固定input_line2() putc2()
mendexEUC固定input_line2() putc2()
jmpostE/SJIS (PS)input_line2() toJIS() putc2()
pdvitompJIS (DVI)E/SfromJIS() putc2()
  • ほとんどの文字コードは、次に指定されたものになります。
    • --kanji オプション
    • それがなければ、環境変数の PTEX_KANJI_ENC
    • それがなければ、./configure 時に指定されたもの
  • 入力ファイルと出力ファイルの「全」は、 環境変数 PTEX_KANJI_ENC や --kanji オプションの指定次第で、 JIS, EUC, UTF-8, SJIS のどれにでも変化します。
  • 内部バッファの「E/S」は、 環境変数 PTEX_KANJI_ENC や --kanji オプションの指定次第で、 EUC と SJIS のどちらかに変化します。
  • 内部バッファの「初期固定」は、./configure 時に選んだ文字コードが使用されて、 環境変数 PTEX_KANJI_ENC や --kanji オプションの影響を受けません。 このため ptex の fmt がそのままでちゃんと動きます。

ヘルプメッセージでの漢字コードを示す文字列は、 ファイル入出力と内部バッファが一致してれば、 これまでのように "(sjis)" のように表示します。 一致しない場合は "(utf8.euc)" と、 ファイルと内部のコードを両方出力するようにしました。

なお、PTEX_KANJI_ENC は環境変数だけが有効で、 $TEXMF/web2c/texmf.cnf は参照しません。 というのも、ptex の内部処理の順序に束縛されて、 version メッセージを出力する段階でプログラム名が決定されておらず、 texmf.cnf を参照できないからです。 ちなみに、PTEX_KANJI_ENC に設定できるものは --kanji オプションと同じく、 JIS, EUC, UTF8, SJIS の文字列です。

文字コード指定関数について

普通のユーザには関係ない話ですが、 内部で利用している関数について解説しておきます。 今回は各ツールにも小さな修正が必要でした。

libkanji の set_kanji_enc_string() を拡張し、 入出力ファイル用と、内部バッファ用の引数を2つとるようにしました。 コードを変更したくないものには NULL を、 ./configure 時に指定したものを指すには "default" を指定します。

多くのツールは、これまでファイルも内部も同じものを使ってましたので、 今回の変更では、同じ引数を2回重複して与えればよいことになります。 内部用に "JIS" や "UTF8" を指定した場合は "EUC" に読み替えてくれます。

jbibtex と mendex は、内部バッファが EUC に固定されていますので、 まずは (NULL, "EUC") を引数に与え、--kanji オプションがあれば (opt, NULL) を与えればよいことになります。

ptex は、fmt ファイルを生成する必要から、 そう簡単に内部コードを変更するわけにいきません。 ですから、環境変数の影響を排除するため、まずは (NULL, "default") を実行します。 その後に --kanji オプションには (opt, NULL) として、ファイルだけを変更します。 一応 --kanji-internal オプションを新設してまして、 当然こちらは (NULL, opt) と処理しますが、 ユーザが使う必要はまったくないでしょう。

ptex-sjis は、内部コードと同時にファイルも切替えたいですから、 まずは ("sjis", "sjis") を引数に与えます。 この後に --kanji オプションを処理します。 ptex-euc も同様です。

文字コードの自動判別 (libkanji-0.87)

TeX ファイルの文字コードを自動判別し、 EUC でも SJIS でも区別することなく platex で処理できるようにしてみました。

当然ながら 100% の精度で文字コードを判別することなど、元々無理な話ですが、 世の中では nkf というソフトが実用上十分な精度を持っていることが知られています。 このコマンドをそのまま利用することにしてみました。

fopen() の代わりに popen() を用いて、 フィルタプログラムの出力を読み込むことにしました。 用いるフィルタプログラムは、環境変数 PTEX_IN_FILTER にフルパスで登録します。 フィルタの出力は JIS にしておくのが安全ですが、 PTEX_KANJI_ENC や --kanji と整合性がとれていれば動きます。

ptexenc-0.96 より --kanji オプション指定でフィルタが無効になるようにしました。

libkanji に関数を新設し、Web2c から利用するようにしました。 多くのツールには変更の必要がありません。 mendex のみ Web2c アプリでないので、libkanji を直接使うようにしました。

さて、こういう拡張を行うと、従来との互換性が問題になります。 一応大丈夫だと思っています。

拡張機能を止めることができるか
PTEX_IN_FILTER を unset するか、あるいは no を代入すれば従来どおりです。

ptexenc-0.96 より --kanji オプションを指定しても無効になるようにしました。

判定を誤ったときは?
拡張機能を止めて、手動で --kanji オプションで指定します。
頻繁に判定を誤るのですが
責任は ptex にはありません。 もっと性能のよいフィルタプログラムを探すなり作るなり:-) して下さい。
文字コードがファイルによって違う場合は?
ファイルごとに判定しますので、 例えば EUC のソースから SJIS のファイルを \input{} していても大丈夫です。
TeX ソースを他人に渡すときは
フィルタで変換した後のファイルを渡すのが安全でしょう。 今のところフィルタが動いても log にはそのことが出力されません。 どんなコマンドがいつ実行されたか、 わかるようにしたほうがよいだろうとは思っています。
nkf 以外の変換プログラムは?
利用できます。ちなみに iconv には自動判定機能がありません。 qkc なら使えそうですが Unicode には対応してないようです。
安田功氏の Utf82TeX と連携させることは可能?
自動判別とは目的が異なりますが、 フィルタに登録することができます。便利になると思います。
セキュリティーホールになる心配は?
少し心配です。今のところ PTEX_IN_FILTER の 先頭文字が '/' の場合だけ動くようにしています。 ptex のオプションでも指定できるのがよいのかもしれませんが、 心配なので様子をうかがっています。

別実装案

フィルタプログラムを登録できることは、 自由度が増す半面、悪いことにも使えそうで、若干心配ではあります。 そこで、代替案を書いておきます。 やはり nkf を利用するものの、フィルタとしては動かさずに、 文字コードの判定だけをさせるというものです。

近頃の nkf は --guess オプションが新設されて、 文字コードの判定結果だけを出力できるようになりました。 これを利用して、ptex 側は入力ファイルの文字コードを 動的に切替えればよさそうです。 文字コード変換ルーチンは ptex (libkanji) 内蔵のものを使うことになります。

こうすると自由度が下がって、Utf82TeX を登録するようなことはできなくなります。 そのほうが変な使い方をする人が現れずに、安心といえば安心かもしれません。 nkf は相当新しい必要があるので、ptetex3 に同梱することになるでしょう。

例えば /etc/passwd を外部に送り出すプログラムを nkf の名前で仕込んでみるとして、どちらが動かしやすいかを考えてみると、 ...、どちらもあまり変わらない気がしてきました。(^_^;)

今後の展開

nkf をフィルタとして使うか、文字コード判定にとどめておくか、 どちらにするか方針を定める必要があるでしょう。 私はセキュリティの専門家ではないので、どちらが安全かよくわかりません。 必要なら nkf を(外部コマンドとしてではなく) ライブラリとして ptex/libkanji にリンクすることも考えます。 もっとも jmpost は環境変数 TEX に登録されたコマンドを内部から実行するので、 現在でも同程度に安全なのかもしれません。

自動判定機構のような再現性の難しいものを入れてくれるな、 という声もあるかもしれません。 他人に TeX ソースを渡す場合は、 判定機構抜きで動くように文字コードを揃えるべきだという 啓蒙活動を行う必要も感じています。

platex-sjis のようなコマンドは、すべて廃止してもよい気がしてきました。 内部コードを EUC と SJIS で切替える必要はあるでしょうか? href 関連で微妙に動作が違うこと、 120区の SJIS の処理くらいしか差がないと思っています。

謝辞

今回の機能拡張は、岡山氏のリクエストに端を発して、 ttk 氏の活動を見据えてすり合わせを行いました。 開発のモチベーションを与えていただいた両氏に感謝します。

ご意見をどうぞ。

  • 「出力ファイルの文字コードについて」ですが1に賛成です。2では、もし仮にSJISで外字領域(120区まである)を使用している場合(pTeXでjfmさえ自前で用意すれば利用可能になっています)を想定すると、JIS(ISO-2022-JP)に変換出来ない部分が出てきてしまいます。それからファイル名の文字コードというのはどうなっていましたっけ?確か-kanji=に連動するとヤバかったような気がするのですが(ごめんなさい、いい加減な言い方で。) -- ttk 2007-02-10 (土) 23:00:19
  • ファイル名に漢字を使ってうまくいくのは、限られた条件の下だけだろうと思います。 Win なら SJIS に統一すればよいのかもしれませんが、 Linux だと Vine-3.x や 4.0 のファイルマネージャ(nautilus?)は EUC で扱いますし、 FC6 あたりだと標準で UTF-8 と、統一ができていません。 (おかげで同一ファイルシステムをデュアルブートで共有すると互いに化けます。) OS は特にファイル名の文字コード変換を行ってないようですので、 以前からうまく動いてなかったと思います。
    SJIS の120区対応も同じことを感じます。 platex-euc と共有するスタイルファイルには表現できない文字になるのですよね。 そもそも *.aux なんかに 120区文字が出力される状況はまれだと思います。 アスキーさんが明示的に対応を表明されているのなら別ですが (表明されてませんよね?)、 わざと動かなくするつもりまではなくとも、 他との兼ね合いでうまく動かなくなってもしょうがないと思います。 もちろん、より安全側に 1. を選択するというのには賛同します。 -- 土村 2007-02-13 (火) 01:03:21


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2007-11-13 (火) 14:13:27 (6000d)