~ubuntu-branches/ubuntu/maverick/uim/maverick

« back to all changes in this revision

Viewing changes to uim/canna.c

  • Committer: Bazaar Package Importer
  • Author(s): Masahito Omote
  • Date: 2004-06-18 19:32:34 UTC
  • Revision ID: james.westby@ubuntu.com-20040618193234-hq78k7h4u7f4l35w
Tags: upstream-0.3.9
ImportĀ upstreamĀ versionĀ 0.3.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  canna.c: Canna for uim.
 
3
 
 
4
  Copyright (c) 2003,2004 uim Project http://uim.freedesktop.org/
 
5
 
 
6
  All rights reserved.
 
7
 
 
8
  Redistribution and use in source and binary forms, with or without
 
9
  modification, are permitted provided that the following conditions
 
10
  are met:
 
11
 
 
12
  1. Redistributions of source code must retain the above copyright
 
13
     notice, this list of conditions and the following disclaimer.
 
14
  2. Redistributions in binary form must reproduce the above copyright
 
15
     notice, this list of conditions and the following disclaimer in the
 
16
     documentation and/or other materials provided with the distribution.
 
17
  3. Neither the name of authors nor the names of its contributors
 
18
     may be used to endorse or promote products derived from this software
 
19
     without specific prior written permission.
 
20
 
 
21
  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
22
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
23
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
24
  ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
25
  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
26
  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
27
  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
28
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
29
  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
30
  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
31
  SUCH DAMAGE.
 
32
*/
 
33
 
 
34
#include "config.h"
 
35
#ifdef HAVE_CANNA_RK_H
 
36
#include <canna/RK.h>
 
37
#include <stdlib.h>
 
38
#include <dlfcn.h>
 
39
#include <errno.h>
 
40
#include <string.h>
 
41
#include "context.h"
 
42
 
 
43
#define MAX_CONTEXT 256
 
44
#define LIBCANNA_SO     "libcanna.so"
 
45
 
 
46
#define BUFSIZE 1024
 
47
 
 
48
static LISP true_sym;
 
49
 
 
50
struct canna_context {
 
51
  char diclist[BUFSIZE];
 
52
 
 
53
  int rk_context_id;
 
54
  int rk_mode;
 
55
 
 
56
  int current_cand_num;
 
57
  int max_current_cand_num;
 
58
 
 
59
  int segment_num;
 
60
  int current_segment_num;
 
61
};
 
62
 
 
63
static struct canna_context *context_array = NULL;
 
64
 
 
65
static int context_array_len;
 
66
static int rk_initialized = -1;
 
67
static char *cannaserver = NULL;
 
68
 
 
69
static struct canna_api {
 
70
  void *lib;
 
71
  /*  struct rkfuncs Rk; */
 
72
  int (*RkInitialize)(char *);
 
73
  int (*RkCreateContext)(void);
 
74
  int (*RkCloseContext)(int);
 
75
  int (*RkBgnBun)(int, char *, int, int);
 
76
  int (*RkEndBun)(int, int);
 
77
  int (*RkFinalize)(void);
 
78
  int (*RkGetDicList)(int, char*, int);
 
79
  int (*RkMountDic)(int, char*, int);
 
80
  int (*RkNfer)(int);
 
81
  int (*RkXfer)(int, int);
 
82
  int (*RkEnlarge)(int);
 
83
  int (*RkShorten)(int);
 
84
  int (*RkGetStat)(int, RkStat*);
 
85
  int (*RkGoTo)(int, int);
 
86
  int (*RkGetKanji)(int, char*, int);
 
87
  int (*RkGetKanjiList)(int, char*, int);
 
88
  int (*RkSetServerName)(char*);
 
89
} api;
 
90
 
 
91
static int
 
92
get_canna_api(void)
 
