誰の役にも立たない SKK メモ

日本語入力に SKK を使ってるんだけど、かといって Emacs は使っていない。そういう変態が新しいホストで SKK な日本語環境を作るときに、この前どうやったんだっけな、といちいち古い記録を調べるのはバカバカしいので、メモをまとめておくぞ、ってなもんで。

ふつーの人がマネをすると、たいてい痛い目を見るので注意。ごく稀にふつーの人にも役に立つことが書いてあったりもするかも。

インストールするもの

X は使わないので(Windows からリモートログインして使うので)、X のインプットメソッドはいらない。

インストール先は FreeBSD だが、ports はあまり使わず野良ビルドが多いので、他の OS でも参考になるだろう(だから他人はマネしちゃいかんってば)。

SKK 辞書の用意、その1

なにはなくとも辞書の用意。こいつは ports をふつーに使う。辞書サーバに cdb 形式辞書を使う dbskkd-cdb を利用するが、cdb な辞書をインストールする japanese/skk-jisyo-cdb ではなく、ふつーの japanese/skk-jisyo をインストールする。理由は後で。

小さな辞書なんかあってもどうせ使わないので、ラージ辞書だけインストールするように以下を /etc/make.conf に記述しておく。

.if ${.CURDIR} == "/usr/ports/japanese/skk-jisyo"
SKK_JISYO_TYPE=	L
.endif

make install すれば /usr/local/share/skk/SKK-JISYO.L がインストールされる。

jvim+skk

skkfep内蔵jvimをインストールする。基本的にドキュメントにあるとおり。

% tar xvzf jvim3.0-j2.1b-skk1.2.18+skkfep0.86c-kh1.2.10+ari1.00a-kh1.2.2.tar.gz

skksrch

インデックスつき辞書作成用のツールをコンパイルする。ari 本体はいらない。

% cd jvim-skkfep-ari/ari
% make skksrch
# cp skksrch /usr/local/bin

libskkfep.a

skkfep ではなく、libskkfep.a を作る。

% cd ../skkfep
% ln -s ../ari/skksrch.c
% vi config.h

config.h の最低限必要な修正は、#include "configs/solaris2.h" となっている行を OS に合わせて変更すること(今回は FreeBSD なので configs/freebsd.h に変更)、SKKFEP_LIB を #define すること(必須!)。

あとは、後のメンテのことを考えて

-# define SKKSRCH_DIC           "/usr/local/share/skk/SKK-JISYO.L"
+# define SKKSRCH_DIC           "/usr/local/share/skk/SKK-JISYO.L.idx"

に変更。それ以外はお好みで。わしの場合は #define KUTOUTEN しておく。

コンパイルする。

% make libskkfep.a

jvim

skk を使える jvim の本体をコンパイルする。

% cd ../jvim/src
% cp makjunix.mak Makefile
% vi Makefile
% diff -u makjunix.mak Makefile
--- makjunix.mak        Sat Jan 18 14:45:36 2003
+++ Makefile    Mon Dec 18 11:43:07 2006
@@ -78,7 +78,7 @@
 BINLOC = $(PREFIX)/bin

 ### Name of target
-TARGET = vim
+TARGET = jvim

 ### Location of man page
 MANLOC = $(PREFIX)/man/man1
@@ -100,7 +100,7 @@

 MANFILE = ../doc/vim.1

-HELPFILE = ../doc/vim.hlp
+HELPFILE = ../doc.j/vim.hlp

 #
 # PART 2: various choices
@@ -214,6 +214,10 @@
 #MACHINE = -DBSD_UNIX -DUSE_LOCALE -DUSE_X11
 #CC=gcc -O -Wall -traditional -Dconst= -I$(X11INCDIR)
 #LIBS = -ltermlib -L$(X11LIBDIR) -lX11
+
+MACHINE = -DBSD_UNIX
+CC=cc -O3 -pipe -Wall
+LIBS = -ltermlib

 # like generic, but with termcap, for Linux, NeXT and others (NOT TESTED YET)
 # standard cc with optimizer

コンパイルオプションは OS によっててきとーにいじる。あとは make してインストール。

% make
# make install

