如何更改默认的 C/C++ gnu readline 换行符?

Posted

技术标签:

【中文标题】如何更改默认的 C/C++ gnu readline 换行符?【英文标题】:How to change default C/C++ gnu readline newline character? 【发布时间】:2021-06-09 17:58:55 【问题描述】:

我的目标是在 telnet 服务器端使用 C/C++ readline 库,因为它提供了开箱即用的所有必要终端功能。 Readline 已经连接到 telnet 套接字,对套接字的读写工作正常。我正在使用libtelnet by Sean Middleditch。

问题在于 readline 输出 '\n' 而不是 '\n\r' 这是一个 telnet 标准去一个新行 = 新行 + 回车。

客户端的当前输出:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
> example
         > another example
                          > 3rd example
                                       > 

预期输出:

Trying 127.0.0.1...
Connected to localhost.
The escape character is '^]'.
> example
> another example
> 3rd example
> 

我阅读文档试图找到一个带有默认换行符的简单变量,但没有这样的东西,或者我一定错过了它。这种行为也有可能会随着 telnet 终端类型而改变——我还没有到这一步。

您知道如何将这个 '\n' 更改为 '\r\n' 吗?

编辑:

Telnet 启动 & Readline 连接到套接字:

void startLibTelnet(int connfd)

    char buffer[512];
    int rs;

    telnet_t *telnet;
        telnet = telnet_init(telopts, _event_handler, 0, &connfd);

    // telnet options
    telnet_negotiate(telnet, TELNET_DO,
            TELNET_TELOPT_LINEMODE);

    telnet_negotiate(telnet, TELNET_WILL,
            TELNET_TELOPT_ECHO);

    telnet_negotiate(telnet, TELNET_WILL,
            TELNET_TELOPT_TTYPE);

    // redirecting readline input/output to TCP socket
    rl_instream = fdopen(connfd, "r");
    rl_outstream = fdopen(connfd, "w");

again:
    // forever loop
    while ( (rs = recv(connfd, buffer, sizeof(buffer), 0)) > 0)
    
        telnet_recv(telnet, buffer, rs);
    
    if (rs  < 0 && errno == EINTR)
        goto again;
    else if (rs  < 0)
        perror("str_echo: read error");


部分事件处理程序:

static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
                void *user_data)

    int sock = *(int*)user_data;

    switch (ev->type) 
    /* data received */
    case TELNET_EV_DATA:
        rl_gets("> ");
        break;
    /* data must be sent */
    case TELNET_EV_SEND:
        _send(sock, ev->data.buffer, ev->data.size);
        break;
    /* request to enable remote feature (or receipt) */
    case TELNET_EV_WILL:
        break;
    /* notification of disabling remote feature (or receipt) */
    case TELNET_EV_WONT:
        break;
    . // here's also 
    . // case DO
    . // case DONT
    default:
        break;
    


我认为我应该保留 readline 模块。最好的解决方案可能是告诉客户端将“\n”或换行解释为“\n\r”或换行和回车。我在查找这种 telnet 选项时遇到问题。

【问题讨论】:

\r\n 不是标准换行符。 C++ 标准只知道\n。你是如何输出线条的?在使用此类换行符的平台(即 Windows)上,cin 在输入时将 \r\n 规范化为 \n,在输出时 cout\n 转换为 \r\n。请提供minimal reproducible example 流的打开模式将决定是否翻译换行符。 binary 模式下的流将 \r\n 视为两个字符。当以text 模式打开时,\r\n 将被视为换行符\r 通常被忽略(作为空格)。 @RemyLebeau 问题已更新。我想我需要一个 telnet 选项来告诉客户端将 '\n' 解释为 '\n\r',对吗? 我认为 libtelnet 负责使 readline 的 C 标准输出符合 RFC854 - 你只需要指示它这样做。 【参考方案1】:

应该改变其行为 IMO 的不是 readline,而是应该执行适当转换的 libtelnet。

libtelnet 的文档提及

void telnet_send_text(telnet_t *telnet, const char *buffer, size_t size);

根据 RFC854 的要求,发送文本字符并将 C 换行符 (\n) 转换为 CR LF,并将 C 回车符 (\r) 转换为 CR NUL,除非已协商以 BINARY 模式传输。

所以它应该能够处理这个问题。如果您需要更详细的帮助,您必须展示 readline 如何与 libtelnet 通信。


编辑 - 看起来您正在使用 libtelnet 来处理来自 telnet 客户端的输入,但允许 readline 将字符直接放在套接字上返回客户端。这是个错误。根据 libtelnet 文档:

注意:发送到连接远程端的所有数据都必须通过 libtelnet 传递,这一点非常重要。您希望通过线路发送的所有用户输入或过程输出都应提供给以下功能之一。不要直接发送或缓冲未处理的输出数据!

也就是说,你需要

client <-> libtelnet <-> readline

不是

client  -> libtelnet -> readline
   |                       /
    ----------<----------- 

认为就是你现在正在做的事情。不过我无法确定,因为我不知道在您显示的代码之外如何设置 connsock

【讨论】:

感谢您的回答! Readline 不完全与 telnet 对话,而是直接与 TCP 套接字对话。它实际上省略了 telnet。看看我编辑的问题,_event_handler() 中有函数调用rl_gets()。我不确定如何将输出从 readline 传递到 telnet。我正在考虑在 readline 输出之间使用管道并在永远循环中从中读取,而不是使用您提到的 telnet_send_text 发送数据。 Readline 正在写入套接字。它应该写入套接字 you 控件,因此您可以通过 libtelnet 将其传递回客户端。 这正是我现在想要实现的目标,很好。但是我没有尝试过任何工作。尝试了管道、memfd、套接字来通信 libelnet 和 readline 如下libtelnet &lt;-&gt; readline,但无法使其工作。您对如何在这两者之间交换数据有什么建议吗? 原谅我的无知。我没有尝试 UNIX 套接字,这可能是解决方案。再次感谢@Useless,没那么没用:) 您可以使用socketpair() 设置双向链接(&lt;-&gt;),或者您可以使用一个pipe() 用于libtelnet -&gt; readline,另一个pipe() 用于反向路径。在这种情况下,一对套接字更简单。

以上是关于如何更改默认的 C/C++ gnu readline 换行符?的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 C/C++ 中的默认 *.exe 图标?

qpython 没有“gnu-readline”功能

GNU Readline 可以处理多个流吗?

有没有用 GNU readline 处理多行输入的好方法?

readline安装

使用GNU/gdb调试Linux C/C++可执行程序查看出错源代码、设置断点