ソースコードの勉強方法

前の投稿でエラーやタイプミスを(あまり成功していませんが)読んだ時点でボブリーはコンソールでストーリーを作成する方法について議論することを提案しました(Shift-PgUp)。



端末に関連する何かをする明白な方法は、他の人がどのようにそれをしたかを見て、同じことをすることです。 これを研究する過程で、興味深い機能に注目しました。いくつかのプログラムは、コンテンツを表示し、アプリケーションを起動する前に画面を復元します(mc、vim、nano、lessなど)。 さらに、起動すると、スクロールバーが消えます(xterm / gnome-terminal内)。



方法を学習するために、最も古い(ncursesに依存しない)アプリケーションとしてMCを使用することにしました。



以下は、mcがどのようにtoggle_panel()をソースコードからの多くの引用とともに行うかについてのロマティックストーリーです。



同時に、読者は「ソースを見る」プロセスがどのように見えるかを見ることができます。



したがって、ソースコードはMCです。 画面の「戻る」はCtrl-Oで見ることができることが知られています。 ボタンの組み合わせは古いノートンコマンダーに登場し、その後のすべてのNCコンソールクローン(Dos Navigator、Volkov Commander、Far Navigatorなど)から借用されました。



原料(apt-get source mc)をダウンロードし、内部を見ました。



すぐに、keybind.cファイルが見つかりました。そこでは、Ctrl文字の組み合わせが「CL」(この場合は「Co」)としてエンコードされていることが簡単にわかりました。 列挙型の単純な配列(または定義ですか?重要ではありません)、必要な行:



     {XCTRL( 'o')、CK_ShowCommandLine、 "Co"}、


さらに(MCのアーキテクチャがわからないため、あまり知りたくありません)、 grepユーティリティを使用してこの関数の場所を見つけるだけです: grep CK_ShowCommandLine -A3 -B3 -r *







検索されたファイル-main.c



 main.c:ケースCK_ShowCommandLine:
 main.c- view_other_cmd();
 main.c- break;


そしてその隣:



ビューアー/ actions_cmd.c:ケースCK_ShowCommandLine:
ビューア/ actions_cmd.c- view_other_cmd();
ビューア/ actions_cmd.c- break;


そして視聴者。 mc自体は同じ関数view_other_cmdを使用します。 同様のgrepは、目的の機能を備えたcmd.cファイルです。



ボイド
 view_other_cmd(void)
 {
     static int message_flag = TRUE;

     if(!xterm_flag &&!console_flag &&!use_subshel​​l &&!output_starts_shell){
         if(message_flag)
            メッセージ(D_ERROR、MSG_ERROR、
                      _(「xtermまたはLinuxコンソールではありません。\ n」
                        「パネルを切り替えることはできません。」));
         message_flag = FALSE;
     } else {
         toggle_panels();
     }
 }


目は古いスタイルのテキスト書式をわずかにカットしますが、...



だから
  1. 求められている関数toggle_pannels()。 実際、私たちはすぐにそれを見て急いでいますが、今ではより一貫性があり、エラーケースを注意深く読みます(Cのクロージャーのエレガントなエミュレーションに注意してください-操作時間全体でエラーメッセージを1回だけ表示するために静的変数を使用しますプログラム)。
  2. エラーが出力されるのは、xtermがなく、コンソールがない場合です。 サブシェル関連の部分は興味がありませんが、別個のxtermチェックに関しては、チェックを入れます。


toggle_pannels()を探しています。 execute.cファイル。 関数が大きいので、興味深い場所を引用します。



     tty_reset_screen();
     do_exit_ca_mode();
     tty_raw_mode();
     if(console_flag)
         handle_console(CONSOLE_RESTORE);
  1. tty_reset_screen-みましょう
  2. do_exit_ca_mode-ああ、面白い
  3. tty_raw_modeは単に文字入力モードを切り替えています
  4. 興味深いことに、コンソールがあれば、handle_consoleは完了です...




ca_modeとは何ですか? 小さなヒッチ(ファイルはsrcではなくlibにあります)、tty /win.c。 その横にあるのは逆do_enter_ca_modeです:

ボイド
 do_enter_ca_mode(void)
 {
     if(xterm_flag){
         fprintf(stdout、/ * ESC_STR ")0" * / ESC_STR "7" ESC_STR "[?47h");
        フラッシュ(stdout);
     }
 }

ボイド
 do_exit_ca_mode(void)
 {
     if(xterm_flag){
         fprintf(stdout、ESC_STR "[?47l" ESC_STR "8" ESC_STR "[m");
        フラッシュ(stdout);
     }
 }


合計-未知のモードの切り替え。 xtermに関連付けられています。 クイックGoogleは、これが「代替画面バッファーを使用する」ことを提案しています。



