ncurses 대화 라이브러리(어디서나 사용 가능)를 사용하려고 합니다.소스 미러는 여기), 대화 상자를 사용할지 아니면 stdin/out/err이 char 블록 장치, ttys 및 어떤 termcaps에 연결되어 있는지 여부에 따라 stderr 및 프롬프트로 인쇄할지 코드에서 동적으로 결정하려고 합니다. 나는 less에서 올바르게 렌더링할 수 있는지 감지하는 데 꽤 신뢰할 만한 코드를 훔쳤고, termcaps ce
, cd
, cl
and cm
, 또는 를 찾고 그렇지 ho
않으면 ll
멍청한 모드로 전환합니다. 그러나 less의 요구 사항은 대화 상자보다 낮을 수 있습니다(많이?)(적어도 yesno 상자만 필요합니다). 대화 상자나 ncurses에 대문자를 확인하지 않고 터미널에 문제를 처리할 수 있는지 물어볼 방법이 없고 대문자가 없으면 initscr이 실패한다는 것에 조금 놀랐습니다. Emacs 셸의 대화 상자(ansi-term이 아님, obvs에서는 잘 작동함)는 의미 없는 텍스트만 내뱉고, 멍청한 터미널( 일반 xterm과 동일)이기 때문에 여기에서 진행되는 기능은 분명히 없습니다.al
sr
export TERM=dumb
저는 대부분의 경우 UNIX 프로그래머가 아닙니다. 이를 수행하는 신뢰할 수 있는 표준 방법이 있습니까? 나를 이상하게 생각하는 것은 이것이 확인하기 쉬운 일이 아니라는 것입니다.
분명히 대화 상자를 통해 코드를 작성하고 그것이 호출하는 모든 ncurses 항목을 기록하려고 시도할 수 있지만 그것은 고통스럽기 때문에 어딘가에서 터미널 기능 요구 사항에 대한 명확한 목록을 찾지 못했기를 바라고 있습니다.
고쳐 쓰다:그래서 나는 "yesno" 대화 상자를 얼마나 잘 얻을 수 있는지 테스트하기 위해 나만의 사용자 정의 terminfo 항목을 만들기로 결정했습니다. 크기가 매우 작기 때문에 테스트 횟수를 줄이는 것이 더 좋습니다. 이를 수행하는 방법을 파악하기 어렵습니다. 따라서 THE FUTURE의 다른 사람이 간략하게 요약한 내용은 다음과 같습니다.
- 다음은 termcap 정의입니다.문제를 파악해야 합니다. terminfo 정의를 사용하고 몇 단계를 건너뛸 수도 있지만 less와 같은 오래된 소프트웨어는 termcap 버전을 사용하므로 해당 공간에서 작업하는 것이 더 쉽습니다.
dialog --title Hi --yesno There 0 0
현재 터미널(또는 ncurses )에서 실행 중인 ncurses 애플리케이션이 있다고 가정하고 TERM envvar가 무엇인지 알아보세요. 저는 화면과 emacs ansi-term에서 작업 중이므로 물론 테스트screen
중입니다 .eterm-color
dumb
- 작업하려는 버전의 덤프를 사용하십시오(새 버전이 작업 버전의 하위 집합이 되기를 원하기 때문에 테스트를 실행 중임).
infocmp eterm > eterm2.info
그러면 해당 버전에 사용하려는 정보가 제공됩니다. - 캡으로 바꿔서
infotocap eterm2.info > eterm2.cap
- 내부를 살펴보고 다음과 같이 경고 없이 거의 실행되지 않는 최소한의 제한 파일인 것처럼 잘라냅니다.
# hacked eterm for testing dialog
eterm2|gnu emacs term.el terminal emulation:\
:am:mi:xn:\
:co#80:li#24:\
:ce=\E[K:cd=\E[J:cl=\E[H\E[J:\
:ho=\E[H:\
:cm=\E[%i%d;%dH:\
:al=\E[L:
- 처음에는 이름도 eterm2로 변경했습니다.
- 다시 정보로 변환
captoinfo eterm2.cap > eterm2.info
mkdir infodb
이 테스트 정보가 컴파일될 로컬 디렉터리를 만듭니다.export TERMINFO=$(pwd)/infodb
termcap/terminfo에서 찾을 수 있는 위치를 알려줍니다.tic -D
로컬 디렉터리가 먼저 출력되어야 합니다.tic -s eterm2.info
이 디렉토리에 컴파일하세요export TERM=eterm2
새로운 해커 터미널 설정- ncurses 애플리케이션을 실행하세요. 그렇지 않으면
dialog --title Hi --yesno There 0 0
간단하게 흑백으로 표시되어야 합니다. - 다른 명령을 다시 추가하여 변경된 내용을 확인할 수 있지만 완료한 후에는
rm -rf infodb
모든 것이 제대로 실행되는지 확인하세요export TERMINFO=
.export TERM=<oldterm>
업데이트 2: 이것은 내가 완성한 코드이며 모든 테스트에서 작동하는 것 같습니다.
if(TermMode == TERM_UNINITIALIZED) {
struct stat s;
if((isatty(STDOUT_FILENO) && (fstat(STDOUT_FILENO,&s) == 0) && S_ISCHR(s.st_mode)) &&
(isatty( STDIN_FILENO) && (fstat( STDIN_FILENO,&s) == 0) && S_ISCHR(s.st_mode)))
{
// both stdout and stdin are char block device ttys, now check termcaps
// mostly stolen from the gnu less source code, since it seems robust
// https://github.com/gwsw/less/blob/22e4af5cccbfab633000c7d610f868a868ad6e1a/screen.c#L1280
char termbuf[2048];
char const* term = getenv("TERM");
int const TGETENT_OK = 1;
if(tgetent(termbuf,term) == TGETENT_OK) {
char sbuf[2048];
char* sp = sbuf;
char* sr = 0;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wwrite-strings"
// ce ce cl are required
if((sr = tgetstr("ce",&sp)) && *sr && // eol clear
(sr = tgetstr("cd",&sp)) && *sr && // eos clear
(sr = tgetstr("cl",&sp)) && *sr) // screen clear
{
// cm or (ho and ll)
if(((sr = tgetstr("cm",&sp)) && *sr) || // cursor move
(((sr = tgetstr("ho",&sp)) && *sr) && // home
((sr = tgetstr("ll",&sp)) && *sr))) // lower left
{
// al or sr
if(((sr = tgetstr("al",&sp)) && *sr) || // add line
((sr = tgetstr("sr",&sp)) && *sr)) // scroll reverse
{
// we've got what we need for ncurses dialog!
TermMode = TERM_DIALOG;
goto term_detected;
}
}
}
#pragma GCC diagnostic pop
}
// we're at least connected to a tty
TermMode = TERM_STDIO;
} else {
// no interaction, so gotta just abort
TermMode = TERM_ABORT;
}
term_detected:
;
}
어쨌든 가장 작은 텀캡이 무엇인지 아는 것은 여전히 좋지만, 적어도 위에 나열된 것들은 작업 부하를 줄여주기 때문에 사용하겠습니다.
고마워요, 크리스