terminfoでやってみる

cuiでプログラムする場合はだいたいcurses(ncurses)を使おうとして何かしっくりこないなーということになりがちだったのだが、w3mをチェックしてみて、cursesの下層のterminfoで使えばよかったんだよ、と気付いた。
で、やってみた。

#include <curses.h>
#include <term.h>
#include <stdlib.h>
#include <assert.h>

class Term
{
public:
	Term()
	{
		setupterm(0, 1, 0);
	}

	~Term()
	{
		resetterm();
	}

	void enterBoldMode()
	{
		tputs(enter_bold_mode, 1, putchar);
	}

	void enterUnderlineMode()
	{
		tputs(enter_underline_mode, 1, putchar);
	}

	void exitMode()
	{
		tputs(exit_attribute_mode, 1, putchar);
	}
};


int main(int argc, char **argv)
{
	if (argc > 2)
	{
		fprintf(stderr, "Usage: termhl [file]\n");
		exit(1);
	}

	FILE *fd=stdin;
	if (argc == 2)
	{
		fd = fopen(argv[1], "r");
		if (fd == NULL)
		{
			perror(argv[1]);
			exit(2);
		}
	}

	Term t;
	bool doLoop=true;
	while(doLoop){
		int c = getc(fd);
		switch(c)
		{
		case EOF:
			doLoop=false;
			break;

		case '\\':
			{
				switch (getc(fd))
				{
				case 'B':
					t.enterBoldMode();
					break;

				case 'U':
					t.enterUnderlineMode();
					break;

				case 'N':
					t.exitMode();
					break;

				default:
					assert(false);
				}
			}
			break;

		default:
			putchar(c);
			break;
		}
	}

	fclose(fd);
	fflush(stdout);

	return 0;
}

Makefile

TARGET=termtest
CXXFLAGS=-I/usr/include/ncurses
LDFLAGS=-lncurses

all: $(TARGET)

$(TARGET): main.o
	g++ -o $@ $^ $(LDFLAGS)

main.o: main.cpp
	g++ -c -o $@ $^ $(CXXFLAGS)

環境はcygwinで実験。

こんな感じで使うとあっさりマルチバイト文字を表示できた。

$ cat input.txt
素\B太字\N素\U下線\N素\B\U太下線\N素
$ ./termtest.exe < input.txt

ということは、マルチバイト文字列を扱うとき、文字列のbytelengthとcolumnlengthを区別して運用したいときにcursesが邪魔になっているような気がするな。
こんな感じでterminfoラッパーを作って、オレオレcursesを作ったらsetlocaleとかも要らないしマルチバイト文字の問題は完全に把握できる。terminfo直接だと細々とめんどくさいところがあるのだろうけど。