2008/07/25(Fri)
○ 昨日
現場の人たちとオサレ系中華料理屋。
お一人様\4500は全て凝った内装の償却に回るようで
出てきた料理は人生の中でワースト3に入るレベルの不味さ。
○[NetBSD] i18n fold(1)
new developerのahoka氏からuserlandもがしがしi18nするぜーとメールもらた。
まずfold(1)を
書き直してたぜぃ! レビューおながいちゅーことなんだが
これwcwidth > 1の場合の動作が壊れまくりんぐ。
んなわけで他実装の挙動から。
coreutil-6.9-17.fc8のfold(1)はいまどき珍しいことにi18n化されとらんのな。
fold --cjkwidthとかアレなものが生えてないかwktkした俺の期待を返せwww
Solaris 8での動作。
$ cat test.txt
ハヒフヘホ
$ fold -w 2 < test.txt
ハ
ヒ
フ
ヘ
ホ
$ fold -w 3 < test.txt
ハ
ヒ
フ
ヘ
ホ
$ fold -w 4 < test.txt
ハヒ
フヘ
ホ
$ fold -w 5 < test.txt
ハヒ
フヘ
ホ
一方、ahoka氏のfold(1)。
$ cat test.txt
ハヒフヘホ
$ fold -w 2 < test.txt
ホ
$ fold -w 3 < test.txt
ハ
フ
ホ
$ fold -w 4 < test.txt
ハ
フ
ホ
$ fold -w 5 < test.txt
ハヒ
ヘホ
この出力結果見て
カップスタ~食べたその日か~ら~
と歌いだす香具師はオッサン。
軽くソース流し読み。
getchar(3) -> getwchar(3)への書換しとるが、これじゃ-bオプションだめぢゃん。
getchar(3)しつつmbrtowc(3)使わないと何バイト読んだか計算できないってば。
いきなりオワタ\(^o^)/ ぜんぶかきなおしです*1
そいとfwrite(3)代わりにwprintf(3)使うのはダメ。
理由はformat stringのparseコストで無駄に性能が落ちるのが一点。
それとwprintf(L"%.*ls")ちゅーのはL'\0'まで出力してるわけで
multibyte stateは必ず初期化されてしまう、つまりstateful encodingの場合
initial stateに戻す為のescape sequenceが冗長に出力されてしまうのよね。
まぁwprintf(L"%.*ls\n")のように改行を含んでる部分はすでに
initial stateに戻ってるので問題ないといえなくもないけど
ここはやっぱりパラノイアでいこうぜ。
あとどーでもいいけどfold-m10nって、i18nかm17nの間違いだよな。
まぁcoreでもi17nとかtypoすることあるのでこれはまぁしゃあねぇか。
つか既にjoerg氏が
指摘済み*2だったにゃ。
○ i18n fold(1) その2
fold(width)の中の
while ((ch = getwchar()) != WEOF) {
...
}
は
size_t bytes, n, len, width;
mbstate_t st;
char buf[BUFSIZ], *s;
wchar_t wc;
bytes = 0;
mbrtowc(NULL, NULL, 0, &st);
while ((n = fread(&buf[0], 1, BUFSIZ, stdin)) > 0) {
for (s = &buf[0]; n > 0; s += len, n -= len, bytes = 0) {
len = mbrtowc(&wc, s, n, &st);
if (len == (size_t)-2) {
bytes += n;
break;
} else if (len == (size_t)-1) {
abort();
} if (wc == L'\0') {
while (s[len++] != '\0');
}
bytes += len;
width = wcwidth(wc);
...
}
}
ややこしいけど、こんな感じでぐるぐるする必要があるやね。
○[NetBSD] i18n fold(1) その3
よく考えたら-bで80byteで折り返しするとゆーのは
input側を80byte数えるのではなくoutput側なのだよな。
ちゅうわけで入力に冗長なescape sequenceが合った場合
そいつはカウントしなくておkなはずだ、うぉぉぉ勘違い。
つまりSolarisのやり方でおk、ahoka氏のfold(1)の場合new_column_withd()で
char dummy[MB_LEN_MAX];
size_t n;
if (!count_bytes) {
....
} else {
n = wctomb(&dummy[0], wc);
_DIAGASSERT(n != (size_t)-1);
col += n;
}
ってな感じでいけるはず。
まぁでもstateful encodingの場合はL'\n'の直前の
escape sequenceの長さをカウントしなけりゃならんし
もうちょいゴニョゴニョせんとだめだけど。