~/.jvimrc に最低限以下を設定すると、入力モードで CTRL-J を打つと skk な入力が可能になる。現時点では辞書がないので、かな入力だけで漢字変換はできない。

:set fepkey=J
:set fepctrl

SKK 辞書の用意、その2

skksrch をインストールしたので、jvim+skkfep で使うインデックスつき SKK 辞書を用意する。また、skkfep は Lisp を理解しないので、変換候補がふつーの文字列ではなく Lisp コードになっているものはあると邪魔。また、変換候補にコメントが入ってる形式の辞書も扱えないのでこれも邪魔。インデックスつき辞書に変換する前に、これらの邪魔なものを取り除いてやる。なお、コメントについては ports で make WITH_SKKJISYO_DELCOMMENTS=yes してやれば除去されるが、lisp の方は消えないのでどっちにしろ変換が必要。

/usr/local/share/skk/Makefile を用意。中身は以下。

all:    SKK-JISYO.L.idx SKK-JISYO.L.cdb

SKK-JISYO.L.idx: SKK-JISYO.L
	awk 'BEGIN { FS = "/" }                         \
	    {                                           \
	        if(/^[^;]/){                            \
	            f = 0;                              \
	            s = $$1;                            \
	            for(i = 2; i < NF; i++) {           \
	                if($$i !~ /^\([a-z]/) {         \
	                    sub(/;.*/, "", $$i);        \
	                    s = s "/" $$i;              \
	                    f = 1;                      \
	                }                               \
	            }                                   \
	            if(f) print s "/";                  \
	        } else {                                \
	            print                               \
	        }                                       \
	     }' SKK-JISYO.L > tmpdic
	/usr/local/bin/skksrch -index tmpdic > SKK-JISYO.L.idx
	rm -f tmpdic

SKK-JISYO.L.cdb:        SKK-JISYO.L.idx
	awk '/^[^;]/ {                                                 \
	       s = substr($$0, index($$0, " ") + 1);                   \
	       print "+" length($$1) "," length(s) ":" $$1 "->" s      \
	    }                                                          \
	    END { print "" }' SKK-JISYO.L.idx |\
	/usr/local/bin/cdb -c SKK-JISYO.L.cdb

make すると、SKK-JISYO.L.idx が作成される。SKK-JISYO.L.idx も作ろうとするが、現時点では失敗する。.idx を元の L 辞書と diff ってみてどう違うか確認してみるとよろし。

jvim で漢字変換できることを確認しておく。

dbskkd-cdb

辞書サーバのインストール。cdb に変換した辞書を利用する dbskkd-cdb を使う。jvim+skkfep は辞書ファイルを直接アクセスできるようにコンパイルしたので、別に必須じゃないけど、Windows な Meadow からも使うこともあるので、入れておくと便利(UNIX では Emacs は使わないくせに、Windows では使う変態ですが何か?)

tinycdb

本家 djb の cdb を使ってもいいんだけど、とくに理由はないがなんか互換ライブラリの気分なので、tinycdb を使う。FreeBSD なら ports からインストールできる。

% cd /usr/ports/database/tinycdb
% make
# make install

SKK 辞書の用意、その3

tinycdb をインストールしたことで cdb コマンドが使えるようになった。cdb 形式辞書を作るため、/usr/local/share/skk で再度 make する。オリジナルの SKK-JISYO.L と、それから加工された .idx と .cdb ができているはず。

dbskkd-cdb

dbskkd-cdb は FreeBSD の ports にちゃんと存在しているが、djb 版 cdb ではなく互換ライブラリの tinycdb を使うことにしたので、ports は使えない(使ってもいいけど)。まあ、ports を使うよりカンタンかもしれん。

% tar xvzf dbskkd-cdb-1.71dev.tar.gz
% cd dbskkd-cdb-1.71dev
% gcc -DSERVER_DIR=\"/usr/local/share/skk\" -O2 -pipe -I/usr/local/include -L/usr/local/lib dbskkd-cdb.c -lcdb -o dbskkd-cdb
# cp dbskkd-cdb /usr/local/libexec

tinycdb のライブラリとヘッダがちゃんとインストールしてあれば、Makefile なしでコンパイルできる。

動作確認。root で以下を実行して、「a」に対する変換候補が得られることを確認。

