ソースコードというのを眺めてみる

このところ、あれこれ本を読んだりソースコードを読んだりしている。Cが少し書けるようになった気がしたので、少しは読めるようになってるのじゃないかと思って、GNU Global+ブラウザでいろいろと読んでみている。

読むだけじゃなくて少し手を入れたりできるだろうかと思って、GNU Screenをいじってみた。ウィンドウの名前をリネームするときの挙動が気に入らないので、これを変更するのが目標。ぼくの設定環境では「Ctrl+J、c」と打つと新規ウィンドウが追加される。3つほどウィンドウを作って、そのうち1つをイー・モバイルの接続監視用の「tail -f /var/log/syslog」とかの表示にしている。なので、このウィンドウ名を、デフォルトの「zsh」から「ppp」に変えるという操作をたまにする。

そのとき画面下部に表示されるUIは、以下の通り。

Set window's title to: zsh
0 zsh  1 zsh  2 zsh

1行目のzshの「後ろ」にカーソルがある。バックスペースを3度叩いてから名前を入れることでリネームを行う。これはおかしい。zの上にカーソルがないと面倒じゃん。名前変えるに決まってるんだから(しかし、上書きモードなんてないだろうし、仕方ないのかな。現在のウィンドウ名を表示するというのも非カラーの端末のことを考えると必要かも)。

それで該当個所を見てみた。process.cの5060行目から始まる関数。

static void
InputAKA()
{
  char *s, *ss;
  int n;
  Input("Set window's title to: ", sizeof(fore->w_akabuf) - 1, INP_COOKED, AKAfin, NULL);
  s = fore->w_title;
  if (!s)
    return;
  for (; *s; s++)
    {
      if ((*(unsigned char *)s & 0x7f) < 0x20 || *s == 0x7f)
	continue;
      ss = s;
      n = 1;
      LayProcess(&ss, &n);
    }
}

Inputって何だ、foreって何だ、IN_COOKEDって何のモードだ、AKAfinで渡す関数は後処理? LayProcessって何のマクロ? みたいに、これを起点にソースコードを眺めてみたら、これが結構おもしろい。上のfor分や「if(!s)」みたいな異様にCっぽい書き方だとか、部分的に現れる1文字の変数名の嵐とか、端末エミュレータ固有の面倒そうな問題とか、いろいろおっかない感じではあるけど、そういうところを除くと、想像以上にオブジェクト指向っぽいウィンドウやレイヤの扱い方をしているらしいことが分かったのが発見。レイヤの構造体には関数ポインタがいっぱい。オブジェクト指向が、単にデータと処理をまとめるだけの話であれば、これでいいじゃんって感じ。

あと、ウィンドウやレイヤの構造体が連結リストとしても実装されていて、なるほど、連結リストはこうやって使うのかという実例が見れた。ウィンドウオブジェクトを保持する構造体には、書き換えフラグがあって、明示的に「t」を書き込むことで、レイヤの書き換え処理を走らせていることとかも、低レベルなウィンドウシステムを見るようでおもしろかった。GUIに比べてCUIなんだからscreenなんて単純なものだろうと勝手に想定していたけど、考えてみたらそんなわけない。

ともあれ、ウィンドウのリネームの変更は、リネーム対象の先頭文字にカーソルを置くという風にはできなかった。InputAKA()の最後に、無理やりカーソル位置を変えるようなことをやってもダメだった。

結局、リネーム対象のウィンドウ名をハナから表示しないように、該当個所(Input以降すべて)をコメントアウトすることにした。

それにしても、ソースコードを読むには英語力必要かもなと思った。foreを見た瞬間に、現在前面に出てるウィンドウオブジェクトへのポインタだろうなと想像できないとつらいだろうし、fore->w_akabufのakaがalso known asだと分からないと読解のヒントが1つ減る。そして、ぼくはついにscreenのソースコード中のあちこちで使われている「fin」という接尾辞が何なのか、よく分からなかったのだった。finishとかfinalとかの意味で、後処理の関数なんかを表している気がするんだけど。

foreだけじゃないけど、そういえば何だかんだグローバル変数がいっぱいあって、それにも驚いた。