terminfoメモ

node.jsでwrapする前にc++でterminfo, termios, readlineの使いかたを練習。

// g++ -o cursor cursor.cpp -lcurses -lreadline

#include <stdlib.h>
#include <term.h>
#include <curses.h>
#include <errno.h>
#include <readline/readline.h>


class Termios
{
    struct termios save_term;
    struct termios temp_term;

    void update()
    {
        errno = 0;
        if(tcsetattr(fileno(stdin), TCSANOW, &temp_term) == -1){
            perror("tcsetattr failure");
            exit(EXIT_FAILURE);
        }
    }

    public:
    Termios()
    {
        // save term
        errno = 0;
        if(tcgetattr(fileno(stdin), &save_term) == -1){
            perror("tcgetattr failure");
            exit(EXIT_FAILURE);
        }
        temp_term=save_term;
    }

    ~Termios()
    {
        restore();
    }

    void no_canonical()
    {
        temp_term.c_iflag &= IGNCR;
        temp_term.c_oflag &= ONLRET;
        temp_term.c_lflag &= (~ISIG & ~ICANON & ~ECHO);
        temp_term.c_cc[VMIN] = 1;
        temp_term.c_cc[VTIME] = 5;
        update();
    }

    void restore()
    {
        tcsetattr(fileno(stdin), TCSANOW, &save_term);
        temp_term=save_term;
    }

    void echo(bool enable)
    {
        if(enable){
            temp_term.c_lflag |= ECHO;
        }
        else{
            temp_term.c_lflag &= ~ECHO;
        }
        update();
    }
};


class Terminfo
{
    public:
        static void initialize()
        {
            if(setupterm(NULL, fileno(stdout), (int *)0) == ERR){
                fprintf(stderr,"setupterm failure\n");
                exit(EXIT_FAILURE);
            }
            cmd("clear");
        }

        static void cmd(const char *cmd)
        {
            errno=0;
            char *parmcmd=tparm(tigetstr(cmd));
            if(parmcmd==NULL){
                perror("tparm NULL");
                exit(EXIT_FAILURE);
            }
            tputs(parmcmd, 1, putchar);
        }
};


Termios termios;

int main(int argc, char **argv)
{
    termios.no_canonical();
    Terminfo::initialize();
    bool loop=true;
    while(loop){
        switch(getchar())
        {
            default:
                break;
            case 'q':
                loop=false;
                break;
            case 'h':
                Terminfo::cmd("cub1");
                break;
            case 'j':
                Terminfo::cmd("cud1");
                break;
            case 'k':
                Terminfo::cmd("cuu1");
                break;
            case 'l':
                Terminfo::cmd("cuf1");
                break;
            case ' ':
                termios.echo(true);
                readline("input:");
                termios.echo(false);
                break;
        }
    }

    return 0;
}

node.jsのncursesを見てみたが、terminfoの関数(tputs, tigetstr, tparmあたり)はエクスポートしていないみたいなので自作することにした。ついでにreadlineも混ぜておいた。