# echo '1a ' | /usr/local/libexec/dbskkd-cdb
1/α/エー/エイ/アー/а/ア/
dbskkd-cdb: pid 99679 end of file detected

起動スクリプト

この節はとくに変態的なことはしない。というか、dbskkd-cdb の方が変態的なのを、こちらで正気に戻す作業をする。dbskkd-cdb を使うユーザすべてに有用なはず。とくに、FreeBSD の ports でインストールしたときに出力される

Note for inetd users:

Add following line to /etc/inetd.conf
   skkserv stream tcp nowait root /usr/local/libexec/dbskkd-cdb dbskkd-cdb

If dbskkd-cdb 1.01 was running, please update your /etc/inetd.conf line.

というメッセージに騙されて、このとおり設定してしまった場合は、この節の方法で設定しなおすべし。これは明らかに間違っているので、けっして従ってはいけない(だいぶ前に ports のメンテナにメールで指摘したんだけど無視されたよ)。

dbskkd-cdb は djb なツールなので、tcpserver から起動することを想定していて、inetd から使うことなんてまったく考えていない。どちらも、いわゆるスーパーデーモンなのだが、動作上のもっとも大きな違いは、子プロセスの標準エラー出力の扱いである。

dbskkd-cdb は tcpserver での利用を前提としているので、ログを自分で syslog に投げず、標準エラー出力に垂れ流すだけである。tcpserver で使うのならばそれで問題ないが、inetd で使うときはログメッセージなのにクライアントにそのまま返されてしまう。上述の FreeBSD ports のメッセージのように、inetd.conf にそのまま dbskkd-cdb を起動する設定を書いてしまうとこの問題があってよろしくない(これでも動くが、たまたまである)。

また、dbskkd-cdb は chroot() するので、root 権限で起動する必要がある。本来は chroot() した後で低い権限に setuid()/setgid() するのだが、上述の設定はこれに必要な設定も抜けている。djb なツールは UID/GID という環境変数にユーザ ID /グループ ID を入れておくとその権限に setuid()/setgid() するというお約束がある。dbskkd-cdb も例外ではない。これが抜けていた場合、権限を放棄せず、ずっと root のまま動き続ける。

FreeBSD ports のメッセージそのままに設定してしまうと、以上の2点が問題になる。これを解消するために、ラッパースクリプトを用意してやって、そのラッパーの方を inetd.conf に設定してやる必要がある。

#!/bin/sh
SKKSERV=/usr/local/libexec/dbskkd-cdb
UID=`id -u nobody`
GID=`id -g nobody`
exec env - UID=$UID GID=$GID $SKKSERV 3>&2 2>&1 1>&3 | /usr/bin/logger -t dbskkd-cdb -p daemon.info
#exec env - UID=$UID GID=$GID $SKKSERV 2>/dev/null

これで chroot() 後の権限を nobody に変更し、かつログはクライアントに返さずに syslog に送るようになる。どうせたいしたログは取れないので、捨てちゃっていいや、という場合は exec の行をコメントアウトしてるものに入れ替える。

このラッパースクリプトを /usr/local/libexec/skkserv とすると、inetd.conf の設定はこんな感じ。

skkserv stream  tcp     nowait  root    /usr/local/libexec/skkserv skkserv

参考までに、3>&2 2>&1 1>&3 というのはシェルの標準出力と標準エラー出力を入れ替えるリダイレクト。前述のように、tcpserver は標準出力だけをクライアントに返して、標準エラー出力はログ用に使うが、inetd はどちらもクライアントに送り、そして dbskkd-cdb は tcpserver しか考慮してないので、ログを標準エラー出力に吐いてしまう。ということで、標準エラー出力(ログ)を標準出力に切り替えて /usr/bin/logger に食わせ、標準出力(変換候補)は標準エラー出力に切り替えてクライアントに返す。これが上の奇怪なリダイレクトの意味である。

inetd を kill -HUP したら、動作確認。

% telnet localhost skkserv
1a 				← a の後にスペース1個
1/α/エー/エイ/アー/а/ア/	← 「a」に対する変換候補が返ってくる
[CTRL-D]

以上で終了。おつかれさまでした。