The Man Who Fell From The Wrong Side Of The Sky:2007年9月分

2007/9/6(Thu)

[NetBSD] pkgsrc/print/acroread7

acroread7でもフォントが変ですか。
うちでは 何もしなくてもちゃんと表示できてるんだよなぁ。
一応以下の設定方法で変更できると思います。

acroread5まではMotifアプリだったのでUIのフォントは~/.Xdefaultsで指定できました。
詳しくは${LOCALBASE}/Acroread5/Reader/intellinux/app-defaults/AcroRead参照してください。

acroread7からはGTK2アプリになったので~/.gtkrc-2.0で指定します。

style "hoge" {
    font_name="Gothic"
}
widget_class "*" style "hoge"

font_nameの右辺にfirefoxと同じくmonafontを指定してます。

もうちょい細かい指定をしたい場合、pangorcとかpango*.aliasの設定なんかも必要ですが
それは又の機会に(まだちゃんと調べてないともいう)。

2007/9/7(Fri)

[C言語] iconv(3)によるコード変換

http://code.nanigac.com/source/view/20 ネタ。

戻り値(size_t)-1の場合、errnoがEINVALあるいはE2BIGの場合にはリスタート可能なんだけど
そこんとこの処理を端折って一律エラー終了してるからあんまりいい例じゃない罠。

それとiconvの場合、変換前/後のバイト列を固定長で確保するのは正直お薦めしない。
↓ readerから読込んだバイト列をiconv(3)で変換してwriterに書き込む「悪い」サンプル。

	FILE *reader, *writer;
	const char *from, *to;
	iconv_t cd;
	char inbuf[BUFSIZ], outbuf[BUFSIZ], *in, *out;
	size_t inbytes, outbytes, irreversible, ret, nconv;

	irreversible = (size_t)0;
	cd = iconv_open(to, from);
	if (cd == (iconv_t)-1)
		errx(1, "can't iconv");
	while ((inbytes = fread(inbuf, 1, sizeof(inbuf), reader)) > 0) {
		in = &inbuf[0];
		while (inbytes > 0) {
			out = &outbuf[0];
			outbytes = sizeof(outbuf);
			ret = iconv(cd, &in, &inbytes, &out, &outbytes);
			nconv = sizeof(outbuf) - outbytes;
			if (ret == (size_t)-1) {
				switch (errno) {
				case EINVAL:
					… (A)
					break;
				case E2BIG:
					… (B)
					break;
				default:
					errx(1, "can't iconv");
				}
			} else {
				irreversible += ret;
			}
			if (nconv > 0)
				fwrite(outbuf, 1, nconv, writer);
		}
	}
	…

inbuf/outbuf を固定長で確保してるんだけど、これだと (A) (B) の2個所で困ることになる。

つーわけでちゃんと残らず余さず文字コード変換したいなら、動的確保すべし。
この コードを参考にしてみてください。

(追記)
コメントへの返答は 9/8のメモに書いたのでそっちもどうぞ。

*1:厳密には stateful encoding で冗長な escape sequence が続く場合、MB_CUR_MAX は無限大になるんだけどね。
*2:fromのワイド文字数 : toのワイド文字数ね、バイト数の比じゃないです。
*3:んでも mbstate_t と違って iconv_t はコンストラクタ/デストラクタあるんだし動的確保しても良かったと思うんだけどね。

Sony α-700

α-10という噂だったけど、伝統の7ナンバー復活、そつなくまとまってていい感じ。

まあ俺は銀塩であと10年は戦う予定(フィルムがあれば、ね)なので、デジには興味ないんだけど。
α-100になかった シンクロターミナルがついたので
紛失しやすいこれのキャップがまた入手可能になるのはいいことだ。

