The Man Who Fell From The Wrong Side Of The Sky:2010年3月1日分

[最新版] [一覧] [前月] [今月] [翌月]

2010/3/1(Mon)

[NetBSD] libedit I18N への道(その5)

昨日の補足だけ。

どうにも春の頭痛胃痛ダブル祭りが絶賛開催中なもんでして…ちうことで
バッファリングとかするとバグらせる悪寒、俺に必要なのはバッファリンに違いない。
なんで余計なことは libc にお任せの高水準API使って書き直しちゃるぞーということで。

今回のケースでは元々動作が怪しいので尊重すべきは
ワイド文字対応コードが入る前のソースであるからして、すべてバックアウトした状態
つまり rev1.30をベースに作業することにしますか。

その1、vi(1)に渡す一時ファイルを作成する部分のオリジナル。

1013 	fd = mkstemp(tempfile);
1014 	if (fd < 0)
1015 		return CC_ERROR;
1016 	cp = el->el_line.buffer;
1017 	write(fd, cp, (size_t)(el->el_line.lastchar - cp));
1018 	write(fd, "\n", 1);
1019 	pid = fork();

説明の必要ありませんね?

書き直したコード。

1016 	fd = mkstemp(tempfile);
1017 	if (fd < 0)
1018 		return CC_ERROR;
1019 	fp = fdopen(fd, "w+");
1020 	if (fp == NULL) {
1021 		close(fd);
1022 		return CC_ERROR;
1023 	}
1024 	for (cp = el->el_line.buffer; cp < el->el_line.lastchar; ++cp) {
1025 		fputwc(*cp, fp);
1026 		if (ferror(fp))
1027 			goto fatal;
1028 	}
1029 	fputwc(L'\n', fp);
1030 	if (ferror(fp))
1031 		goto fatal;
1032 	fflush(fp);
1033 	pid = fork();
1034 	switch (pid) {
1035 	case -1:
1036 		goto fatal;
1037 	case 0:
1038 		fclose(fp);
1039 		execlp("vi", "vi", tempfile, (char *)NULL);
1040 		exit(0);
1041 		/*NOTREACHED*/

という感じ。

その2、vi(1)が編集した一時ファイルを読み込む部分のオリジナル。

1031 		while (waitpid(pid, &status, 0) != pid)
1032 			continue;
1033 		lseek(fd, (off_t)0, SEEK_SET);
1034 		st = read(fd, cp, (size_t)(el->el_line.limit - cp));
1035 		if (st > 0 && cp[st - 1] == '\n')
1036 			st--;
1037 		el->el_line.cursor = cp;
1038 		el->el_line.lastchar = cp + st;
1039 		break;

説明の(ry

書き直し(ry

1043 		while (waitpid(pid, &status, 0) != pid)
1044 			continue;
1045 		unlink(tempfile);
1046 		rewind(fp);
1047 		for (cp = el->el_line.buffer; cp < el->el_line.limit; ++cp) {
1048 			ch = fgetwc(fp);
1049 			if (ferror(fp))
1050 				goto fatal;
1051 			if (feof(fp))
1052 				break;
1053 			*cp = ch;
1054 		}
1055 		if (cp != el->el_line.buffer && *(cp - 1) == L'\n')
1056 			--cp;
1057 		el->el_line.cursor = el->el_line.buffer;
1058 		el->el_line.lastchar = cp;
1059 		break;

あとは-DWIDECHARなしでbuildする場合のためにchartype.hに

#ifdef WIDECHAR

#define ct_fgetwc	fgetwc
#define ct_fputwc	fputwc

#else

#define ct_fgetwc	fgetc
#define ct_fputwc	fputc

#endif

としときましょう。

ただしオリジナルのコードと比較すると -UWIDECHAR の場合には read/write 一発でなく
fgetc/fputc の複数回の呼び出しになるので system call の呼び出し回数は libc が
適切にバッファリングでセーブするとはいえ、ライブラリ関数の呼び出し回数が今度は増えちゃいますやね。
もし性能にシビアな要求がある場合は、vi.c 側で ifndef WIDECHAR の場合は fread/fwrite を
使うことも検討する必要があります、まぁ今回はせいぜい一行(1024文字)までなんでやらんけど。

とりあえずこれでLANG=ja_JP.eucJPで起動したsh(1)でset -o viし、ESC + v押下で
historyをvi(1)上から編集できるのですがvi_histedit()から先でバグってるようで
マルチバイトの場合、実行されるhistoryが不正に切り詰められちゃってる模様。
多分ワイド文字数とバイト数がどっかでごっちゃなんだろうなー。

[C locale の場合]
vmware$ LANG=C sh
vmware$ set -o vi
vmware$ <ESC> v
\xa4\xa2\xa4\xa4\xa4\xa6\xa4\xa8\xa4\xaa
~
~
~
:w!
vmware$
あいうえお: not found
vmware$

[ja_JP.eucJP locale の場合]
vmware$ LANG=ja_JP.eucJP sh
vmware$ set -o vi
vmware$ <ESC> v
あいうえお
~
~
~
:w!
vmware$
あいう: not found
vmware$

現時点での差分は こちら

次回はこの切り詰め問題を追っかける予定ですがいつもの通り未定 :D


[ホームへ] [ページトップへ]