http://gonggeng.org/mediawiki/index.php/Readline-select
Readline-select
一个交互式命令行程序必然包含从终端读取命令执行命令这样的循环。 为了提供像重新调用上一次命令这样的丰富的命令行编辑功能,我们一般会使用 GNU 的 readline 库。 通常我们会这样来编程:
#include <readline/readline.h> #include <readline/history.h> int main (int argc, char **argv) { char *line_read = 0; while (1) { if (line_read) { free (line_read); line_read = (char *)NULL; } line_read = readline ("ccnet> "); /* If the line has any text in it, save it on the history. */ if (line_read && *line_read) { add_history (line_read); handle_command (line_read); } } }
但是如果我们有多个 IO 要处理,比如既要从一个网络 IO 中读数据,又要从标准输入中读取命令,上面的方法就不合适了。
为了解决这个问题,我们需要自己用 select 函数监控这两个 IO,当它们可读的时候通知这两个模块中的输入函数。形象地说,就是把数据“喂给”这两个模块。这样的模式需要 readline 提供“被动喂给”的工作方式。这种工作方式在 readline 中已有实现。
首先,我们需要往 readline 注册回调函数,当 readline 读取到一行后,这个回调函数将被调用:
rl_callback_handler_install ("prompt> ", handle_command);
接下去,在主事件循环中,我们需要调用 rl_callback_read_char() 通知 readline 去读取一个字符。
下面给一个例子:
static void handle_command (char *line) { ... } int main (int argc, char **argv) { int netfd fd_set allfd; int maxfd; netfd = connect_to_server (); FD_ZERO (&allfd); FD_SET (0, &allfd); FD_SET (netfd, &allfd); maxfd = netfd; rl_callback_handler_install ("ccnet> ", handle_command); while (1) { fd_set rfds; int retval; rfds = allfd; retval = select (maxfd + 1, &rfds, NULL, NULL, NULL); if (retval < 0) perror ("select"); if (FD_ISSET(0, &rfds)) rl_callback_read_char(); if (FD_ISSET(netfd, &rfds)) read_from_network (netfd); } }
参考
info readline 2.4.12 Alternate Interface