しかし肝心のレンズの方はDT(APS-C専用設計)3本しかもOEMしか発表ないんか。
マスター…バーボン(以下略
噂の 24mm/F1.4 と 24-70mm/F2.8G には期待してたんだけどなぁ。

2007/9/8(Sat)

続 iconv(3)によるコード変換

shiroさんからコメントもらったので。

EINVALになったら残った入力をシフトして、出来たすき間に新しい入力を

読めば良い(状態遷移を起こす入力は消費されるから、すき間が出来ない
ということはない、と思う)

状態遷移 = escape sequence は必ず出現はしませんし。
Unicode Normarization Form Composition/Decompositionによる変換
JIS2004の丸付き数字とUnicodeとの変換の際のように
N:1変換が行われる場合、隙間が無くなる可能性があります。

E2BIGの場合も、出力バッファをフラッシュしてから処理を続行することを念頭に置いている。

これも同様ですね、1:1ならoutbufに最低でもMB_LEN_MAX保証すれば良さそうですが
1:N変換の時にはinは完全に変換できるバイト列であっても
outbufには1バイトも書き込めない可能性があり、無限ループに陥ります。
以下、GNU libiconvの//TRANSLITの挙動。

#include <iconv.h>
#include <errno.h>

int
main(void)
{
	iconv_t cd;
	char *in = "\\u3231", *out, outbuf[3];
	size_t nin, nout;
	cd = iconv_open("EUC-JP//TRANSLIT", "C99");
	if (cd == (iconv_t)-1)
		exit(1);
	nin = strlen(in);
	out = &outbuf[0];
	nout = sizeof(outbuf);
	printf("%d\n", iconv(cd, &in, &nin, &out, &nout));
	printf("%s\n", strerror(errno));
	printf("%.*s\n", sizeof(outbuf) - nout, outbuf);
}

\\u3231は//TRANSLITで

(株)

に転写されて変換されますが、outbufのサイズがEUC-JPのMB_CUR_MAX=3なら

(株

までは書き込めるはずなんだけど、1バイトもoutに書き込まれないんですよ。
(これは転写した文字は不可逆変換とカウントしてiconvの戻り値として返す仕様との整合を取る為ですな)

このあたりの事情を考慮して入出力バッファですらdynamic allocationが必要ですってのが私の主張。
まあ元々の仕様は固定長バッファを想定して策定されたんだとは思いますが。

"実用上は" と "理論上は" の温度差もあるかも。
固定長であってもある程度のサイズがあれば実用上問題無いからねぇ。
100%問題無いコードを書くとこうなりますよ、ってことで。

2007/9/16(Sun)

連休一日目

━╋━ ┃━╋:
  ┗┓ ┃┏╋
  ━┛ ┗┗┛ の鴨川に遊びに行ってきた。

連休二日目

箱根大湧谷で温泉卵食ってきた。

2007/9/17(Mon)

連休三日目

城ヶ島ぶらぶら。

2007/9/18(Tue)

[NetBSD] isspace(3)

rune(3)の呪いネタ。

そうか UTF-8 では isspace(0xA0) は偽にならんといかんのだな。

あーUTF-8ではU+00A0は2byte(\xC2\xA0)ですねぇ、私も完全に勘違いしてました。
いっそis*の中でbtowc(3)呼んでからrune(3)に渡すとかでお茶濁したい気分。

ちゃんとやるならis*もisw*もctype module側で実装するとかですかねぇ。

ちなみに手元のSolaris8はisspace((int)0xA0)に真を返すのでバグってますな。

一方Linux(FC7)はisspace((int)0xA0)に偽を返しますが
これはlocaledef srcではU+00A0はpunctになってるからかな。
ソース
もしかすると同じバグ持ってるかも。

[NetBSD] iconvctl(3)

Citrusでも実装してくれーというお手紙が届いたんだけど、どうしたもんかねぇ。

2007/9/19(Wed)

[NetBSD] 続isspace(3)

昨日の rune(3)の呪い問題用のpatchは一番手っ取り早いのはこんな感じかなぁ。
/distfiles/citrus/NetBSD/patch-fix_isfunc_problems

やっぱり LC_CTYPE データベースにキャッシュしておくのが理想。

なんでLC_CTYPEに追い出す為にmklocale(1)がctype moduleをloadして
btowc(3)でsingle byteかmultibyteかのチェックをして_RUNETYPE_W bitを立てるかんじ。
本当は_C_ctype_[]とか_C_to{upper,lower}_[]の中身そのままLC_CTYPEに
持ってる方がいいんだろうけど、サイズが微妙なところ。

LC_CTYPEのfile magicのバージョンを変更して
古いLC_CTYPEの場合にはruneglue.cの中でbtowc(3)使って
チェックを行う、ってとこまで書いた方がいいのかな。

AIR EDGE

つなぎ放題x4よりx8の方が期間限定 だけど月額使用料が安くなってるので
AX530INに機種変更してきたお。
2年縛りっても当面ExpressCardなマシン買う予定ないしねぇ。

2007/9/20(Thu)

[NetBSD] isspace(3) その3

げぇー*1cross-toolsのことはすっかりと抜けてた。

とするとLC_CTYPEデータベースの互換性を維持する為に
将来実装するlocaledef(1)はctype module呼び出して
charmap(5)をrune_tに変換するとゆーアイデアも使えないということかぁ。
repertoiremapあたりで何とかするしかないのかな。

まぁ最終手段はlocaledef(1)をcross-toolsにしないとかか。
debian GNU/Linux(これで正式名称ですか?わかりません><)みたいに
/usr/share/i18n と /usr/share/charmap にそれぞれlocale srcだけインストール。
dpkgのpost install hook scriptがlocaledef(1)を呼んでLC_CTYPE他をビルド。
…あかん、syspkgが完成してるならまだしも。現状じゃぁetcupdate(8)くらいしかhookないよなぁ。

ところで__xpg4_setrunelocale()が成功してるとはいえ、setlocale()が終わってないのに
wctob(3)を直接呼んでしまうのはのはちょっと嫌ですね。
いちおreentrant考慮して__xpg4_setrunelocaleが_RuneLocaleなり_citrus_ctype_tを返すように拡張して
それを__runetable_to_netbsd_ctype()に渡した方がいいかもですねぇ。
また_citrus_ctype_wctob()でなく_citrus_ctype_btowc()? どっちでもいいのか。

*1:恐怖新聞AA省略

[i18n] localedef(1)

この辺の書式ってきっちりきまってるものなのでしょうか
Single UNIX(R) Specificationですね *1、opengroupにあるドキュメント読むと良いかと。
http://www.opengroup.org/onlinepubs/009695399/utilities/localedef.html
http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap06.html#tag_06_04
http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html#tag_07_03

それとISO2022を中途半端に考慮した拡張案が↓ISO/IEC TR14652として出てます。
http://open-std.org/JTC1/SC22/WG20/docs/n972-14652ft.pdf
repertoiremapとかLC_IDENTIFICATION他の追加仕様はglibcは既に実装してますな(<include>と<iso2022>は除く)。

コメントに%を使ってるのは別にPostscriptは関係ないです。デフォルトは#ですが自由に変更できるのです。
localedef srcの先頭に

comment_char +
escape_char -

と宣言すればコメントは+、エスケープ(デフォルトは\)は-になります。
なのでyacc/lexで実装しようとするとめんどくさくなるんですよね。
私が書きかけで放置してる実装ではyacc/lex使わずに、NetBSDのfparseln(3)で実装してますが。

元々X/Openが提供してたlocaledef/charmapのソース(今は喪失、ftp://dkuug.dk/i18n/WG15-collection/)で
こんな機能もあるよというサンプルとして、コメントに%、エスケープに/を使ってたのを
glibcはそのまま持ってきたんじゃないかなと。

そいとwctypeで"ucs4-compaliant"というのは草www生やすようなネタですが
wctype(3)/wctrans(3)はuser defined classという仕組みがあるので、自分でlocaledef src書けばこんなのも実装可能ですね。
沼田さんのとこのUI-OSF日本語環境実装規約では、jkana、tohiraなんかが定義されてたかと。
ちなみにCitrusではuser defined classは未実装です。

んでこのネタ元の
http://mail-index.netbsd.org/tech-userlevel/2006/04/02/0000.html
http://mail-index.netbsd.org/tech-userlevel/2006/04/03/0000.html
あたりの話、未だ引き摺ってて一昨日半年ぶりにcommitしたら
すかさずjoerg氏からGNU libiconv emulationをCitrusでも実装キボンヌというメールが飛んできた。
お返事どうしようかなぁ。

将来的にはcharmap + repartoiremapでmkcsmapper(1)をlocaledef(1)に統合したいね。
正直charmapとcsmapperを同時にメンテするのは地獄だぜ、フゥハハハー。

*1:MacOS Xのようにlocaledef(1)を実装せずにmklocale(1)でも最近はUNIX(R)が貰えるらしい...と思ったら今はあるっぽいな。そのうち調べよう。

[OpenBSD] libc old ctype table

OpenBSDはold ctype tableを_RuneLocaleに持たせてcacheが有効 && reentrantになるようにしてんのね。
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/locale/runetype.h?rev=1.4&content-type=text/x-cvsweb-markup
これもNetBSD取り込んだほうがよさげですな。

2007/9/21(Fri)

[OpenBSD] pcc(1) bug

PCCがOpenCVSをうまくコンパイルできない件

gcc -S test.c出力されたtest.sの結果

cvs_cmd_add:
	.long	1
	.byte	97
	.byte	100
	.zero	14
	.byte	110
	.byte	101
	.byte	119
	.zero	13

pcc -S test.cで出力されたtest.sの結果

cvs_cmd_add:
	.byte 97
	.byte 100
	.zero 14
	.byte 110
	.byte 101
	.byte 119
	.zero 17

cvs_cmd_add.cmd_op = 1 が消えてしまってるのでoffsetが4byteズレてますねぇ。
2次元以上の配列を使うと出現する模様。
その辺を調べると良さそうですなぁ。

[OpenBSD] 続 pcc(1) bug

1次元配列

test.c
#include <stdio.h>
struct foo {
	int     bar;
	char    buz[1];
};
struct foo foo = {
	1234,
	{ 'A' }
};
int main(void)
{
	printf ("foo.bar: %d\n",  foo.bar);
	return 0;
}
$ /usr/pkg/libexec/ccom -Xii test.c

beginit(), sclass EXTDEF
asginit 0x807517c
0x807517c) ICON, 1234, 0, int, 0x0, 0x8073668
stkpush: 'foo' EXTDEF strty newtype int
findoff: off 0
init stack:
0x808104c) 'bar' int MOS ninit=0 soff=0
  0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel bar
setval: off 0 fsz 32 p 0x807517c
stkpop
init stack:
0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel buz
ilbrace()
stkpush: 'foo' EXTDEF strty newtype ARY char
init stack:
0x808107c) 'buz' ARY char MOS arydim=1 ninit=0 stsize=8 { soff=32
  0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel buz
asginit 0x8075150
0x8075150) ICON, 65, 0, int, 0x0, 0x8073668
stkpush: 'buz' MOS ARY char newtype char
findoff: off 32
^^^^^^^^^^^^^^^
init stack:
0x8081098) 'buz' char MOS ninit=0 soff=32
  0x808107c) 'buz' ARY char MOS arydim=1 ninit=0 stsize=8 { soff=32
    0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel buz
setval: off 32 fsz 8 p 0x8075150
^^^^^^^^^^^^^^
stkpop
init stack:
0x808107c) 'buz' ARY char MOS arydim=1 ninit=1 stsize=8 { soff=32
  0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel buz
asginit 0x0
irbrace()
stkpop
init stack:
endinit()

2次元配列

test.c
#include <stdio.h>
struct foo {
	int     bar;
	char    buz[1][1];
};
struct foo foo = {
	1234,
	{ { 'A' } }
};
int main(void)
{
	printf ("foo.bar: %d\n",  foo.bar);
	return 0;
}
$ /usr/pkg/libexec/ccom -Xii test.c

beginit(), sclass EXTDEF
asginit 0x80751d4
0x80751d4) ICON, 1234, 0, int, 0x0, 0x8073668
stkpush: 'foo' EXTDEF strty newtype int
findoff: off 0
init stack:
0x8081054) 'bar' int MOS ninit=0 soff=0
  0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel bar