Xtermは2つの画面バッファーを維持します。 通常の画面バッファーを使用すると、saveLinesリソースで設定された最大値まで、保存された出力行を表示するためにスクロールバックできます。 代替画面バッファはディスプレイとまったく同じ大きさで、追加の保存行は含まれません。 代替画面バッファがアクティブな場合、保存された行を表示するためにスクロールバックすることはできません。 Xtermは、2つを切り替えるための制御シーケンスとメニューエントリを提供します。





わかった なるほど。 Xtermには特別なescコードがあります。



Linuxはどうですか? Linuxコンソール(実際、Ctrl-Alt-F1)に移動し、vimを試してください。終了すると、画面に前の内容が表示されます。 少ない...参照してください。 ナノ...参照してください。 つまり、linux(console_codesによる)はこれをサポートしていません。 ええ、明らかに。 mcはどうですか? そして、mcが動作します。 どうやって? なんで? ソースコードmcに戻り、見てください...そして、handle_consoleは何をしますか?



私たちは探しています...(cons.handler.c):

ボイド
 handle_console(unsigned charアクション)
 {
     (void)アクション;

     if(look_for_rxvt_extensions())
        帰る

 #ifdef __linux__
     handle_console_linux(アクション);
 #elif定義(__FreeBSD__)
     handle_console_freebsd(アクション);
 #endif


うーん... LinuxとFreeBSDでは、これは異なる方法で処理されることがわかりました。 (しかし、ソラリスについてはどうですか?オラクルはあなたのソラリスにすぎないので、Oracleはフェルトブーツをコンソールに投げました。)



console_saveを通して、handle_console_linuxを調べます。 何が見えますか? MCは、ioctlを実行するcons.saverと呼ばれる別のプロセスをフォークし、奇妙なデバイス/ dev / vcsa *への読み取りと書き込みを行います。 どんなデバイス?



ああ、新しい不思議な世界



Linuxには、テキストモードのCGA(VGA)アダプターのメモリに対応する擬似デバイスがあり、データは配列として格納されていることがわかります



struct {

char char;

char Attrib;

}



はい、はい、ビデオメモリに直接アクセスできる、昔から忘れられていたDOS。 チェック-確かに、hexdumpファイルは画面の内容を完全に表示します。 デバイスにアクセスするには、この権限が必要であることに注意してください。 通常、これは次のように行われます。デバイスのファイルにグループを配置し、このグループに含まれるファイルの所有者をファイルに公開し、sgidビットを設定します。



Debianでは、cons.saverにはttyグループ(疑似端末にアクセスするための共通グループ)用のsgidビットがあり、特別なvcsaグループ用のcentosがあります。 原則として、RHEL / CentOSのアプローチに同意します。より安全です。



だから、特別なファイル...つまり、MCはなハックの助けを借りて画面の内容を読み取り、必要に応じて書き戻します...



しかし、仮想マシンのコンソールはVGAアダプター上にありません! これは純粋なシリアルポートです。 また、単純なチェックは疑わしいものです-すべての仮想マシンで、VGAアダプターがないため、vcsaは初期状態です。 つまり、ビデオカード。



どうする まあ、まずは、mcがシリアルポートの状況で何をするかを確認してください。 知っているように、UNIX98擬似端末とシリアルポートの間に違いはありません。 実際のLinux(コンソール)に戻り、sshを介して任意のサーバーにログインし、mcを起動します。



したがって、コンソールをシリアルポートで作成している間は、原則としてvcsaの類似物を提供することはできません。また、mcでctrl-oをハックすることはできません。 原則として。



しかし、xtermはどうですか?



xtermのESCコードの実装は簡単です。 しかし... ...仮想マシンのコンテンツにアクセスすることはできません。ユーザーの環境を変更することはできません。つまり、デフォルトでは、linuxはシリアルポートにlinux端末タイプ(TERM = linux)を持ち、xterm / xrvt関数を実装しません意味-とにかく使用されません。



念のため、mcがxterm拡張の存在について学習する方法を確認します...



     const char * termvalue;

     termvalue = getenv( "TERM");




悲しいかな-環境変数(そしてクエリ文字列を期待していた)。 まあ、間違いなく。 ああ。



ところで、FreeBSDでもまったく同じハック(ただし、アーキテクチャ機能に合わせて調整)が使用されています。 ああ。



道徳?



素晴らしいLinuxコンソールでは、Ctrl-Oは完全に機能しません。 悲しいかな、決して。 そして残りは面白かった。



...ところで、ライブサーバーがあり、それが生きている場合、コンソールで何が起こっているかをリモートで確認できます-cat / dev / vcsa *。 また、特別なファンは、コンソールで他のユーザーがどのように機能するかを見ることができます。



All Articles