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; }
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直接だと細々とめんどくさいところがあるのだろうけど。
参考
An example terminfo program
http://uw714doc.sco.com/en/SDK_charm/_An_Example_terminfo_Program.html
こちらの後半「VT-100エスケープシーケンスについて」
http://hp.vector.co.jp/authors/VA016670/escape_code.html
VT100
http://www14.ocn.ne.jp/~bkclass/doc_vt100.html
TERMINFO
http://h50146.www5.hp.com/products/software/oe/tru64unix/manual/v51a_ref/HTML/MAN/MAN4/0087____.HTM