The user enters information in the terminal, at this time a message comes from another process of the program and overwrites the data that the user has already entered but not sent.

How then to restore the erased data and place them on the next line for the received message?

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #define MAX_LEN 25 int main(int argc, char *argv[]) { char message[MAX_LEN]; char answer[MAX_LEN] = "test\n"; pid_t pid; pid = fork(); if (pid < 0) { perror("fork()"); exit(EXIT_FAILURE); } if (pid == 0) { read(STDIN_FILENO, message, MAX_LEN); } if (pid > 0) { while (1) { sleep(2); write(STDOUT_FILENO, "\r", 1); write(STDOUT_FILENO, answer, strlen(answer)); } } return 0; } 
  • one
    There are no threads, fork creates a new process , variables for these processes in different address spaces, changing data in one process does not affect the data in variables with the same name in another process. - avp
  • one
    @avp This is understandable, but here we are talking about the visual display of data. Before write writes a message, it returns the carriage to the beginning of the line and writes over the data that the user has begun to enter but has not finished yet (did not press enter). It is necessary to transfer user data to a new line and save the position of the cursor so that it can continue typing. - dmk
  • one
    So describe it in the question. The simple way is to do nothing here. You need to specifically program this, for example, use curses. Those. you need to divide the screen into 2 parts, enter in one (say, bottom) and display messages in another. Most likely there will also need synchronization between processes. Perhaps the best solution would be to allocate all the work with the screen into a separate process with which 2 others interact (for example, by pipe). - avp

1 answer 1

Example where this is implemented: type in sleep 2 command line and press Enter, now while the sleep command is running type something, but do not press enter. When bash wakes up, it displays an invitation and then your input. A simpler dash interpreter doesn't do that. The secret is to turn off the ECHO terminal mode, which repeats input characters, enable character input mode and implement the display of input characters on your own or using a library, such as the GNU Readline. In the character input mode, read() will return the result when at least one key was pressed (although it also depends on the size of the buffer and the parameters of VMIN and VTIME, but in any case at least one byte is expected).

See the man tcsetattr .

 #include <termios.h> #include <poll.h> ... struct termios t; tcgetattr(2, &t); tcflag_t oldtcflags = t.c_lflag; t.c_lflag &= ~( ECHO | ICANON ); tcsetattr(2, TCSANOW, &t); // буфер ввода и позиция "курсора" в нём, первый символ - возврат в начало строки char input[80]="\r", i=1; // структура для poll, который используем перед read чтобы ждать ввода не более 1 секунды struct pollfd pollev= {fd:0, events:POLLIN}; // самый тупой редактор тупо заполняет буфер и повторяет его на вывод while(i<79) { char b; if(poll(&pollev, 1, 1000)) { if(read(0, &b, 1)!=1) break; input[i++]= b; } // если ничего не введено за одну секунду, всё равно обновим строку, вдруг сообщение испортило экран write(2, input, i); if(b=='\n') break; } input[i]=0; // Восстановление старого режима терминала t.c_lflag = oldtcflags; tcsetattr(2, TCSANOW, &t); // Далее в буфере input первый символ следует игнорировать ... 

This program updates the input line on the screen once a second and each time after entering the next character.

The editor is designed so that stderr (aka descriptor 2) is connected to the same terminal as stdin (aka descriptor 0). If this is not the case (the user decided to redirect the stderr output), he most likely will not see our characters when typing (unless he used a pipe in tee or something like that). Those. in the case of stderr redirection, we may lose the echo emulation. Therefore, I used the same descriptor for tcgetattr/tcsetattr : in the case of redirection to a file or pipe, these functions will not work and the usual line-by-line mode with echo will remain.

In the usual command line, all three descriptors are actually accessible both to read and to write (perhaps in some systems this is not the case). Full emulation will be, if you use the descriptor 0 for all operations in the editor ( read , write , poll , tcgetattr , tcsetattr ), this will allow the user to redirect the output as he pleases, if he redirects input, write and terminal control will not work. It seems to be what you need, but it seems to me based on undocumented features.

  • Only tcgetattr/tcsetattr should be called with the same descriptor (0 - stdin), with which you call read (you set the input stream modes), and write probably should be called with descriptor 1 (stdout), and leave descriptor 2 (stderr) at rest. In the current form, this works, since all the descriptors are dropped from the emulator pseudo-terminal, but with the “iron” terminal (of course, you cannot find it now) tcgetattr/tcsetattr with the descriptor 2 (or 1) will not work. - avp
  • @avp, I think on the contrary, it is better to leave descriptor 1 alone. The user can redirect the output to a file and the editor will continue to work normally. If he also redirects stder somewhere, then there is no need to manage the terminal, tcsetattr will not work and the usual line-by-line input will work. By the way, my write even works with the descriptor 0. Why won't it work with the iron terminal? I'll try to go to orange-pi on the serial port. - sercxjo
  • @avp ./a.out > /dev/tty 2>&1 - this also works. ./a.out |& tee yyy - but this is not how it works, but I doubt that such redirection is necessary. - sercxjo
  • Well, stderr can then be redirected too. Therefore, tcset / get is necessary from 0. With / dev / tty it works naturally, it is the pseudonym of the pseudo-terminal that is associated with the emulator. - avp
  • By the way, now (without redirection) you can read (read) even from 1, at least 2 (and write (write) to 0) and everything will work (such is confusion!) - avp