蝉は、やがて死ぬる午後に気づいた。ああ、私たち、もっと仕合せになってよかったのだ。:2017年05月11日分

2017/05/11(Thu)

[NetBSD] BSD sed(1) fix

@BSD sed(1) a/i/c command bug

こないだのバグ以外にも何かあるやろ~と例のアレ以外のBSD sed(1)のソースを読んでてcompile.cの履歴に

  • FreeBSD (差分)
    Fix from Keith Bostic <bostic@bsdi.com> for bug in sed dealing with
    continuation lines.
    
    Submitted by:	Keith Bostic via Kirk McKusick
    
  • OpenBSD (差分)
    fix for a line continuation bug, more than a year ald. work by mckusick,
    bostic, mark@linus.demon.co.uk, davidg, and bde.
    

というのを見つけたのよね、魔球先生からボス経由での報告だけど何でNだけ20年間忘れられてるんすかね。

可能性としては

  • 黒ヤギさん(クジラ偶蹄目ウシ科ヤギ属)はお手紙を読まずに食べた
  • ハブ(爬虫綱有鱗目クサリヘビ科ハブ属)られた

のいずれかだった可能性だろけ、ああ…これFだけに報告行ってOは拾ってきたパティーンかな。

とりあえずはオレオレN6には入れておこうかとまず現象を確認するべくテストケース…

なーんも
 あ
 りま
   せんで
   し
   た。

うーん20年前という時代のせいか

  • チケットねぇ
  • テストもねぇ
  • barさんとfooさんと数珠を握って空拝む

俺らこんな村~なのでどんなバグなのかはソースから読み取るしか無いんだけど、どうやらsedのコマンドである

  • <位置>a\\\n<文字列> … <位置>の次行に<文字列>を追加
  • <位置>c\\\n<文字列> … <位置>の行を<文字列に>置換
  • <位置>i\\\n<文字列> … <位置>の行に<文字列を>追加

の部分に問題があり、<文字列>の中に「\\\n」による行継続が含まれてる場合のコーナーケースって感じ。

とりあえずソースみながら最小ケース作ってみたけど

$ cat >test.txt
aaa\^D^D
$ cat >test.sed
c\
bbb\^D^D
$ sed -f test.sed test.txt

みたいな感じ、Nだと最後の\の後に改行が無くても勝手に行継続と判断して

bbb

になってしまうんだけど、FやOはちゃんと(?)

bbb\

になる。

んー微妙過ぎてマージするか迷うレベル、もっとパッチの必要性がわかり哲也なケース思いつかんぞ…

ワイ、テキスト処理は即Perlのようなものでカネカネキンコしてしまうのでsed(1)力が低くバグの内容を理解するのに時間かかってしゃーない。

つーかGNU sedもダメっぽいんですが。

$ gsed --version
gsed (GNU sed) 4.4
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Jay Fenlason, Tom Lord, Ken Pizzini,
and Paolo Bonzini.
GNU sed home page: <http://www.gnu.org/software/sed/>.
General help using GNU software: <http://www.gnu.org/gethelp/>.
E-mail bug reports to: <bug-sed@gnu.org>.
$ gsed 'c\
> bbb\' test.txt
bbb
$

これ珍POSIX *1的にはどうなるんだろうな…

@BSD sed(1) y command 8bit clean bug

もういっこ別のバグ、こっちも20年モノ。

  • FreeBSD (差分)
    Make 'y' command 8bit clean
    PR: 6458
    
  • OpenBSD (差分)
    make y command 8 bit clean; Elmar.Bartel@informatik.tu-muenchen.de
    

この修正を取り込んでLANG=ja_JP.SJISで半角カナ扱えるまで確認したけど、ほんとはBSD sed(1)もマルチバイト対応とか必要で8bit cleanとか前世紀級の修正してる場合じゃないんだけどNE。

ところで突然関係ない話挟み込むけど、最近驚いたのGoogle Chromeって半角カナの扱いって

  • カーソル移動でカナと(半)濁点の間にキャレットが移動できない(内部的にリガチャ的な扱いになってる?)
  • なのでIMEで「パ」と入力しF7キーで半角カナに変換し、「ハ」を削って「゜」残すのができない
  • 「パ」の前にキャレット移動してDelete押しても「ハ」「゜」2文字いっぺんに消える
  • 「パ」の後にキャレット移動してBackspace押すと「゜」だけ消えて「ハ」が残る

のにビックリした。

まぁそんな話は置いておいて、マルチバイトの文字置換もできるそうGNU sedならね(タートルネック感)

$ echo 'あいうえお' | gsed 'y/あ/ア/'
アいうえお

まぁyコマンド程度ならこっちもすぐ対応できるけど、他のコマンドともなるとそもそもlibc regex(3)がアレなのでなー

そういえば昔のGSoCでmultibyte regex(3)をスクラッチで書くぜと採択されて、 結局 こんな難しいとは…と他人の書いた実装(tre)マージしただけで終わったやつ、結局はagrep(1)が使ってるだけなんやな。

sed(1)をtreのregex(3)互換レイヤだけで対応できるんかなぁ、treは内部的にwchar_tモデルっぽいけども(いちおうmbtowcが見えた)。 それならこれまでのコードの互換性から考えて、Spencer regex(3)をワイド化したnvi-1.81のアレをlibcに持ってくる方が苦労は少ない気がしないでもない。

@BSD sed(1) treats semicolon as part of label (hi, one-liner!)

もういっちょ、sed(1)で改行全部取っ払って一行に連結するのに

$ cat >test.txt
aaa
bbb
^D
$ sed -e '
:loop
N
$!b loop
s/\n//
' test.txt
aaabbb

とかラベル(ドビュッシーではない)やるのをGNU sedだとワンライナーで書けるように

$ sed -e ':loop;N;$!b loop;s/\n//' test.txt

と蝉コロンをデリミタに使えるんだけど、BSD sedは対応しとらんので

$ sed -e ':loop;N;$!b loop;s/\n//' test.txt
sed: 1: ":loop;N;$!b loop;s/\n//": unused label 'loop;N;$!b loop;s/\n//'
aaa
bbb

となってしまうのを、OpenBSDは律儀に 直してたようなのでそれもマージ。

ワイはそもそもワンライナーで実行せずスクリプト書く人なのでな…

*1:珍はPOSIXの枕詞であり語調を整えたり情緒を添える言葉で意味はありません、なお20年動くプログラムとは20年壊れたままなのである。

誤解

億年ぶりにはてブに※ついてる思ったら

ものすごい誤解だ、釣りだったらスマン