1/* Copyright 1994 NEC Corporation, Tokyo, Japan.
2 *
3 * Permission to use, copy, modify, distribute and sell this software
4 * and its documentation for any purpose is hereby granted without
5 * fee, provided that the above copyright notice appear in all copies
6 * and that both that copyright notice and this permission notice
7 * appear in supporting documentation, and that the name of NEC
8 * Corporation not be used in advertising or publicity pertaining to
9 * distribution of the software without specific, written prior
10 * permission.  NEC Corporation makes no representations about the
11 * suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * NEC CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
16 * NO EVENT SHALL NEC CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
18 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
19 * OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23/************************************************************************/
24/* THIS SOURCE CODE IS MODIFIED FOR TKO BY T.MURAI 1997
25/************************************************************************/
26
27
28#if !defined(lint) && !defined(__CODECENTER__)
29static char rcsid[] = "$Id: bun.c 14875 2005-11-12 21:25:31Z bonefish $";
30#endif
31
32/* LINTLIBRARY */
33
34#include <string.h>
35#include "RKintern.h"
36
37
38#define NEED_DEF
39#ifdef RkSetErrno
40#undef RkSetErrno
41#define RkSetErrno(no)
42#endif
43
44const unsigned  OVERRUN_MARGIN = 0;
45
46#define	STRCMP(d, s)	strcmp((char *)(d), (char *)(s))
47
48inline void
49usncopy(WCHAR_T *dst, WCHAR_T *src, int len)
50{
51	memcpy(dst, src, len * sizeof(WCHAR_T));
52}
53
54static void
55freeBunStorage(struct nstore *s)
56{
57  if (s) {
58    if (s->yomi)
59      free((s->yomi-OVERRUN_MARGIN));
60    if (s->bunq)
61      free((s->bunq-OVERRUN_MARGIN));
62    if (s->xq)
63      free((s->xq-OVERRUN_MARGIN));
64    if (s->xqh)
65      free((s->xqh-OVERRUN_MARGIN));
66    free(s);
67  }
68}
69
70static struct nstore *
71allocBunStorage(unsigned len)
72{
73  struct nstore	*s;
74
75  s = (struct nstore *)malloc((unsigned)sizeof(struct nstore));
76  if (s) {
77    WCHAR_T	*p, *q, pat;
78    int			i;
79
80    s->yomi = (WCHAR_T *)0;
81    s->bunq = (struct nbun *)0;
82    s->xq = (struct nqueue *)0;
83    s->xqh = (struct nword **)0;
84    s->nyomi = (unsigned)0;
85    s->maxyomi = (unsigned)len;
86
87    s->yomi = (WCHAR_T *)calloc((s->maxyomi+1+2*OVERRUN_MARGIN), sizeof(WCHAR_T));
88    s->maxbunq = (unsigned)len;
89    s->maxbun = (unsigned)0;
90    s->curbun = 0;
91    s->bunq = (struct nbun *)calloc((unsigned)(s->maxbunq+1+2*OVERRUN_MARGIN),
92				    sizeof(struct nbun));
93    s->maxxq = len;
94    s->xq = (struct nqueue *)calloc((unsigned)(s->maxxq+1+2*OVERRUN_MARGIN),
95				    sizeof(struct nqueue));
96    s->xqh = (struct nword **)calloc((unsigned)(s->maxxq+1+2*OVERRUN_MARGIN),
97				     sizeof(struct nword *));
98    if (!s->yomi || !s->bunq || !s->xq || !s->xqh) {
99      RkSetErrno(RK_ERRNO_ENOMEM);
100      freeBunStorage(s);
101      return (struct nstore *)0;
102    }
103    s->yomi += OVERRUN_MARGIN;
104    s->bunq += OVERRUN_MARGIN;
105    s->xq += OVERRUN_MARGIN;
106    s->xqh += OVERRUN_MARGIN;
107    p = (WCHAR_T*)&s->yomi[0];
108    q = (WCHAR_T*)&s->yomi[s->maxyomi+1];
109    for (i = 0; pat = (WCHAR_T)~i, i < OVERRUN_MARGIN; i++)
110      p[-i-1] = q[i] = pat;
111    p = (WCHAR_T*)&s->bunq[0];
112    q = (WCHAR_T*)&s->bunq[s->maxbunq+1];
113    for (i = 0; pat = (WCHAR_T)~i, i < OVERRUN_MARGIN; i++)
114      p[-i-1] = q[i] = pat;
115    p = (WCHAR_T*)&s->xq[0];
116    q = (WCHAR_T*)&s->xq[s->maxxq+1];
117    for (i = 0; pat = (WCHAR_T)~i, i < OVERRUN_MARGIN; i++)
118      p[-i-1] = q[i] = pat;
119    p = (WCHAR_T*)&s->xqh[0];
120    q = (WCHAR_T*)&s->xqh[s->maxxq+1];
121    for (i = 0; pat = (WCHAR_T)~i, i < OVERRUN_MARGIN; i++)
122      p[-i-1] = q[i] = pat;
123    s->word_in_use = 0;
124  };
125  if (!s) /* EMPTY */RkSetErrno(RK_ERRNO_ENOMEM);
126  return s;
127}
128
129struct nstore	*
130_RkReallocBunStorage(struct nstore *src, unsigned len)
131{
132  struct nstore	*dst = allocBunStorage(len);
133
134  if (dst) {
135    int		i;
136
137    if (src->yomi) {
138      for (i = 0; i <= (int)src->maxyomi; i++)
139	dst->yomi[i] = src->yomi[i];
140      free((src->yomi-OVERRUN_MARGIN));
141    };
142    dst->nyomi = src->nyomi;
143    if (src->bunq) {
144      for (i = 0; i <= (int)src->maxbun; i++)
145	dst->bunq[i] = src->bunq[i];
146      free((src->bunq-OVERRUN_MARGIN));
147    };
148    dst->maxbun = src->maxbun;
149    dst->curbun = src->curbun;
150    if (src->xq) {
151      for (i = 0; i <= src->maxxq; i++)
152	dst->xq[i] = src->xq[i];
153      free((src->xq-OVERRUN_MARGIN));
154    };
155    if (src->xqh) {
156      for (i = 0; i <= src->maxxq; i++)
157	dst->xqh[i] = src->xqh[i];
158      free((src->xqh-OVERRUN_MARGIN));
159    };
160    dst->word_in_use = src->word_in_use;
161    free(src);
162    return(dst);
163  }
164  return((struct nstore *)0);
165}
166
167inline struct nbun *
168getCurrentBun(struct nstore *store)
169{
170  if (store && 0 <= store->curbun && store->curbun < (int)store->maxbun)
171    return &store->bunq[store->curbun];
172  return (struct nbun *)0;
173}
174
175/* RkBgnBun
176 *	renbunsetu henkan wo kaishi surutameno shokisettei wo okonau
177 * reuturns:
178 *	# >=0	shoki bunsetsu no kosuu
179 *	-1	shoki ka sippai
180 *		RK_ERRNO_ECTXNO
181 *		RK_ERRNO_EINVAL
182 *		RK_ERRNO_ENOMEM
183 */
184int
185RkwBgnBun(int cx_num, WCHAR_T *yomi, int n, int kouhomode)
186{
187  struct RkContext	*cx;
188  unsigned long		mask1, mask2;
189  int			asset = 0;
190
191  if (!(cx = RkGetContext(cx_num))) {
192    RkSetErrno(RK_ERRNO_ECTXNO);
193    return(-1);
194  }
195  if (IS_XFERCTX(cx)) {
196    RkSetErrno(0);
197    return(-1);
198  }
199  for (mask1 = (unsigned long) kouhomode, mask2 = 0L;
200                           mask1; mask1 >>= RK_XFERBITS) {
201    if ((mask1 & (unsigned long)RK_XFERMASK) == (unsigned long)RK_CTRLHENKAN) {
202      mask1 >>= RK_XFERBITS;
203      asset = 1;
204      break;
205    }
206    mask2 = (mask2 << RK_XFERBITS) | ((unsigned long)RK_XFERMASK);
207  }
208  if (!(cx->store = allocBunStorage((unsigned)n))) {
209    RkSetErrno(RK_ERRNO_ENOMEM);
210    return(-1);
211  }
212  cx->flags |= (unsigned)CTX_XFER;
213  cx->concmode = (RK_CONNECT_WORD
214		  | (asset ? ((int)mask1 & ~RK_TANBUN) :
215		     (RK_MAKE_KANSUUJI | RK_MAKE_WORD | RK_MAKE_EISUUJI)));
216  cx->kouhomode = ((unsigned long)kouhomode) & mask2;
217  if (yomi) {
218    int	i;
219
220    if (n <= 0) {
221      RkSetErrno(RK_ERRNO_EINVAL);
222      RkwEndBun(cx_num, 0);
223      return(-1);
224    };
225    for (i = 0; i < n; i++)
226      cx->store->yomi[i] = yomi[i];
227    cx->store->yomi[n] = 0;
228    cx->store->nyomi = n;
229    cx->store->bunq[0].nb_yoff = 0;
230    i = _RkRenbun2(cx, mask1 & RK_TANBUN ? n : 0);
231    return(i);
232  } else {
233    cx->concmode |= RK_MAKE_WORD;
234    cx->flags |= (unsigned) CTX_XAUT;
235    if (n < 0) {
236      RkSetErrno(RK_ERRNO_EINVAL);
237      RkwEndBun(cx_num, 0);
238      return(-1);
239    };
240    return(0);
241  }
242}
243
244/* RkEndBun
245 *	bunsetsu henkan wo shuuryou suru
246 *	hituyou ni oujite, henkan kekka wo motoni gakushuu wo okonau
247 *
248 *	return	0
249 *		-1(RK_ERRNO_ECTX)
250 */
251int
252RkwEndBun(int cx_num, int mode)
253{
254struct RkContext	*cx;
255struct nstore		*store;
256int					i;
257const int			DO_LEARN = 1;
258
259  if (!(cx = RkGetXContext(cx_num)) ||
260      !(store = cx->store)) {
261    RkSetErrno(RK_ERRNO_ECTXNO);
262    return(-1);
263  }
264  if (mode) {
265    if (mode != DO_LEARN) {
266      RkSetErrno(RK_ERRNO_EINVAL);
267      return -1;
268    };
269  }
270  for (i = 0; i < (int)store->maxbun; i++)
271    (void)_RkLearnBun(cx, i, mode);
272  if (cx->flags & CTX_XAUT)
273    _RkFreeQue(store, 0, store->maxxq + 1);
274  cx->concmode &= ~(RK_CONNECT_WORD | RK_MAKE_WORD |
275		    RK_MAKE_KANSUUJI | RK_MAKE_EISUUJI);
276  _RkEndBun(cx);
277  freeBunStorage(store);
278  return(0);
279}
280
281/* RkRemoveBun
282 *	current bunsetu made wo sakujo suru
283 *	current bunsetu ha 0 ni naru.
284 */
285
286int
287RkwRemoveBun(int cx_num, int mode)
288{
289  struct RkContext	*cx;
290  struct nstore		*store;
291  int			i, c;
292
293  if (!(cx = RkGetXContext(cx_num))
294      || !(store = cx->store)
295      || !IS_XFERCTX(cx)
296      || store->maxbun <= 0) {
297    RkSetErrno(RK_ERRNO_ECTXNO);
298    return -1;
299  }
300  for (i = 0; i <= store->curbun; i++)
301    _RkLearnBun(cx, i, mode);
302  c = store->bunq[store->curbun + 1].nb_yoff;
303  for (i = store->curbun + 1; i <= (int)store->maxbun; i++) {
304    store->bunq[i - store->curbun - 1] = store->bunq[i];
305    store->bunq[i - store->curbun - 1].nb_yoff -= c;
306  }
307  store->nyomi -= c;
308  usncopy(store->yomi, store->yomi + c, (unsigned)store->nyomi);
309  store->maxbun -= store->curbun + 1;
310  store->curbun = 0;
311  return(store->maxbun);
312}
313
314/* RkSubstYomi
315 *	change the contents of hiragana buffer
316 * returns:
317 *	# bunsetu
318 */
319
320int
321RkwSubstYomi(int cx_num, int ys, int ye, WCHAR_T *yomi, int newLen)
322{
323  struct RkContext	*cx;
324  struct nstore	*store;
325  struct nbun	*bun;
326
327  if (!(cx = RkGetContext(cx_num))) {
328    RkSetErrno(RK_ERRNO_ECTXNO);
329    return(-1);
330  }
331  if (!(store = cx->store) ||
332      !(bun = &store->bunq[store->maxbun]) ||
333      !IS_XFERCTX(cx) ||
334      !IS_XAUTCTX(cx) ||
335      !(0 <= ys && ys <= ye && ye <= (int)(store->nyomi - bun->nb_yoff)) ||
336      (newLen < 0)) {
337    RkSetErrno(RK_ERRNO_EINVAL);
338    return -1;
339  }
340  return _RkSubstYomi(cx, ys, ye, yomi, newLen);
341}
342
343/* RkFlushYomi
344 *	force to convert the remaining hiragana
345 * returns:
346 *	# bunsetu
347 */
348
349int
350RkwFlushYomi(int cx_num)
351{
352  struct RkContext	*cx;
353  if (!(cx = RkGetContext(cx_num)) ||
354      !IS_XFERCTX(cx) ||
355      !IS_XAUTCTX(cx)) {
356    RkSetErrno(RK_ERRNO_ECTXNO);
357    return(-1);
358  }
359  return(_RkFlushYomi(cx));
360}
361
362/* RkResize/RkEnlarge/RkShorten
363 *	current bunsetsu no ookisa wo henkou
364 */
365int
366_RkResize(int cx_num, int len, int t)
367{
368  struct RkContext	*cx;
369  struct nbun		*bun;
370  struct nstore		*store;
371
372  if (!(cx = RkGetXContext(cx_num)) ||
373      !(store = cx->store) ||
374      !(bun = getCurrentBun(store))) {
375    RkSetErrno(RK_ERRNO_ECTXNO);
376    return(-1);
377  }
378  if (t)
379    len = HowManyChars(store->yomi + store->bunq[store->curbun].nb_yoff, len);
380  if (0 < len && (unsigned)(bun->nb_yoff + len) <= store->nyomi) {
381    bun->nb_flags |= RK_REARRANGED;
382    return(_RkRenbun2(cx, len));
383  }
384  return(store->maxbun);
385}
386
387int
388RkwResize(int cx_num, int len)
389{
390  return(_RkResize(cx_num, len, 0));
391}
392
393int
394RkeResize(int cx_num, int len)
395{
396  return(_RkResize(cx_num, len, 1));
397}
398
399int
400RkwEnlarge(int cx_num)
401{
402  struct RkContext	*cx;
403  struct nstore		*store;
404  struct nbun		*bun;
405
406  if (!(cx = RkGetXContext(cx_num)) ||
407      !(store = cx->store)||
408      !(bun = getCurrentBun(store))) {
409    RkSetErrno(RK_ERRNO_ENOMEM);
410    return(0);
411  }
412  if (store->nyomi > (unsigned)(bun->nb_yoff + bun->nb_curlen) &&
413	   store->yomi[bun->nb_yoff + bun->nb_curlen]) {
414    bun->nb_flags |= RK_REARRANGED;
415    return(_RkRenbun2(cx, (int)(bun->nb_curlen + 1)));
416  }
417  return(store->maxbun);
418}
419
420int
421RkwShorten(int cx_num)
422{
423  struct RkContext	*cx;
424  struct nstore		*store;
425  struct nbun		*bun;
426
427  if (!(cx = RkGetXContext(cx_num)) ||
428      !(store = cx->store) ||
429      !(bun = getCurrentBun(store))) {
430    RkSetErrno(RK_ERRNO_ECTXNO);
431    return 0;
432  }
433  if (bun->nb_curlen > 1) {
434    bun->nb_flags |= RK_REARRANGED;
435    return(_RkRenbun2(cx, (int)(bun->nb_curlen - 1)));
436  }
437  return(store->maxbun);
438}
439
440/* RkStoreYomi
441 *	current bunsetu no yomi wo sitei sareta mono to okikaeru
442 *	okikaeta noti, saihen kan suru
443 */
444
445int
446RkwStoreYomi(int cx_num, WCHAR_T *yomi, int nlen)
447{
448  unsigned		nmax, omax, cp;
449  WCHAR_T			*s, *d, *e;
450  int			i, olen, diff;
451  struct RkContext	*cx;
452  struct nstore		*store;
453  struct nbun		*bun;
454
455  if (!(cx = RkGetXContext(cx_num)) ||
456      !(store = cx->store) ||
457      !(bun = getCurrentBun(store))) {
458    RkSetErrno(RK_ERRNO_ECTXNO);
459    return -1;
460  }
461  if (!yomi || nlen < 0 || uslen(yomi) < nlen) {
462    RkSetErrno(RK_ERRNO_EINVAL);
463    return -1;
464  }
465  nmax = store->nyomi + (diff = nlen - (olen = bun->nb_curlen));
466  omax = store->nyomi;
467  /* nobiru */
468  if (nlen > olen) {
469    if (!(store = _RkReallocBunStorage(store, store->maxyomi + diff))) {
470      RkSetErrno(RK_ERRNO_ENOMEM);
471      return -1;
472    }
473    cx->store = store;
474    bun = getCurrentBun(store);
475    /* shift yomi */
476    s = store->yomi + omax;
477    d = store->yomi + nmax;
478    e = store->yomi + bun->nb_yoff + olen;
479    while (s > e)
480      *--d = *--s;
481  } else if (nlen < olen) {	/* chizimu */
482    s = store->yomi + bun->nb_yoff + olen;
483    d = store->yomi + bun->nb_yoff + nlen;
484    e = store->yomi + omax;
485    while (s < e)
486      *d++ = *s++;
487  }
488  store->yomi[nmax] = (WCHAR_T)0;
489  store->nyomi = nmax;
490  for (i = store->curbun + 1; i <= (int)store->maxbun; i++)
491    store->bunq[i].nb_yoff += diff;
492  cp = store->curbun;
493  if (!nlen) {
494    _RkFreeBunq(store);
495    for (i = store->curbun; i < (int)store->maxbun; i++)
496      store->bunq[i] = store->bunq[i + 1];
497    store->maxbun--;
498    cp = store->curbun;
499    if (cp >= store->maxbun && cp > 0)
500      cp -= 1;
501  } else
502    usncopy((store->yomi + bun->nb_yoff), yomi, (unsigned)nlen);
503  if ((i = _RkRenbun2(cx, 0)) != -1)
504    store->curbun = cp;
505  return(i);
506}
507
508/* RkGoTo/RkLeft/RkRight
509 * 	current bunsetu no idou
510 */
511
512int
513RkwGoTo(int cx_num, int bnum)
514{
515  struct RkContext	*cx;
516  struct nstore	*store;
517
518  if (!(cx = RkGetXContext(cx_num)) ||
519      !(store = cx->store) ||
520      !store->maxbun) {
521    RkSetErrno(RK_ERRNO_ECTXNO);
522    return 0;
523  }
524  if ((0 <= bnum) && (bnum < (int)store->maxbun))
525    store->curbun = bnum;
526  return(store->curbun);
527}
528
529int
530RkwLeft(int cx_num)
531{
532  struct RkContext	*cx;
533  struct nstore	*store;
534
535  if (!(cx = RkGetXContext(cx_num)) ||
536      !(store = cx->store) ||
537      !store->maxbun) {
538    RkSetErrno(RK_ERRNO_ECTXNO);
539    return 0;
540  }
541  if (--store->curbun < 0)
542    store->curbun = store->maxbun - 1;
543  return store->curbun;
544}
545
546int
547RkwRight(int cx_num)
548{
549  struct RkContext	*cx;
550  struct nstore	*store;
551
552  if (!(cx = RkGetXContext(cx_num)) ||
553      !(store = cx->store) ||
554      !store->maxbun) {
555    RkSetErrno(RK_ERRNO_ECTXNO);
556    return 0;
557  }
558  if (++store->curbun >= (int)store->maxbun)
559    store->curbun = 0;
560  return(store->curbun);
561}
562
563/* RkXfer/RkNfer/RkNext/RkPrev
564 *	current kouho wo henkou
565 */
566static int
567countCand(struct RkContext *cx)
568{
569  struct nbun		*bun;
570  int			maxcand = 0;
571  unsigned long		mask;
572
573  bun = getCurrentBun(cx->store);
574  if (bun) {
575    maxcand = bun->nb_maxcand;
576    for (mask = cx->kouhomode; mask; mask >>= RK_XFERBITS)
577      maxcand++;
578  };
579  return(maxcand);
580}
581
582static int
583getXFER(struct RkContext *cx, int cnum)
584{
585  struct nbun	*bun = getCurrentBun(cx->store);
586
587  cnum -= ((int)bun->nb_maxcand);
588  return(cnum < 0 ? RK_NFER : (cx->kouhomode>>(RK_XFERBITS*cnum))&RK_XFERMASK);
589}
590
591int
592RkwXfer(int cx_num, int knum)
593{
594  struct RkContext	*cx;
595  struct nbun		*bun;
596
597  if (!(cx = RkGetXContext(cx_num)) ||
598      !(cx->store) ||
599      !(bun = getCurrentBun(cx->store))) {
600    RkSetErrno(RK_ERRNO_ECTXNO);
601    return 0;
602  }
603  if (0 <= knum && knum < countCand(cx))
604    bun->nb_curcand = knum;
605  return(bun->nb_curcand);
606}
607
608int
609RkwNfer(int cx_num)
610{
611  struct RkContext	*cx;
612  struct nbun	*bun;
613
614  if (!(cx = RkGetXContext(cx_num)) ||
615      !(cx->store) ||
616      !(bun = getCurrentBun(cx->store))) {
617    RkSetErrno(RK_ERRNO_ECTXNO);
618    return(0);
619  }
620  return(bun->nb_curcand = bun->nb_maxcand);
621}
622
623int RkwNext (int);
624
625int
626RkwNext(int cx_num)
627{
628  struct RkContext	*cx;
629  struct nbun	*bun;
630
631  if (!(cx = RkGetXContext(cx_num)) ||
632      !(cx->store) ||
633      !(bun = getCurrentBun(cx->store))) {
634    RkSetErrno(RK_ERRNO_ECTXNO);
635    return(0);
636  }
637  if (++bun->nb_curcand >= (WCHAR_T)countCand(cx))
638    bun->nb_curcand = 0;
639  return(bun->nb_curcand);
640}
641
642int
643RkwPrev(int cx_num)
644{
645  struct RkContext	*cx;
646  struct nbun		*bun;
647
648  if (!(cx = RkGetXContext(cx_num)) ||
649      !(cx->store) ||
650      !(bun = getCurrentBun(cx->store))) {
651    RkSetErrno(RK_ERRNO_ECTXNO);
652    return(0);
653  }
654
655  if (!bun->nb_curcand)
656    bun->nb_curcand = countCand(cx);
657  return(--bun->nb_curcand);
658}
659
660/* findBranch
661 * 	shiteisareta kouho wo fukumu path wo motomeru
662 */
663static struct nword *
664findBranch(struct nstore *store, int cnum)
665{
666  struct nbun		*bun;
667  struct nword		*w;
668
669  if (!(bun = getCurrentBun(store)) ||
670      (0 > cnum) ||
671      (cnum >= (int)bun->nb_maxcand))
672    return((struct nword *)0);
673  for (w = bun->nb_cand; w; w = w->nw_next) {
674    if (CanSplitWord(w) && bun->nb_curlen == w->nw_ylen) {
675      if (cnum-- <= 0)
676	return(w);
677    }
678  }
679  return((struct nword *)0);
680}
681
682/* RkGetStat
683 */
684int
685RkwGetStat(int cx_num, RkStat *st)
686{
687  struct RkContext	*cx;
688  struct nstore		*store;
689  struct nbun		*bun;
690  struct nword		*cw, *lw;
691
692  if (!(cx = RkGetXContext(cx_num)) ||
693      !(store = cx->store) ||
694      !(bun = getCurrentBun(store)) ||
695      !st) {
696    RkSetErrno(RK_ERRNO_ECTXNO);
697    return -1;
698  }
699  /* set up void values */
700  st->bunnum = st->candnum = st->maxcand =
701    st->diccand = st->ylen = st->klen = st->tlen = 0;
702  st->bunnum  = store->curbun;
703  st->candnum = bun->nb_curcand;
704
705  st->maxcand = countCand(cx);
706  st->diccand = bun->nb_maxcand;
707  st->ylen    = bun->nb_curlen;
708  st->klen    = bun->nb_curlen;
709  st->tlen    = 1;
710  /* look up the word node containing the current candidate */
711  cw = findBranch(store, (int)bun->nb_curcand);
712  if (cw) {
713    st->klen = st->tlen = 0;
714    for (; cw; cw = cw->nw_left) {
715      if (!(lw = cw->nw_left))
716	break;
717      if (cw->nw_klen == lw->nw_klen)
718	st->klen += (cw->nw_ylen - lw->nw_ylen);
719      else
720	st->klen += (cw->nw_klen - lw->nw_klen);
721      st->tlen++;
722    }
723  } else {
724    WCHAR_T	*yomi = store->yomi + bun->nb_yoff;
725    switch(getXFER(cx, (int)bun->nb_curcand)) {
726    default:
727    case RK_XFER:
728      st->klen = RkwCvtHira((WCHAR_T *)0, 0, yomi, st->ylen);
729      break;
730    case RK_KFER:
731      st->klen = RkwCvtKana((WCHAR_T *)0, 0, yomi, st->ylen);
732      break;
733    case RK_HFER:
734      st->klen = RkwCvtHan((WCHAR_T *)0, 0, yomi, st->ylen);
735      break;
736    case RK_ZFER:
737      st->klen = RkwCvtZen((WCHAR_T *)0, 0, yomi, st->ylen);
738      break;
739    }
740  }
741  return 0;
742}
743
744/* RkGetStat
745 */
746int
747RkeGetStat(int cx_num, RkStat *st)
748{
749  struct RkContext *cx;
750  struct nstore *store;
751  WCHAR_T *yomi;
752  int res, klen;
753  WCHAR_T *kanji = (WCHAR_T *)malloc(sizeof(WCHAR_T) * (RK_LEN_WMAX + 1));
754  if (!kanji) {
755    return -1;
756  }
757
758  if (!(cx = RkGetXContext(cx_num)) || !(store = cx->store)) {
759    RkSetErrno(RK_MSG_ECTXNO);
760    res = -1;
761    goto return_res;
762  }
763
764  yomi = store->yomi + store->bunq[store->curbun].nb_yoff;
765  klen = RkwGetKanji(cx_num, kanji, RK_LEN_WMAX + 1);
766  res = RkwGetStat(cx_num, st);
767  if (res < 0 || klen != st->klen) {
768    res = -1;
769    goto return_res;
770  }
771  if (st) {
772    st->ylen = HowManyBytes(yomi, st->ylen);
773    st->klen = HowManyBytes(kanji, klen);
774  }
775 return_res:
776  free(kanji);
777  return res;
778}
779
780static int
781addIt(struct nword * cw, WCHAR_T * key, int (*proc) (...), WCHAR_T * dst, int ind, int maxdst, unsigned long mode, RkContext * cx)
782{
783	struct nword       *lw;
784	WCHAR_T              *y;
785	RkLex               lex;
786
787	lw = cw->nw_left;
788	if (lw) {
789		ind = addIt(lw, key, proc, dst, ind, maxdst, mode, cx);
790		y = key + lw->nw_ylen;
791		lex.ylen = cw->nw_ylen - lw->nw_ylen;
792		lex.klen = cw->nw_klen - lw->nw_klen;
793		lex.rownum = cw->nw_rowcol;
794#ifdef NEED_DEF
795		lex.colnum = cw->nw_rowcol;
796#endif
797		lex.dicnum = cw->nw_class;
798		ind = (*proc) (dst, ind, maxdst, y, _RkGetKanji(cw, y, mode), &lex, cx);
799	}
800	return ind;
801}
802
803
804inline int
805getIt(RkContext * cx, int cnum, int (*proc) (...), WCHAR_T * dst, int max)
806{
807	struct nstore      *store = cx->store;
808	struct nbun        *bun;
809	struct nword       *w;
810
811	if (!(bun = getCurrentBun(store)) ||
812	    !(w = findBranch(store, cnum)))
813		return (-1);
814	return addIt(w, store->yomi + bun->nb_yoff, proc, dst, 0, max,
815		     cx->concmode, cx);
816}
817
818/*ARGSUSED*/
819inline int
820addYomi(WCHAR_T *dst, int ind, int max, WCHAR_T *yomi, WCHAR_T *kanji, RkLex *lex)
821{
822  int		ylen;
823
824  ylen = lex->ylen;
825  while (ylen--) {
826    if (ind < max) {
827      if (dst)
828	dst[ind] = *yomi++;
829      ind++;
830    }
831  }
832  return ind;
833}
834/* RkGetYomi
835 *	current bunsetu no yomi wo toru
836 */
837
838int RkwGetYomi (int, WCHAR_T *, int);
839
840int
841RkwGetYomi(int cx_num, WCHAR_T *yomi, int maxyomi)
842{
843  struct RkContext	*cx;
844  struct nbun	*bun;
845  RkLex	lex;
846  int		i;
847  struct nstore	*store;
848
849  if (!(cx = RkGetXContext(cx_num)) ||
850      !(store = cx->store) ||
851      !(bun = getCurrentBun(store))) {
852    RkSetErrno(RK_ERRNO_ECTXNO);
853    return -1;
854  };
855  if (!yomi) {
856    RkSetErrno(RK_ERRNO_EINVAL);
857    return -1;
858  };
859  lex.ylen = bun->nb_curlen;
860  i = addYomi(yomi, 0, maxyomi - 1,
861	      store->yomi + bun->nb_yoff,
862	      store->yomi+bun->nb_yoff,
863	      &lex);
864  if (yomi && i < maxyomi)
865    yomi[i] = (WCHAR_T)0;
866  return i;
867}
868
869int
870RkwGetLastYomi(int cx_num, WCHAR_T *yomi, int maxyomi)
871{
872  struct RkContext	*cx;
873  struct nbun	*bun;
874  struct nstore	*store;
875  int		nyomi;
876
877  if (!(cx = RkGetXContext(cx_num)) ||
878      !(store = cx->store) ||
879      !(bun = &store->bunq[store->maxbun])) {
880    RkSetErrno(RK_ERRNO_ECTXNO);
881    return -1;
882  }
883  if (!(cx->flags & CTX_XAUT) || maxyomi < 0) {
884    RkSetErrno(RK_ERRNO_EINVAL);
885    return -1;
886  }
887  nyomi = store->nyomi - bun->nb_yoff;
888  if (yomi) {
889    usncopy(yomi, store->yomi + bun->nb_yoff, (unsigned)(maxyomi));
890    if (nyomi + 1 < maxyomi) {
891      yomi[nyomi] = (WCHAR_T)0;
892    } else {
893      yomi[maxyomi - 1] = (WCHAR_T)0;
894    };
895  }
896  return nyomi;
897}
898
899/*ARGSUSED*/
900static int
901addKanji(WCHAR_T *dst, int ind, int max, WCHAR_T *yomi, WCHAR_T *kanji, RkLex *lex, struct RkContext *cx) /* ARGSUSED */
902{
903  int		klen;
904
905  klen = lex->klen;
906  while (klen-- > 0) {
907    if (ind < max) {
908      if (dst)
909	dst[ind] = *kanji++;
910      ind++;
911    }
912  }
913  return ind;
914}
915
916static int
917getKanji(struct RkContext *cx, int cnum, WCHAR_T *dst, int maxdst)
918{
919  struct nbun	*bun = getCurrentBun(cx->store);
920  WCHAR_T		*yomi;
921  int		i, ylen;
922
923  i = getIt(cx, cnum, (int(*)(...))addKanji, dst, maxdst - 1);
924  if (i < 0) {
925    yomi = cx->store->yomi + bun->nb_yoff;
926    ylen = bun->nb_curlen;
927    switch(getXFER(cx, cnum)) {
928    default:
929    case RK_XFER:
930      i = RkwCvtHira(dst, maxdst, yomi, ylen); break;
931    case RK_KFER:
932      i = RkwCvtKana(dst, maxdst, yomi, ylen); break;
933    case RK_HFER:
934      i = RkwCvtHan(dst, maxdst, yomi, ylen); break;
935    case RK_ZFER:
936      i = RkwCvtZen(dst, maxdst, yomi, ylen); break;
937    }
938  }
939  if (dst && i < maxdst)
940    dst[i] = (WCHAR_T)0;
941  return i;
942}
943
944/* RkGetKanji
945 *	current bunsetu no kanji tuduri wo toru
946 */
947
948int
949RkwGetKanji(int cx_num, WCHAR_T *dst, int maxdst)
950{
951  RkContext	*cx;
952  struct nbun	*bun;
953  int		i;
954
955  if (!(cx = RkGetXContext(cx_num)) ||
956      !(cx->store) ||
957      !(bun = getCurrentBun(cx->store))) {
958    RkSetErrno(RK_ERRNO_ECTXNO);
959    return -1;
960  }
961
962  i = getKanji(cx, (int)bun->nb_curcand, dst, maxdst);
963  if (dst && i < maxdst)
964    dst[i] = 0;
965  return i;
966}
967
968/* RkGetKanjiList
969 * 	genzai sentaku sareta kouho mojiretu wo toridasu
970 */
971int
972RkwGetKanjiList(int cx_num, WCHAR_T *dst, int maxdst)
973{
974  struct RkContext	*cx;
975  int			i, len, ind = 0, num = 0;
976  int			maxcand;
977
978  if (!(cx = RkGetXContext(cx_num)) ||
979      !(cx->store)) {
980    RkSetErrno(RK_ERRNO_ECTXNO);
981    return -1;
982  }
983  maxcand = countCand(cx);
984  for (i = 0; i < maxcand; i++) {
985    if (dst)
986      len = getKanji(cx, i, dst + ind, maxdst - ind - 1);
987    else
988      len = getKanji(cx, i, dst, maxdst - ind - 1);
989    if (0 < len && ind + len + 1 < maxdst - 1) {
990      if (dst)
991	dst[ind + len] = (WCHAR_T)0;
992      ind += len + 1;
993      num++;
994    }
995  }
996  if (dst && ind < maxdst)
997    dst[ind] = (WCHAR_T)0;
998  return num;
999}
1000
1001/* RkGetLex
1002 *	current bunsetu no hishi jouhou wo toru
1003 */
1004/*ARGSUSED*/
1005static int
1006addLex(RkLex *dst, int ind, int max, WCHAR_T *yomi, WCHAR_T *kanji, RkLex *lex, struct RkContext *cx) /* ARGSUSED */
1007{
1008  if (ind + 1 <= max) {
1009    if (dst)
1010      dst[ind] = *lex;
1011    ind++;
1012  }
1013  return ind;
1014}
1015
1016int
1017RkwGetLex(int cx_num, RkLex *dst, int maxdst)
1018{
1019  RkContext	*cx;
1020  struct nbun	*bun;
1021  int	i;
1022
1023  if (!(cx = RkGetXContext(cx_num)) ||
1024      !(cx->store) ||
1025      !(bun = getCurrentBun(cx->store))) {
1026    RkSetErrno(RK_ERRNO_ECTXNO);
1027    return -1;
1028  }
1029  i = getIt(cx, (int)bun->nb_curcand, (int(*)(...))addLex, (WCHAR_T *)dst, maxdst - 1);
1030  if (i < 0) {
1031    if (dst && 1 < maxdst) {
1032      dst[0].ylen = bun->nb_curlen;
1033      dst[0].klen = bun->nb_curlen;
1034      dst[0].rownum  = cx->gram->P_BB; /* ʸÀá */
1035      dst[0].colnum  = cx->gram->P_BB; /* ʸÀá */
1036      dst[0].dicnum  = ND_EMP;
1037    }
1038    i = 1;
1039  }
1040  return i;
1041}
1042
1043/* RkeGetLex -- ¤Û¤Ü RkwGetLex ¤ÈƱ¤¸¤À¤¬Ä¹¤µ¤Ï¥Ð¥¤¥ÈŤÇÊÖ¤ë */
1044
1045int
1046RkeGetLex(int cx_num, RkLex *dst, int maxdst)
1047{
1048  struct RkContext *cx;
1049  struct nstore *store;
1050  WCHAR_T *yomi, *kp;
1051  int nwords, i;
1052  WCHAR_T *kanji = (WCHAR_T *)malloc(sizeof(WCHAR_T) * (RK_LEN_WMAX + 1));
1053  if (!kanji) {
1054    return -1;
1055  }
1056
1057  if (!(cx = RkGetXContext(cx_num)) ||
1058      !(store = cx->store)) {
1059    RkSetErrno(RK_MSG_ECTXNO);
1060    nwords = -1;
1061    goto return_nwords;
1062  }
1063
1064  yomi = store->yomi + store->bunq[store->curbun].nb_yoff;
1065  (void)RkwGetKanji(cx_num, kanji, RK_LEN_WMAX + 1);
1066  kp = kanji;
1067  nwords = RkwGetLex(cx_num, dst, maxdst);
1068  if (dst) {
1069    for (i = 0; i < nwords; i++) {
1070      int tmp;
1071      tmp = dst[i].ylen;
1072      dst[i].ylen = HowManyBytes(yomi, tmp); yomi += tmp;
1073      tmp = dst[i].klen;
1074      dst[i].klen = HowManyBytes(kp, tmp); kp += tmp;
1075    }
1076  }
1077 return_nwords:
1078  free(kanji);
1079  return nwords;
1080}
1081
1082/*ARGSUSED*/
1083static int
1084addHinshi(WCHAR_T *dst, int ind, int max, WCHAR_T *yomi, WCHAR_T *kanji, RkLex *lex, struct RkContext *cx)
1085{
1086  int	bytes;
1087  WCHAR_T	*p;
1088#ifndef USE_MALLOC_FOR_BIG_ARRAY
1089  WCHAR_T	hinshi[256];
1090#else
1091  WCHAR_T *hinshi = (WCHAR_T *)malloc(sizeof(WCHAR_T) * 256);
1092  if (!hinshi) {
1093    return ind;
1094  }
1095#endif
1096
1097  if (cx) {
1098    p = RkUparseGramNum(cx->gram->gramdic, lex->rownum, hinshi, 256);
1099    if (p) {
1100      bytes = p - hinshi;
1101      if (ind + bytes  < max) {
1102	if (dst)
1103	  usncopy(dst + ind, hinshi, bytes);
1104	ind += bytes;
1105      }
1106    }
1107  }
1108#ifdef USE_MALLOC_FOR_BIG_ARRAY
1109  free(hinshi);
1110#endif
1111  return ind;
1112}
1113
1114/* RkGetHinshi
1115 *	current bunsetu no hinshi mojiretu wo toru
1116 */
1117int
1118RkwGetHinshi(int cx_num, WCHAR_T *dst, int maxdst)
1119{
1120  struct RkContext	*cx;
1121  struct nbun		*bun;
1122  int			i;
1123
1124  if (!(cx = RkGetXContext(cx_num)) ||
1125      !(cx->store) ||
1126      !(bun = getCurrentBun(cx->store))) {
1127    RkSetErrno(RK_ERRNO_ECTXNO);
1128    return(-1);
1129  }
1130  i = getIt(cx, (int)bun->nb_curcand, (int(*)(...))addHinshi, dst, maxdst - 1);
1131  if (i < 0) {
1132    if (dst && 1 < maxdst)
1133      dst[0] = (WCHAR_T)0;
1134    i = 1;
1135  }
1136  return(i);
1137}
1138
1139#include <sys/types.h>
1140#include <sys/stat.h>
1141
1142#define	CloseContext(a)	{if ((a) != cx_num) RkwCloseContext(a);}
1143
1144int
1145RkwQueryDic(int cx_num, char *dirname, char *dicname, struct DicInfo *status)
1146{
1147  struct RkContext	*cx;
1148  int			new_cx_num, size;
1149  unsigned char		*buff;
1150  char			*file;
1151  struct DM		*dm;
1152  struct DF		*df;
1153  struct stat		st;
1154
1155  if (!(cx = RkGetContext(cx_num))
1156      || !status || !dirname || !dicname || !dicname[0])
1157    return(-1);
1158  size = strlen(dicname) + 1;
1159  if (!(buff = (unsigned char *)malloc(size)))
1160    return(-1);
1161  (void)strcpy((char *)buff, dicname);
1162  if (*dirname && strcmp(dirname, cx->ddpath[0]->dd_name)
1163      && strcmp(dirname, (char *)SYSTEM_DDHOME_NAME)) {
1164    if((new_cx_num = RkwCreateContext()) < 0) {
1165      free(buff);
1166      return BADCONT;
1167    }
1168    if(RkwSetDicPath(new_cx_num, dirname) < 0) {
1169      CloseContext(new_cx_num);
1170      free(buff);
1171      return NOTALC;
1172    }
1173    if (!(cx = RkGetContext(new_cx_num))) {
1174      free(buff);
1175      return(-1);
1176    }
1177  } else {
1178    if (!strcmp(dirname, (char *)SYSTEM_DDHOME_NAME))
1179      dirname = SYSTEM_DDHOME_NAME;
1180    else
1181      dirname = cx->ddpath[0]->dd_name;
1182    new_cx_num = cx_num;
1183  }
1184  if (!strcmp(dirname, (char *)SYSTEM_DDHOME_NAME)) {
1185    if (!(dm = _RkSearchDDP(cx->ddpath, dicname))) {
1186      CloseContext(new_cx_num);
1187      free(buff);
1188      return NOENT;
1189    }
1190  } else {
1191    if (!(dm = _RkSearchUDDP(cx->ddpath, (unsigned char *)dicname))) {
1192      CloseContext(new_cx_num);
1193      free(buff);
1194      return NOENT;
1195    }
1196  }
1197  df = dm->dm_file;
1198  if (df) {
1199    file = _RkCreatePath(df->df_direct, df->df_link);
1200    if (file) {
1201      status->di_dic = (unsigned char *)dm->dm_nickname;
1202      status->di_file = (unsigned char *)df->df_link;
1203      status->di_form = (DM2TYPE(dm) == DF_TEMPDIC) ? RK_TXT : RK_BIN;
1204      status->di_kind = dm->dm_class;
1205      status->di_count = stat(file, &st) >= 0 ? st.st_size : 0;
1206      status->di_time = stat(file, &st) >= 0 ? st.st_ctime : 0;
1207      status->di_mode = 0;
1208      CloseContext(new_cx_num);
1209      free(file);
1210      free(buff);
1211      return(0);
1212    }
1213  }
1214  free(buff);
1215  CloseContext(new_cx_num);
1216  return(-1);
1217}
1218
1219int
1220_RkwSync(struct RkContext *cx, char *dicname)
1221{
1222  struct DM	*dm, *qm;
1223
1224  dm = _RkSearchDicWithFreq(cx->ddpath, dicname, &qm);
1225
1226  if (dm)
1227    return(DST_SYNC(cx, dm, qm));
1228  else
1229    return (-1);
1230}
1231
1232
1233int
1234RkwSync(int cx_num, char *dicname)
1235{
1236  struct RkContext	*cx;
1237  int ret = -1;
1238  const off_t DL_SIZE = 1024;
1239
1240  if (!(cx = RkGetContext(cx_num)))
1241    return (-1);
1242
1243  if (!dicname || !*dicname) {
1244    int i, rv;
1245    char *p;
1246#ifndef USE_MALLOC_FOR_BIG_ARRAY
1247    char diclist[DL_SIZE];
1248#else
1249    char *diclist = (char *)malloc(DL_SIZE);
1250    if (!diclist) {
1251      return -1;
1252    }
1253#endif
1254
1255    if (!(i = RkwGetDicList(cx_num, diclist, DL_SIZE))) {
1256      ret = 0;
1257    }
1258    else {
1259      if (i > 0) {
1260	for (p = diclist, rv = 0; *p;) {
1261	  rv += _RkwSync(cx, p);
1262	  p += strlen(p) + 1;
1263	}
1264	if (!rv) {
1265	  ret = 0;
1266	  goto return_ret;
1267	}
1268      }
1269      ret = -1;
1270    }
1271  return_ret:;
1272#ifdef USE_MALLOC_FOR_BIG_ARRAY
1273    free(diclist);
1274#endif
1275  } else {
1276    ret = _RkwSync(cx, dicname);
1277  }
1278  return ret;
1279}
1280
1281/*ARGSUSED*/
1282int RkwGetSimpleKanji(int cxnum, char *dicname, WCHAR_T *yomi, int maxyomi, WCHAR_T *kanjis, int maxkanjis, char *hinshis, int maxhinshis)
1283{
1284  return -1;
1285}
1286
1287/*ARGSUSED*/
1288int
1289RkwStoreRange(int cx_num, WCHAR_T *yomi, int maxyomi)
1290{
1291  return(0);
1292}
1293
1294/*ARGSUSED*/
1295int
1296RkwSetLocale(int cx_num, unsigned char *locale)
1297{
1298  return(0);
1299}
1300