C プログラムを作成していて、$EDITOR
変数を含むファイルを開いて変更したいと考えています。
$EDITOR
が設定されていないかどうか、および欠落している部分が編集のためにファイルを開くことであるかどうかを既に確認したと仮定するとexecl()
、最良のオプションですか、それとも別の機能を使用する必要がありますか?
私は Arch Linux で作業しています。
シングルスレッドプログラムを使用していることが合理的に確信できる場合、標準入力と標準出力 (およびおそらく標準エラーも) が端末に送られ、課せられたシグナル処理に動揺することはありません。によって、シェル経由でコマンドを実行するためにsystem()
使用できます。system()
を信頼したくない場合は、関数ファミリーのsystem()
1 つ(および) が必要なことを行います。標準の I/O チャネルについても十分に確認する必要があります — 一部のエディタは、ランダムなファイルやパイプ入力を与えられてもうまく反応しません。使用するシグナル処理と、そのインストール方法を選択できます。スレッドセーフの問題に対処することができます。中程度の作業量です。exec*()
fork()
ユーザーに編集用の「実際の」ファイルを渡すか、そのコピーを渡すかについては、おそらく慎重に検討する必要があります。あなたのコードはおそらく、エディターが正常に終了したかどうかを認識するはずです (正常に終了しなかった場合は、おそらく出力ファイルを無視する必要があります)。また、ファイルの新しいバージョンのサイズが適切かどうかを確認することもできます (たとえば、0 バイトではありませんが、状況によっては問題にならない場合もあります)。編集中のファイルが重要な構成ファイルである場合、これについて心配する必要があります。以前のコマンドを再実行する必要がある場合 (履歴メカニズム)、これらの詳細の一部について心配する必要はありません。
これは私のプログラムの history 'edit' コマンドです。これにより、ユーザーはファイルにコピーするコマンドの範囲を指定できます。ファイルは編集され、結果 (空の場合もあります) が実行されます。コードそのままです。ほとんどの関数呼び出しはプログラム固有の関数に対するものですが、ほとんどの名前は解釈可能でなければなりません (私はそう思います)。ctxt_*()
関数ファミリーは、プログラムの現在の設定である「コンテキスト」を処理します。必要以上の環境変数で動作します。このsql_file()
関数は、現在のコンテキストで入力ファイルからコマンドを実行します — このコードは、コマンドを実行する新しいコンテキストを作成します。
/* Edit history command(s) */
static void do_edit(char *s)
{
FILE *fp;
long c1;
long c2;
char tmpfname[BUFSIZ];
char sys[BUFSIZ];
const char *editor;
if (ctxt_gethistory() != OP_ON)
{
cmd_warning(E_HISTORYOFF, "");
return;
}
s = skipblanks(s);
c1 = c2 = 0;
if (sscanf(s, "%ld%ld", &c1, &c2) != 2)
c2 = c1;
if ((fp = fopen_namedtmpfile(tmpfname, sizeof(tmpfname))) == 0)
{
cmd_warning(E_FAILCREATETMPFILE, "");
return;
}
hist_output(fp, c1, c2, H_COMMAND);
fclose(fp);
if ((editor = getenv("DBEDIT")) == NIL(char *) &&
(editor = getenv("VISUAL")) == NIL(char *) &&
(editor = getenv("EDITOR")) == NIL(char *))
editor = DEF_EDITOR;
esnprintf(sys, sizeof(sys), "%s %s", editor, tmpfname);
system(sys);
fp = fopen(tmpfname, "r");
unlink(tmpfname);
if (fp == 0)
{
cmd_warning(E_FAILREOPENTMPFILE, tmpfname);
}
else
{
/* Copy file to history log */
if ((c1 = hist_input(fp)) > 0)
cmd_set_promptnum(c1);
fseek(fp, 0L, SEEK_SET);
ctxt_newcontext();
ctxt_newinput(fp, "<<temp>>");
ctxt_sethistory(op_off);
sql_file();
ctxt_endcontext();
}
}