summaryrefslogtreecommitdiff
path: root/src-util/egg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src-util/egg.c')
-rw-r--r--src-util/egg.c551
1 files changed, 551 insertions, 0 deletions
diff --git a/src-util/egg.c b/src-util/egg.c
new file mode 100644
index 0000000..1ef46a2
--- /dev/null
+++ b/src-util/egg.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2002 The Free Software Initiative of Japan
+ * Author: NIIBE Yutaka
+ */
+
+/*
+ * ANTHY Low Level Agent
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <anthy/anthy.h>
+
+#include "config.h"
+
+/*
+ * connection context
+ * S -- open -> [ ] -- new ----> [ ] -- convert --> [ ] --> get_candidates
+ * <- close -- <- release - <-- commit -- --> resize_segment
+ * <-- cancel -- --> select_candidate
+ *
+ */
+
+struct context {
+ struct anthy_context *ac;
+ int buflen;
+ unsigned char *buf;
+ int removed, inserted;
+ int sellen;
+ int *selection;
+};
+
+#define MAX_CONTEXT 16
+static struct context contexts[MAX_CONTEXT];
+
+extern int use_utf8;
+
+#define INITIAL_BUFLEN 512
+#define INITIAL_SELLEN 128
+
+/*
+ * Returns -1 on error.
+ * Returns >= 0 on success, and the number is context descriptor.
+ */
+static int
+new_context (void)
+{
+ int i;
+
+ for (i = 0; i < MAX_CONTEXT; i++)
+ if (contexts[i].buflen == 0) { /* Found free one */
+ struct context *c = &contexts[i];
+
+ if ((c->buf = (unsigned char *)malloc (INITIAL_BUFLEN)) == NULL)
+ return -1;
+
+ if ((c->selection = (int *)malloc (INITIAL_SELLEN)) == NULL) {
+ free (c->buf);
+ c->buf = NULL;
+ return -1;
+ }
+
+ if ((c->ac = anthy_create_context ()) == NULL) {
+ free (c->buf);
+ c->buf = NULL;
+ free (c->selection);
+ c->selection = NULL;
+ return -1;
+ }
+ if (use_utf8) {
+ anthy_context_set_encoding(c->ac, ANTHY_UTF8_ENCODING);
+ }
+
+ c->buflen = INITIAL_BUFLEN;
+ c->sellen = INITIAL_SELLEN;
+ return i;
+ }
+
+ /* No free context to be used */
+ return -1;
+}
+
+static int
+release_context (int c_desc)
+{
+ struct context *c = &contexts[c_desc];
+
+ anthy_release_context(c->ac);
+ free (c->buf);
+ c->buf = NULL;
+ c->buflen = 0;
+ free (c->selection);
+ c->selection = NULL;
+ c->sellen = 0;
+
+ return 0;
+}
+
+static struct context *
+c_desc_to_context (int c_desc)
+{
+ return &contexts[c_desc];
+}
+
+static int
+get_number_of_segments (struct context *c)
+{
+ struct anthy_conv_stat cs;
+
+ if (anthy_get_stat(c->ac, &cs) < 0)
+ return -1;
+
+ return cs.nr_segment;
+}
+
+static int
+begin_conversion (struct context *c, const char *input)
+{
+ int i;
+ int seg_num;
+ if (anthy_set_string(c->ac, (char *)input) < 0)
+ return -1;
+
+ seg_num = get_number_of_segments (c);
+ if (seg_num >= c->sellen) {
+ c->sellen *= 2;
+ c->selection = realloc (c->selection, c->sellen);
+ if (c->selection == NULL) { /* Fatal */
+ c->sellen = -1;
+ return -1;
+ }
+ }
+
+ for (i = 0; i < seg_num; i++)
+ c->selection[i] = 0;
+
+ return 0;
+}
+
+static int
+end_conversion (struct context *c, int cancel)
+{
+ int n;
+ int seg_num;
+ int can_num;
+
+ if (!cancel) {
+ n = get_number_of_segments (c);
+ for (seg_num = 0; seg_num < n; seg_num++) {
+ can_num = c->selection[seg_num];
+ anthy_commit_segment(c->ac, seg_num, can_num);
+ }
+ }
+
+ return 0;
+}
+
+static int
+get_segment_number_of_candidates (struct context *c, int seg_num)
+{
+ struct anthy_segment_stat ss;
+
+ if (anthy_get_segment_stat (c->ac, seg_num, &ss) != 0)
+ return -1;
+
+ return ss.nr_candidate;
+}
+
+static const unsigned char *
+get_segment_candidate (struct context *c, int seg_num, int cand_num)
+{
+ int len;
+
+ while (1) {
+ len = anthy_get_segment (c->ac, seg_num, cand_num,
+ (char *)c->buf, c->buflen);
+
+ if (len < 0)
+ return NULL;
+
+ if (len < c->buflen)
+ return c->buf;
+
+ c->buflen *= 2;
+ c->buf = realloc (c->buf, c->buflen);
+ if (c->buf == NULL) { /* Fatal */
+ c->buflen = -1;
+ return NULL;
+ }
+ }
+}
+
+static const unsigned char *
+get_segment_yomi (struct context *c, int seg_num)
+{
+ return get_segment_candidate (c, seg_num, NTH_UNCONVERTED_CANDIDATE);
+}
+
+static const unsigned char *
+get_segment_converted (struct context *c, int seg_num)
+{
+ return get_segment_candidate (c, seg_num, 0);
+}
+
+static int
+resize_segment (struct context *c, int seg_num, int inc_dec)
+{
+ int i;
+ struct anthy_conv_stat cs;
+
+ if (anthy_get_stat(c->ac, &cs) < 0)
+ return -1;
+
+ /* Replace all segments after SEG_NUM */
+ c->removed = cs.nr_segment - seg_num;
+ anthy_resize_segment(c->ac, seg_num, inc_dec?-1:1);
+ if (anthy_get_stat(c->ac, &cs) < 0)
+ return -1;
+ c->inserted = cs.nr_segment - seg_num;
+
+ if (cs.nr_segment >= c->sellen) {
+ c->sellen *= 2;
+ c->selection = realloc (c->selection, c->sellen);
+ if (c->selection == NULL) { /* Fatal */
+ c->sellen = -1;
+ return -1;
+ }
+ }
+ for (i = seg_num; i < cs.nr_segment; i++)
+ c->selection[i] = 0;
+
+ return seg_num;
+}
+
+/* Only valid after call of resize_segment or select_candidate */
+static int
+get_number_of_segments_removed (struct context *c, int seg_num)
+{
+ (void)seg_num;
+ return c->removed;
+}
+
+/* Only valid after call of resize_segment or select_candidate */
+static int
+get_number_of_segments_inserted (struct context *c, int seg_num)
+{
+ (void)seg_num;
+ return c->inserted;
+}
+
+static int
+select_candidate (struct context *c, int seg_num, int can_num)
+{
+ /*
+ * Anthy does not have capability to affect the result of selection
+ * to other segments.
+ */
+ c->removed = 0;
+ c->inserted = 0;
+
+ /*
+ * Record, but not call anthy_commit_segment.
+ */
+ c->selection[seg_num] = can_num;
+
+ return seg_num;
+}
+
+static int
+say_hello (void)
+{
+ const char *options = "";
+
+ printf ("Anthy (Version %s) [%s] : Nice to meet you.\r\n", VERSION,
+ options);
+ fflush (stdout);
+ return 0;
+}
+
+#define ERROR_CODE_UNKNOWN 400
+#define ERROR_CODE_UNSUPPOTED 401
+
+static int
+say_unknown (void)
+{
+ printf ("-ERR %d Unknown command.\r\n", ERROR_CODE_UNKNOWN);
+ fflush (stdout);
+ return 0;
+}
+
+static int
+do_commit (const char *line)
+{
+ char *p;
+ struct context *c;
+ int c_desc, cancel, r;
+
+ c_desc = strtol (line+7, &p, 10);
+ c = c_desc_to_context (c_desc);
+ cancel = strtol (p+1, &p, 10);
+ r = end_conversion (c, cancel);
+ if (r < 0)
+ printf ("-ERR %d commit failed.\r\n", -r);
+ else
+ printf ("+OK\r\n");
+ fflush (stdout);
+ return 0;
+}
+
+static void
+output_segments (struct context *c, int seg_num, int removed, int inserted)
+{
+ int i;
+
+ printf ("+DATA %d %d %d\r\n", seg_num, removed, inserted);
+ for (i = seg_num; i < seg_num + inserted; i++) {
+ int nc;
+
+ nc = get_segment_number_of_candidates (c, i);
+ printf ("%d " ,nc);
+ printf ("%s ", get_segment_converted (c, i));
+ printf ("%s\r\n", get_segment_yomi (c, i));
+ }
+ printf ("\r\n");
+}
+
+static int
+do_convert (const char *line)
+{
+ char *p;
+ struct context *c;
+ int c_desc, r;
+
+ c_desc = strtol (line+8, &p, 10);
+ c = c_desc_to_context (c_desc);
+ r = begin_conversion (c, p+1);
+ if (r < 0)
+ printf ("-ERR %d convert failed.\r\n", -r);
+ else
+ {
+ int n = get_number_of_segments (c);
+ output_segments (c, 0, 0, n);
+ }
+
+ fflush (stdout);
+ return 0;
+}
+
+static int
+do_get_candidates (const char *line)
+{
+ char *p;
+ struct context *c;
+ int c_desc, seg_num, cand_offset, max_cands;
+ int nc, i, max;
+
+ c_desc = strtol (line+15, &p, 10);
+ seg_num = strtol (p+1, &p, 10);
+ cand_offset = strtol (p+1, &p, 10);
+ max_cands = strtol (p+1, &p, 10);
+
+ c = c_desc_to_context (c_desc);
+ nc = get_segment_number_of_candidates (c, seg_num);
+
+ max = cand_offset + max_cands;
+ if (nc < cand_offset + max_cands)
+ max = nc;
+
+ printf ("+DATA %d %d\r\n", cand_offset, max);
+ for (i = cand_offset; i < max; i++)
+ printf ("%s\r\n", get_segment_candidate (c, seg_num, i));
+ printf ("\r\n");
+
+ fflush (stdout);
+ return 0;
+}
+
+static int
+do_new_context (const char *line)
+{
+ int r;
+
+ /* XXX: Should check arguments */
+ if (strncmp (" INPUT=#18 OUTPUT=#18", line+11, 20) != 0) {
+ printf ("-ERR %d unsupported context\r\n", ERROR_CODE_UNSUPPOTED);
+ return 1;
+ }
+
+ r = new_context ();
+ if (r < 0)
+ printf ("-ERR %d new context failed.\r\n", -r);
+ else
+ printf ("+OK %d\r\n", r);
+
+ fflush (stdout);
+ return 0;
+}
+
+static int
+do_release_context (const char *line)
+{
+ int c_desc;
+ int r;
+ char *p;
+
+ c_desc = strtol (line+15, &p, 10);
+ r = release_context (c_desc);
+ if (r < 0)
+ printf ("-ERR %d release context failed.\r\n", -r);
+ else
+ printf ("+OK\r\n");
+
+ fflush (stdout);
+ return 0;
+}
+
+static int
+do_resize_segment (const char *line)
+{
+ char *p;
+ struct context *c;
+ int c_desc, seg_num, inc_dec, r;
+
+ c_desc = strtol (line+15, &p, 10);
+ seg_num = strtol (p+1, &p, 10);
+ inc_dec= strtol (p+1, &p, 10);
+ c = c_desc_to_context (c_desc);
+ r = resize_segment (c, seg_num, inc_dec);
+
+ if (r < 0)
+ printf ("-ERR %d resize failed.\r\n", -r);
+ else {
+ int removed, inserted;
+
+ seg_num = r;
+ removed = get_number_of_segments_removed (c, seg_num);
+ inserted = get_number_of_segments_inserted (c, seg_num);
+
+ output_segments (c, seg_num, removed, inserted);
+ }
+
+ fflush (stdout);
+ return 0;
+}
+
+static int
+do_select_candidate (const char *line)
+{
+ char *p;
+ struct context *c;
+ int c_desc, seg_num, cand_num, r;
+
+ c_desc = strtol (line+17, &p, 10);
+ seg_num = strtol (p+1, &p, 10);
+ cand_num = strtol (p+1, &p, 10);
+ c = c_desc_to_context (c_desc);
+ r = select_candidate (c, seg_num, cand_num);
+
+ if (r < 0)
+ printf ("-ERR %d select failed.\r\n", -r);
+ else {
+ int removed;
+
+ seg_num = r;
+ removed = get_number_of_segments_removed (c, seg_num);
+
+ if (removed == 0)
+ printf ("+OK\r\n");
+ else {
+ int inserted = get_number_of_segments_inserted (c, seg_num);
+
+ output_segments (c, seg_num, removed, inserted);
+ }
+ }
+
+ fflush (stdout);
+ return 0;
+}
+
+static int
+do_quit (const char *line)
+{
+ (void)line;
+ return 1;
+}
+
+struct dispatch_table {
+ const char *command;
+ int size;
+ int (*func)(const char *line);
+};
+
+static struct dispatch_table dt[] = {
+ { "COMMIT", 6, do_commit },
+ { "CONVERT", 7, do_convert },
+ { "GET-CANDIDATES", 14, do_get_candidates },
+ { "NEW-CONTEXT", 11, do_new_context },
+ { "QUIT", 4, do_quit },
+ { "RELEASE-CONTEXT", 15, do_release_context },
+ { "RESIZE-SEGMENT", 14, do_resize_segment },
+ { "SELECT-CANDIDATE", 16, do_select_candidate },
+};
+
+static int
+dt_cmp (const char *line, struct dispatch_table *d)
+{
+ return strncmp (line, d->command, d->size);
+}
+
+#define MAX_LINE 512
+static char line[MAX_LINE];
+
+void egg_main (void);
+
+void
+egg_main (void)
+{
+ int done = 0;
+ char *s, *p;
+
+ say_hello ();
+
+ while (!done) {
+ struct dispatch_table *d;
+
+ s = fgets (line, MAX_LINE, stdin);
+ if (s == NULL) {
+ fprintf (stderr, "null input\n");
+ break;
+ }
+ if ((p = (char *)memchr(s, '\n', MAX_LINE)) == NULL) {
+ fprintf (stderr, "no newline\n");
+ break;
+ }
+ if (p > s && *(p-1) == '\r')
+ *(p-1) = '\0';
+ else
+ *p = '\0';
+ d = (struct dispatch_table *)
+ bsearch (s, dt,
+ sizeof (dt) / sizeof (struct dispatch_table),
+ sizeof (struct dispatch_table),
+ (int (*)(const void *, const void *))dt_cmp);
+ if (d != NULL)
+ done = d->func (s);
+ else
+ say_unknown ();
+ }
+}