setval: off 0 fsz 32 p 0x80751d4
stkpop
init stack:
0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel buz
ilbrace()
stkpush: 'foo' EXTDEF strty newtype ARY ARY char
init stack:
0x8081084) 'buz' ARY ARY char MOS arydim=1 ninit=0 stsize=8 { soff=32
  0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel buz
ilbrace()
stkpush: 'buz' MOS ARY ARY char newtype ARY char
init stack:
0x80810a0) 'buz' ARY char MOS arydim=1 ninit=0 stsize=8 { soff=32
  0x8081084) 'buz' ARY ARY char MOS arydim=1 ninit=0 stsize=8 { soff=32
    0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel buz
asginit 0x807517c
0x807517c) ICON, 65, 0, int, 0x0, 0x8073668
stkpush: 'buz' MOS ARY char newtype char
findoff: off 0
^^^^^^^^^^^^^
init stack:
0x80810bc) 'buz' char MOS ninit=0 soff=32
  0x80810a0) 'buz' ARY char MOS arydim=1 ninit=0 stsize=8 { soff=32
    0x8081084) 'buz' ARY ARY char MOS arydim=1 ninit=0 stsize=8 { soff=32
      0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel buz
setval: off 0 fsz 8 p 0x807517c
^^^^^^^^^^^^^
stkpop
init stack:
0x80810a0) 'buz' ARY char MOS arydim=1 ninit=1 stsize=8 { soff=32
  0x8081084) 'buz' ARY ARY char MOS arydim=1 ninit=0 stsize=8 { soff=32
    0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel buz
asginit 0x0
irbrace()
stkpop
init stack:
0x8081084) 'buz' ARY ARY char MOS arydim=1 ninit=1 stsize=8 { soff=32
  0x80724ac) 'foo' strty EXTDEF ninit=0 stsize=64 soff=10 curel buz
