我正在编写一个 C 程序,我想用$EDITOR
变量打开一个文件来对其进行更改。
假设我已经检查了$EDITOR
是否未设置并且缺少的部分是打开文件进行编辑,是execl()
最好的选择还是应该使用不同的功能?
我在 Arch linux 下工作。
如果你有理由确定你在一个单线程程序中,你有标准输入和标准输出(可能还有标准错误)到一个终端,你不会被强加给你的信号处理所困扰通过system()
,您可以使用system()
通过 shell 执行命令。
如果您不想 trust system()
,那么exec*()
功能系列之一(加号fork()
)将满足您的需求。您仍然需要合理确定标准 I/O 通道——一些编辑器对随机文件或管道输入反应不佳。您可以选择要使用的信号处理方式以及安装方式。您可以处理任何线程安全问题。这是一个适度的工作量。
您可能需要仔细考虑是否给用户提供“真实”文件以进行编辑或复制。您的代码应该可以识别编辑器是否成功退出(如果没有成功退出,则应该忽略输出文件)。您可能还想检查文件的新版本的大小是否合理(例如,不是零字节 - 但这可能无关紧要;这取决于上下文)。如果正在编辑的文件是一个珍贵的配置文件,你会担心这个;如果是重新执行之前的一些命令(一种历史机制),你就不用担心其中的一些细节了。
这是我的程序中的历史“编辑”命令。它允许用户指定要复制到文件中的命令范围,然后对其进行编辑,然后执行结果(可能为空)。它是逐字代码。大多数函数调用都是针对特定于程序的函数,但大多数名称应该是可解释的(我认为)。函数系列处理“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();
}
}