Sample Header Ad - 728x90

is there a list of minimum term capabilities for dialog(ncurses)?

1 vote
0 answers
177 views
I'm trying to write some code using the ncurses dialog library (available everywhere, source mirror is here ) and I'm trying to decide dynamically in code whether to use dialog or just print to stderr and prompt with getc() based on whether stdin/out/err are hooked up to char block devices, ttys, and what termcaps they have. I've stolen some code from less that seems pretty reliable at detecting whether it can render properly, and it looks for termcaps ce,cd,cl and either cm, or ho and ll, and either al or sr, otherwise it switches to dumb mode. But less has (much?) lower requirements than dialog, presumably (I just need yesno boxes, at least). I'm kind of surprised there's no check for caps in dialog or in ncurses, and no way to just ask if the terminal can handle things, or fail initscr if it doesn't have the caps? dialog on an emacs shell (not on ansi-term, it works fine there obvs) just spews nonsense text because it's a dumb terminal (same if you export TERM=dumb in a normal xterm), so there's clearly no capabilities checking going on here. I'm not a unix programmer most of the time, so is there some standard way of doing this that's robust? It's odd to me that this isn't a thing that's easy to check for. I can obviously grovel through the dialog yesno code and try to record all the ncurses stuff it calls, but that's a pain, so I'm hoping I'm just failing to find a clear terminal capabilities requirements list somewhere. **Update:** so I decided to mess around with making my own custom terminfo entry to test how minimal I could go and still get the yesno dialog, and it's pretty minimal, so the less tests are basically good. It was hard to figure out how to do this, so here's a brief summary for other folks from THE FUTURE: - Here are the termcap definitions you'll need to figure things out; you can work directly with terminfo definitions and skip a couple steps, but old software like less are using the termcap versions and so it'll be easier to just work in that space. - Assuming you've got an ncurses app that runs on your current terminal (or dialog --title Hi --yesno There 0 0), figure out what your TERM envvar is. I'm working in screen and emacs ansi-term, so they're screen and eterm-color in my tests, and of course dumb - Dump the one you want to muck with (that you're running the tests with because you want your new one to be a subset of a working one) using infocmp eterm > eterm2.info, this gives you the info version to work with. - Convert it to cap with infotocap eterm2.info > eterm2.cap - Look inside, and cut it way down, like here's my minimal cap file that will just barely run less without warnings:
#       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:
- Notice I changed the name at the beginning to eterm2 as well. - Convert that back to info with captoinfo eterm2.cap > eterm2.info - mkdir infodb to make the local dir where you're going to compile this test info. - export TERMINFO=$(pwd)/infodb to tell termcap/terminfo where to find it - tic -D should output that local dir first - tic -s eterm2.info will compile it to that dir - export TERM=eterm2 to set your new hacked terminal - Run your ncurses app or dialog --title Hi --yesno There 0 0 and it should show up in all its black and white simple glory. - You can play around with adding other commands back in to see what changes, but when you're done, rm -rf infodb, export TERMINFO=, and export TERM= and make sure things run right. **Update2:** Here is the code I ended up with which seems to work in all my tests:
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;
            char const* term = getenv("TERM");
            int const TGETENT_OK = 1;
            if(tgetent(termbuf,term) == TGETENT_OK) {
                char sbuf;
                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:
        ;
    }
Anyway, it would still be very nice to know what the minimal termcaps are, but at the very least the ones listed above for less work, so I'm going to use those. Thanks, Chris
Asked by Chris Hecker (19 rep)
Oct 22, 2022, 02:49 AM
Last activity: Oct 23, 2022, 12:16 AM