asginit 0x0
irbrace()
stkpop
init stack:
endinit()

pass1は上手くいってるようなので、cgram.yは無実っぽいんだが
init.cの中で2次元配列に対するfindoff()の動作が変な気がする。
これ bar <-> buz との offsetでなくて buz <-> buz[0] とのoffsetが返されてる希ガス。
いやまぁ、ちゃんとソース読んでないのでよう知らんけど。

[NetBSD] pcc(1) bug その3

ついさっきNetBSDにもsrc/dist/pccとしてCVS importされよったので、他OS事ではなくなった模様 orz。
どーやらさっきの予想はあたってるっぽい、init.cの429行目

429                         if (il->off == off) {
430                                 /* replace */
431                                 nfree(il->n);
432                                 il->n = p;
433                         } else

offsetが同じなのでbarのnodeはbuzのnodeで上書きされちゃってるということですな。

2007/9/22(Sat)

[NetBSD] GNU libiconv emulation

joerg氏に今何の機能が足りてなくて、何のアプリで困ってるのか再確認するメール投げた。

忘れたぜwwwってちょ、おまwwwwwヒドスwwwww
xmllint/xmlprocで問題があった鴨って、ちょwwwPyXMLはiconv(3)使ってなくね?

以下おさらいの意味で、GNU libiconvとCitrus iconvの挙動の違い。

