~ubuntu-branches/ubuntu/hardy/uim/hardy

« back to all changes in this revision

Viewing changes to uim/skk.c

  • Committer: Bazaar Package Importer
  • Author(s): Masahito Omote
  • Date: 2005-12-04 13:10:42 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051204131042-ktzc8b17zi7a3cw8
Tags: 1:0.4.9.1-1
* New upstream release
* libuim0-nox, libuim-nox-dev, and libuim0-dbg-nox is now obsolete.
  Because libuim0 does not depends on X11. They now become dummy package,
  therefore you can safely remove them.
* Add --enable-debug in configure again.
* debian/patches/08_fix_privilage_escalation_CVE_2005_3149: disabled.
* Fix Error on purge because update-uim-config is not found.
  (closes: Bug#339345)
* uim-qt: New package for Qt utilities for uim. qt-immodule does not
  contained yet because of Debian's Qt3 does not support immodule and
  because uim does not recognize libqt4-dev's headers properly. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
  Copyright (c) 2003-2005 uim Project http://uim.freedesktop.org/
 
4
 
 
5
  All rights reserved.
 
6
 
 
7
  Redistribution and use in source and binary forms, with or without
 
8
  modification, are permitted provided that the following conditions
 
9
  are met:
 
10
 
 
11
  1. Redistributions of source code must retain the above copyright
 
12
     notice, this list of conditions and the following disclaimer.
 
13
  2. Redistributions in binary form must reproduce the above copyright
 
14
     notice, this list of conditions and the following disclaimer in the
 
15
     documentation and/or other materials provided with the distribution.
 
16
  3. Neither the name of authors nor the names of its contributors
 
17
     may be used to endorse or promote products derived from this software
 
18
     without specific prior written permission.
 
19
 
 
20
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
 
21
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
22
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
23
  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
 
24
  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
25
  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
26
  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
27
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
28
  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
29
  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
30
  SUCH DAMAGE.
 
31
 
 
32
*/
 
33
 
 
34
/*
 
35
 * SKK is a simple Japanese input method
 
36
 *
 
37
 * Many many things are to be implemented!
 
38
 */
 
39
#include <sys/types.h>
 
40
#include <sys/mman.h>
 
41
#include <sys/stat.h>
 
42
#include <fcntl.h>
 
43
#include <unistd.h>
 
44
#include <string.h>
 
45
#include <stdlib.h>
 
46
#include <stdio.h>
 
47
#include <ctype.h>
 
48
#include <signal.h>
 
49
#include <errno.h>
 
50
#include <sys/socket.h>
 
51
#include <netinet/in.h>
 
52
#include <netdb.h>
 
53
 
 
54
#include "uim-scm.h"
 
55
#include "context.h"
 
56
#include "plugin.h"
 
57
 
 
58
#define skk_isalpha(ch) (skk_islower(ch) || skk_isupper(ch))
 
59
#define skk_islower(ch) ((((unsigned char)ch) >= 'a') && (((unsigned char)ch) <= 'z'))
 
60
#define skk_isupper(ch) ((((unsigned char)ch) >= 'A') && (((unsigned char)ch) <= 'Z'))
 
61
#define skk_isascii(ch) ((((unsigned char)ch) & ~0x7f) == 0)
 
62
 
 
63
#define IGNORING_WORD_MAX       63
 
64
 
 
65
/*
 
66
 * cand : candidate
 
67
 */
 
68
 
 
69
 
 
70
/* candidate array for each okurigana
 
71
 *
 
72
 * |C0|C1| .. |Cnr_real_cands| ..              |Cnr_cands|
 
73
 * <-------should be saved --><-- cache of master dict -->
 
74
 */
 
75
struct skk_cand_array {
 
76
  /* okurigana string */
 
77
  char *okuri;
 
78
 
 
79
  int nr_cands; /* length of cands array allocated */
 
80
  int nr_real_cands; /* length of read from file part */
 
81
  /* candidate string */
 
82
  char **cands;
 
83
 
 
84
  /* this array was used and merged with okuri-nasi entry array */
 
85
  int is_used;
 
86
  /* link to its parent line */
 
87
  struct skk_line *line;
 
88
};
 
89
 
 
90
/* skk dictionary line */
 
91
struct skk_line {
 
92
  /* line index. head part */
 
93
  char *head;
 
94
  /* line index. okurigana part. value will be 0 if it is okuri-nasi
 
95
     entry */
 
96
  char okuri_head;
 
97
  /* array of candidate array for different okuri-gana */
 
98
  int nr_cand_array;
 
99
  struct skk_cand_array *cands;
 
100
  /* modified or read from file */
 
101
  int need_save;
 
102
  /* link to next entry in the list */
 
103
  struct skk_line *next;
 
104
};
 
105
 
 
106
/* skk dictionary file */
 
107
static struct dic_info {
 
108
  /* address of mmap'ed dictionary file */
 
109
  void *addr;
 
110
  /* byte offset of first valid entry in mmap'ed region */
 
111
  int first;
 
112
  /* byte offset of first okuri-nasi entry */
 
113
  int border;
 
114
  /* size of dictionary file */
 
115
  int size;
 
116
  /* head of cached skk dictionary line list. LRU ordered */
 
117
  struct skk_line head;
 
118
  /* timestamp of personal dictionary */
 
119
  time_t personal_dic_timestamp;
 
120
  /* whether cached lines are modified or not */
 
121
  int cache_modified;
 
122
  /* length of cached lines */
 
123
  int cache_len;
 
124
  /* skkserv is initialized */
 
125
  int skkserv_ok;
 
126
  /* skkserv port number */
 
127
  int skkserv_portnum;
 
128
} *skk_dic;
 
129
 
 
130
/* completion */
 
131
struct skk_comp_array {
 
132
  /* index of completion */
 
133
  char *head;
 
134
  /* array of completion string */
 
135
  int nr_comps;
 
136
  char **comps;
 
137
  /**/
 
138
  int refcount;
 
139
  /**/
 
140
  struct skk_comp_array *next;
 
141
} *skk_comp;
 
142
 
 
143
static char *sanitize_word(const char *str, const char *prefix);
 
144
static int is_purged_cand(const char *str);
 
145
static void merge_purged_cands(struct skk_cand_array *src_ca,
 
146
                struct skk_cand_array *dst_ca, int src_nth, int dst_nth);
 
147
static void merge_purged_cand_to_dst_array(struct skk_cand_array *src_ca,
 
148
                struct skk_cand_array *dst_ca, char *purged_cand);
 
149
 
 
150
/* skkserv connection */
 
151
#define SKK_SERVICENAME "skkserv"
 
152
#define SKK_SERVER_HOST "localhost"
 
153
#define SKK_SERV_BUFSIZ 1024
 
154
 
 
155
static int skkservsock = -1;
 
156
static FILE *rserv, *wserv;
 
157
static char *SKKServerHost = NULL;
 
158
/* prototype */
 
159
static int open_skkserv(int portnum);
 
160
static void close_skkserv(void);
 
161
 
 
162
static int
 
163
calc_line_len(const char *s)
 
164
{
 
165
  int i;
 
166
  for (i = 0; s[i] != '\n'; i++);
 
167
  return i;
 
168
}
 
169
 
 
170
static int
 
171
is_okuri(const char *line_str)
 
172
{
 
173
  const char *b;
 
174
  /* find first white space */
 
175
  b = strchr(line_str, ' ');
 
176
  if (!b)
 
177
    return 0;
 
178
  /* check previous character */
 
179
  b--;
 
180
  if (skk_isalpha(*b))
 
181
    return 1;
 
182
  return 0;
 
183
}
 
184
 
 
185
static int
 
186
find_first_line(struct dic_info *di)
 
187
{
 
188
  char *s = di->addr;
 
189
  int off = 0;
 
190
 
 
191
  while (off < di->size && s[off] == ';') {
 
192
    int l = calc_line_len(&s[off]);
 
193
    off += l + 1;
 
194
  }
 
195
  return off;
 
196
}
 
197
 
 
198
static int
 
199
find_border(struct dic_info *di)
 
200
{
 
201
  char *s = di->addr;
 
202
  int off = 0;
 
203
  while (off < di->size) {
 
204
    int l = calc_line_len(&s[off]);
 
205
    if (s[off] == ';') {
 
206
      off += l + 1;
 
207
      continue;
 
208
    }
 
209
    if (!is_okuri(&s[off]))
 
210
      return off;
 
211
    off += l + 1;
 
212
  }
 
213
  /* every entry is okuri-ari, it may not happen. */
 
214
  return di->size - 1;
 
215
}
 
216
 
 
217
static struct dic_info *
 
218
open_dic(const char *fn, uim_bool use_skkserv, int skkserv_portnum)
 
219
{
 
220
  struct dic_info *di;
 
221
  struct stat st;
 
222
  int fd;
 
223
  void *addr = NULL;
 
224
  int mmap_done = 0;
 
225
 
 
226
  if (!(di = (struct dic_info *)malloc(sizeof(struct dic_info))))
 
227
    return NULL;
 
228
 
 
229
  di->skkserv_portnum = skkserv_portnum;
 
230
  if (use_skkserv)
 
231
    di->skkserv_ok = open_skkserv(skkserv_portnum);
 
232
  else {
 
233
    di->skkserv_ok = 0;
 
234
    fd = open(fn, O_RDONLY);
 
235
    if (fd != -1) {
 
236
      if (fstat(fd, &st) != -1) {
 
237
        addr = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
 
238
        if (addr != MAP_FAILED) {
 
239
          mmap_done = 1;
 
240
        }
 
241
      }
 
242
    }
 
243
    close(fd);
 
244
  }
 
245
 
 
246
  di->addr = mmap_done ? addr : NULL;
 
247
  di->size = mmap_done ? st.st_size : 0;
 
248
  di->first = mmap_done ? find_first_line(di) : 0;
 
249
  di->border = mmap_done ? find_border(di) : 0;
 
250
 
 
251
  di->head.next = NULL;
 
252
  di->personal_dic_timestamp = 0;
 
253
  di->cache_modified = 0;
 
254
  di->cache_len = 0;
 
255
  
 
256
  return di;
 
257
}
 
258
 
 
259
static const char *
 
260
find_line(struct dic_info *di, int off)
 
261
{
 
262
  char *ptr = di->addr;
 
263
  while (off > 0 && (ptr[off] != '\n' || ptr[off + 1] == ';'))
 
264
    off--;
 
265
 
 
266
  if (off)
 
267
    off++;
 
268
 
 
269
  return &ptr[off];
 
270
}
 
271
 
 
272
static char *
 
273
extract_line_index(struct dic_info *di, int off, char *buf, int len)
 
274
{
 
275
  const char *p = find_line(di, off);
 
276
  int i;
 
277
  if (p[0] == ';')
 
278
    return NULL;
 
279
 
 
280
  for (i = 0; i < len && p[i] != ' '; i++)
 
281
    buf[i] = p[i];
 
282
  buf[i] = '\0';
 
283
 
 
284
  return buf;
 
285
}
 
286
 
 
287
static int
 
288
do_search_line(struct dic_info *di, const char *s, int min,
 
289
               int max, int d)
 
290
{
 
291
  char buf[256];
 
292
  char *r;
 
293
  int idx = (min + max) / 2;
 
294
  int c = 0;
 
295
 
 
296
  if (abs(max - min) < 4)
 
297
    return -1;
 
298
 
 
299
  r = extract_line_index(di, idx, buf, 256);
 
300
  if (r)
 
301
    c = strcmp(s, r);
 
302
  else
 
303
    return -1;
 
304
 
 
305
  if (!c)
 
306
    return idx;
 
307
 
 
308
  if (c * d > 0)
 
309
    return do_search_line(di, s, idx, max, d);
 
310
  else
 
311
    return do_search_line(di, s, min, idx, d);
 
312
 
 
313
  return -1;
 
314
}
 
315
 
 
316
/* This function name is temporary. I want a better name. */
 
317
static char *
 
318
first_space(char *str)
 
319
{
 
320
  while (*str && (*str != ' '))
 
321
    str++;
 
322
 
 
323
  return str;
 
324
}
 
325
 
 
326
/* This function returns a pointer with '/' or '\0' */
 
327
static char *
 
328
next_cand_slash(char *str)
 
329
{
 
330
  int i = 0;
 
331
  int open_bracket = 0;
 
332
 
 
333
  while (*str && (*str != '/' || open_bracket == 1)) {
 
334
    if (*str == '[' && i == 0)
 
335
      open_bracket = 1;
 
336
 
 
337
    if (open_bracket == 1 && *str == ']' && *(str + 1) == '/')
 
338
      open_bracket = 0;
 
339
    str++;
 
340
    i++;
 
341
  }
 
342
  return str;
 
343
}
 
344
 
 
345
static char *
 
346
next_slash_in_bracket(char *str)
 
347
{
 
348
  while (*str && *str != '/')
 
349
    str++;
 
350
 
 
351
  return str;
 
352
}
 
353
 
 
354
static char *
 
355
okuri_in_bracket(char *str)
 
356
{
 
357
  char *p, *term;
 
358
 
 
359
  if (!str)
 
360
    return NULL;
 
361
 
 
362
  p = strdup(str);
 
363
  term = next_slash_in_bracket(p);
 
364
  *term = '\0';
 
365
  return p;
 
366
}
 
367
 
 
368
static char *
 
369
nth_candidate(char *str, int nth)
 
370
{
 
371
  char *p, *term;
 
372
  int i;
 
373
 
 
374
  str = first_space(str);
 
375
  for (i = 0; i <= nth; i++) {
 
376
    str = next_cand_slash(str);
 
377
    if (*str == '/')
 
378
      str++;
 
379
    /*
 
380
     * we don't need sanity check here since argument nth is limited
 
381
     * by caller
 
382
     *
 
383
     * if (*str == '\0')
 
384
     *  return NULL;
 
385
     */ 
 
386
  }
 
387
 
 
388
  if (*str == '\0')
 
389
    return NULL;
 
390
 
 
391
  p = strdup(str);
 
392
  term = next_cand_slash(p);
 
393
  *term = '\0';
 
394
  return p;
 
395
}
 
396
 
 
397
static uim_lisp
 
398
skk_dic_open(uim_lisp fn_, uim_lisp use_skkserv_, uim_lisp skkserv_portnum_)
 
399
{
 
400
  const char *fn = uim_scm_refer_c_str(fn_);
 
401
  uim_bool use_skkserv = uim_scm_c_bool(use_skkserv_);
 
402
  int skkserv_portnum = uim_scm_c_int(skkserv_portnum_);
 
403
  
 
404
  if (!skk_dic) {
 
405
    skk_dic = open_dic(fn, use_skkserv, skkserv_portnum);
 
406
  }
 
407
  return uim_scm_f();
 
408
}
 
409
 
 
410
static void
 
411
free_skk_line(struct skk_line *sl)
 
412
{
 
413
  int i, j;
 
414
 
 
415
  if (!sl)
 
416
    return ;
 
417
 
 
418
  for (i = 0; i < sl->nr_cand_array; i++) {
 
419
    struct skk_cand_array *ca = &sl->cands[i];
 
420
    for (j = 0; j < ca->nr_cands; j++)
 
421
      free(ca->cands[j]);
 
422
    free(ca->okuri);
 
423
    free(ca->cands);
 
424
  }
 
425
  free(sl->head);
 
426
  free(sl->cands);
 
427
}
 
428
 
 
429
static struct skk_cand_array *
 
430
find_candidate_array_from_line(struct skk_line *sl, const char *okuri,
 
431
                               int create_if_notfound)
 
432
{
 
433
  int i;
 
434
  struct skk_cand_array *ca;
 
435
 
 
436
  if (!okuri || !strlen(okuri))
 
437
    return &sl->cands[0];
 
438
 
 
439
  for (i = 1; i < sl->nr_cand_array; i++) {
 
440
    if (okuri && !strcmp(okuri, sl->cands[i].okuri))
 
441
      return &sl->cands[i];
 
442
  }
 
443
 
 
444
  if (!create_if_notfound)
 
445
    return &sl->cands[0];
 
446
 
 
447
  /* allocate now */
 
448
  sl->nr_cand_array++;
 
449
  sl->cands = realloc(sl->cands,
 
450
                      sizeof(struct skk_cand_array) * sl->nr_cand_array);
 
451
  ca = &sl->cands[sl->nr_cand_array - 1];
 
452
  ca->is_used = 0;
 
453
  ca->cands = NULL;
 
454
  ca->nr_cands = 0;
 
455
  ca->nr_real_cands = 0;
 
456
  ca->okuri = strdup(okuri);
 
457
  ca->line = sl;
 
458
  return ca;
 
459
}
 
460
 
 
461
static void
 
462
push_back_candidate_to_array(struct skk_cand_array *ca, const char *cand)
 
463
{
 
464
  ca->nr_cands++;
 
465
  if (ca->cands)
 
466
    ca->cands = realloc(ca->cands, sizeof(char *) * ca->nr_cands);
 
467
  else
 
468
    ca->cands = malloc(sizeof(char *));
 
469
  ca->cands[ca->nr_cands - 1] = strdup(cand);
 
470
}
 
471
 
 
472
static void
 
473
merge_base_candidates_to_array(struct skk_line *sl,
 
474
                               struct skk_cand_array *dst_ca)
 
475
{
 
476
  int i, j;
 
477
  struct skk_cand_array *src_ca;
 
478
 
 
479
  if (!sl)
 
480
    return ;
 
481
 
 
482
  src_ca = &sl->cands[0];
 
483
  if (src_ca == dst_ca)
 
484
    return ;
 
485
 
 
486
  for (i = 0; i < src_ca->nr_cands; i++) {
 
487
    int dup = 0;
 
488
    int src_purged_cand_index = -1;
 
489
    int dst_purged_cand_index = -1;
 
490
 
 
491
    if (i < src_ca->nr_real_cands && is_purged_cand(src_ca->cands[i]))
 
492
      src_purged_cand_index = i;
 
493
 
 
494
    for (j = 0; j < dst_ca->nr_cands; j++) {
 
495
      if (dst_purged_cand_index == -1 && is_purged_cand(dst_ca->cands[j]))
 
496
        dst_purged_cand_index = j;
 
497
      if (!strcmp(src_ca->cands[i], dst_ca->cands[j])) {
 
498
        dup = 1;
 
499
      }
 
500
    }
 
501
    if (!dup) {
 
502
      if (src_purged_cand_index != -1 && dst_purged_cand_index != -1)
 
503
        merge_purged_cands(src_ca, dst_ca, src_purged_cand_index,
 
504
                        dst_purged_cand_index);
 
505
      else if (src_purged_cand_index != -1 && dst_purged_cand_index == -1)
 
506
        merge_purged_cand_to_dst_array(src_ca, dst_ca,
 
507
                        src_ca->cands[src_purged_cand_index]);
 
508
#if 0
 
509
      /*
 
510
       * Just adding words subsequent to real_cands
 
511
       * (push_back_candidate_to_array) is enough.
 
512
       */
 
513
      else if (src_purged_cand_index == -1 && dst_purged_cand_index != -1)
 
514
        merge_word_to_dst_cand_array_with_purged_words(dst_ca,
 
515
                        src_ca, src_ca->cands[i]);
 
516
#endif
 
517
      else
 
518
        push_back_candidate_to_array(dst_ca, src_ca->cands[i]);
 
519
    }
 
520
  }
 
521
}
 
522
 
 
523
static void
 
524
compose_line_parts(struct dic_info *di, struct skk_line *sl,
 
525
                   char *okuri, char *line)
 
526
{
 
527
  int nth;
 
528
  char *tmp;
 
529
  struct skk_cand_array *ca = find_candidate_array_from_line(sl, okuri, 1);
 
530
 
 
531
  nth = 0;
 
532
  do {
 
533
    tmp = nth_candidate(line, nth);
 
534
    if (tmp) {
 
535
      if (tmp[0] == '[') {
 
536
        char *str = okuri_in_bracket(&tmp[1]);
 
537
        tmp[0] = ' '; /* create first_space */
 
538
        compose_line_parts(di, sl, str, &tmp[0]);
 
539
        free(str);
 
540
      } else if (tmp[0] != ']') {
 
541
        push_back_candidate_to_array(ca, tmp);
 
542
      }
 
543
      nth++;
 
544
      free(tmp);
 
545
    } else {
 
546
      break;
 
547
    }
 
548
  } while (1);
 
549
}
 
550
 
 
551
static struct skk_line *
 
552
alloc_skk_line(const char *word, char okuri_head)
 
553
{
 
554
  struct skk_line *sl;
 
555
  sl = malloc(sizeof(struct skk_line));
 
556
  sl->need_save = 0;
 
557
  sl->head = strdup(word);
 
558
  sl->okuri_head = okuri_head;
 
559
  sl->nr_cand_array = 1;
 
560
  sl->cands = malloc(sizeof(struct skk_cand_array));
 
561
  sl->cands[0].okuri = NULL;
 
562
  sl->cands[0].cands = NULL;
 
563
  sl->cands[0].nr_cands = 0;
 
564
  sl->cands[0].nr_real_cands = 0;
 
565
  sl->cands[0].is_used = 0;
 
566
  sl->cands[0].line = sl;
 
567
  return sl;
 
568
}
 
569
 
 
570
static struct skk_line *
 
571
copy_skk_line(struct skk_line *p)
 
572
{
 
573
  int i, j;
 
574
  struct skk_line *sl;
 
575
 
 
576
  if (!p)
 
577
    return NULL;
 
578
 
 
579
  sl = malloc(sizeof(struct skk_line));
 
580
  sl->need_save = p->need_save;
 
581
  sl->head = strdup(p->head);
 
582
  sl->okuri_head = p->okuri_head;
 
583
  sl->nr_cand_array = p->nr_cand_array;
 
584
  sl->cands = malloc(sizeof(struct skk_cand_array) * sl->nr_cand_array);
 
585
  for (i = 0; i < sl->nr_cand_array; i++) {
 
586
    struct skk_cand_array *ca = &sl->cands[i];
 
587
    struct skk_cand_array *q = &p->cands[i];
 
588
 
 
589
    ca->okuri = q->okuri ? strdup(q->okuri) : NULL;
 
590
    ca->nr_cands = q->nr_cands;
 
591
    ca->nr_real_cands = q->nr_real_cands;
 
592
    ca->cands = malloc(sizeof(char *) * ca->nr_cands);
 
593
    for (j = 0; j < ca->nr_cands; j++)
 
594
      ca->cands[j] = strdup(q->cands[j]);
 
595
    ca->is_used = q->is_used;
 
596
    ca->line = sl;
 
597
  }
 
598
  sl->next = NULL;
 
599
  return sl;
 
600
}
 
601
 
 
602
/*
 
603
 * Compose skk line
 
604
 */
 
605
static struct skk_line *
 
606
compose_line(struct dic_info *di, const char *word, char okuri_head, char *entry)
 
607
{
 
608
  struct skk_line *sl;
 
609
 
 
610
  sl = alloc_skk_line(word, okuri_head);
 
611
  /* parse */
 
612
  compose_line_parts(di, sl, NULL, entry);
 
613
 
 
614
  return sl;
 
615
}
 
616
 
 
617
static void
 
618
add_line_to_cache_head(struct dic_info *di, struct skk_line *sl)
 
619
{
 
620
  sl->next = di->head.next;
 
621
  di->head.next = sl;
 
622
 
 
623
  di->cache_len++;
 
624
  di->cache_modified = 1;
 
625
}
 
626
 
 
627
static void
 
628
move_line_to_cache_head(struct dic_info *di, struct skk_line *sl)
 
629
{
 
630
  struct skk_line *prev;
 
631
 
 
632
  if (di->head.next == sl)
 
633
    return;
 
634
 
 
635
  prev = di->head.next;
 
636
  while (prev->next != sl) {
 
637
    prev = prev->next;
 
638
  }
 
639
  prev->next = sl->next;
 
640
  sl->next = di->head.next;
 
641
  di->head.next = sl;
 
642
 
 
643
  di->cache_modified = 1;
 
644
}
 
645
 
 
646
#if 0
 
647
static void
 
648
add_line_to_cache_last(struct dic_info *di, struct skk_line *sl)
 
649
{
 
650
  struct skk_line *prev;
 
651
 
 
652
  if (di->head.next == NULL)
 
653
    di->head.next = sl;
 
654
  else {
 
655
    prev = di->head.next;
 
656
    while (prev->next) {
 
657
      prev = prev->next;
 
658
    }   
 
659
    prev->next = sl;
 
660
  }
 
661
  sl->next = NULL;
 
662
 
 
663
  di->cache_len++;
 
664
  di->cache_modified = 1;
 
665
}
 
666
#endif
 
667
 
 
668
static struct skk_line *
 
669
search_line_from_server(struct dic_info *di, const char *s, char okuri_head)
 
670
{
 
671
  char r;
 
672
  struct skk_line *sl;
 
673
  int n = 0, ret;
 
674
  char buf[SKK_SERV_BUFSIZ];
 
675
  char *line;
 
676
  char *idx = alloca(strlen(s) + 2);
 
677
 
 
678
  sprintf(idx, "%s%c", s, okuri_head);
 
679
 
 
680
  fprintf(wserv, "1%s \n", idx);
 
681
  ret = fflush(wserv);
 
682
  if (ret != 0 && errno == EPIPE) {
 
683
    di->skkserv_ok = open_skkserv(di->skkserv_portnum);
 
684
    return NULL;
 
685
  }
 
686
 
 
687
  line = malloc(strlen(idx) + 2);
 
688
  sprintf(line, "%s ", idx);
 
689
  read(skkservsock, &r, 1);
 
690
  if (r == '1') {  /* succeeded */
 
691
    while (1) {
 
692
      ret = read(skkservsock, &r, 1);
 
693
      if (ret <= 0) {
 
694
        fprintf(stderr, "skkserv connection closed\n");
 
695
        return NULL;
 
696
      }
 
697
 
 
698
      if (r == '\n') {
 
699
        line = realloc(line, strlen(line) + n + 1);
 
700
        strncat(line, buf, n);
 
701
        break;
 
702
      }
 
703
 
 
704
      buf[n] = r;
 
705
      if (n == SKK_SERV_BUFSIZ - 1) {
 
706
        line = realloc(line, strlen(line) + n + 2);
 
707
        strncat(line, buf, n + 1);
 
708
        n = 0;
 
709
      } else {
 
710
        n++;
 
711
      }
 
712
    }
 
713
    sl = compose_line(di, s, okuri_head, line);
 
714
    free(line);
 
715
    return sl;
 
716
  } else {
 
717
    while (read(skkservsock, &r, 1) > 0 && r != '\n');
 
718
    return NULL;
 
719
  }
 
720
}
 
721
        
 
722
static struct skk_line *
 
723
search_line_from_file(struct dic_info *di, const char *s, char okuri_head)
 
724
{
 
725
  int n;
 
726
  const char *p;
 
727
  int len;
 
728
  char *line;
 
729
  char *idx = alloca(strlen(s) + 2);
 
730
  struct skk_line *sl;
 
731
 
 
732
  if (!di->addr)
 
733
    return NULL;
 
734
 
 
735
  sprintf(idx, "%s%c", s, okuri_head);
 
736
  if (okuri_head)
 
737
    n = do_search_line(di, idx, di->first, di->border - 1, -1);
 
738
  else
 
739
    n = do_search_line(di, idx, di->border, di->size - 1, 1);
 
740
 
 
741
  if (n == -1)
 
742
    return NULL;
 
743
 
 
744
  p = find_line(di, n);
 
745
  len = calc_line_len(p);
 
746
  line = malloc(len + 1);
 
747
  line[0] = '\0';
 
748
  strncat(line, p, len);
 
749
  sl = compose_line(di, s, okuri_head, line);
 
750
  free(line);
 
751
  return sl;
 
752
}
 
753
 
 
754
static struct skk_line *
 
755
search_line_from_cache(struct dic_info *di, const char *s, char okuri_head)
 
756
{
 
757
  struct skk_line *sl;
 
758
 
 
759
  if (!di)
 
760
    return NULL;
 
761
 
 
762
  /* search from cache */
 
763
  for (sl = di->head.next; sl; sl = sl->next) {
 
764
    if (!strcmp(sl->head, s) && sl->okuri_head == okuri_head)
 
765
      return sl;
 
766
  }
 
767
  return NULL;
 
768
}
 
769
 
 
770
 
 
771
static struct skk_cand_array *
 
772
find_cand_array(struct dic_info *di, const char *s,
 
773
                char okuri_head, const char *okuri,
 
774
                int create_if_not_found)
 
775
{
 
776
  struct skk_line *sl, *sl_file;
 
777
  struct skk_cand_array *ca;
 
778
  int from_file = 0;
 
779
 
 
780
  if (!di)
 
781
    return NULL;
 
782
 
 
783
  sl = search_line_from_cache(di, s, okuri_head);
 
784
  if (!sl) {
 
785
    if (di->skkserv_ok)
 
786
      sl = search_line_from_server(di, s, okuri_head);
 
787
    else
 
788
      sl = search_line_from_file(di, s, okuri_head);
 
789
    if (!sl) {
 
790
      if (!create_if_not_found)
 
791
        return NULL;
 
792
      sl = alloc_skk_line(s, okuri_head);
 
793
    }
 
794
    from_file = 1;
 
795
    add_line_to_cache_head(di, sl);
 
796
  }
 
797
 
 
798
  ca = find_candidate_array_from_line(sl, okuri, create_if_not_found);
 
799
 
 
800
  if (!ca->is_used) {
 
801
    merge_base_candidates_to_array(sl, ca);
 
802
    ca->is_used = 1;
 
803
    if (!from_file) {
 
804
      if (di->skkserv_ok)
 
805
        sl_file = search_line_from_server(di, s, okuri_head);
 
806
      else
 
807
        sl_file = search_line_from_file(di, s, okuri_head);
 
808
      merge_base_candidates_to_array(sl_file, ca);
 
809
      free_skk_line(sl_file);
 
810
    }
 
811
  }
 
812
 
 
813
  return ca;
 
814
}
 
815
 
 
816
static struct skk_cand_array *
 
817
find_cand_array_lisp(uim_lisp head_, uim_lisp okuri_head_, uim_lisp okuri_,
 
818
                     int create_if_not_found)
 
819
{
 
820
  char o;
 
821
  const char *hs;
 
822
  const char *okuri = NULL;
 
823
  struct skk_cand_array *ca;
 
824
 
 
825
  hs = uim_scm_refer_c_str(head_);
 
826
  if (okuri_ != uim_scm_null_list()) {
 
827
    okuri = uim_scm_refer_c_str(okuri_);
 
828
  }
 
829
  if (okuri_head_ == uim_scm_null_list()) {
 
830
    o = '\0';
 
831
  } else {
 
832
    const char *os = uim_scm_refer_c_str(okuri_head_);
 
833
    o = os[0];
 
834
  }
 
835
 
 
836
  ca = find_cand_array(skk_dic, hs, o, okuri, create_if_not_found);
 
837
  return ca;
 
838
}
 
839
 
 
840
/*
 
841
 * purged_cand: /(skk-ignore-dic-word "foo" "bar" ...)/
 
842
 * purged_words: {"foo", "bar", ..., NULL}
 
843
 */
 
844
static int
 
845
is_purged_cand(const char *str)
 
846
{
 
847
  char *p;
 
848
 
 
849
  p = strstr(str, "(skk-ignore-dic-word ");
 
850
  if (p == str)
 
851
    return 1;
 
852
 
 
853
  return 0;
 
854
}
 
855
 
 
856
static char **
 
857
get_purged_words(const char *str)
 
858
{
 
859
  char *p;
 
860
  char **words = NULL;
 
861
  char *word = NULL;
 
862
  const char *evaluated_word;
 
863
  int nr = 0;
 
864
  int open = 0;
 
865
  int len = 0, word_len;
 
866
  uim_lisp return_val;
 
867
 
 
868
  p = strstr(str, "(skk-ignore-dic-word");
 
869
  if (!p)
 
870
    return NULL;
 
871
 
 
872
  p = first_space(p);
 
873
  if (*p == '\0')
 
874
    return NULL;
 
875
  p++;
 
876
 
 
877
  while (*p != '\0') {
 
878
    if (*p == '"' && p[-1] != '\\') {
 
879
      open = open ? 0 : 1;
 
880
      if (open) {
 
881
        p++;
 
882
        word = p;
 
883
        len = 0;
 
884
      } else {
 
885
        char *orig = malloc(len + 1);
 
886
        nr++;
 
887
        if (words)
 
888
          words = realloc(words, sizeof(char *) * nr);
 
889
        else {
 
890
          words = malloc(sizeof(char *));
 
891
        }
 
892
        strncpy(orig, word, len);
 
893
        orig[len] = '\0';
 
894
 
 
895
        /* need to eval word. siod dependent like \073 -> ';' */
 
896
        UIM_EVAL_FSTRING1(NULL, "(string-append \"%s\")", orig);
 
897
        return_val = uim_scm_return_value();
 
898
        if (return_val == uim_scm_null_list()) {
 
899
          words[nr - 1] = malloc(len + 1);
 
900
          strncpy(words[nr - 1], orig, len);
 
901
          words[nr - 1][len] = '\0';
 
902
        } else {
 
903
          evaluated_word = uim_scm_refer_c_str(return_val);
 
904
          word_len = strlen(evaluated_word);
 
905
          words[nr - 1] = malloc(word_len + 1);
 
906
          strncpy(words[nr - 1], evaluated_word, word_len);
 
907
          words[nr - 1][word_len] = '\0';
 
908
        }
 
909
        free(orig);
 
910
      }
 
911
    }
 
912
    p++;
 
913
    len++;
 
914
  }
 
915
  if (words) {
 
916
    words = realloc(words, sizeof(char *) * (nr + 1));
 
917
    words[nr] = NULL;
 
918
  }
 
919
  return words;
 
920
}
 
921
 
 
922
static int
 
923
nr_purged_words(char **p)
 
924
{
 
925
  int i = 0;
 
926
 
 
927
  while (p && p[i])
 
928
    i++;
 
929
  return i;
 
930
}
 
931
 
 
932
static void
 
933
free_allocated_purged_words(char **p)
 
934
{
 
935
  int i = 0;
 
936
 
 
937
  if (!p)
 
938
    return;
 
939
 
 
940
  while (p[i]) {
 
941
    free(p[i]);
 
942
    i++;
 
943
  }
 
944
  free(p);
 
945
}
 
946
 
 
947
static int
 
948
is_purged_only(struct skk_cand_array *ca)
 
949
{
 
950
  int i, j;
 
951
  char **purged_words;
 
952
 
 
953
  if (ca->nr_real_cands > 1)
 
954
    return 0;
 
955
 
 
956
  if ((purged_words = get_purged_words(ca->cands[0])) != NULL) {
 
957
    int nr_purged = nr_purged_words(purged_words);
 
958
    /* going to compare words beyond nr_real_cands */
 
959
    for (i = ca->nr_real_cands; i < ca->nr_cands; i++) {
 
960
      for (j = 0; j < nr_purged; j++) {
 
961
        /* return false if there is any different candidate */
 
962
        if (strcmp(ca->cands[i], purged_words[j])) {
 
963
          free_allocated_purged_words(purged_words);
 
964
          return 0;
 
965
        }
 
966
      }
 
967
    }
 
968
    free_allocated_purged_words(purged_words);
 
969
    return 1;
 
970
  }
 
971
  return 0;
 
972
}
 
973
 
 
974
static int
 
975
match_to_discarding_index(int indices[], int n)
 
976
{
 
977
  int i = 0;
 
978
  while (indices[i] != -1) {
 
979
    if (indices[i] == n)
 
980
      return 1;
 
981
    i++;
 
982
  }
 
983
  return 0;
 
984
}
 
985
 
 
986
static uim_lisp
 
987
skk_get_entry(uim_lisp head_, uim_lisp okuri_head_, uim_lisp okuri_)
 
988
{
 
989
  struct skk_cand_array *ca;
 
990
  ca = find_cand_array_lisp(head_, okuri_head_, okuri_, 0);
 
991
  if (ca && ca->nr_cands > 0 && !is_purged_only(ca))
 
992
      return uim_scm_t();
 
993
 
 
994
  return uim_scm_f();
 
995
}
 
996
 
 
997
static uim_lisp
 
998
skk_store_replaced_numeric_str(uim_lisp head_)
 
999
{
 
1000
  const char *str;
 
1001
  int len;
 
1002
 
 
1003
  int prev_is_num = 0;
 
1004
  int i, numlen = 0, start = 0;
 
1005
  char *numstr = NULL;
 
1006
  uim_lisp lst = uim_scm_null_list();
 
1007
 
 
1008
  str = uim_scm_refer_c_str(head_);
 
1009
  len = strlen(str);
 
1010
 
 
1011
  for (i = 0; i < len; i++) {
 
1012
    if (isdigit((unsigned char)str[i])) {
 
1013
      if (prev_is_num == 0) {
 
1014
        start = i;
 
1015
        numlen = 1;
 
1016
      } else {
 
1017
        numlen++;
 
1018
      }
 
1019
      prev_is_num = 1;
 
1020
    } else {
 
1021
      if (prev_is_num) {
 
1022
        /* add number into list */
 
1023
        if (!numstr)
 
1024
          numstr = malloc(numlen + 1);
 
1025
        else
 
1026
          numstr = realloc(numstr, numlen + 1);
 
1027
        strncpy(numstr, &str[start], numlen);
 
1028
        numstr[numlen] = '\0';
 
1029
        lst = uim_scm_cons(uim_scm_make_str(numstr), lst);
 
1030
      }
 
1031
      prev_is_num = 0;
 
1032
    }
 
1033
  }
 
1034
  
 
1035
  /*
 
1036
   * Add last number into list if string is ended with numeric
 
1037
   * character.
 
1038
   */
 
1039
  if (prev_is_num) {
 
1040
    if (!numstr)
 
1041
      numstr = malloc(numlen + 1);
 
1042
    else
 
1043
      numstr = realloc(numstr, numlen + 1);
 
1044
    strncpy(numstr, &str[start], numlen);
 
1045
    numstr[numlen] = '\0';
 
1046
    lst = uim_scm_cons(uim_scm_make_str(numstr), lst);
 
1047
  }
 
1048
  free(numstr);
 
1049
 
 
1050
  return uim_scm_reverse(lst);
 
1051
}
 
1052
 
 
1053
static char *wide_num_list[] =
 
1054
  {"��", "��", "��", "��", "��", "��", "��", "��", "��", "��"};
 
1055
static char *kanji_num_list[] =
 
1056
  {"��", "��", "��", "��", "��", "��", "ϻ", "��", "Ȭ", "��"};
 
1057
static char *kanji_num_position_list[] =
 
1058
  {NULL, "��", "ɴ", "��", "��", NULL, NULL, NULL, "��", NULL,
 
1059
   NULL, NULL, "��", NULL, NULL, NULL, "��", NULL, NULL, NULL};
 
1060
static char *kanji_check_num_list[] =
 
1061
  {"��", "��", "б", "��", "��", "��", "ϻ", "��", "Ȭ", "��"};
 
1062
static char *kanji_check_num_position_list[] =
 
1063
  {NULL, "��", "ɴ", "��", "��", NULL, NULL, NULL, "��", NULL,
 
1064
   NULL, NULL, "��", NULL, NULL, NULL, "��", NULL, NULL, NULL};
 
1065
 
 
1066
static char *
 
1067
numeric_wide_or_kanji_conv(const char *numstr, int method)
 
1068
{
 
1069
  char *mbstr;
 
1070
  int i, len;
 
1071
 
 
1072
  len = strlen(numstr);
 
1073
  mbstr = malloc(len * 2 + 1);
 
1074
 
 
1075
  for (i = 0; i < len; i++) {
 
1076
    if (method == 1)
 
1077
      strcpy(&mbstr[i * 2], wide_num_list[numstr[i] - '0']);
 
1078
    else
 
1079
      strcpy(&mbstr[i * 2], kanji_num_list[numstr[i] - '0']);
 
1080
  }
 
1081
  mbstr[len * 2] = '\0';
 
1082
 
 
1083
  return mbstr;
 
1084
}
 
1085
 
 
1086
static char *
 
1087
numeric_kanji_with_position_conv(const char *numstr)
 
1088
{
 
1089
  char *mbstr;
 
1090
  int i, j, len, mblen;
 
1091
  int position;
 
1092
  int head_is_zero = 0;
 
1093
 
 
1094
  len = strlen(numstr);
 
1095
  if (len > 20) /* too big number */
 
1096
    return strdup(numstr);
 
1097
 
 
1098
  mbstr = malloc(len * 2 + 1);
 
1099
  mblen = len * 2;
 
1100
 
 
1101
  for (i = 0, j = 0; j < len; i++, j++) {
 
1102
    position = len - j - 1;
 
1103
    if (numstr[j] == '0') {
 
1104
      i--;
 
1105
      mblen -= 2;
 
1106
      /* check zero at the head */
 
1107
      if (j == 0) {
 
1108
        head_is_zero = 1;
 
1109
      } else {
 
1110
        /* add ��, ��, ��, �� for zero */
 
1111
        if ((position >= 4) && ((position % 4) == 0) && !head_is_zero) {
 
1112
          int use_position = 0;
 
1113
          if (j >= 3) {
 
1114
            if (!((numstr[j - 1] == '0') && (numstr[j - 2] == '0') &&
 
1115
                                    (numstr[j - 3] == '0')))
 
1116
              use_position = 1;
 
1117
          } else if (j == 2) {
 
1118
            if (!((numstr[j - 1] == '0') && (numstr[j - 2] == '0')))
 
1119
              use_position = 1;
 
1120
          } else if (j == 1) {
 
1121
            if (!(numstr[j - 1] == '0'))
 
1122
              use_position = 1;
 
1123
          }
 
1124
          if (use_position) {
 
1125
            i++;
 
1126
            mblen += 2;
 
1127
            if (mblen > len * 2)
 
1128
              mbstr = realloc(mbstr, mblen + 2);
 
1129
            strcpy(&mbstr[i * 2], kanji_num_position_list[position]);
 
1130
          }
 
1131
        }
 
1132
      }
 
1133
    } else {
 
1134
      if (head_is_zero == 1)
 
1135
        head_is_zero = 0;
 
1136
 
 
1137
      /* replace numstr[j] with kanji number */
 
1138
      if (numstr[j] == '1') {
 
1139
        /*
 
1140
         * use "��" only for the one at the place of ��, ��, ��, ��,
 
1141
         * �� or ������
 
1142
         */
 
1143
        if (((position % 4) == 0) ||
 
1144
            ((position >= 7) &&
 
1145
             ((position % 4) == 3) &&
 
1146
             (numstr[j + 1] == '0') &&
 
1147
             (numstr[j + 2] == '0') &&
 
1148
             (numstr[j + 3] == '0'))) {
 
1149
          strcpy(&mbstr[i * 2], kanji_num_list[1]);
 
1150
        } else {
 
1151
          i--;
 
1152
          mblen -= 2;
 
1153
        }
 
1154
      } else {
 
1155
        strcpy(&mbstr[i * 2], kanji_num_list[numstr[j] - '0']);
 
1156
      }
 
1157
 
 
1158
      /* add ��, ɴ, �� for number whose place is exceeded �� */
 
1159
      if (position > 4) {
 
1160
        if ((position % 4) != 0) {
 
1161
          i++;
 
1162
          mblen += 2;
 
1163
          if (mblen > len * 2)
 
1164
            mbstr = realloc(mbstr, mblen + 2);
 
1165
          strcpy(&mbstr[i * 2], kanji_num_position_list[position % 4]);
 
1166
        }
 
1167
      }
 
1168
 
 
1169
      /* add position */
 
1170
      if (kanji_num_position_list[position]) {
 
1171
        i++;
 
1172
        mblen += 2;
 
1173
        if (mblen > len * 2)
 
1174
          mbstr = realloc(mbstr, mblen + 2);
 
1175
        strcpy(&mbstr[i * 2], kanji_num_position_list[position]);
 
1176
      }
 
1177
    }
 
1178
  }
 
1179
 
 
1180
  /* in case of zero */
 
1181
  if (head_is_zero) {
 
1182
    strcpy(&mbstr[0], kanji_num_list[0]);
 
1183
    mblen = 2;
 
1184
  }
 
1185
 
 
1186
  mbstr[mblen] = '\0';
 
1187
  return mbstr;
 
1188
}
 
1189
 
 
1190
static char *
 
1191
numeric_kanji_for_check_conv(const char *numstr)
 
1192
{
 
1193
  char *mbstr;
 
1194
  int i, j, len, mblen;
 
1195
  int position;
 
1196
  int head_is_zero = 0;
 
1197
 
 
1198
  len = strlen(numstr);
 
1199
  if (len > 20) /* too big number */
 
1200
    return strdup(numstr);
 
1201
 
 
1202
  mbstr = malloc(len * 2 + 1);
 
1203
  mblen = len * 2;
 
1204
 
 
1205
  for (i = 0, j = 0; j < len; i++, j++) {
 
1206
    position = len - j - 1;
 
1207
    if (numstr[j] == '0') {
 
1208
      i--;
 
1209
      mblen -= 2;
 
1210
      /* check zero at the head */
 
1211
      if (j == 0) {
 
1212
        head_is_zero = 1;
 
1213
      } else {
 
1214
        /* add ��, ��, ��, �� for zero */
 
1215
        if ((position >= 4) && ((position % 4) == 0) && !head_is_zero) {
 
1216
          int use_position = 0;
 
1217
          if (j >= 3) {
 
1218
            if (!((numstr[j - 1] == '0') && (numstr[j - 2] == '0') &&
 
1219
                                    (numstr[j - 3] == '0')))
 
1220
              use_position = 1;
 
1221
          } else if (j == 2) {
 
1222
            if (!((numstr[j - 1] == '0') && (numstr[j - 2] == '0')))
 
1223
              use_position = 1;
 
1224
          } else if (j == 1) {
 
1225
            if (!((numstr[j - 1] == '0')))
 
1226
              use_position = 1;
 
1227
          }
 
1228
          if (use_position) {
 
1229
            i++;
 
1230
            mblen += 2;
 
1231
            if (mblen > len * 2)
 
1232
              mbstr = realloc(mbstr, mblen + 2);
 
1233
            strcpy(&mbstr[i * 2], kanji_check_num_position_list[position]);
 
1234
          }
 
1235
        }
 
1236
      }
 
1237
    } else {
 
1238
      if (head_is_zero == 1)
 
1239
        head_is_zero = 0;
 
1240
 
 
1241
      /* replace numstr[j] with kanji number */
 
1242
      strcpy(&mbstr[i * 2], kanji_check_num_list[numstr[j] - '0']);
 
1243
 
 
1244
      /* add ��, ɴ, �� for number whose place is exceeded �� */
 
1245
      if (position > 4) {
 
1246
        if ((position % 4) != 0) {
 
1247
          i++;
 
1248
          mblen += 2;
 
1249
          if (mblen > len * 2)
 
1250
            mbstr = realloc(mbstr, mblen + 2);
 
1251
          strcpy(&mbstr[i * 2], kanji_check_num_position_list[position % 4]);
 
1252
        }
 
1253
      }
 
1254
 
 
1255
      /* add position */
 
1256
      if (kanji_check_num_position_list[position]) {
 
1257
        i++;
 
1258
        mblen += 2;
 
1259
        if (mblen > len * 2)
 
1260
          mbstr = realloc(mbstr, mblen + 2);
 
1261
        strcpy(&mbstr[i * 2], kanji_check_num_position_list[position]);
 
1262
      }
 
1263
    }
 
1264
  }
 
1265
 
 
1266
  /* in case of zero */
 
1267
  if (head_is_zero) {
 
1268
    strcpy(&mbstr[0], kanji_check_num_list[0]);
 
1269
    mblen = 2;
 
1270
  }
 
1271
 
 
1272
  mbstr[mblen] = '\0';
 
1273
  return mbstr;
 
1274
}
 
1275
 
 
1276
static char *
 
1277
numeric_shogi_conv(const char *numstr)
 
1278
{
 
1279
  char *mbstr;
 
1280
  int len;
 
1281
 
 
1282
  len = strlen(numstr);
 
1283
  if (len != 2) /* allow two digit number only */
 
1284
    return strdup(numstr);
 
1285
    
 
1286
  mbstr = malloc(5);
 
1287
  strcpy(&mbstr[0], wide_num_list[numstr[0] - '0']);
 
1288
  strcpy(&mbstr[2], kanji_num_list[numstr[1] - '0']);
 
1289
  mbstr[4] = '\0';
 
1290
 
 
1291
  return mbstr;
 
1292
}
 
1293
 
 
1294
/* returns string with malloc() */
 
1295
static char *
 
1296
numeric_convert(const char *numstr, int method)
 
1297
{
 
1298
  char *ret;
 
1299
 
 
1300
  /*
 
1301
   *  method #4 is already handled in skk_get_nth_candidate()
 
1302
   */
 
1303
  switch (method) {
 
1304
  case 0:
 
1305
    ret = strdup(numstr);
 
1306
    break;
 
1307
  case 1: /* ���ѿ��� */
 
1308
  case 2: /* ������ �̼��̵�� */
 
1309
    ret = numeric_wide_or_kanji_conv(numstr, method);
 
1310
    break;
 
1311
  case 3: /* ������ �̼��ͭ�� */
 
1312
    ret = numeric_kanji_with_position_conv(numstr);
 
1313
    break;
 
1314
  case 5: /* ���ڼ�ɽ�� */
 
1315
    ret = numeric_kanji_for_check_conv(numstr);
 
1316
    break;
 
1317
  case 9: /* ����ɽ�� */
 
1318
    ret = numeric_shogi_conv(numstr);
 
1319
    break;
 
1320
  default:
 
1321
    ret = strdup(numstr);
 
1322
    break;
 
1323
  }
 
1324
  return ret;
 
1325
}
 
1326
 
 
1327
static uim_lisp
 
1328
skk_merge_replaced_numeric_str(uim_lisp str_, uim_lisp numlst_)
 
1329
{
 
1330
  char *str;
 
1331
  int i, j, len, newlen;
 
1332
  int method;
 
1333
  int convlen;
 
1334
  const char *numstr;
 
1335
  char *convstr;
 
1336
  uim_lisp merged_str;
 
1337
 
 
1338
  if (str_ == uim_scm_null_list())
 
1339
    return uim_scm_null_list();
 
1340
 
 
1341
  str = uim_scm_c_str(str_);
 
1342
  len = strlen(str);
 
1343
  newlen = len;
 
1344
 
 
1345
  for (i = 0, j = 0; j < len; i++, j++) {
 
1346
    if (str[i] == '#') {
 
1347
      method = str[i + 1] - '0';
 
1348
      if (uim_scm_nullp(numlst_))
 
1349
         break;
 
1350
 
 
1351
      numstr = uim_scm_refer_c_str(uim_scm_car(numlst_));
 
1352
 
 
1353
      convstr = numeric_convert(numstr, method);
 
1354
      convlen = strlen(convstr);
 
1355
 
 
1356
      newlen = newlen - 2 + convlen;
 
1357
      str = realloc(str, newlen + 1);
 
1358
      memmove(&str[i + convlen], &str[i + 2], newlen - i - convlen + 1);
 
1359
      memcpy(&str[i], convstr, convlen);
 
1360
      i = i - 2 + convlen;
 
1361
 
 
1362
      numlst_ = uim_scm_cdr(numlst_);
 
1363
    }
 
1364
  }
 
1365
 
 
1366
  merged_str = uim_scm_make_str(str);
 
1367
  free(str);
 
1368
  return merged_str;
 
1369
}
 
1370
 
 
1371
static uim_lisp
 
1372
skk_replace_numeric(uim_lisp head_)
 
1373
{
 
1374
  char *str;
 
1375
  int prev_is_num = 0;
 
1376
  int i, j, len, newlen;
 
1377
  uim_lisp result;
 
1378
 
 
1379
  str = uim_scm_c_str(head_);
 
1380
  len = strlen(str);
 
1381
  newlen = len;
 
1382
 
 
1383
  for (i = 0, j = 0; j < len; i++, j++) {
 
1384
    if (isdigit((unsigned char)str[i])) {
 
1385
      if (prev_is_num == 0) {
 
1386
        str[i] = '#';
 
1387
      } else {
 
1388
        memmove(&str[i], &str[i + 1], newlen - i);
 
1389
        newlen--;
 
1390
        i--;
 
1391
      }
 
1392
      prev_is_num = 1;
 
1393
    } else {
 
1394
      prev_is_num = 0;
 
1395
    }
 
1396
  }
 
1397
  result = uim_scm_make_str(str);
 
1398
  free(str);
 
1399
  return result;
 
1400
}
 
1401
 
 
1402
static char *
 
1403
find_numeric_conv_method4_mark(const char *cand, int *nth)
 
1404
{
 
1405
  int i, len;
 
1406
  char *p;
 
1407
 
 
1408
  len = strlen(cand);
 
1409
 
 
1410
  p = strstr(cand, "#4");
 
1411
  if (p) {
 
1412
    for (i = 0; i < len; i++) {
 
1413
      if (cand[i] == '#' && isdigit((unsigned char)cand[i + 1])) {
 
1414
        (*nth)++;
 
1415
        if (cand[i + 1] == '4')
 
1416
          break;
 
1417
      }
 
1418
    }
 
1419
  }
 
1420
  return p;
 
1421
}
 
1422
 
 
1423
static uim_lisp
 
1424
get_nth(int nth, uim_lisp lst_)
 
1425
{
 
1426
  int i;
 
1427
  /* nth start from 1 */
 
1428
  for (i = 1; i < nth; i++) {
 
1429
    if (uim_scm_nullp(lst_)) {
 
1430
      return uim_scm_null_list();
 
1431
    }
 
1432
    lst_ = uim_scm_cdr(lst_);
 
1433
  }
 
1434
  return uim_scm_car(lst_);
 
1435
}
 
1436
 
 
1437
static int
 
1438
get_purged_cand_index(struct skk_cand_array *ca)
 
1439
{
 
1440
  int i, n = -1;
 
1441
 
 
1442
  if (!ca)
 
1443
    return -1;
 
1444
 
 
1445
  for (i = 0; i < ca->nr_real_cands; i++) {
 
1446
    if (is_purged_cand(ca->cands[i])) {
 
1447
      n = i;
 
1448
      break;
 
1449
    }
 
1450
  }
 
1451
  return n;
 
1452
}
 
1453
 
 
1454
static int
 
1455
get_ignoring_indices(struct skk_cand_array *ca, int indices[])
 
1456
{
 
1457
  int i, j, k = 0;
 
1458
  int purged_cand_index;
 
1459
  
 
1460
  purged_cand_index= get_purged_cand_index(ca);
 
1461
 
 
1462
  if (purged_cand_index != -1) {
 
1463
    char **purged_words = get_purged_words(ca->cands[purged_cand_index]);
 
1464
    int nr_purged = nr_purged_words(purged_words);
 
1465
 
 
1466
    indices[k] = purged_cand_index;
 
1467
    k++;
 
1468
 
 
1469
    for (i = ca->nr_real_cands; i < ca->nr_cands; i++) {
 
1470
      if (k >= IGNORING_WORD_MAX)
 
1471
        break;
 
1472
      for (j = 0; j < nr_purged; j++) {
 
1473
        if (!strcmp(ca->cands[i], purged_words[j])) {
 
1474
          indices[k] = i;
 
1475
          k++;
 
1476
        }
 
1477
      }
 
1478
    }
 
1479
    indices[k] = -1;
 
1480
    free_allocated_purged_words(purged_words);
 
1481
  } else {
 
1482
    indices[0] = -1;
 
1483
  }
 
1484
  return k;
 
1485
}
 
1486
 
 
1487
static uim_lisp
 
1488
skk_get_nth_candidate(uim_lisp nth_, uim_lisp head_, uim_lisp okuri_head_, uim_lisp okuri_, uim_lisp numlst_)
 
1489
{
 
1490
  int n;
 
1491
  struct skk_cand_array *ca, *subca;
 
1492
  int i, j, k = 0;
 
1493
  char *cands = NULL;
 
1494
  char *p;
 
1495
  const char *numstr;
 
1496
  int method_place = 0;
 
1497
  int sublen, newlen;
 
1498
  int mark;
 
1499
  uim_lisp str_ = uim_scm_null_list();
 
1500
 
 
1501
  int ignoring_indices[IGNORING_WORD_MAX + 1];
 
1502
 
 
1503
  n = uim_scm_c_int(nth_);
 
1504
  ca = find_cand_array_lisp(head_, okuri_head_, okuri_, 0);
 
1505
  get_ignoring_indices(ca, ignoring_indices);
 
1506
 
 
1507
  if (ca) {
 
1508
    /* handle #4 method of numeric conversion */
 
1509
    if (!uim_scm_nullp(numlst_)) {
 
1510
      for (i = 0; i < ca->nr_cands; i++) {
 
1511
        if (match_to_discarding_index(ignoring_indices, i))
 
1512
          continue;
 
1513
 
 
1514
        if ((p = find_numeric_conv_method4_mark(ca->cands[i], &method_place))) {
 
1515
          numstr = uim_scm_refer_c_str(get_nth(method_place, numlst_));
 
1516
          subca = find_cand_array(skk_dic, numstr, 0, NULL, 0);
 
1517
          if (subca) {
 
1518
            for (j = 0; j < subca->nr_cands; j++) {
 
1519
              if (k == n) {
 
1520
                cands = strdup(ca->cands[i]);
 
1521
                sublen = strlen(subca->cands[j]);
 
1522
                newlen = strlen(ca->cands[i]) - 2 + sublen;
 
1523
                mark = p - ca->cands[i];
 
1524
 
 
1525
                cands = realloc(cands, newlen + 1);
 
1526
                memmove(&cands[mark + sublen],
 
1527
                        &cands[mark + 2],
 
1528
                        newlen - mark - sublen + 1);
 
1529
                memcpy(&cands[mark], subca->cands[j], sublen);
 
1530
 
 
1531
                str_ = uim_scm_make_str(cands);
 
1532
                free(cands);
 
1533
                return str_;
 
1534
              }
 
1535
              k++;
 
1536
            }
 
1537
          }
 
1538
        } else {
 
1539
           if (k == n) {
 
1540
             cands = ca->cands[i];
 
1541
             break;
 
1542
           }
 
1543
           k++;
 
1544
        }
 
1545
      }
 
1546
    } else {
 
1547
      for (i = 0; i < ca->nr_cands; i++) {
 
1548
        if (match_to_discarding_index(ignoring_indices, i))
 
1549
          continue;
 
1550
        if (k == n) {
 
1551
          cands = ca->cands[i];
 
1552
          break;
 
1553
        }
 
1554
        k++;
 
1555
      }
 
1556
    }
 
1557
  }
 
1558
 
 
1559
  if (cands)
 
1560
    str_ = uim_scm_make_str(cands);
 
1561
  return str_;
 
1562
}
 
1563
 
 
1564
static uim_lisp
 
1565
skk_get_nr_candidates(uim_lisp head_, uim_lisp okuri_head_, uim_lisp okuri_, uim_lisp numlst_)
 
1566
{
 
1567
  struct skk_cand_array *ca, *subca;
 
1568
  int n = 0;
 
1569
  int i, nr_cands = 0;
 
1570
  const char *numstr;
 
1571
  int method_place = 0;
 
1572
 
 
1573
  int ignoring_indices[IGNORING_WORD_MAX + 1];
 
1574
 
 
1575
  ca = find_cand_array_lisp(head_, okuri_head_, okuri_, 0);
 
1576
  if (ca)
 
1577
    n = ca->nr_cands;
 
1578
  nr_cands = n;
 
1579
  nr_cands -= get_ignoring_indices(ca, ignoring_indices);
 
1580
 
 
1581
  /* handle #4 method of numeric conversion */
 
1582
  if (!uim_scm_nullp(numlst_)) {
 
1583
    for (i = 0; i < n; i++) {
 
1584
      if (match_to_discarding_index(ignoring_indices, i))
 
1585
        continue;
 
1586
 
 
1587
      if (find_numeric_conv_method4_mark(ca->cands[i], &method_place)) {
 
1588
        numstr = uim_scm_refer_c_str(get_nth(method_place, numlst_));
 
1589
        nr_cands--;
 
1590
        subca = find_cand_array(skk_dic, numstr, 0, NULL, 0);
 
1591
        if (subca)
 
1592
          nr_cands += subca->nr_cands;
 
1593
        break;
 
1594
      }
 
1595
    }
 
1596
  }
 
1597
  return uim_scm_make_int(nr_cands);
 
1598
}
 
1599
 
 
1600
static struct skk_comp_array *
 
1601
make_comp_array_from_cache(struct dic_info *di, const char *s)
 
1602
{
 
1603
  struct skk_line *sl;
 
1604
  struct skk_comp_array *ca;
 
1605
 
 
1606
  if (!di)
 
1607
    return NULL;
 
1608
 
 
1609
  ca = malloc(sizeof(struct skk_comp_array));
 
1610
  ca->nr_comps = 0;
 
1611
  ca->refcount = 0;
 
1612
  ca->comps = NULL;
 
1613
  ca->head = NULL;
 
1614
  ca->next = NULL;
 
1615
 
 
1616
  /* search from cache */
 
1617
  for (sl = di->head.next; sl; sl = sl->next) {
 
1618
    if (/* string 's' is part of sl->head */
 
1619
        !strncmp(sl->head, s, strlen(s)) && strcmp(sl->head, s) &&
 
1620
        /* and sl is okuri-nasi line */
 
1621
        (sl->okuri_head == '\0')) {
 
1622
      ca->nr_comps++;
 
1623
      ca->comps = realloc(ca->comps, sizeof(char *) * ca->nr_comps);
 
1624
      ca->comps[ca->nr_comps - 1] = strdup(sl->head);
 
1625
    }
 
1626
  }
 
1627
 
 
1628
  if (ca->nr_comps == 0) {
 
1629
    free(ca);
 
1630
    ca = NULL;
 
1631
  } else {
 
1632
    ca->head = strdup(s);
 
1633
    ca->next = skk_comp;
 
1634
    skk_comp = ca;
 
1635
  }
 
1636
  return ca;
 
1637
}
 
1638
 
 
1639
static struct skk_comp_array *
 
1640
find_comp_array(struct dic_info *di, const char *s)
 
1641
{
 
1642
  struct skk_comp_array *ca;
 
1643
 
 
1644
  if (strlen(s) == 0)
 
1645
    return NULL;
 
1646
 
 
1647
  for (ca = skk_comp; ca; ca = ca->next) {
 
1648
    if (!strcmp(ca->head, s))
 
1649
      break;
 
1650
  }
 
1651
  if (ca == NULL) {
 
1652
    ca = make_comp_array_from_cache(di, s);
 
1653
  }
 
1654
 
 
1655
  return ca;
 
1656
}
 
1657
 
 
1658
static struct skk_comp_array *
 
1659
find_comp_array_lisp(uim_lisp head_)
 
1660
{
 
1661
  const char *hs;
 
1662
  struct skk_comp_array *ca;
 
1663
  
 
1664
  hs = uim_scm_refer_c_str(head_);
 
1665
  ca = find_comp_array(skk_dic, hs);
 
1666
  return ca;
 
1667
}
 
1668
 
 
1669
static uim_lisp
 
1670
skk_get_completion(uim_lisp head_)
 
1671
{
 
1672
  struct skk_comp_array *ca;
 
1673
  ca = find_comp_array_lisp(head_);
 
1674
  if (ca) {
 
1675
    ca->refcount++;
 
1676
    return uim_scm_t();
 
1677
  }
 
1678
  return uim_scm_f();
 
1679
}
 
1680
 
 
1681
static uim_lisp
 
1682
skk_get_nth_completion(uim_lisp nth_, uim_lisp head_)
 
1683
{
 
1684
  int n;
 
1685
  struct skk_comp_array *ca;
 
1686
  char *str;
 
1687
 
 
1688
  ca = find_comp_array_lisp(head_);
 
1689
  n = uim_scm_c_int(nth_);
 
1690
  if (ca && ca->nr_comps > n) {
 
1691
    str = ca->comps[n];
 
1692
    return uim_scm_make_str(str);
 
1693
  }
 
1694
  return uim_scm_null_list();
 
1695
}
 
1696
 
 
1697
static uim_lisp
 
1698
skk_get_nr_completions(uim_lisp head_)
 
1699
{
 
1700
  int n = 0;
 
1701
  struct skk_comp_array *ca;
 
1702
 
 
1703
  ca = find_comp_array_lisp(head_);
 
1704
  if (ca) {
 
1705
    n = ca->nr_comps;
 
1706
  }
 
1707
  return uim_scm_make_int(n);
 
1708
}
 
1709
 
 
1710
static uim_lisp
 
1711
skk_clear_completions(uim_lisp head_)
 
1712
{
 
1713
  int i;
 
1714
  struct skk_comp_array *ca, *ca_prev;
 
1715
  const char *hs;
 
1716
 
 
1717
  hs = uim_scm_refer_c_str(head_);
 
1718
  for (ca = skk_comp; ca; ca = ca->next) {
 
1719
    if (!strcmp(ca->head, hs)) {
 
1720
      ca->refcount--;
 
1721
      break;
 
1722
    }
 
1723
  }
 
1724
 
 
1725
  if (ca && ca->refcount == 0) {
 
1726
    for (i = 0; i < ca->nr_comps; i++) {
 
1727
      free(ca->comps[i]);
 
1728
    }
 
1729
    free(ca->comps);
 
1730
    free(ca->head);
 
1731
 
 
1732
    if (ca == skk_comp) {
 
1733
      skk_comp = ca->next;
 
1734
      free(ca);
 
1735
    } else {
 
1736
      ca_prev = skk_comp;
 
1737
      while (ca_prev->next != ca) {
 
1738
        ca_prev = ca_prev->next;
 
1739
      }
 
1740
      ca_prev->next = ca->next;
 
1741
      free(ca);
 
1742
    }
 
1743
  }
 
1744
  return uim_scm_t();
 
1745
}
 
1746
 
 
1747
static void
 
1748
reorder_candidate(struct skk_cand_array *ca, const char *str)
 
1749
{
 
1750
  int i;
 
1751
  int nth = 0;
 
1752
  char *tmp;
 
1753
  /* find index of the candidate */
 
1754
  for (i = 0; i < ca->nr_cands; i++) {
 
1755
    if (!strcmp(str, ca->cands[i])) {
 
1756
      nth = i;
 
1757
      break;
 
1758
    }
 
1759
  }
 
1760
 
 
1761
  /* shift array */
 
1762
  tmp = ca->cands[nth];
 
1763
  if (nth) {
 
1764
    for (i = nth; i > 0; i--)
 
1765
      ca->cands[i] = ca->cands[i - 1];
 
1766
    ca->cands[0] = tmp;
 
1767
    skk_dic->cache_modified = 1;
 
1768
  }
 
1769
  /* */
 
1770
  if (nth >= ca->nr_real_cands)
 
1771
    ca->nr_real_cands++;
 
1772
}
 
1773
 
 
1774
static void push_purged_word(struct skk_cand_array *ca, int nth, int append, char *word)
 
1775
{
 
1776
  char *cand = ca->cands[nth];
 
1777
  int len, oldlen = strlen(cand);
 
1778
  char *p = sanitize_word(word, NULL);
 
1779
 
 
1780
  if (!p)
 
1781
    return;
 
1782
 
 
1783
  if (append) {
 
1784
    /* check whether the word is already registerd */
 
1785
    char **purged_words = get_purged_words(cand);
 
1786
    int nr_purged = nr_purged_words(purged_words);
 
1787
    int j;
 
1788
    for (j = 0; j < nr_purged; j++) {
 
1789
      if (!strcmp(purged_words[j], word)) {
 
1790
        free_allocated_purged_words(purged_words);
 
1791
        return;
 
1792
      }
 
1793
    }
 
1794
    free_allocated_purged_words(purged_words);
 
1795
 
 
1796
    len = oldlen + strlen(p) + 3;
 
1797
    cand = realloc(cand, len + 1);
 
1798
    if (cand) {
 
1799
      cand[oldlen - 1] = '\0';
 
1800
      strcat(cand, " \"");
 
1801
      strcat(cand, p);
 
1802
      strcat(cand, "\")");
 
1803
      ca->cands[nth] = cand;
 
1804
      skk_dic->cache_modified = 1;
 
1805
    }
 
1806
  } else {
 
1807
    cand = realloc(cand, strlen("(skk-ignore-dic-word \"\")") + strlen(p) + 1);
 
1808
    if (cand) {
 
1809
      sprintf(cand, "(skk-ignore-dic-word \"%s\")", p);
 
1810
      ca->cands[nth] = cand;
 
1811
      skk_dic->cache_modified = 1;
 
1812
    }
 
1813
  }
 
1814
}
 
1815
 
 
1816
static void remove_candidate_from_array(struct skk_cand_array *ca, int nth)
 
1817
{
 
1818
  int i;
 
1819
 
 
1820
  free(ca->cands[nth]);
 
1821
  for (i = nth; i < ca->nr_cands - 1; i++)
 
1822
    ca->cands[i] = ca->cands[i + 1];
 
1823
  if (nth < ca->nr_real_cands)
 
1824
    ca->nr_real_cands--;
 
1825
  ca->nr_cands--;
 
1826
  skk_dic->cache_modified = 1;
 
1827
}
 
1828
 
 
1829
static void
 
1830
merge_word_to_real_cand_array(struct skk_cand_array *ca, const char *word)
 
1831
{
 
1832
  int i, nth = -1;
 
1833
  char *tmp;
 
1834
 
 
1835
  push_back_candidate_to_array(ca, word);
 
1836
  nth = ca->nr_cands - 1;
 
1837
 
 
1838
  /* move word at the end of real cand array */
 
1839
  tmp = ca->cands[nth];
 
1840
  if (nth >= ca->nr_real_cands) {
 
1841
    for (i = nth; i > ca->nr_real_cands; i--)
 
1842
      ca->cands[i] = ca->cands[i - 1];
 
1843
    ca->cands[ca->nr_real_cands] = tmp;
 
1844
    ca->nr_real_cands++;
 
1845
  }
 
1846
}
 
1847
 
 
1848
static int exist_in_purged_cand(struct skk_cand_array *ca,
 
1849
                const char *word)
 
1850
{
 
1851
  int i, purged_cand_index;
 
1852
  char **purged_words;
 
1853
  int nr_purged;
 
1854
 
 
1855
  purged_cand_index = get_purged_cand_index(ca);
 
1856
  if (purged_cand_index == -1)
 
1857
    return 0;
 
1858
 
 
1859
  purged_words = get_purged_words(ca->cands[purged_cand_index]);
 
1860
  nr_purged = nr_purged_words(purged_words);
 
1861
 
 
1862
  for (i = 0; i < nr_purged; i++) {
 
1863
    if (!strcmp(purged_words[i], word)) {
 
1864
      free_allocated_purged_words(purged_words);
 
1865
      return 1;
 
1866
    }
 
1867
  }
 
1868
  free_allocated_purged_words(purged_words);
 
1869
  return 0;
 
1870
}
 
1871
 
 
1872
static int index_in_real_cands(struct skk_cand_array *ca, const char *str)
 
1873
{
 
1874
  int i;
 
1875
  for (i = 0; i < ca->nr_real_cands; i++) {
 
1876
    if (!strcmp(ca->cands[i], str))
 
1877
      return i;
 
1878
  }
 
1879
  return -1;
 
1880
}
 
1881
 
 
1882
static void
 
1883
remove_purged_words_from_dst_cand_array(struct skk_cand_array *src_ca,
 
1884
                struct skk_cand_array *dst_ca, const char *purged_cand)
 
1885
{
 
1886
  char **purged_words;
 
1887
  int nr_words;
 
1888
  int i, j;
 
1889
 
 
1890
  purged_words = get_purged_words(purged_cand);
 
1891
  nr_words = nr_purged_words(purged_words);
 
1892
 
 
1893
  for (i = 0; i < nr_words; i++) {
 
1894
    int dup = 0;
 
1895
 
 
1896
    if (index_in_real_cands(src_ca, purged_words[i]) != -1)
 
1897
      continue;
 
1898
 
 
1899
    for (j = 0; j < dst_ca->nr_real_cands; j++) {
 
1900
       if (!strcmp(purged_words[i], dst_ca->cands[j])) {
 
1901
         dup = 1;
 
1902
         break;
 
1903
       }
 
1904
    }
 
1905
    if (dup)
 
1906
      remove_candidate_from_array(dst_ca, j);
 
1907
  }
 
1908
  free_allocated_purged_words(purged_words);
 
1909
}
 
1910
 
 
1911
static void
 
1912
merge_purged_cands(struct skk_cand_array *src_ca, struct skk_cand_array *dst_ca,
 
1913
                int src_nth, int dst_nth)
 
1914
{
 
1915
  char *src_cand = src_ca->cands[src_nth];
 
1916
  char *dst_cand = dst_ca->cands[dst_nth];
 
1917
  char **dst_purged_words, **src_purged_words;
 
1918
  int nr_dst_purged_words, nr_src_purged_words;
 
1919
  int i, j;
 
1920
 
 
1921
  src_purged_words = get_purged_words(src_cand);
 
1922
  dst_purged_words = get_purged_words(dst_cand);
 
1923
  nr_src_purged_words = nr_purged_words(src_purged_words);
 
1924
  nr_dst_purged_words = nr_purged_words(dst_purged_words);
 
1925
 
 
1926
  for (i = 0; i < nr_src_purged_words; i++) {
 
1927
    int dup = 0;
 
1928
    for (j = 0; j < nr_dst_purged_words; j++) {
 
1929
      if (!strcmp(src_purged_words[i], dst_purged_words[j])) {
 
1930
        dup = 1;
 
1931
        break;
 
1932
      }
 
1933
    }
 
1934
    if (!dup) {
 
1935
      push_purged_word(dst_ca, dst_nth, 1, src_purged_words[i]);
 
1936
      remove_purged_words_from_dst_cand_array(src_ca, dst_ca, src_ca->cands[src_nth]);
 
1937
    }
 
1938
  }
 
1939
  free_allocated_purged_words(dst_purged_words);
 
1940
  free_allocated_purged_words(src_purged_words);
 
1941
}
 
1942
 
 
1943
static void
 
1944
merge_purged_cand_to_dst_array(struct skk_cand_array *src_ca,
 
1945
                struct skk_cand_array *dst_ca, char *purged_cand)
 
1946
{
 
1947
  remove_purged_words_from_dst_cand_array(src_ca, dst_ca, purged_cand);
 
1948
  merge_word_to_real_cand_array(dst_ca, purged_cand);
 
1949
}
 
1950
 
 
1951
static void
 
1952
merge_word_to_dst_cand_array_with_purged_words(struct skk_cand_array *dst_ca,
 
1953
                struct skk_cand_array *src_ca, const char *src_cand)
 
1954
{
 
1955
  int i, nth;
 
1956
  char *tmp;
 
1957
 
 
1958
  if (exist_in_purged_cand(dst_ca, src_cand) && !exist_in_purged_cand(src_ca, src_cand))
 
1959
    return;
 
1960
 
 
1961
  push_back_candidate_to_array(dst_ca, src_cand);
 
1962
  nth = dst_ca->nr_cands - 1;
 
1963
 
 
1964
  /* move word at the end of real cand array */
 
1965
  tmp = dst_ca->cands[nth];
 
1966
  if (nth >= dst_ca->nr_real_cands) {
 
1967
    for (i = nth; i > dst_ca->nr_real_cands; i--)
 
1968
      dst_ca->cands[i] = dst_ca->cands[i - 1];
 
1969
    dst_ca->cands[dst_ca->nr_real_cands] = tmp;
 
1970
    dst_ca->nr_real_cands++;
 
1971
  }
 
1972
}
 
1973
 
 
1974
static void
 
1975
merge_real_candidate_array(struct skk_cand_array *src_ca,
 
1976
                           struct skk_cand_array *dst_ca)
 
1977
{
 
1978
  int i, j;
 
1979
  int src_nr_real_cands = src_ca->nr_real_cands;
 
1980
  int dst_nr_real_cands = dst_ca->nr_real_cands;
 
1981
 
 
1982
  if (!src_ca || !dst_ca)
 
1983
    return ;
 
1984
 
 
1985
  for (i = 0; i < src_nr_real_cands; i++) {
 
1986
    int dup = 0;
 
1987
    int src_purged_cand_index = -1;
 
1988
    int dst_purged_cand_index = -1;
 
1989
 
 
1990
    if (is_purged_cand(src_ca->cands[i]))
 
1991
      src_purged_cand_index = i;
 
1992
 
 
1993
    for (j = 0; j < dst_nr_real_cands; j++) {
 
1994
      if (dst_purged_cand_index == -1 && is_purged_cand(dst_ca->cands[j]))
 
1995
        dst_purged_cand_index = j;
 
1996
      if (!strcmp(src_ca->cands[i], dst_ca->cands[j]))
 
1997
        dup = 1;
 
1998
    }
 
1999
 
 
2000
    if (!dup) {
 
2001
      /* be careful! */
 
2002
      if (src_purged_cand_index != -1 && dst_purged_cand_index != -1)
 
2003
        merge_purged_cands(src_ca, dst_ca, src_purged_cand_index,
 
2004
                        dst_purged_cand_index);
 
2005
      else if (src_purged_cand_index != -1 && dst_purged_cand_index == -1)
 
2006
        merge_purged_cand_to_dst_array(src_ca, dst_ca,
 
2007
                        src_ca->cands[src_purged_cand_index]);
 
2008
      else if (src_purged_cand_index == -1 && dst_purged_cand_index != -1)
 
2009
        merge_word_to_dst_cand_array_with_purged_words(dst_ca, src_ca,
 
2010
                        src_ca->cands[i]);
 
2011
      else
 
2012
        merge_word_to_real_cand_array(dst_ca, src_ca->cands[i]);
 
2013
    }
 
2014
  }
 
2015
}
 
2016
 
 
2017
static uim_lisp
 
2018
skk_commit_candidate(uim_lisp head_, uim_lisp okuri_head_,
 
2019
                     uim_lisp okuri_, uim_lisp nth_, uim_lisp numlst_)
 
2020
{
 
2021
  int nth;
 
2022
  struct skk_cand_array *ca, *subca;
 
2023
  char *str = NULL;
 
2024
  int i, j, k = 0;
 
2025
  uim_lisp numstr_;
 
2026
  const char *numstr;
 
2027
  int method_place = 0;
 
2028
 
 
2029
  int ignoring_indices[IGNORING_WORD_MAX + 1];
 
2030
 
 
2031
  nth = uim_scm_c_int(nth_);
 
2032
  ca = find_cand_array_lisp(head_, okuri_head_, okuri_, 0);
 
2033
 
 
2034
  if (!ca)
 
2035
    return uim_scm_f();
 
2036
  get_ignoring_indices(ca, ignoring_indices);
 
2037
 
 
2038
  /* handle #4 method of numeric conversion */
 
2039
  if (!uim_scm_nullp(numlst_)) {
 
2040
    for (i = 0; i < ca->nr_cands; i++) {
 
2041
      if (match_to_discarding_index(ignoring_indices, i))
 
2042
        continue;
 
2043
 
 
2044
      if (find_numeric_conv_method4_mark(ca->cands[i], &method_place)) {
 
2045
        numstr_ = get_nth(method_place, numlst_);
 
2046
        numstr = uim_scm_refer_c_str(numstr_);
 
2047
        subca = find_cand_array(skk_dic, numstr, 0, NULL, 0);
 
2048
        if (subca) {
 
2049
          for (j = 0; j < subca->nr_cands; j++) {
 
2050
            if (k == nth) {
 
2051
              str = ca->cands[i];
 
2052
              /* reorder sub candidate */
 
2053
              skk_commit_candidate(numstr_, uim_scm_null_list(), uim_scm_null_list(), uim_scm_make_int(j), uim_scm_null_list());
 
2054
              break;
 
2055
            }
 
2056
            k++;
 
2057
          }
 
2058
        }
 
2059
        if (str)
 
2060
          break;
 
2061
      } else {
 
2062
        if (k == nth) {
 
2063
           str = ca->cands[i];
 
2064
           break;
 
2065
        }
 
2066
        k++;
 
2067
      }
 
2068
    }
 
2069
    if (!str)
 
2070
      return uim_scm_f();
 
2071
  } else {
 
2072
    for (i = 0; i < ca->nr_cands; i++) {
 
2073
      if (match_to_discarding_index(ignoring_indices, i))
 
2074
        continue;
 
2075
      if (k == nth) {
 
2076
        str = ca->cands[i];
 
2077
        break;
 
2078
      }
 
2079
      k++;
 
2080
    }
 
2081
    if (!str)
 
2082
      return uim_scm_f();
 
2083
  }
 
2084
  reorder_candidate(ca, str);
 
2085
 
 
2086
  if (okuri_ != uim_scm_null_list()) {
 
2087
    struct skk_line *sl;
 
2088
    const char *okuri;
 
2089
    int found = 0;
 
2090
 
 
2091
    okuri = uim_scm_refer_c_str(okuri_);
 
2092
    sl = ca->line;
 
2093
    for (i = 1; i < sl->nr_cand_array; i++) {
 
2094
      if (!strcmp(okuri, sl->cands[i].okuri)) {
 
2095
        found = 1;
 
2096
        break;
 
2097
      }
 
2098
    }
 
2099
    if (!found) {
 
2100
      ca = find_cand_array_lisp(head_, okuri_head_, okuri_, 1);
 
2101
      reorder_candidate(ca, str);
 
2102
    } else {
 
2103
      /* also reorder base candidate array */
 
2104
      reorder_candidate(&sl->cands[0], str);
 
2105
    }
 
2106
  }
 
2107
 
 
2108
  ca->line->need_save = 1;
 
2109
  move_line_to_cache_head(skk_dic, ca->line);
 
2110
 
 
2111
  return uim_scm_f();
 
2112
}
 
2113
 
 
2114
static void purge_candidate(struct skk_cand_array *ca, int nth)
 
2115
{
 
2116
    char *str;
 
2117
    int i;
 
2118
    
 
2119
    if (nth == -1)
 
2120
      return;
 
2121
 
 
2122
    str = strdup(ca->cands[nth]);
 
2123
 
 
2124
    if ((i = get_purged_cand_index(ca)) == -1) {
 
2125
      /* new purged cand in the array */
 
2126
      push_purged_word(ca, nth, 0, str);
 
2127
    } else {
 
2128
      /* append the word to already existing purged cand and remove it own */
 
2129
      push_purged_word(ca, i, 1, str);
 
2130
      remove_candidate_from_array(ca, nth);
 
2131
    }
 
2132
    
 
2133
#if 0
 
2134
    if (ca->okuri) {
 
2135
      /* also purge the word in the base cand array */
 
2136
      int index = index_in_real_cands(&ca->line->cands[0], str);
 
2137
      if (index != -1)
 
2138
        purge_candidate(&ca->line->cands[0], index);
 
2139
    }
 
2140
#endif
 
2141
    free(str);
 
2142
}
 
2143
 
 
2144
static uim_lisp
 
2145
skk_purge_candidate(uim_lisp head_, uim_lisp okuri_head_,
 
2146
                    uim_lisp okuri_, uim_lisp nth_, uim_lisp numlst_)
 
2147
{
 
2148
  int nth = uim_scm_c_int(nth_);
 
2149
  struct skk_cand_array *ca, *subca;
 
2150
  char *str = NULL;
 
2151
  int i, j, k = 0;
 
2152
  uim_lisp numstr_;
 
2153
  const char *numstr;
 
2154
  int method_place = 0;
 
2155
 
 
2156
  int ignoring_indices[IGNORING_WORD_MAX + 1];
 
2157
 
 
2158
  ca = find_cand_array_lisp(head_, okuri_head_, okuri_, 0);
 
2159
  if (!ca)
 
2160
    return uim_scm_f(); /* shouldn't happen */
 
2161
  get_ignoring_indices(ca, ignoring_indices);
 
2162
 
 
2163
  /* handle #4 method of numeric conversion */
 
2164
  if (!uim_scm_nullp(numlst_)) {
 
2165
    for (i = 0; i < ca->nr_cands; i++) {
 
2166
      if (match_to_discarding_index(ignoring_indices, i))
 
2167
        continue;
 
2168
 
 
2169
      if (find_numeric_conv_method4_mark(ca->cands[i], &method_place)) {
 
2170
        numstr_ = get_nth(method_place, numlst_);
 
2171
        numstr = uim_scm_refer_c_str(numstr_);
 
2172
        subca = find_cand_array(skk_dic, numstr, 0, NULL, 0);
 
2173
        if (subca) {
 
2174
          for (j = 0; j < subca->nr_cands; j++) {
 
2175
            if (k == nth) {
 
2176
              str = ca->cands[i];
 
2177
              /*
 
2178
               * don't purge word in sub candidate array
 
2179
               * skk_purge_candidate(numstr_, uim_scm_null_list(), uim_scm_null_list(), uim_scm_make_int(j), uim_scm_null_list());
 
2180
               */
 
2181
              break;
 
2182
            }
 
2183
            k++;
 
2184
          }
 
2185
        }
 
2186
        if (str)
 
2187
          break;
 
2188
      } else {
 
2189
        if (k == nth) {
 
2190
           str = ca->cands[i];
 
2191
           break;
 
2192
        }
 
2193
        k++;
 
2194
      }
 
2195
    }
 
2196
    if (!str)
 
2197
      return uim_scm_f();
 
2198
  } else {
 
2199
    for (i = 0; i < ca->nr_cands; i++) {
 
2200
      if (match_to_discarding_index(ignoring_indices, i))
 
2201
        continue;
 
2202
      if (k == nth)
 
2203
        break;
 
2204
      k++;
 
2205
    }
 
2206
  }
 
2207
  if (i < ca->nr_real_cands)
 
2208
    purge_candidate(ca, i);
 
2209
 
 
2210
  return uim_scm_t();
 
2211
}
 
2212
 
 
2213
static void
 
2214
learn_word_to_cand_array(struct skk_cand_array *ca, const char *word)
 
2215
{
 
2216
  int i, nth = -1;
 
2217
  for (i = 0; i < ca->nr_cands; i++) {
 
2218
    if (!strcmp(word, ca->cands[i])) {
 
2219
      nth = i;
 
2220
      break;
 
2221
    }
 
2222
  }
 
2223
  if (nth == -1)
 
2224
    push_back_candidate_to_array(ca, word);
 
2225
 
 
2226
  reorder_candidate(ca, word);
 
2227
  ca->line->need_save = 1;
 
2228
}
 
2229
 
 
2230
static char *
 
2231
quote_word(const char *word, const char *prefix)
 
2232
{
 
2233
  char *str;
 
2234
  const char *p;
 
2235
  int len;
 
2236
 
 
2237
  if (prefix)
 
2238
    str = strdup(prefix);
 
2239
  else
 
2240
    str = strdup("");
 
2241
 
 
2242
  for (p = word; *p; p++) {
 
2243
    len = strlen(str);
 
2244
 
 
2245
    switch (*p) {
 
2246
    case '/':
 
2247
            str = realloc(str, len + strlen("\\057") + 1);
 
2248
            strcat(str, "\\057");
 
2249
            break;
 
2250
    case '[':
 
2251
            str = realloc(str, len + strlen("[") + 1);
 
2252
            strcat(str, "[");
 
2253
            break;
 
2254
    case ']':
 
2255
            str = realloc(str, len + strlen("]") + 1);
 
2256
            strcat(str, "]");
 
2257
            break;
 
2258
    case '\n':
 
2259
            str = realloc(str, len + strlen("\\n") + 1);
 
2260
            strcat(str, "\\n");
 
2261
            break;
 
2262
    case '\r':
 
2263
            str = realloc(str, len + strlen("\\r") + 1);
 
2264
            strcat(str, "\\r");
 
2265
            break;
 
2266
    case '\\':
 
2267
            str = realloc(str, len + strlen("\\\\") + 1);
 
2268
            strcat(str, "\\\\");
 
2269
            break;
 
2270
    case ';':
 
2271
            str = realloc(str, len + strlen("\\073") + 1);
 
2272
            strcat(str, "\\073");
 
2273
            break;
 
2274
    case '"':
 
2275
            str = realloc(str, len + strlen("\\\"") + 1);
 
2276
            strcat(str, "\\\"");
 
2277
            break;
 
2278
    default:
 
2279
            str = realloc(str, len + 2);
 
2280
            str[len] = *p;
 
2281
            str[len + 1] = '\0';
 
2282
            break;
 
2283
    }
 
2284
  }
 
2285
  len = strlen(str);
 
2286
  if (prefix) {
 
2287
    str = realloc(str, len + strlen("\")") + 1);
 
2288
    strcat(str, "\")");
 
2289
  }
 
2290
 
 
2291
  return str;
 
2292
}
 
2293
 
 
2294
static char *
 
2295
sanitize_word(const char *str, const char *prefix)
 
2296
{
 
2297
  const char *p;
 
2298
  int is_space_only = 1;
 
2299
 
 
2300
  if (!str || !strlen(str)) {
 
2301
    return NULL;
 
2302
  }
 
2303
  for (p = str; *p; p++) {
 
2304
    switch (*p) {
 
2305
    case '/':
 
2306
    case '[':
 
2307
    case ']':
 
2308
    case '\n':
 
2309
    case '\r':
 
2310
    case '\\':
 
2311
    case ';':
 
2312
    case '"':
 
2313
      return quote_word(str, prefix);
 
2314
    case ' ':
 
2315
      break;
 
2316
    default:
 
2317
      is_space_only = 0;
 
2318
      break;
 
2319
    }
 
2320
  }
 
2321
  if (is_space_only)
 
2322
    return NULL;
 
2323
 
 
2324
  return strdup(str);
 
2325
}
 
2326
 
 
2327
static uim_lisp
 
2328
skk_learn_word(uim_lisp head_, uim_lisp okuri_head_, uim_lisp okuri_, uim_lisp word_)
 
2329
{
 
2330
  struct skk_cand_array *ca;
 
2331
  char *word;
 
2332
  const char *tmp;
 
2333
 
 
2334
  tmp = uim_scm_refer_c_str(word_);
 
2335
  word = sanitize_word(tmp, "(concat \"");
 
2336
  if (!word)
 
2337
    return uim_scm_f();
 
2338
 
 
2339
  ca = find_cand_array_lisp(head_, okuri_head_, okuri_, 1);
 
2340
  if (ca) {
 
2341
    learn_word_to_cand_array(ca, word);
 
2342
  }
 
2343
 
 
2344
  tmp = uim_scm_refer_c_str(okuri_);
 
2345
  if (strlen(tmp)) {
 
2346
    ca = find_cand_array_lisp(head_, okuri_head_, uim_scm_null_list(), 1);
 
2347
    if (ca) {
 
2348
      learn_word_to_cand_array(ca, word);
 
2349
    }
 
2350
  }
 
2351
  free(word);
 
2352
  return uim_scm_f();
 
2353
}
 
2354
 
 
2355
static void
 
2356
reverse_cache(struct dic_info *di)
 
2357
{
 
2358
  struct skk_line *sl, *prev, *next;
 
2359
 
 
2360
  prev= NULL;
 
2361
  sl = di->head.next;
 
2362
  while (sl) {
 
2363
    next = sl->next;
 
2364
    sl->next = prev;
 
2365
    prev = sl;
 
2366
    sl = next;
 
2367
  }
 
2368
  di->head.next = prev;
 
2369
}
 
2370
 
 
2371
static void
 
2372
parse_dic_line(struct dic_info *di, char *line)
 
2373
{
 
2374
  char *buf, *sep;
 
2375
  struct skk_line *sl;
 
2376
  int i;
 
2377
 
 
2378
  buf = alloca(strlen(line) + 1);
 
2379
  strcpy(buf, line);
 
2380
  sep = strchr(buf, ' ');
 
2381
 
 
2382
  if (!sep || (sep == buf))
 
2383
    return;
 
2384
 
 
2385
  *sep = '\0';
 
2386
  if (!skk_isascii(buf[0]) && skk_islower(sep[-1])) { /* okuri-ari entry */
 
2387
    char okuri_head = sep[-1];
 
2388
    sep[-1] = '\0';
 
2389
    sl = compose_line(di, buf, okuri_head, line);
 
2390
  } else {
 
2391
    sl = compose_line(di, buf, 0, line);
 
2392
  }
 
2393
  sl->need_save = 1;
 
2394
  /* set nr_real_cands for the candidate array from personal dictionaly */
 
2395
  for (i = 0; i < sl->nr_cand_array; i++)
 
2396
    sl->cands[i].nr_real_cands = sl->cands[i].nr_cands;
 
2397
  add_line_to_cache_head(di, sl);
 
2398
}
 
2399
 
 
2400
static void
 
2401
write_out_array(FILE *fp, struct skk_cand_array *ca)
 
2402
{
 
2403
  int i;
 
2404
  if (ca->okuri) {
 
2405
    fprintf(fp, "[%s/", ca->okuri);
 
2406
    for (i = 0; i < ca->nr_real_cands; i++)
 
2407
      fprintf(fp, "%s/", ca->cands[i]);
 
2408
    fprintf(fp, "]/");
 
2409
  } else {
 
2410
    for (i = 0; i < ca->nr_real_cands; i++)
 
2411
      fprintf(fp, "%s/", ca->cands[i]);
 
2412
  }
 
2413
}
 
2414
 
 
2415
static void
 
2416
write_out_line(FILE *fp, struct skk_line *sl)
 
2417
{
 
2418
  struct skk_cand_array *ca;
 
2419
  int i;
 
2420
 
 
2421
  fprintf(fp, "%s", sl->head);
 
2422
  if (sl->okuri_head) {
 
2423
    fprintf(fp, "%c /", sl->okuri_head);
 
2424
  } else {
 
2425
    fprintf(fp, " /");
 
2426
  }
 
2427
  for (i = 0; i < sl->nr_cand_array; i++) {
 
2428
    ca = &sl->cands[i];
 
2429
    write_out_array(fp, ca);
 
2430
  }
 
2431
  fprintf(fp, "\n");
 
2432
}
 
2433
 
 
2434
static int
 
2435
open_lock(const char *name, int type)
 
2436
{
 
2437
  int fd;
 
2438
  struct flock fl;
 
2439
  char *lock_fn;
 
2440
 
 
2441
  lock_fn = malloc(sizeof(char) * (strlen(name) + strlen(".lock") + 1));
 
2442
  if (lock_fn == NULL)
 
2443
    return -1;
 
2444
  sprintf(lock_fn, "%s.lock", name);
 
2445
 
 
2446
  fd = open(lock_fn, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
 
2447
  if (fd == -1) {
 
2448
    free(lock_fn);
 
2449
    return fd;
 
2450
  }
 
2451
 
 
2452
  fl.l_type = type;
 
2453
  fl.l_whence = SEEK_SET;
 
2454
  fl.l_start = 0;
 
2455
  fl.l_len = 0;
 
2456
  if (fcntl(fd, F_SETLKW, &fl) == -1) {
 
2457
    close(fd);
 
2458
    fd = -1;
 
2459
  }
 
2460
 
 
2461
  free(lock_fn);
 
2462
  return fd;
 
2463
}
 
2464
 
 
2465
static void
 
2466
close_lock(int fd)
 
2467
{
 
2468
  struct flock fl;
 
2469
 
 
2470
  if (fd < 0)
 
2471
    return;
 
2472
 
 
2473
  fl.l_type = F_UNLCK;
 
2474
  fl.l_whence = SEEK_SET;
 
2475
  fl.l_start = 0;
 
2476
  fl.l_len = 0;
 
2477
 
 
2478
  fcntl(fd, F_SETLKW, &fl);
 
2479
  close(fd);
 
2480
}
 
2481
 
 
2482
static uim_lisp
 
2483
read_personal_dictionary(struct dic_info *di, const char *fn)
 
2484
{
 
2485
  struct stat st;
 
2486
  FILE *fp;
 
2487
  char buf[4096]; /* XXX */
 
2488
  int err_flag = 0;
 
2489
  int lock_fd;
 
2490
 
 
2491
  if (!di)
 
2492
    return uim_scm_f();
 
2493
 
 
2494
  lock_fd = open_lock(fn, F_RDLCK);
 
2495
 
 
2496
  if (stat(fn, &st) == -1) {
 
2497
    close_lock(lock_fd);
 
2498
    return uim_scm_f();
 
2499
  }
 
2500
 
 
2501
  fp = fopen(fn, "r");
 
2502
  if (!fp) {
 
2503
    close_lock(lock_fd);
 
2504
    return uim_scm_f();
 
2505
  }
 
2506
 
 
2507
  di->personal_dic_timestamp = st.st_mtime;
 
2508
 
 
2509
  while (fgets(buf, 4096, fp)) { /* XXX */
 
2510
    int len = strlen(buf);
 
2511
    if (buf[len - 1] == '\n') {
 
2512
      if (err_flag == 0) {
 
2513
        if (buf[0] != ';') {
 
2514
          buf[len - 1] = '\0';
 
2515
          parse_dic_line(di, buf);
 
2516
        }
 
2517
      } else {
 
2518
        /* erroneous line ends here */
 
2519
        err_flag = 0;
 
2520
      }
 
2521
    } else {
 
2522
      err_flag = 1;
 
2523
    }
 
2524
  }
 
2525
  fclose(fp);
 
2526
  close_lock(lock_fd);
 
2527
  reverse_cache(di);
 
2528
  return uim_scm_t();
 
2529
}
 
2530
 
 
2531
static uim_lisp
 
2532
skk_read_personal_dictionary(uim_lisp fn_)
 
2533
{
 
2534
  const char *fn = uim_scm_refer_c_str(fn_);
 
2535
  return read_personal_dictionary(skk_dic, fn);
 
2536
}
 
2537
 
 
2538
static void push_back_candidate_array_to_sl(struct skk_line *sl,
 
2539
                                      struct skk_cand_array *src_ca)
 
2540
{
 
2541
  int i;
 
2542
  struct skk_cand_array *ca;
 
2543
 
 
2544
  sl->nr_cand_array++;
 
2545
  sl->cands = realloc(sl->cands,
 
2546
                  sizeof(struct skk_cand_array) * sl->nr_cand_array);
 
2547
  ca = &sl->cands[sl->nr_cand_array - 1];
 
2548
  ca->is_used = src_ca->is_used;
 
2549
  ca->nr_cands = src_ca->nr_cands;
 
2550
  ca->cands = malloc(sizeof(char *) * src_ca->nr_cands);
 
2551
  for (i = 0; i < ca->nr_cands; i++)
 
2552
    ca->cands[i] = strdup(src_ca->cands[i]);
 
2553
 
 
2554
  ca->nr_real_cands = src_ca->nr_real_cands;
 
2555
  ca->okuri = strdup(src_ca->okuri);
 
2556
  ca->line = sl;
 
2557
}
 
2558
 
 
2559
static void compare_and_merge_skk_line(struct skk_line *dst_sl,
 
2560
                                       struct skk_line *src_sl)
 
2561
{
 
2562
  int i, j;
 
2563
  struct skk_cand_array *dst_ca, *src_ca;
 
2564
 
 
2565
  if (dst_sl == NULL || src_sl == NULL)
 
2566
    return;
 
2567
 
 
2568
  src_ca = &src_sl->cands[0];
 
2569
  dst_ca = &dst_sl->cands[0];
 
2570
  /*
 
2571
   * check all candidate array since purged words may exist.
 
2572
   */
 
2573
  /* if (src_ca->nr_real_cands >= dst_ca->nr_real_cands) */
 
2574
    merge_real_candidate_array(src_ca, dst_ca);
 
2575
 
 
2576
  for (i = 1; i < src_sl->nr_cand_array; i++) {
 
2577
    int dup = 0;
 
2578
    src_ca = &src_sl->cands[i];
 
2579
 
 
2580
    for (j = 1; j < dst_sl->nr_cand_array; j++) {
 
2581
      dst_ca = &dst_sl->cands[j];
 
2582
      if (!strcmp(src_ca->okuri, dst_ca->okuri)) {
 
2583
        dup = 1;
 
2584
      /* if (src_ca->nr_real_cands >= dst_ca->nr_real_cands) */
 
2585
          merge_real_candidate_array(src_ca, dst_ca);
 
2586
      }
 
2587
    }
 
2588
    if (!dup)
 
2589
      push_back_candidate_array_to_sl(dst_sl, src_ca);
 
2590
  }
 
2591
}
 
2592
 
 
2593
/* for merge sort */
 
2594
static int
 
2595
compare_entry(struct skk_line *p, struct skk_line *q)
 
2596
{
 
2597
  int ret;
 
2598
  ret = strcmp(p->head, q->head);
 
2599
 
 
2600
  if (ret != 0)
 
2601
    return ret;
 
2602
  else
 
2603
    return p->okuri_head - q->okuri_head;
 
2604
}
 
2605
 
 
2606
/*
 
2607
 * Retern lines with differential "midashi-go" between two personal
 
2608
 * dictionaly caches.  Also merge candidate arrays for line with same
 
2609
 * "midashi-go".  p and q are needed to be sorted.
 
2610
 */
 
2611
static struct skk_line *
 
2612
cache_line_diffs(struct skk_line *p, struct skk_line *q, int *len)
 
2613
{
 
2614
  struct skk_line *r, *s, head;
 
2615
  int cmp;
 
2616
 
 
2617
  for (r = &head; p && q; ) {
 
2618
    cmp = compare_entry(p, q);
 
2619
    if (cmp < 0) {
 
2620
      p = p->next;
 
2621
    } else if (cmp > 0) {
 
2622
      s = copy_skk_line(q);
 
2623
      r->next = s;
 
2624
      r = s;
 
2625
      q = q->next;
 
2626
      (*len)++;
 
2627
    } else {
 
2628
      compare_and_merge_skk_line(p, q);
 
2629
      p = p->next;
 
2630
      q = q->next;
 
2631
    }
 
2632
  }
 
2633
  while (q) {
 
2634
    s = copy_skk_line(q);
 
2635
    r->next = s;
 
2636
    r = s;
 
2637
    q = q->next;
 
2638
    (*len)++;
 
2639
  }
 
2640
  r->next = NULL;
 
2641
  return head.next;
 
2642
}
 
2643
 
 
2644
/* for merge sort */
 
2645
static struct skk_line *
 
2646
lmerge(struct skk_line *p, struct skk_line *q)
 
2647
{
 
2648
  struct skk_line *r, head;
 
2649
 
 
2650
  for (r = &head; p && q; ) {
 
2651
    if (compare_entry(p, q) < 0) {
 
2652
      r->next = p;
 
2653
      r = p;
 
2654
      p = p->next;
 
2655
    } else {
 
2656
      r->next = q;
 
2657
      r = q;
 
2658
      q = q->next;
 
2659
    }
 
2660
  }
 
2661
  r->next = (p ? p : q);
 
2662
  return head.next;
 
2663
}
 
2664
 
 
2665
/* merge sort */
 
2666
static struct skk_line *
 
2667
lsort(struct skk_line *p)
 
2668
{
 
2669
  struct skk_line *q, *r;
 
2670
 
 
2671
  if (p) {
 
2672
    q = p;
 
2673
    for (r = q->next; r && (r = r->next) != NULL; r = r->next)
 
2674
      q = q->next;
 
2675
    r = q->next;
 
2676
    q->next = NULL;
 
2677
    if (r)
 
2678
      p = lmerge(lsort(r), lsort(p));
 
2679
  }
 
2680
  return p;
 
2681
}
 
2682
 
 
2683
static void
 
2684
update_personal_dictionary_cache(const char *fn)
 
2685
{
 
2686
  struct dic_info *di;
 
2687
  struct skk_line *sl, *tmp, *diff, **cache_array;
 
2688
  int i, diff_len = 0;
 
2689
 
 
2690
  di = (struct dic_info *)malloc(sizeof(struct dic_info));
 
2691
  if (di == NULL)
 
2692
    return;
 
2693
  di->head.next = NULL;
 
2694
  read_personal_dictionary(di, fn);
 
2695
  di->head.next = lsort(di->head.next);
 
2696
 
 
2697
  /* keep original sequence of cache */
 
2698
  cache_array = (struct skk_line **)malloc(sizeof(struct skk_line *)
 
2699
                  * skk_dic->cache_len);
 
2700
  if (cache_array == NULL)
 
2701
    return;
 
2702
  i = 0;
 
2703
  sl = skk_dic->head.next;
 
2704
  while (sl) {
 
2705
    cache_array[i] = sl;
 
2706
    sl = sl->next;
 
2707
    i++;
 
2708
  }
 
2709
 
 
2710
  skk_dic->head.next = lsort(skk_dic->head.next);
 
2711
 
 
2712
  /* get differential lines and merge candidate */
 
2713
  diff = cache_line_diffs(skk_dic->head.next, di->head.next, &diff_len);
 
2714
 
 
2715
  /* revert sequence of the cache */
 
2716
  if (cache_array[0]) {
 
2717
    sl = skk_dic->head.next = cache_array[0];
 
2718
    for (i = 0; i < skk_dic->cache_len - 1; i++) {
 
2719
      sl->next = cache_array[i + 1];
 
2720
      sl = sl->next;
 
2721
    }
 
2722
    sl->next = NULL;
 
2723
  }
 
2724
 
 
2725
  /* add differential lines at the top of the cache */
 
2726
  if (diff != NULL) {
 
2727
    sl = diff;
 
2728
    while (sl->next) {
 
2729
      sl = sl->next;
 
2730
    }
 
2731
    sl->next = skk_dic->head.next;
 
2732
    skk_dic->head.next = diff;
 
2733
    skk_dic->cache_len += diff_len;
 
2734
  }
 
2735
  skk_dic->cache_modified = 1;
 
2736
 
 
2737
  sl = di->head.next;
 
2738
  while (sl) {
 
2739
    tmp = sl;
 
2740
    sl = sl->next;
 
2741
    free_skk_line(tmp);
 
2742
  }
 
2743
  free(di);
 
2744
  free(cache_array);
 
2745
}
 
2746
 
 
2747
static uim_lisp
 
2748
skk_save_personal_dictionary(uim_lisp fn_)
 
2749
{
 
2750
  FILE *fp;
 
2751
  const char *fn = uim_scm_refer_c_str(fn_);
 
2752
  char *tmp_fn = NULL;
 
2753
  struct skk_line *sl;
 
2754
  struct stat st;
 
2755
  int lock_fd = -1;
 
2756
 
 
2757
  if (!skk_dic || skk_dic->cache_modified == 0)
 
2758
    return uim_scm_f();
 
2759
 
 
2760
  if (fn) {
 
2761
    if (stat(fn, &st) != -1) {
 
2762
      if (st.st_mtime != skk_dic->personal_dic_timestamp)
 
2763
        update_personal_dictionary_cache(fn);
 
2764
    }
 
2765
 
 
2766
    lock_fd = open_lock(fn, F_WRLCK);
 
2767
    if (!(tmp_fn = malloc(strlen(fn) + 5)))
 
2768
      goto error;
 
2769
 
 
2770
    sprintf(tmp_fn, "%s.tmp", fn);
 
2771
    fp = fopen(tmp_fn, "w");
 
2772
    if (!fp)
 
2773
      goto error;
 
2774
 
 
2775
  } else {
 
2776
    fp = stdout;
 
2777
  }
 
2778
 
 
2779
  for (sl = skk_dic->head.next; sl; sl = sl->next) {
 
2780
    if (sl->need_save)
 
2781
      write_out_line(fp, sl);
 
2782
  }
 
2783
 
 
2784
  if (fclose(fp) != 0)
 
2785
    goto error;
 
2786
 
 
2787
  if (rename(tmp_fn, fn) != 0)
 
2788
    goto error;
 
2789
 
 
2790
  if (stat(fn, &st) != -1) {
 
2791
    skk_dic->personal_dic_timestamp = st.st_mtime;
 
2792
    skk_dic->cache_modified = 0;
 
2793
  }
 
2794
 
 
2795
error:
 
2796
  close_lock(lock_fd);
 
2797
  free(tmp_fn);
 
2798
  return uim_scm_f();
 
2799
}
 
2800
 
 
2801
static uim_lisp
 
2802
skk_get_annotation(uim_lisp str_)
 
2803
{
 
2804
  const char *str, *sep;
 
2805
  uim_lisp res;
 
2806
 
 
2807
  if (str_ == uim_scm_null_list())
 
2808
    return uim_scm_null_list();
 
2809
 
 
2810
  str = uim_scm_refer_c_str(str_);
 
2811
  sep = strrchr(str, ';');
 
2812
  if (sep && (*(++sep) != '\0')) {
 
2813
    res = uim_scm_make_str(sep);
 
2814
  } else {
 
2815
    res = uim_scm_make_str("");
 
2816
  }
 
2817
  return res;
 
2818
}
 
2819
 
 
2820
static uim_lisp
 
2821
skk_remove_annotation(uim_lisp str_)
 
2822
{
 
2823
  char *str, *sep;
 
2824
  uim_lisp res;
 
2825
 
 
2826
  if (str_ == uim_scm_null_list())
 
2827
    return uim_scm_null_list();
 
2828
 
 
2829
  str = uim_scm_c_str(str_);
 
2830
  sep = strrchr(str, ';');
 
2831
  if (sep && (*(sep + 1) != '\0')) {
 
2832
    *sep = '\0';
 
2833
  }
 
2834
  res = uim_scm_make_str(str);
 
2835
  free(str);
 
2836
  return res;
 
2837
}
 
2838
 
 
2839
static uim_lisp
 
2840
skk_eval_candidate(uim_lisp str_)
 
2841
{
 
2842
  const char *cand, *evaluated_str;
 
2843
  char *p, *q, *str;
 
2844
  size_t len;
 
2845
  uim_lisp cand_, return_val;
 
2846
 
 
2847
  if (str_ == uim_scm_null_list())
 
2848
    return uim_scm_null_list();
 
2849
 
 
2850
  cand = uim_scm_refer_c_str(str_);
 
2851
 
 
2852
  /* eval concat only for now */
 
2853
  if ((p = strstr(cand, "(concat \"")) == NULL)
 
2854
    return str_;
 
2855
 
 
2856
  /* check close paren */
 
2857
  q = strrchr(p, ')');
 
2858
  if (!q || (strstr(p, "\")") == NULL))
 
2859
    return str_;
 
2860
 
 
2861
  /* ignore make-string */
 
2862
  if (strstr(p, "make-string"))
 
2863
    return str_;
 
2864
 
 
2865
  len = q - p + 1;
 
2866
  /* replace elisp's concat with string-append */
 
2867
  str = malloc(len + strlen("string-append") - strlen("concat") + 1);
 
2868
  strcpy(str, "(string-append");
 
2869
  strncat(str, p + strlen("(concat"), q - (p + strlen("(concat")) + 1);
 
2870
 
 
2871
  /* XXX string expansion like \073 -> ';' is siod dependent */
 
2872
  UIM_EVAL_FSTRING1(NULL, "%s", str);
 
2873
  return_val = uim_scm_return_value();
 
2874
  if (return_val == uim_scm_null_list()) {
 
2875
    free(str);
 
2876
    return str_;
 
2877
  }
 
2878
  evaluated_str = uim_scm_refer_c_str(return_val);
 
2879
 
 
2880
  /* get evaluated candidate */
 
2881
  len = p - cand + strlen(evaluated_str);
 
2882
  if (len > strlen(str))
 
2883
    str = realloc(str, len + 1);
 
2884
 
 
2885
  if (p != cand) {
 
2886
    strncpy(str, cand, p - cand);
 
2887
    str[p - cand] = '\0';
 
2888
    strcat(str, evaluated_str);
 
2889
  } else {
 
2890
    strcpy(str, evaluated_str);
 
2891
  }
 
2892
 
 
2893
  cand_ = uim_scm_make_str(str);
 
2894
  free(str);
 
2895
  return cand_;
 
2896
}
 
2897
 
 
2898
 
 
2899
void
 
2900
uim_plugin_instance_init(void)
 
2901
{
 
2902
  uim_scm_init_subr_3("skk-lib-dic-open", skk_dic_open);
 
2903
  uim_scm_init_subr_1("skk-lib-read-personal-dictionary", skk_read_personal_dictionary);
 
2904
  uim_scm_init_subr_1("skk-lib-save-personal-dictionary", skk_save_personal_dictionary);
 
2905
  uim_scm_init_subr_3("skk-lib-get-entry", skk_get_entry);
 
2906
  uim_scm_init_subr_1("skk-lib-store-replaced-numstr", skk_store_replaced_numeric_str);
 
2907
  uim_scm_init_subr_2("skk-lib-merge-replaced-numstr", skk_merge_replaced_numeric_str);
 
2908
  uim_scm_init_subr_1("skk-lib-replace-numeric", skk_replace_numeric);
 
2909
  uim_scm_init_subr_5("skk-lib-get-nth-candidate", skk_get_nth_candidate);
 
2910
  uim_scm_init_subr_4("skk-lib-get-nr-candidates", skk_get_nr_candidates);
 
2911
  uim_scm_init_subr_5("skk-lib-commit-candidate", skk_commit_candidate);
 
2912
  uim_scm_init_subr_5("skk-lib-purge-candidate", skk_purge_candidate);
 
2913
  uim_scm_init_subr_4("skk-lib-learn-word", skk_learn_word);
 
2914
  uim_scm_init_subr_1("skk-lib-get-annotation", skk_get_annotation);
 
2915
  uim_scm_init_subr_1("skk-lib-remove-annotation", skk_remove_annotation);
 
2916
  uim_scm_init_subr_1("skk-lib-get-completion", skk_get_completion);
 
2917
  uim_scm_init_subr_2("skk-lib-get-nth-completion", skk_get_nth_completion);
 
2918
  uim_scm_init_subr_1("skk-lib-get-nr-completions", skk_get_nr_completions);
 
2919
  uim_scm_init_subr_1("skk-lib-clear-completions", skk_clear_completions);
 
2920
  uim_scm_init_subr_1("skk-lib-eval-candidate", skk_eval_candidate);
 
2921
}
 
2922
 
 
2923
void
 
2924
uim_plugin_instance_quit(void)
 
2925
{
 
2926
  struct skk_line *sl, *tmp;
 
2927
 
 
2928
  if (!skk_dic)
 
2929
    return;
 
2930
 
 
2931
  if (skk_dic->addr) {
 
2932
    munmap(skk_dic->addr, skk_dic->size);
 
2933
  }
 
2934
  sl = skk_dic->head.next;
 
2935
  while (sl) {
 
2936
    tmp = sl;
 
2937
    sl = sl->next;
 
2938
    free_skk_line(tmp);
 
2939
  }
 
2940
 
 
2941
  if (skk_dic->skkserv_ok)
 
2942
    close_skkserv();
 
2943
 
 
2944
  free(skk_dic);
 
2945
  skk_dic = NULL;
 
2946
}
 
2947
 
 
2948
/* skkserv related */
 
2949
static int
 
2950
open_skkserv(int portnum)
 
2951
{
 
2952
  int sock;
 
2953
  struct sockaddr_in hostaddr;
 
2954
  struct hostent *entry;
 
2955
  /* struct servent *serv; */
 
2956
  struct protoent *proto;
 
2957
  int a1, a2, a3, a4;
 
2958
  char *hostname;
 
2959
 
 
2960
  signal(SIGPIPE, SIG_IGN);
 
2961
 
 
2962
  /* serv = getservbyname(SKK_SERVICENAME, "tcp"); */
 
2963
  memset((char*)&hostaddr, 0, sizeof(struct sockaddr_in));
 
2964
  if ((proto = getprotobyname("tcp")) == NULL) {
 
2965
    return 0;
 
2966
  }
 
2967
 
 
2968
  if ((sock = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0) {
 
2969
    return 0;
 
2970
  }
 
2971
 
 
2972
  if (SKKServerHost)
 
2973
    hostname = SKKServerHost;
 
2974
  else if ((hostname = getenv("SKKSERVER")) == NULL) {
 
2975
#ifdef SKK_SERVER_HOST
 
2976
    hostname = SKK_SERVER_HOST;
 
2977
#else
 
2978
    return 0;
 
2979
#endif
 
2980
  }
 
2981
  if ('0' <= *hostname && *hostname <= '9') {
 
2982
    if (sscanf(hostname,"%d.%d.%d.%d", &a1, &a2, &a3, &a4) != 4) {
 
2983
      return 0;
 
2984
    }
 
2985
    a1 = (a1 << 24) | (a2 << 16) | (a3 << 8) | a4;
 
2986
    hostaddr.sin_addr.s_addr = htonl(a1);
 
2987
  } else {
 
2988
    if ((entry = gethostbyname(hostname)) == NULL) {
 
2989
      return 0;
 
2990
    }
 
2991
    memcpy(&hostaddr.sin_addr, entry->h_addr, entry->h_length);
 
2992
  }
 
2993
  hostaddr.sin_family = AF_INET;
 
2994
  /* hostaddr.sin_port = serv ? serv->s_port : htons(portnum); */
 
2995
  hostaddr.sin_port = htons(portnum);
 
2996
  if (connect(sock, (struct sockaddr *)&hostaddr, sizeof(struct sockaddr_in)) < 0) {
 
2997
    return 0;
 
2998
  }
 
2999
  fprintf(stderr, "SKKSERVER=%s\n", hostname);
 
3000
  skkservsock = sock;
 
3001
  rserv = fdopen(sock, "r");
 
3002
  wserv = fdopen(sock, "w");
 
3003
  return 1;
 
3004
}
 
3005
 
 
3006
static void
 
3007
close_skkserv()
 
3008
{
 
3009
  if (skkservsock >= 0) {
 
3010
    fprintf(wserv, "0\n");
 
3011
    fflush(wserv);
 
3012
  }
 
3013
}