93
{
 
94
  api.lib = dlopen(LIBCANNA_SO, RTLD_NOW);
 
95
  if(!api.lib)
 
96
    return -1;
 
97
 
 
98
  api.RkInitialize = dlsym(api.lib, "RkInitialize");
 
99
  api.RkFinalize = dlsym(api.lib, "RkFinalize");
 
100
  api.RkGetDicList = dlsym(api.lib, "RkGetDicList");
 
101
  api.RkMountDic = dlsym(api.lib, "RkMountDic");
 
102
  api.RkCreateContext = dlsym(api.lib, "RkCreateContext");
 
103
  api.RkCloseContext = dlsym(api.lib, "RkCloseContext");
 
104
  api.RkBgnBun = dlsym(api.lib, "RkBgnBun");
 
105
  api.RkEndBun = dlsym(api.lib, "RkEndBun");
 
106
  api.RkGoTo = dlsym(api.lib, "RkGoTo");
 
107
  api.RkGetKanji = dlsym(api.lib, "RkGetKanji");
 
108
  api.RkGetKanjiList = dlsym(api.lib, "RkGetKanjiList");
 
109
  api.RkGetStat = dlsym(api.lib, "RkGetStat");
 
110
  api.RkXfer = dlsym(api.lib, "RkXfer");
 
111
  api.RkNfer = dlsym(api.lib, "RkXfer");
 
112
  api.RkEnlarge = dlsym(api.lib, "RkEnlarge");
 
113
  api.RkShorten = dlsym(api.lib, "RkShorten");
 
114
  if(api.RkInitialize && api.RkFinalize && api.RkGetDicList &&
 
115
     api.RkMountDic && api.RkCreateContext && api.RkCloseContext &&
 
116
     api.RkBgnBun && api.RkEndBun && api.RkGoTo && api.RkGetKanji &&
 
117
     api.RkGetKanjiList && api.RkGetStat && api.RkXfer && api.RkNfer &&
 
118
     api.RkEnlarge && api.RkShorten)
 
119
  {
 
120
    /* ok! */
 
121
    return 0;
 
122
  }
 
123
  return -1;
 
124
}
 
125
 
 
126
static struct canna_context *
 
127
get_canna_context(int id)
 
128
{
 
129
  int i;
 
130
  struct canna_context *context;
 
131
 
 
132
  context = context_array;
 
133
 
 
134
  if(id >= MAX_CONTEXT || id < 0)
 
135
    return NULL;
 
136
  for(i = 0; i < id; i++)
 
137
    context++;
 
138
 
 
139
/*  printf("rk_context_id: %d\n", context->rk_context_id);
 
140
    printf("segment_num: %d\n", context->segment_num); */
 
141
  return context;
 
142
}
 
143
 
 
144
static LISP
 
145
init_canna_lib(LISP str_)
 
146
{
 
147
  struct canna_context *context;
 
148
  int i;
 
149
 
 
150
  if (get_canna_api() == -1)
 
151
    return NIL;
 
152
 
 
153
  if(str_ != NIL)
 
154
    cannaserver = uim_get_c_string(str_);
 
155
  else
 
156
    cannaserver = NULL;
 
157
 
 
158
  context_array = malloc(sizeof(struct canna_context) * MAX_CONTEXT);
 
159
  if(context_array == NULL)
 
160
    return NIL;
 
161
 
 
162
  context = context_array;
 
163
 
 
164
  for (i = 0; i < MAX_CONTEXT; i++) {
 
165
    context->rk_context_id = -1;
 
166
    context->rk_mode = (RK_XFER << RK_XFERBITS) | RK_KFER;
 
167
 
 
168
    context->current_cand_num = -1;
 
169
    context->max_current_cand_num = -1;
 
170
 
 
171
    context->segment_num = -1;
 
172
    context->current_segment_num = -1;
 
173
 
 
174
    context->diclist[0] = '\0';
 
175
    context++;
 
176
  }
 
177
 
 
178
  return true_sym;
 
179
}
 
180
 
 
181
static LISP
 
182
create_context() {
 
183
  int i;
 
184
  char *buf;
 
185
  int buflen;
 
186
  struct canna_context *cc = context_array;
 
187
 
 
188
  if(rk_initialized == -1) {
 
189
    if(api.RkInitialize(cannaserver) == -1) {
 
190
      fprintf(stderr, "%s\n", strerror(errno));
 
191
      return NIL;
 
192
    }
 
193
    rk_initialized = 1;
 
194
  }
 
195
 
 
196
  for(i = 0; i < MAX_CONTEXT; i++) {
 
197
     if(cc->rk_context_id == -1) {
 
198
        int dic_num;
 
199
        cc->rk_context_id = api.RkCreateContext();
 
200
        dic_num = api.RkGetDicList(cc->rk_context_id,
 
201
                                   cc->diclist, BUFSIZE);
 
202
        if(dic_num == 0) {
 
203
            return NIL;
 
204
        } else if(dic_num == -1) {
 
205
            /* invalid context number */
 
206
            return NIL;
 
207
        } else {
 
208
            int j;
 
209
            /* buf[] = "dicname1\0dicname2\0dicname3\0...dicname_n\0\0" */
 
210
            buf = cc->diclist;
 
211
            for(j = 0; j < dic_num; j++) {
 
212
                api.RkMountDic(cc->rk_context_id, buf, 0);
 
213
                buflen = strlen(buf) + 1;
 
214
                buf += buflen;
 
215
            }
 
216
        }
 
217
        return intcons(i);
 
218
     }
 
219
     cc++;
 
220
  }
 
221
  return NIL;
 
222
}
 
223
 
 
224
static LISP
 
225
release_context(LISP id_)
 