(A) GNU libiconvとCitrus iconvは、変換を行うbyte sequenceが不正
(mbrtowc(3)に食わせるとEILSEQを返すような場合ね)である時は
同じ動作をします、ま当然ですけどね、フフン。

[test.c]
#include <assert.h>
#include <errno.h>
#include <iconv.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int
main(void)
{
        iconv_t cd;
        char buf[BUFSIZ];
        char *s, *in, *out;
        size_t n, nin, nout, ret;

        s = "ABCD\xa0"; /* ABCD + illegal */
        n = strlen(s);

        cd = iconv_open("US-ASCII", "UTF-8");
        if (cd == (iconv_t)-1)
                abort();

        in = s;
        nin = n;
        out = &buf[0];
        nout = sizeof(buf);

	errno = 0;
        ret = iconv(cd, (const char **)&in, &nin, &out, &nout);
        printf("ret: %d\n", ret);
        printf("%s\n", strerror(errno));
        printf("in - converted:[%.*s]\n", n - nin, s);
        printf("in - illegal:[%.*s]\n", nin, in);
        printf("nin:[%zd]\n", nin);
        printf("out:[%.*s]\n", sizeof(buf) - nout, buf);
        printf("nout:[%zd]\n", nout);

        return 0;
}

* GNU libiconvの場合(A-1)
$ CFLAGS="-I/usr/pkg/include" \
> LDFLAGS="-L/usr/pkg/lib -liconv -Wl,-rpath=/usr/pkg/lib" make test
$ nm test | grep iconv
         U libiconv
         U libiconv_open
