ncursesのデバッグ

基本的に、別画面を出して、gdb から等外プロセスにattachすればよい。

ncursesにはトレース機能がついている。 通常では利用できない。トレース付きのライブラリを 別途インストールするようになっているが、それは static link用だったため、なぜかリンクエラーが出てしまった。 同じ名前のものがlibcにあるため、どちらを使うかで エラーが出ている様子。

コンパイル時にデバッグとトレースを有効にしてコンパイル すればOK。その後、プログラム内でtrace()関数を呼び出す。 これは man curses_trace に書いてある。フルトレースすると けっこうな量になる。

PutAttrCharの中でマルチバイト文字列を出力している。 PUTCというマクロを使っている。このマクロを処理した後、_nc_outputchars が2 になっているので2バイト(UCS2)処理は正しく行われている様子。

もうちょっと追ってみる。

doupdateの996行目あたり

 994         UpdateAttrs(SP_PARM, normal);
 995
 996     NCURSES_SP_NAME(_nc_flush) (NCURSES_SP_ARG);
 997     WINDOW_ATTRS(CurScreen(SP_PARM)) = WINDOW_ATTRS(NewScreen(SP_PARM));
で、画面に表示される。そこまでは、

TransformLine(955行目)あたりから、PutRange->EmitRange->PutChar->PutAttrChar。 メモリ上は正しくUCS2な文字が入っている様子。ただ、996行目の_nc_flush(実体は flushを呼び出すだけを実行すると、文字が表示され、桁がずれる。

wnoutrefresh()のあたりにブレークポイントを仕掛け、winという構造体の中身を ダンプ。これが画面に対応しているデータを保持しているらしい。それを見ると、 win->_lineが各行データを保持しているらしい。ここには、各1文字毎に文字の値と 属性値を保持している。中身は確かに、1つの文字毎にきちんと格納されている。 ということで、内部データ(UCS2)での保持については問題なくできているはず。 ワイド文字->マルチバイト文字に変換し、エスケープシーケンスで出力する時に おかしい? _nc_getchという関数があるが、これは、チャイルドプロセスを起こす時などに、 ESCシーケンスで画面を消したりするのに使われるようだが、画面表示の時には使われない。

さらに、_nc_flush()の所にブレークポイントを仕掛け、その時の状態を見る。 1バイト文字では、1バイトずつバッファに文字が入り、そのまま出力される。 UCS文字の場合は、_nc_flush()が呼び出されてもバッファに文字が入っていない。 3回呼び出された後、バッファにUTF-8文字が入り、そのあとに1バイトの空白文字 が入っている。よって、_nc_flushに来る前に空白が付けられている。