226
{
 
227
  int id = get_c_int(id_);
 
228
  struct canna_context *cc = get_canna_context(id);
 
229
 
 
230
  if(cc == NULL)
 
231
    return NIL;
 
232
 
 
233
  if(cc->rk_context_id == -1)
 
234
    return NIL;
 
235
 
 
236
  if(api.RkCloseContext(cc->rk_context_id) != -1) {
 
237
    cc->rk_context_id = -1;
 
238
    return true_sym;
 
239
  } else {
 
240
    return NIL;
 
241
  }
 
242
}
 
243
 
 
244
static void
 
245
_reset_conversion(int id)
 
246
{
 
247
  struct canna_context *cc = get_canna_context(id);
 
248
  if(cc == NULL)
 
249
     return;
 
250
 
 
251
  if(cc->segment_num >= 0) {
 
252
     cc->segment_num = -1;
 
253
     api.RkEndBun(cc->rk_context_id, 0);
 
254
  }
 
255
}
 
256
 
 
257
static void
 
258
_update_status(int id)
 
259
{
 
260
  RkStat stat;
 
261
  struct canna_context *cc = get_canna_context(id);
 
262
  if(cc == NULL)
 
263
     return;
 
264
 
 
265
  if(cc->rk_context_id == -1)
 
266
     return;
 
267
 
 
268
  if(api.RkGetStat(cc->rk_context_id, &stat) == 0)
 
269
  {
 
270
    cc->current_segment_num = stat.bunnum;
 
271
    cc->current_cand_num = stat.candnum;
 
272
    cc->max_current_cand_num = stat.maxcand;
 
273
  } else {
 
274
    _reset_conversion(id);
 
275
  }
 
276
}
 
277
 
 
278
static void
 
279
_update_segment (const int id, const int segment_num)
 
280
{
 
281
  int i, tmp_segment_num;
 
282
  char buf[BUFSIZE];
 
283
  struct canna_context *cc = get_canna_context(id);
 
284
 
 
285
  if(cc == NULL)
 
286
    return;
 
287
 
 
288
  if(cc->rk_context_id == -1)
 
289
    return;
 
290
 
 
291
  tmp_segment_num = segment_num;
 
292
  if(segment_num >= cc->segment_num)
 
293
    tmp_segment_num = 0;
 
294
 
 
295
  for(i = 0; i <= tmp_segment_num; i++) {
 
296
    int len;
 
297
    api.RkGoTo(cc->rk_context_id, i);
 
298
    len = api.RkGetKanji(cc->rk_context_id, buf, BUFSIZE);
 
299
/*    printf("segment: %d, buf: %s\n", i, buf); */
 
300
  }
 
301
 
 
302
  api.RkGoTo(cc->rk_context_id, tmp_segment_num);
 
303
  _update_status(id);
 
304
}
 
305
 
 
306
static LISP
 
307
begin_conversion(LISP id_, LISP str_)
 
308
{
 
309
  int id = get_c_int(id_);
 
310
  char *str;
 
311
  int len, segment_num, mode;
 
312
  struct canna_context *cc = get_canna_context(id);
 
313
 
 
314
  if(cc == NULL)
 
315
    return NIL;
 
316
 
 
317
  if(cc->rk_context_id == -1)
 
318
    return NIL;
 
319
 
 
320
  mode = cc->rk_mode;
 
321
  str = uim_get_c_string(str_);
 
322
  len = strlen(str);
 
323
 
 
324
  segment_num = api.RkBgnBun(cc->rk_context_id, str, len, mode);
 
325
 
 
326
  if(segment_num == -1) {
 
327
     /* failed to conversion */
 
328
     if(str != NULL)
 
329
        free(str);
 
330
     return NIL;
 
331
  }
 
332
 
 
333
  cc->segment_num = segment_num;
 
334
  _update_segment(id, 0);
 
335
 
 
336
  if(str != NULL)
 
337
     free(str);
 
338
 
 
339
  return intcons(cc->segment_num);
 
340
}
 
341
 
 
342
static LISP
 
343
get_nth_candidate(LISP id_, LISP seg_, LISP nth_)
 
344
{
 
345
  int id = get_c_int(id_);
 
346
  int seg = get_c_int(seg_);
 
347
  int nth = get_c_int(nth_);
 
348
  struct canna_context *cc = get_canna_context(id);
 
349
  char buf[BUFSIZE];
 
350
  int len;
 
351
 
 
352
  if(cc == NULL)
 
353
    return NIL;
 
354
 
 
355
  _update_segment(id, seg);
 
356
  if(nth > cc->max_current_cand_num)
 
357
    nth = 0;
 
358
 
 
359
  api.RkXfer(cc->rk_context_id, nth);
 
360
  len = api.RkGetKanji(cc->rk_context_id, buf, BUFSIZE);
 
361
 
 
362
/*  printf("nth: %d, kanji: %s\n", nth, buf); */
 
363
  return strcons(len, buf);
 
364
}
 
365
 
 
366
static LISP
 