$ ldd test
test:
        -liconv.2 => /usr/pkg/lib/libiconv.so.2
        -lc.12 => /usr/lib/libc.so.12
$ ./test
ret: -1
Illegal byte sequence
in - converted:[ABCD]
in - illegal:[\xa0]
nin:[1]
out:[ABCD]
nout:[1020]

* Citrus iconvの場合(A-2)
$ rm -f test && make test
$ nm test | grep iconv
         U iconv
         U iconv_open
$ ldd test
test:
        -lc.12 => /usr/lib/libc.so.12
$ ./test
ret: -1
Illegal byte sequence
in - converted:[ABCD]
in - illegal:[\xa0]
nin:[1]
out:[ABCD]
nout:[1020]

inの先頭は不正なバイト列を指し、戻り値は(size_t)-1で
errnoにはEILSEQがセットされます。

(B)しかし一方で

ケースでは、両者は異なる動作をします。

[test.c.diff]
--- test.c.orig    2007-09-22 04:45:32.000000000 +0900
+++ test.c 2007-09-22 04:45:19.000000000 +0900
@@ -13,7 +13,7 @@
        char *s, *in, *out;
        size_t n, nin, nout, ret;
 
-       s = "ABCD\xa0"; /* ABCD + illegal */
+       s = "\xc2\xa0""ABCD"; /* U+00A0 + ABCD */
        n = strlen(s);
 
        cd = iconv_open("US-ASCII", "UTF-8");

* GNU libiconvの場合(B-1)
$ patch -p0 < test.c.diff
$ CFLAGS="-I/usr/pkg/include" \
> LDFLAGS="-L/usr/pkg/lib -liconv -Wl,-rpath=/usr/pkg/lib" make test
$ ./test
ret: -1
Illegal byte sequence
in - converted:[]
in - illegal:[\xc2\xa0ABCD]
nin:[6]
out:[]
nout:[1024]

* Citrus iconvの場合(B-2)
$ rm -f test && make test
$ ./test
ret: 1
Undefined error: 0
in - converted:[\xc2\xa0ABCD]
in - illegal:[]
nin:[0]
out:[?ABCD]
nout:[1019]

GNU libiconvは不正なbyte sequenceに出会ったときと同じ動作をします。
一方Citrus iconvは?や〓といった代替文字に置換して
戻り値として不可逆変換な文字数を返します。

IEEE Std 1003.1-2001には、このケースについて

``If iconv() encounters a character in the input buffer that is valid,
but for which an identical character does not exist in the target codeset,
iconv() shall perform an implementation-defined conversion on this character.''

と書かれていて、実装依存でいいから何かしら変換をしろとあります。
つまり、GNU libiconvが勝手に変換を止めてしまうのは規格違反の疑いがあります。

しかし、libxml2などではこのGNU libiconvの規格違反な動作に依存した
コーディングがあるらしく、 このスレッドで議論になってます。
一方の当事者、Bruno Haible氏も登場しますな。
私の投げたpatchを適用してみましょう。

[test.c.diff]
--- test.c.orig    2007-09-22 04:53:35.000000000 +0900
+++ test.c 2007-09-22 04:52:12.000000000 +0900
@@ -11,7 +11,7 @@
        iconv_t cd;
        char buf[BUFSIZ];
        char *s, *in, *out;
-       size_t n, nin, nout, ret;
+       size_t n, nin, nout, ret, dummy;
 
        s = "\xc2\xa0""ABCD"; /* U+00A0 + ABCD */
        n = strlen(s);
@@ -26,7 +26,8 @@
        nout = sizeof(buf);
 
        errno = 0;
-       ret = iconv(cd, (const char **)&in, &nin, &out, &nout);
+       ret = __iconv(cd, (const char **)&in, &nin, &out, &nout,
+       __ICONV_F_STOP_NO_CORRESPONDING_CHAR, &dummy);
        printf("ret: %d\n", ret);
        printf("%s\n", strerror(errno));
        printf("in - converted:[%.*s]\n", n - nin, s);

