在 C 中按 "Ctrl + c" 退出阅读监听
Exit read listening when pressing "Ctrl + c" in C
我正在用 C 语言重写一个 shell,我遇到了一个问题。
写命令时——例如 echo "this
——我们得到一个新提示("dquote>",在 zsh 中),我们可以使用 "Ctrl + c" 退出它并返回到我们的上一个命令提示符。
我被困在那里;我只是无法退出我的读取功能(在 "dquote>" 上监听),我试图在按下 "ctrl + c" 时在标准输出上写一个 EOF 但它没有读取它。
我切换到非规范模式。
我用 signal(SIGINT, sig_hand);
捕捉信号
然后我在捕捉到信号时执行这部分代码:
static void sig_hand(int sig)
{
if (g_shell.is_listen_bracket) // if is the first prompt or no
putchar(4); // EOT
else
{
putstr("\n");
print_prompt();
}
}
和我的阅读功能:
int j;
char command[ARG_MAX];
char buff[3];
j = -1;
while (1)
{
bzero(buff, 3);
read(0, buff, 3);
if (buff[0] == 4 && !buff[1] && !buff[2])
return (ctrl_d(shell));
else if (isprint(buff[0]) && !buff[1] && !buff[2]) // if is between 32 and 126 (ascii)
{
command[++j] = buff[0];
putchar(buff[0]);
}
}
command[++j] = '[=12=]';
return (strdup(command));
所以我的代码在等待 "read(0, buff, 3);",我想在按 ctrl + c 时退出它。
感谢您的帮助!
不要把EOF
当成一个可以'打印到stdout
'的字符,它是文件句柄可以的状态在,这意味着没有更多的数据到来。要将 stdout
置于 EOF
状态,您必须调用 close()
- 这很可能不是您想要的。
注意 - 0x04
实际上是 EOT
,传输结束。
无论如何,为什么要将 EOT
发送到应用程序的 stdout
?如果这表现得像你认为的那样,那么终端仿真器(或连接到你的标准输出的任何东西)将退出 - 而不是你的 shell,它肯定不会恢复你的 shell从“等待更多输入”状态到“等待输入”状态。
你需要在signal handler中处理^C
,适当调整你的shell状态,让它放弃当前的输入模式,重绘基本提示。
编辑: 您需要记住的是,您的 'shell' 正在向终端仿真器写入文本(输出)和控制字符 - 终端仿真器正在写入文本(输入)和控制字符到您的 'shell'.
如果您想将提示从 dquote>
还原为 mysh$
,那么 您 必须通过向终端写入新提示来更新终端。
要跟踪您当前正在做的事情,使用 State Machine 方法可能最有意义。您可能有几个状态,包括:
INPUT_WAITING
INPUT_WAITING_CONT
COMMAND_RUN
当处于 INPUT_WAITING
状态时,您将打印 mysh$
提示,并处理输入。
当收到换行符时,您将决定“我们是否拥有所有信息?”,如果没有则进入 INPUT_WAITING_CONT
状态,或者 COMMAND_RUN
如果你这样做,请说明。
INPUT_WAIT_CONT
状态将打印出 dquote>
提示,并采取类似的操作... 'do we have enough information?' 是:COMMAND_RUN
,否:INPUT_WAIT_CONT
.
然后由您恢复到 INPUT_WAIT
状态并在用户按下 ^C
或命令执行完成时重绘 mysh$
提示。
我正在用 C 语言重写一个 shell,我遇到了一个问题。
写命令时——例如 echo "this
——我们得到一个新提示("dquote>",在 zsh 中),我们可以使用 "Ctrl + c" 退出它并返回到我们的上一个命令提示符。
我被困在那里;我只是无法退出我的读取功能(在 "dquote>" 上监听),我试图在按下 "ctrl + c" 时在标准输出上写一个 EOF 但它没有读取它。
我切换到非规范模式。
我用 signal(SIGINT, sig_hand);
然后我在捕捉到信号时执行这部分代码:
static void sig_hand(int sig)
{
if (g_shell.is_listen_bracket) // if is the first prompt or no
putchar(4); // EOT
else
{
putstr("\n");
print_prompt();
}
}
和我的阅读功能:
int j;
char command[ARG_MAX];
char buff[3];
j = -1;
while (1)
{
bzero(buff, 3);
read(0, buff, 3);
if (buff[0] == 4 && !buff[1] && !buff[2])
return (ctrl_d(shell));
else if (isprint(buff[0]) && !buff[1] && !buff[2]) // if is between 32 and 126 (ascii)
{
command[++j] = buff[0];
putchar(buff[0]);
}
}
command[++j] = '[=12=]';
return (strdup(command));
所以我的代码在等待 "read(0, buff, 3);",我想在按 ctrl + c 时退出它。
感谢您的帮助!
不要把EOF
当成一个可以'打印到stdout
'的字符,它是文件句柄可以的状态在,这意味着没有更多的数据到来。要将 stdout
置于 EOF
状态,您必须调用 close()
- 这很可能不是您想要的。
注意 - 0x04
实际上是 EOT
,传输结束。
无论如何,为什么要将 EOT
发送到应用程序的 stdout
?如果这表现得像你认为的那样,那么终端仿真器(或连接到你的标准输出的任何东西)将退出 - 而不是你的 shell,它肯定不会恢复你的 shell从“等待更多输入”状态到“等待输入”状态。
你需要在signal handler中处理^C
,适当调整你的shell状态,让它放弃当前的输入模式,重绘基本提示。
编辑: 您需要记住的是,您的 'shell' 正在向终端仿真器写入文本(输出)和控制字符 - 终端仿真器正在写入文本(输入)和控制字符到您的 'shell'.
如果您想将提示从 dquote>
还原为 mysh$
,那么 您 必须通过向终端写入新提示来更新终端。
要跟踪您当前正在做的事情,使用 State Machine 方法可能最有意义。您可能有几个状态,包括:
INPUT_WAITING
INPUT_WAITING_CONT
COMMAND_RUN
当处于 INPUT_WAITING
状态时,您将打印 mysh$
提示,并处理输入。
当收到换行符时,您将决定“我们是否拥有所有信息?”,如果没有则进入 INPUT_WAITING_CONT
状态,或者 COMMAND_RUN
如果你这样做,请说明。
INPUT_WAIT_CONT
状态将打印出 dquote>
提示,并采取类似的操作... 'do we have enough information?' 是:COMMAND_RUN
,否:INPUT_WAIT_CONT
.
然后由您恢复到 INPUT_WAIT
状态并在用户按下 ^C
或命令执行完成时重绘 mysh$
提示。