/* tcfilter.c: input filter for T-Code/TUT-Code using tclib */ /* * 概要: * GNU screen用のT-Code/TUT-Code入力フィルタです。 * screenのcolonプロンプト:でexec .!. tcfilterのように実行します。 * * オプション: * -o 起動直後からT-Code/TUT-Codeモードをオンにします。 * -k <トグルキー> T-Code/TUT-Codeモードのトグルキーを指定します。 * デフォルトのトグルキーはCTRL-Jです。 * トグルキーの指定は、CTRLキーとの組み合わせを示す^を使うか、 * \の後に文字コードを8進数3桁で指定します。 * CTRL-Jを指定する場合の例: -k ^j もしくは -k \012 * * プログラムの説明: * tclibを使っています。 * TUT-Codeの場合はTUTコード対応パッチを適用したtclibを使ってください。 * * tcfilterは入力をstdinから読んで、stdoutに出力します。 * screenからtcfilterをexec .!.で起動すると、tcfilterのstdoutが * screen内のアプリケーションプロセスに結びつけられるため、 * tcfilterのstdoutへの出力がアプリケーションプロセスに送られます。 * キーボード入力 --stdin--> tcfilter --stdout--> アプリケーションプロセス * (詳細はscreenのinfoのexec commandの部分を参照) * * 基本的にはtclibに付属のsample.cと同じですが、以下のような違いがあります。 * - stdinをrawモードにして、リターンキーを押さなくても出力されるように変更。 * - 起動時に指定するオプション(-o, -k)を追加。 * * バグ: * - 交ぜ書き変換や部首合成変換の編集中の文字列が表示されません。 * - T-Code/TUT-Codeモードがオンかオフかの表示をしないので、 * 今の状態がわからなくなることがあります。 */ #include #include #include #include #include #include #include #include "tclib.h" static void parse_args(int argc, char *argv[]); static void usage(void); static int tinit(void); static void tterm(void); static void onsignal(int sig); static int toggle_key = '\012'; /* CTRL-J */ static int default_on = 0; /* whether tc_mode_on() on start */ static struct termios otty, ntty; static int ttyraw = 0; int main(int argc, char *argv[]) { tc_param_t *param; char result[MAXLINE]; char local_echo[MAXLINE]; int tc_mode; unsigned char uc; parse_args(argc, argv); /* set option values */ param = tc_init_lib(NULL, TC_USE_TSERV); if (param == NULL) { fprintf(stderr, "failed to tc_init_lib().\n"); exit(1); } if (isatty(0)) { if (tinit() < 0) { fprintf(stderr, "failed to setup terminal.\n"); exit(3); } setbuf(stdout, NULL); } tc_mode = 0; if (default_on) { tc_mode_on(param); tc_mode = 1; } /* main loop */ while (read(0, &uc, 1) == 1) { if (uc == toggle_key) { tc_mode ^= 1; if (tc_mode) tc_mode_on(param); else tc_mode_off(param); continue; } if (tc_mode) { if (tc_char(uc, result, local_echo, param)) { fputs(result, stdout); /* fputs(local_echo, stderr); */ } } else { fputc(uc, stdout); } } tterm(); tc_end_lib(param); return 0; } static void parse_args(int argc, char *argv[]) { int i; for (i = 1; i < argc; i++) { if (argv[i][0] != '-') { fprintf(stderr, "unknown parameter: %s\n", argv[i]); exit(2); } switch (argv[i][1]) { case '?': usage(); exit(0); break; case 'o': default_on = 1; break; case 'k': if (++i >= argc) { fprintf(stderr, "toggle key not specified for -k\n"); exit(2); } switch (argv[i][0]) { case '\\': if (sscanf(argv[i]+1, "%o", &toggle_key) < 1) { fprintf(stderr, "toggle key specification error: %s\n", argv[i]); exit(2); } break; case '^': toggle_key = argv[i][1]; if (islower(toggle_key) && toggle_key < 0x80) { toggle_key = toupper(toggle_key); toggle_key -= '@'; } else if (toggle_key >= '@' && toggle_key <= '_') { toggle_key -= '@'; } else { fprintf(stderr, "illegal toggle key character('%c') after '^'\n", toggle_key); exit(2); } break; default: toggle_key = argv[i][1]; break; } break; default: fprintf(stderr, "unknown option: %s\n", argv[i]); exit(2); break; } } } static void usage(void) { fprintf(stderr, "Usage: tcfilter [-o] [-k ]\n" " -o: enable tc mode on start.\n" " -k: specify tc mode toggle key as ^k or octal \\ooo.\n" " (ex: -k ^j or -k \\012 for CTRL-J)\n" " -?: display this help message\n"); } /* put stdin into a raw mode */ /* W・リチャード・スティーヴンス『詳解UNIXプログラミング』プログラム11.10参照 */ static int tinit(void) { if (tcgetattr(0, &otty) < 0) return -1; /* not terminal? */ signal(SIGINT, onsignal); signal(SIGQUIT, onsignal); signal(SIGTERM, onsignal); signal(SIGHUP, onsignal); ntty = otty; ntty.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG); ntty.c_iflag &= ~(BRKINT|ICRNL|INPCK|ISTRIP|IXON); ntty.c_cflag &= ~(CSIZE|PARENB); ntty.c_cflag |= CS8; ntty.c_oflag &= ~(OPOST); ntty.c_cc[VMIN] = 1; ntty.c_cc[VTIME] = 0; if (tcsetattr(0, TCSAFLUSH, &ntty) < 0) { tterm(); return -1; } ttyraw = 1; return 0; } static void tterm(void) { if (ttyraw) tcsetattr(0, TCSAFLUSH, &otty); ttyraw = 0; } static void onsignal(int sig) { tterm(); exit(0); }