* Citrus iconv(C-1)
$ cd /usr/src
$ patch -p0 -E -l < ~/patch-iconv
$ cd lib/libc
$ make depend all install
$ cd ../i18n_module/iconv_std
$ make depend all install
$ cd
$ patch -p0 < test.c.diff
$ make test
$ ./test
ret: -1
Illegal byte sequence
in - converted:[]
in - illegal:[\xc2\xa0ABCD]
nin:[6]
out:[]
nout:[1024]

GNU libiconvの挙動をemulateし、C-1とB-1の結果が同じになりました。
しかしまあ、こんなpatchを下手にcommitして将来縛られたくないので絶賛放置中。

余談ですが、iconv(3)の戻り値の不可逆変換された文字数は
(A)のケースと絡むと信用できないので注意が必要。

[test.c.diff]
--- test.c.orig	2007-09-22 04:53:35.000000000 +0900
+++ test.c	2007-09-22 13:05:09.000000000 +0900
@@ -13,7 +13,7 @@
 	char *s, *in, *out;
 	size_t n, nin, nout, ret;
 
-	s = "\xc2\xa0""ABCD"; /* U+00A0 + ABCD */
+	s = "\xc2\xa0\xa0"; /* U+00A0 + illegal */
 	n = strlen(s);
 
 	cd = iconv_open("US-ASCII", "UTF-8");
* Citrus iconv(D-1)
$ make test
$ ./test
ret: -1
Illegal byte sequence
in - converted:[\xc2\x0]
in - illegal:[\xa0]
nin:[1]
out:[?]
nout:[1023]

戻り値として不正な変換が行われたことを表す(size_t)-1が返り
不可逆変換された文字数1は失われてしまいます。
まあ普通はEILSEQだったらそこで終了なはずなので
失われてもいいという判断なのですが、どうも無理矢理keep goingしたがる
アプリが世の中多いようで。

2007/9/23(Sun)

[OpenBSD] pcc(1) bug

直った模様、すばらしい。

[OpenBSD] pcc(1) bit field bug

まだあるらすい。

#include <stdio.h>
struct {
	int bar : 1;
} foo = {
	1
};
int
main(void)
{
	printf("%d\n", foo.bar);
}

[GCCの場合]
$ ./test
-1
[PCCの場合]
$ ./test
1

pcc -Sで吐いたアセンブラ。

	.data
	.align 4
	.globl foo
foo:
	.byte 1
	.zero 3
	.text
	.globl main
	.align 4
main:
	pushl %ebp
	movl %esp,%ebp
.L88:
	movl foo,%eax
        ^^^^^^^^^^^^^
	andl $1,%eax
        ^^^^^^^^^^^^
	pushl %eax
        ^^^^^^^^^^
	pushl $.L90
	call printf
	addl $8, %esp
.L89:
	leave
	ret
	.section .rodata
.L90:
	.ascii "%d\12\0"

printf(3)にunsignedで渡してますなぁ。

bit field 32が変なのはまだ見てないけどinit.cが腐ってるげ。

連休1 - 2日目

また胃がチクチクしてきて寝たきり、ピロリ菌は強かった。

2007/9/24(Mon)

[OpenBSD] pcc(1) bit field bug その2

昨日の続き、前回の例であれば

    andl $1,%eax

ではなくて

    sall $31,%eax
    sarl $31,%eax

となればいいはず、つまり以下のようなassemblerを吐けるようになれば多分おk。

local2.cをまだ読んでないのでpatchまではご容赦をば。

(追記)
http://marc.info/?l=pcc-list&m=119063203603031&w=2
Otto氏は実装依存だからどうでもいいんじゃね?とおっしゃってる模様。
実装依存って

struct foo {
    signed int bar : 2;
};

の場合