367
get_nr_segments(LISP id_)
 
368
{
 
369
  int id = get_c_int(id_);
 
370
  RkStat stat;
 
371
  struct canna_context *cc = get_canna_context(id);
 
372
 
 
373
  if(cc == NULL)
 
374
     return NIL;
 
375
 
 
376
  if(cc->rk_context_id == -1)
 
377
     return NIL;
 
378
 
 
379
  return intcons(cc->segment_num);
 
380
}
 
381
 
 
382
static LISP
 
383
get_nr_candidate(LISP id_, LISP nth_)
 
384
{
 
385
  int id = get_c_int(id_);
 
386
  int nth = get_c_int(nth_);
 
387
  RkStat stat;
 
388
  struct canna_context *cc = get_canna_context(id);
 
389
 
 
390
  if(cc == NULL)
 
391
     return NIL;
 
392
 
 
393
  if(cc->rk_context_id == -1)
 
394
     return NIL;
 
395
 
 
396
  api.RkGoTo(cc->rk_context_id, nth);
 
397
 
 
398
  if(api.RkGetStat(cc->rk_context_id, &stat) == 0)
 
399
    return intcons(stat.maxcand);
 
400
  else
 
401
    return NIL;
 
402
}
 
403
 
 
404
static LISP
 
405
resize_segment(LISP id_, LISP s_, LISP nth_)
 
406
{
 
407
  int id = get_c_int(id_);
 
408
  int s = get_c_int(s_);
 
409
  int nth = get_c_int(nth_);
 
410
  struct canna_context *cc = get_canna_context(id);
 
411
 
 
412
  if(cc == NULL)
 
413
     return NIL;
 
414
 
 
415
  if(cc->rk_context_id == -1)
 
416
     return NIL;
 
417
 
 
418
  api.RkGoTo(cc->rk_context_id, s);
 
419
  api.RkNfer(cc->rk_context_id);
 
420
 
 
421
  if(nth > 0)
 
422
      cc->segment_num = api.RkEnlarge(cc->rk_context_id);
 
423
  else
 
424
      cc->segment_num = api.RkShorten(cc->rk_context_id);
 
425
 
 
426
  _update_segment(id, cc->current_segment_num);
 
427
 
 
428
  return true_sym;
 
429
}
 
430
 
 
431
static LISP
 
432
commit_segment(LISP id_, LISP s_, LISP nth_)
 
433
{
 
434
  int id = get_c_int(id_);
 
435
  int s = get_c_int(s_);
 
436
  int nth = get_c_int(nth_);
 
437
  struct canna_context *cc = get_canna_context(id);
 
438
 
 
439
  if(cc == NULL)
 
440
     return NIL;
 
441
 
 
442
  if(cc->rk_context_id == -1)
 
443
     return NIL;
 
444
 
 
445
  api.RkEndBun(cc->rk_context_id, 1);
 
446
  cc->segment_num = -1;
 
447
}
 
448
 
 
449
static LISP
 
450
reset_conversion(LISP id_)
 
451
{
 
452
  int id = get_c_int(id_);
 
453
 
 
454
  _reset_conversion(id);
 
455
}
 
456
 
 
457
void
 
458
uim_init_canna(void)
 
459
{
 
460
  true_sym = siod_true_value();
 
461
  init_subr_1("canna-lib-init", init_canna_lib);
 
462
 
 
463
  init_subr_0("canna-lib-alloc-context", create_context);
 
464
  init_subr_1("canna-lib-release-context", release_context);
 
465
  init_subr_3("canna-lib-get-nth-candidate", get_nth_candidate);
 
466
  init_subr_1("canna-lib-get-nr-segments",get_nr_segments);
 
467
  init_subr_2("canna-lib-get-nr-candidates", get_nr_candidate);
 
468
  init_subr_3("canna-lib-resize-segment", resize_segment);
 
469
  init_subr_2("canna-lib-begin-conversion", begin_conversion);
 
470
  init_subr_3("canna-lib-commit-segment", commit_segment);
 
471
  init_subr_1("canna-lib-reset-conversion", reset_conversion);
 
472
}
 
473
 
 
474
void
 
475
uim_quit_canna(void)
 
476
{
 
477
  if(cannaserver != NULL) {
 
478
     free(cannaserver);
 
479
     cannaserver = NULL;
 
480
  }
 
481
 
 
482
  if(api.RkFinalize)
 
483
     api.RkFinalize();
 
484
 
 
485
  if(api.lib) {
 
486
     dlclose(api.lib);
 
487
     memset(&api, 0, sizeof(struct canna_api));
 
488
  }
 
489
 
 
490
  if(context_array != NULL) {
 
491
     free(context_array);
 
492
     context_array = NULL;
 
493
  }
 
494
}
 
495
#endif /* HAVE_CANNA_RK_H */