我正在尝试实现一个基本的shell.
我需要读取用户输入,直到按下某些分隔符,才能执行相应的操作.这些分隔符可以是单个"a",单个"b"或单个"c".
输入示例如下所示(>shell提示符在哪里):
> 111-222-333-444a
Ok, '111-222-333-444' entered
Run Code Online (Sandbox Code Playgroud)
因为我想听一下键盘事件如'向上箭头'来删除当前命令并打印最后一个命令(实现历史记录功能).
因为我想听'tabulation'这样的键盘事件来自动完成当前命令(实现自动完成功能).
到目前为止,我的代码如下所示:
bool done = false;
char c;
while (!done && std::cin.get(c))
{
switch (c)
{
case 'a':
// Do something corresponding to 'a'
done = true;
break;
case 'b':
// Do something corresponding to 'b'
done = true;
break;
case 'c':
// Do something corresponding to 'c'
done = true;
break;
default:
// buffer input until a delimiter is pressed
break;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,循环似乎只有在按下"新行"键后才会执行.此行为会终止用户输入的交互式本质.
我知道std :: ostream是缓冲的,所以在发生某些事件之前内容不会写入磁盘,但是std :: istream呢.它是缓冲的吗?如果是,那么它是如何绕过这种行为的?
此外,我已将此问题标记为"家庭作业",因为如果不是学校的练习,这是我自己尝试做的练习,我不想只挑选一个实现所有这些东西的库.
如果您使用的是POSIX操作系统,则可以使用声明的函数和结构将终端设置为无缓冲termios.h.基本上你需要禁用规范输入,并为非规范模式设置终端.这些链接可以帮助您理解两种终端模式之间的区别:
非规范输入(来自libc手册)
在非规范输入模式下,将忽略ERASE和KILL等特殊编辑字符.用户编辑输入的系统工具在非规范模式下被禁用,因此所有输入字符(除非它们特别用于信号或流控制目的)都将完全按照键入的方式传递给应用程序.应用程序可以根据需要为用户提供编辑输入的方法.
对于规范输入 - 想想shell; 实际上,想想老式的Bourne shell,因为Bash和亲戚都有命令行编辑.你键入一行输入; 如果你犯了一个错误,你使用擦除字符(默认是退格,通常;有时是DEL)来擦除前一个字符...对于非规范输入 - 想想vi或vim或...你按一个字符,然后它可立即使用该程序.在你回归之前,你不会被耽搁.
本章介绍了为控制异步通信端口而提供的通用终端接口.它是依赖于实现的,无论是支持网络连接还是同步端口,还是两者都支持
实质上,您遇到的问题不在于C++ iostream接口本身,而在于如何设置C++ iostream接口正在读取的控制终端.因此,利用无缓冲的I/O将是一个依赖于平台的操作,并且将根据您使用的是Windows还是实际的POSIX兼容平台(这包括适用于Windows的POSIX环境,如Cygwin)而有所不同.
如果你发现搞乱终端设置太麻烦了,你也可以查看一个跨平台的curses编程库,比如PDCurses,它将抽象出底层终端类型的大部分复杂性.
关于是否std::istream缓冲以及如何缓冲的直接问题的答案是:是的,std::istream缓冲是否使用派生自的类,该类std::streambuf定义了具体源的实际缓冲和读取方法(或者,当std::ostream对目标使用 时)。这是否真的做任何缓冲取决于这个具体的类,它的操作通常是无法避免的。
也就是说,这不是你的问题!问题是,如果程序在按下换行键之前,通常不会将输入发送到标准输入。这是为了某些行编辑可以由终端实现完成,而不必由每个程序完成。不幸的是,没有可移植的方法来改变这一点。在 POSIX 上,您可以0使用tcgetattr()和将标准输入流(使用文件描述符)转换为非规范模式tcsetattr()。我不知道如何在非 POSIX 系统上实现这一点。