って話で、unsignedと同じ扱いになっていいって話では無い気がするのだが、
(なのでsignedで1bitのみ宣言すると古い実装ではエラーだか警告になる)
ちと自信が無い、調べるのマンドクサ('A`)

まあどっちみちunsignedで宣言しないと怖いよ、ということだけは覚えておくべきネタ。

GCCのドキュメントには

The ISO C standard leaves it up to the implementation whether a bit-field
declared plain int is signed or not. This in effect creates two alternative dialects of C.

ってあるね、plain intってsignedもunsignedもつかないってことだよな?
んでplain intに対しては

-fsigned-bitfields
-funsigned-bitfields
-fno-signed-bitfields
-fno-unsigned-bitfields
    These options control whether a bit-field is signed or unsigned, when the
declaration does not use either signed or unsigned. By default, such a bit-field is
signed, because this is consistent: the basic integer types such as int are signed types.

と制御可能なわけだ。

んでpcc(1)はちゃんと明示的に符号をつけても

struct {
    signed int bar: 1;
} foo = {
    1
}
int
main(void)
{
    printf("%d\n", foo.bar);
}

$ ./test
1

となるわけで、やっぱりこの動作はおかしいと思うが、自信ナサスwwwwww

さて、どしたもんかね...ちゃんと仕様書調べないとなぁ。

連休3日目

H2ブロッカー胃腸薬の助けを借りてなんとか外出、スーツと靴を新調してきた。

2007/9/26(Wed)

[OpenBSD] pcc(1) _Bool bug

tamoさんがpcc-listに投げてる _Bool問題

これ現行では

char b = 1;
int
main(void)
{
        b += 2;
}

の場合は

        .data
        .globl b
b:
        .byte 1
        .text
        .globl main
        .align 4
main:
        pushl %ebp
        movl %esp,%ebp
.L12:
        movb b,%al
        addb $2,%al
        ^^^^^^^^^^^
        movb %al,b
.L13:
        leave
        ret

となるのを

#include <stdbool.h>

_Bool b = true;
int
main(void)
{
        b += 2;
}

とした場合には_Bool型を考慮して

        .data
        .globl b
b:
        .byte 1
        .text
        .globl main
        .align 4
main:
        pushl %ebp
        movl %esp,%ebp
.L12:
        movb b,%al
        incb %al
        ^^^^^^^^
        movb %al,b
.L13:
        leave
        ret

つーassemblerを吐くような対応が入ってるっぽい、んで

--- test.c.orig    2007-09-25 21:25:32.000000000 +0900
+++ test.c 2007-09-25 21:25:37.000000000 +0900
@@ -4,5 +4,5 @@
 int
 main(void)
 {
-       b += 2;
+       ++b;
 }

の場合は何もしなくても

        incb %al

になるので、こっちには何も対応を入れてないっぽいね。

これはそもそも_Boolに対してincbを使うのが間違いで、どっちも一律

--- test.s.orig    2007-09-25 21:24:54.000000000 +0900
+++ test.s 2007-09-25 21:26:57.000000000 +0900
@@ -10,7 +10,7 @@
        movl %esp,%ebp
 .L12:
        movb b,%al
-       incb %al
+       movb $1,%al
        movb %al,b
 .L13:
        leave

つーassemblerを吐かないと駄目ってことだと思う、 マイナス演算子の場合は当然
movb $0,%al
ね。

2007/9/27(Thu)

[OpenBSD] pcc(1) _Bool bug その2

ここか。

左辺を 0 or 1に書き換えてるので昨日書いた挙動になってるわけね。
さて、どう直したものか。

[NetBSD] isspace(3) その4

パッチ
これで問題なさそうならcommitしちゃいますかね、もうちょいお掃除したい気もするけど。

2007/9/28(Fri)

最近買ったもの

2007/9/29(Sat)

[NetBSD] isspace(3) その5

commitしますた、そのうちde __P()とかANSIfyとかu_intXX_t->uintXX_tもしないとな。

2007/9/30(Sun)

[OpenBSD][DragonFlyBSD] Citrus patch

NetBSD-currentに追従してみたが、最近仕事してないのバレバレ。
まだどっちもbuildの確認すらしてないのでexperimentalってことで。
/distfiles/citrus/OpenBSD/experimental/
/distfiles/citrus/DragonFlyBSD/experimental/

そいやいつのまにかNetBSD-currentからrune_tが消えてんのね。
他の*BSDも同様に対処したわけだが、大丈夫かどうかは知らん。

こないだjoerg氏にDragonFlyBSDへのmergeを相談したんだけど
作業してる時間NE-のでhasso氏に相談してちょ、との事なんだが
こんなでかいpatchをいきなり送りつけて大丈夫だろか。