简体   繁体   中英

How to change default C/C++ gnu readline newline character?

My goal is to use the C/C++ readline library on the telnet server-side as it delivers all necessary terminal functionality out of the box. Readline is already connected to the telnet socket, read and write to the socket works fine. I'm using libtelnet by Sean Middleditch .

The problem is that the readline outputs '\n' instead of '\n\r' which is a telnet standard to go to a new line = New Line + Carriage Return.

Current output on the client-side:

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

Expected output:

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

I read documentation trying to find a simple variable with a default newline character, but there's no such thing, or I must've missed it. There's also a chance that this behavior might be changed with the telnet terminal type - I not this far yet.

Do you have any idea on how to change this '\n' to '\r\n'?

Edit:

Telnet initiated & Readline connected to socket:

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");
}

Part of the event handler:

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;
    }
}

I think I should leave the readline module as is. The best solution is probably telling the client side to interpret '\n' or Line Feed as '\n\r' or Line Feed and Carriege Return. I'm having problems finding this kind of telnet option.

It's not readline that should be changing its behaviour IMO, but libtelnet that should be performing the appropriate translation.

The documentation for libtelnet mentions

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

Sends text characters with translation of C newlines (\n) into CR LF and C carriage returns (\r) into CR NUL, as required by RFC854, unless transmission in BINARY mode has been negotiated.

so it should be able to handle this. You'll have to show how readline is talking to libtelnet if you need more detailed help.


Edit - it looks like you're using libtelnet to handle input from the telnet client, but allowing readline to put characters directly on the socket back to the client. This is a mistake. Per the libtelnet documentation:

Note: it is very important that ALL data sent to the remote end of the connection be passed through libtelnet. All user input or process output that you wish to send over the wire should be given to one of the following functions. Do NOT send or buffer unprocessed output data directly!

That is, you need

client <-> libtelnet <-> readline

not

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

which I think is what you're doing now. I can't tell for certain though, since I don't know how conn and sock are set up outside the code you've shown.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM