내 터미널에서 표준 입력의 텍스트가 표시되지 않는 문제에 직면했습니다. 내 프로그램은 다음을 수행합니다
일정 시간이 지나도 사용자 입력이 없을 때 프로그램을 종료하는 SIGALRM 핸들러를 설정합니다.
void sigalrm_handler(int arg)
{
exit(0);
}
주요 기능에서:
{
...
alarm(100);
line = readline(line = readline(prompt);)
...
}
그러나 프로그램이 종료된 후 터미널에 입력한 내용을 볼 수 없습니다. 그러나 명령은 잘 작동합니다.
일시적으로 실행하면
system("reset")
문제가 해결되었습니다. 하지만 더 깨끗한 솔루션이 필요합니다. int rl_reset_line_state ()
나는 그것들을 시도했지만
int rl_reset_terminal (char *terminal_name)
작동하지 않는 것 같습니다.
답변1
최신 쉘은 프로그램이 종료된 후 터미널 상태를 복원하는 경향이 있지만, 오래되었거나 성능이 떨어지는 쉘은 그렇지 않을 수 있습니다. APUE 및 기타 텍스트의 일반적인 접근 방식은 터미널 상태의 복사본을 저장한 tcgetattr
다음 프로그램이 종료될 때 해당 상태를 복원하는 것입니다.
#include <sys/time.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <readline/readline.h>
#include <readline/history.h>
struct itimerval Alarm_Timer;
struct termios Original_Termios;
int Need_Reset;
void sigalrm_handler(int arg)
{
if (Need_Reset)
tcsetattr(STDIN_FILENO, TCSANOW, &Original_Termios);
exit(0);
}
int main(void)
{
char *line;
tcgetattr(STDIN_FILENO, &Original_Termios);
Need_Reset = 1;
signal(SIGALRM, sigalrm_handler);
Alarm_Timer.it_value.tv_sec = 3;
setitimer(ITIMER_REAL, &Alarm_Timer, NULL);
line = readline("* ");
if (Need_Reset)
tcsetattr(STDIN_FILENO, TCSANOW, &Original_Termios);
exit(0);
}
답변2
첫째, 등을 위한 libreadline
자체 신호 처리기를 설치하고 해당 신호를 받은 후(termios/stty 설정을 복원한 후) 정상적으로 종료됩니다.ALRM
INT
다음과 같은 간단한 프로그램을 실행/추적하여 이를 확인할 수 있습니다.
#include <readline/readline.h>
#include <unistd.h>
int main(void){
alarm(3); readline("foo> ");
}
따라서 신호 처리기를 제거할 수 있습니다.
둘째, 당신은안 돼요exit(3)
신호 처리기에서 호출됩니다. 시스템 호출 exit(3)
과 달리_exit(2)
아니요신호는 등록된 핸들러를 실행해야 하기 때문에 안전합니다 atexit(3)
. 예를 들어, 다른 핸들러가 이미 실행 중인 동안 이 핸들러가 호출되면 exit(3)
어떤 일이 발생할지 상상해 보세요.exit(3)
터미널을 원시 모드로 전환 등을 사용 하는 대신 자체 코드를 사용하는 경우 readline(3)
항상 시작 시 터미널 상태를 저장해야 합니다 .그리고SIGCONT
신호 수신 후 종료 전 복원그리고신호를 받은 후 SIGTSTP
. 많은 예에서처럼 시작/종료 시에만 해당되는 것은 아닙니다. 커서 주소 지정을 사용하는 경우 termios 설정을 저장/복원할 때 /off ca_mode
문자(on /off)도 사용해야 합니다 smcup
.rmcup