summaryrefslogtreecommitdiff
path: root/src-util/agent.c
diff options
context:
space:
mode:
Diffstat (limited to 'src-util/agent.c')
-rw-r--r--src-util/agent.c1153
1 files changed, 1153 insertions, 0 deletions
diff --git a/src-util/agent.c b/src-util/agent.c
new file mode 100644
index 0000000..6baede7
--- /dev/null
+++ b/src-util/agent.c
@@ -0,0 +1,1153 @@
+/*
+ * 標準入出力でコマンドを受けたり,変換結果を送るなどの通信を
+ * アプリケーション(おもにEmacs)と行うことにより,アプリケーションに
+ * Anthyによる入力機能を容易かつ安全に追加できる.
+ *
+ * Funded by IPA未踏ソフトウェア創造事業 2002 2/26
+ * Copyright (C) 2001-2002 UGAWA Tomoharu
+ * Copyright (C) 2002-2004 TABATA Yusuke,
+ */
+/*
+ * *マルチコンテキストの扱いを決めかねている
+ * *入出力にstdioを使うかfdを使うか決めかねている
+ */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <anthy/anthy.h>
+#include <anthy/input.h>
+
+#include "rkconv.h"
+
+#include <config.h>
+
+extern void egg_main(void);
+
+/* 何回次候補を押すと候補の列挙を一覧モードに切替えるか? */
+#define DEFAULT_ENUM_CAND_LIMIT 3
+
+
+/* キーに対応する定数 */
+#define KEY_SHIFT 0x00010000
+#define KEY_CTRL 0x00020000
+#define KEY_ALT 0x00040000
+
+#define KEY_SPACE ' '
+#define KEY_OPAR '('
+#define KEY_CPAR ')'
+
+#define KEY_ENTER 0x00000100
+#define KEY_DELETE 0x00000200
+#define KEY_LEFT 0x00000300
+#define KEY_RIGHT 0x00000400
+#define KEY_ESC 0x00000500
+#define KEY_BACKSPACE 0x00000600
+#define KEY_UP 0x00000700
+#define KEY_DOWN 0x00000800
+
+#define KEY_CTRL_A (KEY_CTRL | 'A')
+#define KEY_CTRL_E (KEY_CTRL | 'E')
+#define KEY_CTRL_J (KEY_CTRL | 'J')
+#define KEY_CTRL_K (KEY_CTRL | 'K')
+#define KEY_CTRL_H (KEY_CTRL | 'H')
+#define KEY_CTRL_D (KEY_CTRL | 'D')
+#define KEY_SHIFT_LEFT (KEY_SHIFT | KEY_LEFT)
+#define KEY_SHIFT_RIGHT (KEY_SHIFT | KEY_RIGHT)
+
+#define BUF_GROW_SIZE 4096
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+
+/*
+ * コマンドにはキーが押されたことを示す普通のコマンドと
+ * 高水準な命令のハイレベルコマンドがある.
+ */
+enum {
+ /* ハイレベルコマンド */
+ CMDH_IGNORE_ICTXT, CMDH_GETPREEDIT, CMDH_SELECT_CONTEXT,
+ CMDH_RELEASE_CONTEXT, CMDH_MAP_EDIT, CMDH_MAP_SELECT,
+ CMDH_GET_CANDIDATE, CMDH_SELECT_CANDIDATE, CMDH_CHANGE_TOGGLE,
+ CMDH_MAP_CLEAR, CMDH_SET_BREAK_INTO_ROMAN,
+ CMDH_SET_PREEDIT_MODE, CMDH_PRINT_CONTEXT,
+
+ /* キーコマンド */
+ CMD_SPACE = 1000,
+ CMD_ENTER,
+ CMD_BACKSPACE,
+ CMD_DELETE,
+ CMD_UP,
+ CMD_ESC,
+ CMD_SHIFTARROW,
+ CMD_ARROW,
+ CMD_KEY,
+ CMD_GOBOL,
+ CMD_GOEOL,
+ CMD_CUT
+};
+
+struct high_level_command_type {
+ const char* name;
+ int cmd;
+ int n_arg;
+ int opt_arg;
+} high_level_command_type[] = {
+ /* コンテキストの情報を表示する */
+ {"PRINT_CONTEXT", CMDH_PRINT_CONTEXT, 0, 0},
+ /* トグルに使うキーを変更する */
+ {"CHANGE_TOGGLE", CMDH_CHANGE_TOGGLE, 1, 0},
+ /* コンテキストを選択する */
+ {"SELECT_CONTEXT", CMDH_SELECT_CONTEXT, 1, 0},
+ {"RELEASE_CONTEXT", CMDH_RELEASE_CONTEXT, 0, 0},
+ {"MAP_CLEAR", CMDH_MAP_CLEAR, 1, 0},
+ {"MAP_EDIT", CMDH_MAP_EDIT, 3, 0},
+ {"MAP_SELECT", CMDH_MAP_SELECT, 1, 0},
+ {"GET_CANDIDATE", CMDH_GET_CANDIDATE, 1, 0},
+ {"SELECT_CANDIDATE", CMDH_SELECT_CANDIDATE, 1, 0},
+ /* バックスペースでローマ字に戻る */
+ {"BREAK_INTO_ROMAN", CMDH_SET_BREAK_INTO_ROMAN, 1, 0},
+ /**/
+ {"SET_PREEDIT_MODE", CMDH_SET_PREEDIT_MODE, 1, 0},
+ /**/
+ {NULL, -1, 0, 0}
+};
+
+struct command {
+ int cmd;
+ char** arg;
+ int n_arg;
+ struct command* next;
+};
+
+struct connection {
+ char* rbuf;
+ int n_rbuf;
+ int s_rbuf;
+ int rfd;
+
+ char* wbuf;
+ int n_wbuf;
+ int s_wbuf;
+ int wfd;
+};
+
+static void send_error(void);
+
+static struct connection* conn;
+static struct anthy_input_config* config;
+static struct command* command_queue;
+static int daemon_sock = -1;
+static int anonymous;
+static int egg;
+static char *personality;
+int use_utf8;
+
+static char *
+encode_command_arg(char *a)
+{
+ int i, j, len;
+ char *s;
+
+ len = strlen(a);
+ s = malloc(len + 1);
+ for(i = 0,j = 0; i < len; i++) {
+ if (a[i] != '\\') {
+ s[j] = a[i];
+ j++;
+ continue;
+ }
+ /* バックスラッシュ */
+ i++;
+ switch (a[i]) {
+ case 0:
+ case '\\':
+ s[j] = '\\';
+ j++;
+ break;
+ case '\"':
+ s[j] = '\"';
+ j++;
+ break;
+ case 'X':
+ {
+ char buf[5];
+ unsigned char *p;
+ int num;
+ /* ToBeDone エラーチェック */
+ strncpy(buf, &a[i+1], 4);
+ i+= 5;
+ sscanf(buf, "%x", (unsigned int *)&num);
+ p = (unsigned char *)buf;
+ p[0] = num & 255;
+ p[1] = num >> 8;
+ j += sprintf(&s[j], "%c%c", buf[1] , buf[0]);
+ }
+ break;
+ }
+ }
+ s[j] = 0;
+
+ return s;
+}
+
+static int
+ensure_buffer(char** buf, int* size, int to_size)
+{
+ if (*size < to_size) {
+ *buf = (char*) realloc(*buf, to_size);
+ if (*buf == NULL) {
+ return -1;
+ }
+ *size = to_size;
+ }
+ return 0;
+}
+
+static void
+kill_connection(struct connection* conn)
+{
+ (void) conn;
+ exit(0);
+}
+
+static struct command *
+make_command0(int no)
+{
+ struct command* cmd;
+
+ cmd = (struct command*) malloc(sizeof(struct command));
+ cmd->cmd = no;
+ cmd->n_arg = 0;
+ cmd->arg = NULL;
+ cmd->next = NULL;
+
+ return cmd;
+}
+
+static struct command *
+make_command1(int no, const char* arg1)
+{
+ struct command* cmd;
+
+ cmd = (struct command*) malloc(sizeof(struct command));
+ cmd->cmd = no;
+ cmd->n_arg = 1;
+ cmd->arg = (char**) malloc(sizeof(char*) * 1);
+ cmd->arg[0] = strdup(arg1);
+ cmd->next = NULL;
+
+ return cmd;
+}
+
+static struct key_name_table {
+ const char* name;
+ int code;
+ int is_modifier;
+} key_name_table[] = {
+ {"shift", KEY_SHIFT, 1},
+ {"ctrl", KEY_CTRL, 1},
+ {"alt", KEY_ALT, 1},
+
+ {"space", KEY_SPACE, 0},
+ {"opar", KEY_OPAR, 0},
+ {"cpar", KEY_CPAR, 0},
+ {"enter", KEY_ENTER, 0},
+ {"esc", KEY_ESC, 0},
+ {"backspace", KEY_BACKSPACE, 0},
+ {"delete", KEY_DELETE, 0},
+ {"left", KEY_LEFT, 0},
+ {"right", KEY_RIGHT, 0},
+ {"up", KEY_UP, 0},
+
+ {NULL, 0, 0}
+};
+
+/*
+ * エンコードされたキーの情報を取得する
+ */
+static int
+read_encoded_key(char** buf)
+{
+ char* p;
+ char* str;
+
+ int key = 0;
+
+ /* 閉じ括弧を探す */
+ for (p = *buf + 1; *p; p++) {
+ if (*p == ')') {
+ break;
+ }
+ }
+
+ if (*p == '\0') {
+ *buf = p;
+ return '\0';
+ }
+
+ str = *buf + 1;
+ *p = '\0';
+ *buf = p + 1;
+
+ p = strtok(str, " \t\r");
+ if (!p) {
+ return '\0';
+ }
+
+ do {
+ if (p[1] == '\0') {
+ return key | *p;
+ } else {
+ struct key_name_table* e;
+
+ for (e = key_name_table; e->name; e++) {
+ if (strcmp(e->name, p) == 0) {
+ key |= e->code;
+ if (e->is_modifier == 0) {
+ return key;
+ }
+ }
+ }
+ }
+ } while((p = strtok(NULL, " \t\r")));
+
+ return '\0';
+}
+
+static struct high_level_command_type *
+find_command_type(char *str)
+{
+ struct high_level_command_type* cmdn;
+ for (cmdn = high_level_command_type; cmdn->name; cmdn++) {
+ if (!strcmp(str, cmdn->name)) {
+ return cmdn;
+ }
+ }
+ return NULL;
+}
+
+/* ハイレベルコマンドをパースする */
+static struct command *
+make_hl_command(char *buf)
+{
+ /* high-level command */
+ struct high_level_command_type* cmdn;
+ struct command* cmd = NULL;
+ char* p;
+ int i;
+
+ /* コマンドの種類を調べる */
+ p = strtok(buf, " \t\r");
+ if (!p) {
+ return NULL;
+ }
+ cmdn = find_command_type(p);
+ if (!cmdn) {
+ return NULL;
+ }
+
+ /* コマンドを作る */
+ cmd = (struct command*) malloc(sizeof(struct command));
+ cmd->cmd = cmdn->cmd;
+ cmd->n_arg = cmdn->n_arg;
+ if (cmd->n_arg > 0) {
+ cmd->arg = (char**) malloc(sizeof(char*) * cmd->n_arg);
+ } else {
+ cmd->arg = NULL;
+ }
+ for (i = 0; i < cmd->n_arg; i++) {
+ p = strtok(NULL, " \t\r");
+ if (!p) {
+ while (i-- > 0)
+ free(cmd->arg[i]);
+ free(cmd->arg);
+ free(cmd);
+ return NULL;
+ }
+ cmd->arg[i] = encode_command_arg(p);
+ }
+ while ((p = strtok(NULL, " \t\r"))) {
+ if (!p) {
+ break;
+ }
+ cmd->n_arg++;
+ cmd->arg = (char**) realloc(cmd->arg, sizeof(char*) * cmd->n_arg);
+ cmd->arg[cmd->n_arg - 1] = encode_command_arg(p);
+ }
+ cmd->next = NULL;
+ return cmd;
+}
+
+/* 普通のコマンドをパースする */
+static struct command *
+make_ll_command(char *buf)
+{
+ struct command* cmd_head = NULL;
+ struct command* cmd = NULL;
+ char* p;
+
+ for (p = buf; *p; ) {
+ struct command* cmd0 = NULL;
+ int c;
+
+ if (isspace((int)(unsigned char) *p)) {
+ p++;
+ continue;
+ } else if (*p == '(') {
+ c = read_encoded_key(&p);
+ } else {
+ c = *p++;
+ }
+
+ switch (c) {
+ case '\0':
+ break;
+ case KEY_SPACE:
+ cmd0 = make_command0(CMD_SPACE);
+ break;
+ case KEY_CTRL_J:
+ case KEY_ENTER:
+ case KEY_DOWN:
+ cmd0 = make_command0(CMD_ENTER);
+ break;
+ case KEY_BACKSPACE:
+ case KEY_CTRL_H:
+ cmd0 = make_command0(CMD_BACKSPACE);
+ break;
+ case KEY_DELETE:
+ case KEY_CTRL_D:
+ cmd0 = make_command0(CMD_DELETE);
+ break;
+ case KEY_SHIFT_LEFT:
+ cmd0 = make_command1(CMD_SHIFTARROW, "-1");
+ break;
+ case KEY_SHIFT_RIGHT:
+ cmd0 = make_command1(CMD_SHIFTARROW, "1");
+ break;
+ case KEY_LEFT:
+ cmd0 = make_command1(CMD_ARROW, "-1");
+ break;
+ case KEY_RIGHT:
+ cmd0 = make_command1(CMD_ARROW, "1");
+ break;
+ case KEY_UP:
+ cmd0 = make_command0(CMD_UP);
+ break;
+ case KEY_ESC:
+ cmd0 = make_command0(CMD_ESC);
+ break;
+ case KEY_CTRL_A:
+ cmd0 = make_command0(CMD_GOBOL);
+ break;
+ case KEY_CTRL_E:
+ cmd0 = make_command0(CMD_GOEOL);
+ break;
+ case KEY_CTRL_K:
+ cmd0 = make_command0(CMD_CUT);
+ break;
+ default:
+ if ((c & 0xffffff80) == 0) {
+ /* ASCII文字 */
+ char str[2];
+
+ str[0] = (char)c;
+ str[1] = '\0';
+ /* cmd_key */
+ cmd0 = make_command1(CMD_KEY, str);
+ }
+ break;
+ }
+
+ if (cmd0) {
+ if (cmd) {
+ cmd->next = cmd0;
+ } else {
+ cmd_head = cmd0;
+ }
+ cmd = cmd0;
+ }
+ } /* for (p) */
+
+ if (cmd) {
+ cmd->next = make_command0(CMDH_GETPREEDIT);
+ } else {
+ cmd_head = make_command0(CMDH_GETPREEDIT);
+ }
+
+ return cmd_head;
+}
+
+static struct command*
+make_command(char* buf)
+{
+
+ if (*buf == ' ') {
+ /* ハイレベルコマンド */
+ struct command *cmd;
+ cmd = make_hl_command(buf);
+ if (!cmd) {
+ send_error();
+ }
+ return cmd;
+ }
+ return make_ll_command(buf);
+}
+
+static int
+proc_connection(void)
+{
+ fd_set rfds;
+ fd_set wfds;
+ int max_fd;
+ int ret;
+
+ max_fd = -1;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ if (daemon_sock >= 0) {
+ max_fd = daemon_sock;
+ FD_SET(daemon_sock, &rfds);
+ }
+ max_fd = MAX(conn->rfd, max_fd);
+ FD_SET(conn->rfd, &rfds);
+ if (conn->n_wbuf > 0) {
+ max_fd = MAX(conn->wfd, max_fd);
+ FD_SET(conn->wfd, &wfds);
+ }
+
+ if (max_fd == -1)
+ return -1;
+
+ ret = select(max_fd + 1, &rfds, &wfds, NULL, NULL);
+ if (ret < 0) {
+ return -1;
+ }
+
+ if (conn->n_wbuf > 0 && FD_ISSET(conn->wfd, &wfds)) {
+ ret = write(conn->wfd, conn->wbuf, conn->n_wbuf);
+ if (ret <= 0) {
+ kill_connection (conn);
+ } else {
+ conn->n_wbuf -= ret;
+ if (conn->n_wbuf > 0) {
+ memmove(conn->wbuf, conn->wbuf + ret, conn->n_wbuf);
+ }
+ }
+ }
+
+ if (FD_ISSET(conn->rfd, &rfds)) {
+ ensure_buffer(&conn->rbuf, &conn->s_rbuf,
+ conn->n_rbuf + BUF_GROW_SIZE);
+ ret = read(conn->rfd,
+ conn->rbuf + conn->n_rbuf, conn->s_rbuf - conn->n_rbuf);
+ if (ret <= 0) {
+ kill_connection (conn);
+ } else {
+ conn->n_rbuf += ret;
+ }
+ }
+ return 0;
+}
+
+static struct command *
+read_command(void)
+{
+ struct command* cmd;
+
+AGAIN:
+ if (command_queue != NULL) {
+ cmd = command_queue;
+ command_queue = cmd->next;
+ return cmd;
+ }
+
+ while (1) {
+
+ char* p;
+ for (p = conn->rbuf; p < conn->rbuf + conn->n_rbuf; p++) {
+ if (*p == '\n') {
+ *p = '\0';
+ cmd = make_command(conn->rbuf);
+ conn->n_rbuf -= p + 1 - conn->rbuf;
+ memmove(conn->rbuf, p + 1, conn->n_rbuf);
+ if (cmd) {
+ command_queue = cmd;
+ goto AGAIN;
+ }
+ }
+ }
+
+ if (proc_connection() == -1) {
+ return NULL;
+ }
+
+ }
+}
+
+static void
+write_reply(const char* buf)
+{
+ printf("%s", buf);
+}
+
+static void
+send_error(void)
+{
+ write_reply("ERR\r\n");
+}
+
+static void
+send_ok(void)
+{
+ write_reply("OK\r\n");
+}
+
+static void
+send_number10(int num)
+{
+ char buf[20];
+
+ sprintf(buf, "%d", num);
+ write_reply(buf);
+}
+
+static void
+send_string(const char* str)
+{
+ write_reply(str);
+}
+
+static void
+send_quote_string(const char* str)
+{
+ char buf[20]; /* このぐらいあれば大抵大丈夫 */
+ const char *p;
+ char *q, *end;
+
+ end = buf + sizeof(buf) - 2;
+ for (q = buf, p = str; *p;) {
+ if (q >= end) {
+ *q = '\0';
+ write_reply(buf);
+ q = buf;
+ }
+
+ switch (*p) {
+ case '\"':
+ case '\\':
+ *q++ = '\\';
+ break;
+ default:
+ break;
+ }
+
+ *q++ = *p++;
+ }
+ *q = '\0';
+ write_reply(buf);
+}
+
+static void
+send_preedit(struct anthy_input_preedit* pedit)
+{
+ send_string("(");
+ send_number10(pedit->state);
+
+ if (pedit->commit != NULL) {
+ send_string(" ((COMMIT) \"");
+ send_quote_string(pedit->commit);
+ send_string("\")");
+ }
+
+ if (pedit->cut_buf != NULL) {
+ send_string(" ((CUTBUF) \"");
+ send_quote_string(pedit->cut_buf);
+ send_string("\")");
+ }
+
+ switch (pedit->state) {
+ case ANTHY_INPUT_ST_OFF:
+ case ANTHY_INPUT_ST_NONE:
+ break;
+ case ANTHY_INPUT_ST_EDIT:
+ case ANTHY_INPUT_ST_CONV:
+ case ANTHY_INPUT_ST_CSEG:
+ {
+ struct anthy_input_segment* seg;
+
+ for (seg = pedit->segment; seg; seg = seg->next) {
+ if (seg->str == NULL) {
+ if (seg->flag & ANTHY_INPUT_SF_CURSOR)
+ send_string(" cursor");
+ } else {
+ if (seg->flag & ANTHY_INPUT_SF_CURSOR) {
+ if (seg->flag & ANTHY_INPUT_SF_ENUM)
+ send_string(" ((UL RV ENUM) \"");
+ else if (seg->flag & ANTHY_INPUT_SF_ENUM_REVERSE)
+ send_string(" ((UL RV ENUMR) \"");
+ else
+ send_string(" ((UL RV) \"");
+ } else
+ send_string(" ((UL) \"");
+
+ send_quote_string(seg->str);
+ send_string("\" ");
+ send_number10(seg->cand_no);
+ send_string(" ");
+ send_number10(seg->nr_cand);
+ send_string(")");
+ }
+ }
+ }
+ break;
+ }
+
+ send_string(")\r\n");
+}
+
+static void
+send_single_candidate(struct anthy_input_segment* seg)
+{
+ send_string("(\"");
+ send_quote_string(seg->str);
+ send_string("\" ");
+ send_number10(seg->cand_no);
+ send_string(" ");
+ send_number10(seg->nr_cand);
+ send_string(")\r\n");
+}
+
+static void
+free_command(struct command* cmd)
+{
+ int i;
+
+ for (i = 0; i < cmd->n_arg; i++)
+ free(cmd->arg[i]);
+ free(cmd->arg);
+ free(cmd);
+}
+
+struct input_context_list {
+ int id;
+ struct anthy_input_context* ictx;
+ struct input_context_list* next;
+};
+
+static struct input_context_list* ictx_list = NULL;
+
+static void
+new_input_context(int id)
+{
+ struct input_context_list* ictxl;
+
+ ictxl =
+ (struct input_context_list*) malloc(sizeof (struct input_context_list));
+ ictxl->id = id;
+ ictxl->ictx = anthy_input_create_context(config);
+ ictxl->next = ictx_list;
+ ictx_list = ictxl;
+}
+
+static struct anthy_input_context*
+get_current_input_context(void)
+{
+ if (ictx_list == NULL)
+ new_input_context(0);
+
+ return ictx_list->ictx;
+}
+
+static void
+cmdh_get_preedit(struct anthy_input_context* ictx)
+{
+ struct anthy_input_preedit* pedit;
+
+ pedit = anthy_input_get_preedit(ictx);
+ send_preedit(pedit);
+ anthy_input_free_preedit(pedit);
+}
+
+static void
+cmdh_select_input_context(struct command* cmd)
+{
+ int id;
+ struct input_context_list** p;
+
+ id = atoi(cmd->arg[0]);
+ for (p = &ictx_list; *p; p = &(*p)->next) {
+ if ((*p)->id == id) {
+ struct input_context_list* sel;
+ sel = *p;
+ *p = sel->next;
+ sel->next = ictx_list;
+ ictx_list = sel;
+ send_ok();
+ return;
+ }
+ }
+
+ new_input_context(id);
+ send_ok();
+}
+
+static void
+cmdh_release_input_context(struct command* cmd)
+{
+ struct input_context_list* sel;
+ (void)cmd;
+ if (!ictx_list) {
+ send_ok();
+ return ;
+ }
+ sel = ictx_list;
+ ictx_list = ictx_list->next;
+ anthy_input_free_context(sel->ictx);
+ free(sel);
+ send_ok();
+}
+
+static void
+cmdh_change_toggle(struct command *cmd)
+{
+ int toggle = cmd->arg[0][0];
+ int ret;
+
+ ret = anthy_input_edit_toggle_config(config, toggle);
+
+ if (ret != 0) {
+ send_error();
+ return;
+ }
+ anthy_input_change_config(config);
+ send_ok();
+}
+
+static void
+cmdh_map_clear(struct command *cmd)
+{
+ anthy_input_clear_rk_config(config, atoi(cmd->arg[0]));
+ anthy_input_change_config(config);
+ send_ok();
+}
+
+static void
+cmdh_set_break_into_roman(struct command *cmd)
+{
+ anthy_input_break_into_roman_config(config, atoi(cmd->arg[0]));
+ anthy_input_change_config(config);
+ send_ok();
+}
+
+static void
+cmdh_set_preedit_mode(struct command *cmd)
+{
+ anthy_input_preedit_mode_config(config, atoi(cmd->arg[0]));
+ anthy_input_change_config(config);
+ send_ok();
+}
+
+static void
+cmdh_map_edit(struct command* cmd)
+{
+ /* MAP,from,to */
+ int map_no = atoi(cmd->arg[0]);
+ int ret;
+
+ ret = anthy_input_edit_rk_config(config, map_no,
+ cmd->arg[1], cmd->arg[2], NULL);
+
+ if (ret != 0) {
+ send_error();
+ return;
+ }
+ anthy_input_change_config(config);
+ send_ok();
+}
+
+static void
+cmdh_map_select(struct anthy_input_context* ictx,
+ struct command* cmd)
+{
+ char* map_name;
+ int map_no;
+
+ map_name = cmd->arg[0];
+ if (strcmp(map_name, "alphabet") == 0)
+ map_no = ANTHY_INPUT_MAP_ALPHABET;
+ else if (strcmp(map_name, "hiragana") == 0)
+ map_no = ANTHY_INPUT_MAP_HIRAGANA;
+ else if (strcmp(map_name, "katakana") == 0)
+ map_no = ANTHY_INPUT_MAP_KATAKANA;
+ else if (strcmp(map_name, "walphabet") == 0)
+ map_no = ANTHY_INPUT_MAP_WALPHABET;
+ else if (strcmp(map_name, "hankaku_kana") == 0)
+ map_no = ANTHY_INPUT_MAP_HANKAKU_KANA;
+ else {
+ send_error();
+ return;
+ }
+
+ anthy_input_map_select(ictx, map_no);
+ send_ok();
+}
+
+static void
+cmdh_get_candidate(struct anthy_input_context* ictx,
+ struct command* cmd)
+{
+ struct anthy_input_segment* seg;
+ int cand_no;
+
+ cand_no = atoi(cmd->arg[0]);
+
+ seg = anthy_input_get_candidate(ictx, cand_no);
+ if (seg == NULL)
+ send_error();
+ else {
+ send_single_candidate(seg);
+ anthy_input_free_segment(seg);
+ }
+}
+
+static void
+cmdh_select_candidate(struct anthy_input_context* ictx,
+ struct command* cmd)
+{
+ int ret;
+ int cand_no;
+
+ cand_no = atoi(cmd->arg[0]);
+ ret = anthy_input_select_candidate(ictx, cand_no);
+ if (ret < 0) {
+ send_error();
+ } else {
+ cmdh_get_preedit(ictx);
+ }
+}
+
+static void
+cmd_shift_arrow(struct anthy_input_context* ictx,
+ struct command* cmd)
+{
+ int lr = atoi(cmd->arg[0]);
+ anthy_input_resize(ictx, lr);
+}
+
+static void
+cmd_arrow(struct anthy_input_context* ictx, struct command* cmd)
+{
+ int lr = atoi(cmd->arg[0]);
+ anthy_input_move(ictx, lr);
+}
+
+static void
+cmd_key(struct anthy_input_context* ictx, struct command* cmd)
+{
+ anthy_input_str(ictx, cmd->arg[0]);
+}
+
+/*
+ * コマンドをディスパッチする
+ */
+static void
+dispatch_command(struct anthy_input_context* ictx,
+ struct command* cmd)
+{
+ switch (cmd->cmd) {
+ case CMDH_IGNORE_ICTXT:
+ send_error();
+ break;
+ case CMDH_PRINT_CONTEXT:
+ /* Dirty implementation, would cause corrpution.*/
+ {
+ anthy_context_t ac = anthy_input_get_anthy_context(ictx);
+ if (ac) {
+ anthy_print_context(ac);
+ }
+ }
+ break;
+ case CMDH_GETPREEDIT:
+ cmdh_get_preedit(ictx);
+ break;
+ case CMDH_SELECT_CONTEXT:
+ cmdh_select_input_context(cmd);
+ break;
+ case CMDH_RELEASE_CONTEXT:
+ cmdh_release_input_context(cmd);
+ break;
+ case CMDH_MAP_EDIT:
+ cmdh_map_edit(cmd);
+ break;
+ case CMDH_CHANGE_TOGGLE:
+ cmdh_change_toggle(cmd);
+ break;
+ case CMDH_MAP_CLEAR:
+ cmdh_map_clear(cmd);
+ break;
+ case CMDH_MAP_SELECT:
+ cmdh_map_select(ictx, cmd);
+ break;
+ case CMDH_GET_CANDIDATE:
+ cmdh_get_candidate(ictx, cmd);
+ break;
+ case CMDH_SELECT_CANDIDATE:
+ cmdh_select_candidate(ictx, cmd);
+ break;
+ case CMDH_SET_BREAK_INTO_ROMAN:
+ cmdh_set_break_into_roman(cmd);
+ break;
+ case CMDH_SET_PREEDIT_MODE:
+ cmdh_set_preedit_mode(cmd);
+ break;
+ /* key commands follows */
+
+ case CMD_SPACE:
+ anthy_input_space(ictx);
+ break;
+ case CMD_ENTER:
+ anthy_input_commit(ictx);
+ break;
+ case CMD_BACKSPACE:
+ anthy_input_erase_prev(ictx);
+ break;
+ case CMD_DELETE:
+ anthy_input_erase_next(ictx);
+ break;
+ case CMD_UP:
+ anthy_input_prev_candidate(ictx);
+ break;
+ case CMD_ESC:
+ anthy_input_quit(ictx);
+ break;
+ case CMD_SHIFTARROW:
+ cmd_shift_arrow(ictx, cmd);
+ break;
+ case CMD_ARROW:
+ cmd_arrow(ictx, cmd);
+ break;
+ case CMD_KEY:
+ cmd_key(ictx, cmd);
+ break;
+ case CMD_GOBOL:
+ anthy_input_beginning_of_line(ictx);
+ break;
+ case CMD_GOEOL:
+ anthy_input_end_of_line(ictx);
+ break;
+ case CMD_CUT:
+ anthy_input_cut(ictx);
+ break;
+ }
+}
+
+static void
+main_loop(void)
+{
+ struct anthy_input_context* ictx;
+ struct command* cmd;
+
+ while (1) {
+ cmd = read_command();
+ if (!cmd)
+ break;
+ ictx = get_current_input_context();
+
+ dispatch_command(ictx, cmd);
+ fflush(stdout);
+
+ free_command(cmd);
+ }
+}
+
+static void
+print_version(void)
+{
+ printf(PACKAGE "-agent "VERSION "\n");
+ exit(0);
+}
+
+static void
+parse_args(int argc, char **argv)
+{
+ int i;
+ char *conffile = NULL, *dir = NULL, *dic = NULL;
+
+
+ for (i = 1; i < argc; i++) {
+ char *str = argv[i];
+ if (!strcmp("--version", str)) {
+ print_version();
+ } else if (!strcmp("--anonymous", str)) {
+ anonymous = 1;
+ } else if (!strcmp("--egg", str)) {
+ egg = 1;
+ } else if (!strncmp("--personality=", str, 14)) {
+ personality = &str[14];
+ } else if (!strcmp("--utf8", str)) {
+ use_utf8 = 1;
+ } else if (i < argc - 1) {
+ char *arg = argv[i+1];
+ if (!strcmp("--dir", str)) {
+ dir = arg;
+ i++;
+ } else if (!strcmp("--dic", str)) {
+ dic = arg;
+ i++;
+ } else if (!strcmp("--conffile", str)) {
+ conffile = arg;
+ i++;
+ }
+ }
+ }
+ if (conffile) {
+ anthy_conf_override("CONFFILE", conffile);
+ }
+ if (dir) {
+ anthy_conf_override("ANTHYDIR", dir);
+ }
+ if (dic) {
+ anthy_conf_override("SDIC", dic);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ parse_args(argc, argv);
+ if (anthy_input_init()) {
+ printf("Failed to init anthy\n");
+ exit(0);
+ }
+ if (anonymous) {
+ anthy_input_set_personality("");
+ } else if (personality) {
+ anthy_input_set_personality(personality);
+ }
+
+ if (egg) {
+ egg_main();
+ anthy_quit();
+ } else {
+ config = anthy_input_create_config();
+ conn = (struct connection*) malloc(sizeof(struct connection));
+ conn->rbuf = NULL;
+ conn->n_rbuf = 0;
+ conn->s_rbuf = 0;
+ conn->rfd = 0;
+ conn->wbuf = NULL;
+ conn->n_wbuf = 0;
+ conn->s_wbuf = 0;
+ conn->wfd = 1;
+
+ main_loop();
+ }
+ return 0;
+}