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#if !defined(lint) && !defined(__CODECENTER__)
24static char rcsid[]="$Id: context.c 10525 2004-12-23 21:23:50Z korli $";
25#endif
26/*LINTLIBRARY*/
27
28#include "RKintern.h"
29#include "patchlevel.h"
30#include <canna/jrkanji.h>
31
32#include <string.h>
33#include <unistd.h>
34#include <StorageDefs.h>
35#include <stdio.h>
36
37static unsigned long now_context = 0L;
38
39#define cx_gwt		cx_extdata.ptr
40#define	STRCMP(d, s)	strcmp((char *)(d), (char *)(s))
41
42struct RkGram SG;
43struct RkParam SX;
44
45/* RkInitialize: Renbunsetsu Henkan shokika
46 *	subeteno Renbunsetsu henkan kannsuu wo siyou suru maeni
47 *      itido dake call suru koto.
48 * returns: -1/0
49 */
50static struct RkContext	*CX;
51
52#ifdef MMAP
53/* If you compile with Visual C++, then please comment out the next 3 lines. */
54#include <sys/types.h>  /* mmap */
55#include <sys/mman.h>   /* mmap */
56#include <fcntl.h>      /* mmap */
57int fd_dic = -1;        /* mmap */
58#endif
59
60#define DEFAULTGRAMDIC "/canna/fuzokugo.cbd"
61
62static int _RkInitialize(char *ddhome, int numCache);
63static void _RkFinalizeWord(void);
64static int fillContext(int cx_num);
65static int diccmp(const struct dics *a, const struct dics *b);
66
67static int
68_RkInitialize(char *ddhome, int numCache)
69{
70  int			i = strlen(ddhome);
71  struct RkParam	*sx = &SX;
72  struct DD		*dd = &sx->dd;
73  char			path[B_PATH_NAME_LENGTH];
74  int con;
75
76#ifdef MMAP
77  if((fd_dic == -1) && (fd_dic = open("/dev/zero", O_RDWR)) < 0) {
78    /* leave open as it was, because WIN does not come here.  1996.6 kon */
79    con = -1;
80    goto return_con;
81  }
82#endif
83
84  if (sx->flag & SX_INITED) {
85    con = -1;
86    goto return_con;
87  }
88
89//  gramdic = (char *)malloc(strlen(DEFAULTGRAMDIC) + i + 1);
90  if (1) {
91    sprintf(path, "%s%s", ddhome, DEFAULTGRAMDIC);
92    SG.gramdic = RkOpenGram(path);
93//    free(gramdic);
94    if (SG.gramdic) {
95      /* confirm user/ and group/ directory */
96    if (1) {
97		sprintf(path, "%s/%s", ddhome, USER_DIC_DIR);
98	if (close(open(path, 0, 0664)) < 0 &&
99	    mkdir(path, MKDIR_MODE) < 0) {
100	}	else {
101
102	  if (1) {
103	    sprintf(path, "%s/%s", ddhome, GROUP_DIC_DIR);
104	    if (close(open(path, 0, 0664)) < 0 &&
105		mkdir(path, MKDIR_MODE) < 0) {
106	    }
107	    else {
108	      sx->word = (struct nword *)0;
109	      dd->dd_next = dd->dd_prev = dd;
110	      sx->ddhome = strdup(ddhome);
111	      if (sx->ddhome) {
112		SG.P_BB  = RkGetGramNum(SG.gramdic, "BB");
113		SG.P_NN  = RkGetGramNum(SG.gramdic, "NN");
114		SG.P_T00 = RkGetGramNum(SG.gramdic, "T00");
115		SG.P_T30 = RkGetGramNum(SG.gramdic, "T30");
116		SG.P_T35 = RkGetGramNum(SG.gramdic, "T35");
117#ifdef FUJIEDA_HACK
118		SG.P_KJ  = RkGetGramNum(SG.gramdic, "KJ");
119#endif
120		CX = (struct RkContext *)
121		  calloc(INIT_CONTEXT, sizeof(struct RkContext));
122		if (CX) {
123		  now_context += INIT_CONTEXT;
124		  if (_RkInitializeCache(numCache) == 0) {
125		    sx->ddpath = _RkCreateDDP(SYSTEM_DDHOME_NAME);
126		    if (sx->ddpath) {
127		      con = RkwCreateContext();
128		      if (con >= 0) {
129			sx->flag |= SX_INITED;
130			goto return_con;
131		      }
132		      _RkFreeDDP(sx->ddpath);
133		      sx->ddpath = (struct DD **)0;
134		    }
135		    _RkFinalizeCache();
136		  }
137		  free(CX);
138		  now_context = 0L;
139		}
140		free(sx->ddhome);
141	      }
142	    }
143	  }
144	}
145      }
146      RkCloseGram(SG.gramdic);
147    }
148  }
149  con = -1;
150 return_con:
151  return con;
152}
153
154int
155RkwInitialize(char *ddhome)
156{
157  /*
158   * Word:	????
159   * Cache:	36B*512 	= 20KB
160   * Heap:	30*1024B	= 30KB
161   */
162#ifdef WIN
163  return(ddhome ? _RkInitialize(ddhome, 512*3) : -1);
164#else
165  return(ddhome ? _RkInitialize(ddhome, 512*10) : -1);
166#endif
167}
168
169/* RkFinalize: Renbunsetu henkan shuuryou shori
170 *
171 */
172static void
173_RkFinalizeWord(void)		/* finalize free word list */
174{
175  struct nword	*w, *t;
176
177  /* dispose each page in list */
178  for (w = SX.page; w; w = t) {
179    t = w->nw_next;
180    free(w);
181  }
182  SX.word = (struct nword *)0;
183  SX.page = (struct nword *)0;
184  SX.word_in_use = 0;
185  SX.page_in_use = 0;
186}
187
188void
189RkwFinalize(void)
190{
191  struct RkParam	*sx = &SX;
192  int	i;
193
194  /* already initialized */
195  if (!(sx->flag & SX_INITED))
196    return;
197  /* houchi sareta context wo close */
198  for(i = 0; (unsigned long)i < now_context; i++)
199    if (IS_LIVECTX(&CX[i]))
200      RkwCloseContext(i);
201  free(CX);
202  now_context = 0L;
203  /* sonohoka no shuuryou shori */
204  _RkFinalizeWord();
205  _RkFinalizeCache();
206  free(sx->ddhome);
207  sx->ddhome = (char *)0;
208  _RkFreeDDP(sx->ddpath);
209  RkCloseGram(SG.gramdic);
210  sx->flag &= ~SX_INITED;
211
212#ifdef MMAP
213  close(fd_dic);
214  fd_dic = -1;
215#endif
216
217  return;
218}
219
220/* RkGetSystem: System heno pointer wo motomeru
221 */
222struct RkParam	*
223RkGetSystem(void)
224{
225  return(&SX);
226}
227
228/* RkGetSystemDD: System heno pointer wo motomeru
229 */
230struct DD	*
231RkGetSystemDD(void)
232{
233  struct RkParam	*sx;
234  return(((sx = RkGetSystem()) && sx->ddpath) ? sx->ddpath[0] : (struct DD *)0);
235}
236
237/* RkGetContext: Context heno pointer wo motomeru
238 *	-> RKintern.h
239 */
240struct RkContext *
241RkGetContext(int cx_num)
242{
243  return(IsLiveCxNum(cx_num) ? &CX[cx_num] : (struct RkContext *)0);
244}
245
246struct RkContext *
247RkGetXContext(int cx_num)
248{
249  struct RkContext	*cx;
250
251  cx = RkGetContext(cx_num);
252  if (cx)
253    if (!IS_XFERCTX(cx))
254      cx = (struct RkContext *)0;
255  return(cx);
256}
257
258void
259_RkEndBun(struct RkContext *cx)
260{
261    struct DD	**ddp = cx->ddpath;
262    int		c;
263
264    cx->flags &= ~(CTX_XFER|CTX_XAUT);
265    cx->concmode &= ~(RK_CONNECT_WORD | RK_MAKE_WORD |
266		      RK_MAKE_KANSUUJI | RK_MAKE_EISUUJI);
267    for (c = 0; c < 4; c++) {
268	struct MD	*head, *md, *nd;
269
270	head = cx->md[c];
271	for (md = head->md_next; md != head; md = nd) {
272	    struct DM 	*dm = md->md_dic;
273	    struct DF	*df = dm->dm_file;
274	    struct DD	*dd = df->df_direct;
275
276	    nd = md->md_next;
277	    if (md->md_flags & MD_MPEND) 	/* release pending */
278		md->md_flags &= ~MD_MPEND;
279	    if (md->md_flags & MD_UPEND) 	/* unmount pending */
280		_RkUmountMD(cx, md);
281	    else
282	    if (!_RkIsInDDP(ddp, dd)) 		/* unreachable */
283		_RkUmountMD(cx, md);
284	};
285    };
286}
287
288/* RkSetDicPath
289 *
290 */
291
292int
293RkwSetDicPath(int cx_num, char *path)
294{
295  struct RkContext	*cx = RkGetContext(cx_num);
296  struct DD		**newc;
297
298  newc = _RkCreateDDP(path);
299  if (newc) {
300    _RkFreeDDP(cx->ddpath);
301    cx->ddpath = newc;
302    return(0);
303  };
304  return(-1);
305}
306
307/*
308  fillContext -- ¥³¥ó¥Æ¥¯¥¹¥È¹½Â¤ÂΤηè¤Þ¤Ã¤¿¤È¤³¤í¤ËÃͤòËä¤á¤Æ¤ä¤ë¡£
309
310  return value:
311    0 OK
312   -1 ¥À¥á
313 */
314
315static int
316fillContext(int cx_num)
317{
318  struct RkContext *cx = &CX[cx_num];
319  int i;
320
321  /* create mount list headers */
322  for (i = 0; i < 4; i++) {
323    struct MD *mh;
324
325    if (!(mh = (struct MD *)calloc(1, sizeof(struct MD)))) {
326      int j;
327
328      for (j = 0 ; j < i; j++) {
329	free(cx->md[i]);
330      }
331      return -1;
332    }
333    mh->md_next = mh->md_prev = mh;
334    mh->md_dic = (struct DM *)0;
335    mh->md_flags = 0;
336    cx->md[i] = mh;
337  }
338  cx->dmprev = (struct DM *)0;
339  cx->qmprev = (struct DM *)0;
340  cx->nv = (struct NV *)0;
341  cx->ddpath = (struct DD **)0;
342  cx->kouhomode = (unsigned long)0;
343  cx->concmode = 0;
344  cx->litmode = (unsigned long *)calloc(MAXLIT, sizeof(unsigned long));
345  cx->gram = &SG;
346  if (cx->litmode) {
347    for (i = 0; i < MAXLIT; i++) {
348      cx->litmode[i] = 0x87654321;
349    }
350    cx->poss_cont = 0;
351#ifdef EXTENSION_NEW
352    cx->cx_gwt = (pointer)calloc(1, sizeof(struct _rec));
353    if (cx->cx_gwt) {
354      struct _rec	*gwt = (struct _rec *)cx->cx_gwt;
355      gwt->gwt_cx = -1;  /* means no GetWordTextdic context
356			    is available */
357      gwt->gwt_dicname = (unsigned char *)0;
358      cx->flags = CTX_LIVE | CTX_NODIC;
359      return 0;
360    }
361    free(cx->litmode);
362#else
363    cx->flags = CTX_LIVE | CTX_NODIC;
364    return 0;
365#endif
366  }
367  return -1;
368}
369
370int
371RkwCreateContext(void)
372{
373  int	cx_num, i;
374  struct RkContext *newcx;
375
376  /* saisho no aki context wo mitsukeru */
377  for(cx_num = 0; cx_num < (int)now_context; cx_num++) {
378    if(!CX[cx_num].flags) {
379      /* create mount list headers */
380      if (fillContext(cx_num) == 0) {
381	return cx_num;
382      }
383    }
384  }
385  newcx = (RkContext *)realloc(CX, (size_t) sizeof(RkContext)
386			       * (now_context+ADD_CONTEXT));
387  if (newcx) {
388    CX = newcx;
389    for (i = now_context ; i < (int)now_context + ADD_CONTEXT ; i++) {
390      CX[i].flags = (unsigned)0;
391    }
392    cx_num = now_context;
393    now_context += ADD_CONTEXT;
394    if (fillContext(cx_num) == 0) {
395      return cx_num;
396    }
397  }
398  return(-1);
399}
400
401int
402RkwCloseContext(int cx_num)
403{
404  struct RkContext	*cx;
405  int				i;
406
407  if (!(cx  = RkGetContext(cx_num)))
408    return(-1);
409/* terminate bunsetu henkan */
410  if (IS_XFERCTX(cx))
411    RkwEndBun(cx_num, 0);
412  _RkFreeDDP(cx->ddpath);
413  cx->ddpath = (struct DD **)0;
414  /* subete no jisho wo MD suru */
415  for (i = 0; i < 4; i++) {
416    struct MD	*mh, *m, *n;
417
418    /* destroy mount list */
419    mh = cx->md[i];
420    if (mh) {
421      for (m = mh->md_next; m != mh; m = n) {
422	n = m->md_next;
423	(void)_RkUmountMD(cx, m);
424      };
425      free(mh);
426      cx->md[i] = (struct MD *)0;
427    };
428  };
429  cx->dmprev = (struct DM *)0;
430  cx->qmprev = (struct DM *)0;
431  /* convertion table */
432  if (cx->litmode) {
433    free(cx->litmode);
434    cx->litmode = (unsigned long *)0;
435  }
436  cx->flags = 0;
437
438  /* free grammatical dictionary */
439  cx->gram->refcount--;
440  if (cx->gram->refcount == 0 && cx->gram != &SG) {
441    RkCloseGram(cx->gram->gramdic);
442    free(cx->gram);
443  }
444  cx->gram = (struct RkGram *)0;
445
446#ifdef EXTENSION_NEW
447  if (cx->cx_gwt) {
448    struct _rec	*gwt = (struct _rec *)cx->cx_gwt;
449    if (gwt) {
450      (void)RkwCloseContext(gwt->gwt_cx);
451      if (gwt->gwt_dicname)
452	free(gwt->gwt_dicname);
453      free(gwt);
454    };
455    cx->cx_gwt = (pointer)0;
456  };
457  freeTdn(cx);
458#endif
459  return 0;
460}
461/* RkDuplicateContext
462 *	onaji naiyou no context wo sakuseisuru
463 */
464
465int
466RkwDuplicateContext(int cx_num)
467{
468  struct RkContext	*sx;
469  int			dup = -1;
470
471  dup = RkwCreateContext();
472  if (dup >= 0) {
473    int		i;
474    struct RkContext	*dx;
475
476    sx  = RkGetContext(cx_num);
477    if (sx) {
478      dx = RkGetContext(dup);
479
480      /* use the same grammatical information */
481      dx->gram = sx->gram;
482      dx->gram->refcount++;
483      if (!(sx->flags & CTX_NODIC)) {
484	dx->flags &= ~CTX_NODIC;
485      }
486
487      /* copy the mount list */
488      for (i = 0; i < 4; i++) {
489	struct MD	*mh, *md;
490
491	/* should mount dictionaries in reverse order */
492	mh = sx->md[i];
493	for (md = mh->md_prev; md != mh; md = md->md_prev)
494	  (void)_RkMountMD(dx, md->md_dic, md->md_freq,
495			   md->md_flags & MD_WRITE, 0);
496      };
497      dx->ddpath = _RkCopyDDP(sx->ddpath);
498      if (sx->litmode && dx->litmode)
499	for (i = 0; i < MAXLIT; i++)
500	  dx->litmode[i] = sx->litmode[i];
501    } else {
502      RkwCloseContext(dup);
503      return -1;
504    }
505  }
506  return(dup);
507}
508
509/* RkMountDic: append the specified dictionary at the end of the mount list */
510int
511RkwMountDic(int cx_num, char *name, int mode)		/* mount mode */
512{
513  struct RkContext	*cx;
514  int firsttime;
515
516  if (!name)
517    return(-1);
518  cx = RkGetContext(cx_num);
519  if (cx) {
520    struct DM *dm, *qm;
521
522    firsttime = (cx->flags & CTX_NODIC) ? 1 : 0;
523    if (firsttime) { /* ºÇ½é¤Ë¥Þ¥¦¥ó¥È*¤·¤è¤¦¤È*¤·¤¿¤é¹ß¤í¤¹ */
524      cx->flags &= ~CTX_NODIC;
525    }
526
527    dm = _RkSearchDicWithFreq(cx->ddpath, name, &qm);
528    if (dm) {
529      struct MD	*mh = cx->md[dm->dm_class];
530      struct MD	*md, *nd;
531      int		count = 0;
532
533      /* search the dictionary */
534      for (md = mh->md_next; md != mh; md = nd) {
535	nd = md->md_next;
536	if (md->md_dic == dm) {	/* already mounted */
537	  /* cancel the previous unmount */
538	  if (md->md_flags & MD_UPEND)
539	    md->md_flags &= ~MD_UPEND;
540	  count++;
541	};
542      };
543      if (!count) {
544	return _RkMountMD(cx, dm, qm, mode, firsttime);
545      }
546    }
547  }
548  return(-1);
549}
550/* RkUnmountDic: removes the specified dictionary from the mount list */
551int
552RkwUnmountDic(int cx_num, char *name)
553{
554  struct RkContext	*cx;
555  int			i;
556
557  if (!name)
558    return(-1);
559  cx = RkGetContext(cx_num);
560  if (cx) {
561    for (i = 0; i < 4; i++)  {
562      struct MD	*mh = cx->md[i];
563      struct MD	*md, *nd;
564
565      for (md = mh->md_next; md != mh; md = nd) {
566	struct DM	*dm = md->md_dic;
567	char *ename;
568
569	ename = md->md_freq ? md->md_freq->dm_nickname : dm->dm_nickname;
570	nd = md->md_next;
571	if (!STRCMP(ename, name)) {
572	  _RkUmountMD(cx, md);
573	}
574      }
575    }
576    return(0);
577  }
578  return(-1);
579}
580
581/* RkRemountDic: relocate the specified dictionary among the mount list */
582int
583RkwRemountDic(int cx_num, char *name, int mode)		/* mount mode */
584{
585  struct RkContext	*cx;
586  int			i, isfound = 0;
587  char *ename;
588
589  if (!name)
590    return(-1);
591  cx = RkGetContext(cx_num);
592  if (cx) {
593    for (i = 0; i < 4; i++) {
594      struct MD	*mh = cx->md[i];
595      struct MD	*md, *pd;
596
597      /* do in reverse order */
598      for (md = mh->md_prev; md != mh; md = pd) {
599	struct DM	*dm = md->md_dic;
600
601	ename = md->md_freq ? md->md_freq->dm_nickname : dm->dm_nickname;
602	pd = md->md_prev;
603	if (!STRCMP(ename, name)) {
604	  /* remove from mount list */
605	  md->md_prev->md_next = md->md_next;
606	  md->md_next->md_prev = md->md_prev;
607	  /* insert according to the mode */
608	  if (!mode) {    /* sentou he */
609	    md->md_next = mh->md_next;
610	    md->md_prev = mh;
611	    mh->md_next->md_prev = md;
612	    mh->md_next = md;
613	  } else {          /* saigo he */
614	    md->md_next = mh;
615	    md->md_prev = mh->md_prev;
616	    mh->md_prev->md_next = md;
617	    mh->md_prev = md;
618	  };
619	  isfound++;
620	};
621      };
622    };
623    if (isfound)
624      return(0);
625  };
626  return(-1);
627}
628
629/* RkGetDicList: collects the names of the mounted dictionaies */
630int
631RkwGetMountList(int cx_num, char *mdname, int maxmdname)
632{
633  struct RkContext	*cx;
634  struct MD		*mh, *md;
635  int			p, i, j;
636  int			count = -1;
637
638  cx  = RkGetContext(cx_num);
639  if (cx) {
640    i = count = 0;
641    for (p = 0; p < 4; p++) {
642      mh = cx->md[p];
643      for (md = mh->md_next; md != mh; md = md->md_next) {
644	struct DM	*dm = md->md_dic;
645	char *name;
646
647	if (md->md_flags & (MD_MPEND|MD_UPEND)) {
648	  continue;
649	};
650	name = md->md_freq ? md->md_freq->dm_nickname : dm->dm_nickname;
651	j = i + strlen(name) + 1;
652	if (j + 1 < maxmdname) {
653	  if (mdname) {
654	    (void)strcpy(mdname + i, name);
655	  }
656	  i = j;
657	  count++;
658	};
659      };
660    };
661    if (i + 1 < maxmdname && mdname)
662      mdname[i++] = (char)0;
663  };
664  return(count);
665}
666
667/* RkGetDicList: collects the names of dictionary */
668
669struct dics {
670  char *nickname, *dicname;
671  int dictype;
672};
673
674
675static int
676diccmp(const struct dics *a, const struct dics *b)
677{
678  int res;
679
680  res = strcmp(a->nickname, b->nickname);
681  if (res == 0) {
682    res = strcmp(a->dicname, b->dicname);
683    if (res == 0) {
684      if (a->dictype == b->dictype) {
685	res = 0;
686      }
687      else if (a->dictype == DF_FREQDIC) {
688	res = -1;
689      }
690      else if (b->dictype == DF_FREQDIC) {
691	res = 1;
692      }
693      else if (a->dictype == DF_PERMDIC) {
694	res = -1;
695      }
696      else if (b->dictype == DF_PERMDIC) {
697	res = 1;
698      }else{
699	res = 0;
700      }
701    }
702  }
703  return res;
704}
705
706int
707RkwGetDicList(int cx_num, char *mdname, int maxmdname)
708{
709  struct RkContext	*cx;
710  struct DD   		**ddp, *dd;
711  struct DF   		*df, *fh;
712  struct DM  		*dm, *mh;
713  int			i, j, k, n;
714  int			count = -1;
715  struct dics *diclist;
716
717  /* ¤Þ¤º¿ô¤ò¿ô¤¨¤ë */
718  if ((cx  = RkGetContext(cx_num)) && (ddp = cx->ddpath)) {
719    count = 0;
720    for (i = 0; (dd = ddp[i]) != (struct DD *)0 ; i++) {
721      fh = &dd->dd_files;
722      for (df = fh->df_next; df != fh; df = df->df_next) {
723	mh = &df->df_members;
724	for (dm = mh->dm_next; dm != mh; dm = dm->dm_next) {
725	  count++;
726	}
727      }
728    }
729    /* ¼­½ñ¥ê¥¹¥È¤ÎÇÛÎó¤ò (char *)malloc ¤¹¤ë */
730    diclist = (struct dics *)malloc(count * sizeof(struct dics));
731    if (diclist) {
732      struct dics *dicp = diclist, *prevdicp = (struct dics *)0;
733
734      for (i = 0 ; (dd = ddp[i]) != (struct DD *)0 ; i++) {
735	fh = &dd->dd_files;
736	for (df = fh->df_next; df != fh; df = df->df_next) {
737	  mh = &df->df_members;
738	  for (dm = mh->dm_next; dm != mh; dm = dm->dm_next) {
739	    dicp->nickname = dm->dm_nickname;
740	    dicp->dicname = dm->dm_dicname;
741	    dicp->dictype = df->df_type;
742	    dicp++;
743	  }
744	}
745      }
746      qsort(diclist, count, sizeof(struct dics),
747	    (int (*)(const void *, const void *))diccmp);
748
749      n = count;
750      for (i = j = 0, dicp = diclist ; i < n ; i++, dicp++) {
751	if (prevdicp && !strcmp(prevdicp->nickname, dicp->nickname)) {
752	  /* prev ¤Èº£¤Î¼­½ñ¤È¤Ç nickname ¤¬°ìÃפ·¤Æ¤¤¤ë¾ì¹ç */
753	  count--;
754	}
755	else {
756	  k = j + strlen(dicp->nickname) + 1;
757	  if (k + 1 < maxmdname) {
758	    if (mdname) {
759	      (void)strcpy(mdname + j, dicp->nickname);
760	      j = k;
761	    }
762	  }
763	  prevdicp = dicp;
764	}
765      }
766      if (j + 1 < maxmdname && mdname) {
767	mdname[j++] = 0;
768      }
769      free(diclist);
770    }
771    else {
772      count = -1; /* ¤ä¤Ã¤Ñ¤êÀµ³Î¤Ê¿ô¤¬Ê¬¤«¤é¤Ê¤«¤Ã¤¿ */
773    }
774  }
775  return(count);
776}
777
778/* RkGetDirList: collects the names of directories */
779int
780RkwGetDirList(int cx_num, char *ddname, int maxddname)
781{
782  struct RkContext	*cx;
783  struct DD   		**ddp, *dd;
784  int			p, i, j;
785  int			count = -1;
786
787  if ((cx  = RkGetContext(cx_num)) && (ddp = cx->ddpath)) {
788    i = count = 0;
789    for (p = 0; (dd = ddp[p]) != (struct DD *)0 ; p++) {
790      j = i + strlen(dd->dd_name) + 1;
791      if (j + 1 < maxddname) {
792	if (ddname)
793	  (void)strcpy(ddname + i, dd->dd_name);
794	i = j;
795	count++;
796      };
797    };
798    if (i + 1 < maxddname && ddname)
799      ddname[i++] = (char)0;
800  };
801  return(count);
802}
803
804/* RkDefineDic
805 *	mount the dictionary onto the specified context.
806 */
807int
808RkwDefineDic(int cx_num, char *name, WCHAR_T *word)
809{
810  struct RkContext	*cx;
811  int			i;
812
813  if ((cx = RkGetContext(cx_num)) && word && name) {
814    char        *prevname = (char *)0;
815
816    if (cx->dmprev)
817      prevname = cx->dmprev->dm_nickname;
818    if (cx->qmprev)
819      prevname = cx->qmprev->dm_nickname;
820
821    if (prevname && !STRCMP(prevname, name))
822      return(DST_CTL(cx->dmprev, cx->qmprev, DST_DoDefine, word,
823		     cx->gram->gramdic));
824    else {
825      for (i = 0; i < 4; i++)  {
826	struct MD	*mh = cx->md[i];
827	struct MD	*md, *nd;
828
829	for (md = mh->md_next; md != mh; md = nd) {
830	  struct DM	*dm = md->md_dic;
831	  struct DM	*qm = md->md_freq;
832	  char          *dname = (char *)0;
833
834	  if (dm)
835	    dname = dm->dm_nickname;
836	  if (qm)
837	    dname = qm->dm_nickname;
838
839	  if (dname) {
840	    if (!STRCMP(dname, name)) {
841	      cx->dmprev = dm;
842	      cx->qmprev = qm;
843	      return(DST_CTL(dm, qm, DST_DoDefine, word, cx->gram->gramdic));
844	    }
845	  }
846	  nd = md->md_next;
847	}
848      }
849    }
850  }
851  return(-1);
852}
853
854
855/* RkDeleteDic
856 *	mount the dictionary onto the specified context.
857 */
858int
859RkwDeleteDic(int cx_num, char *name, WCHAR_T *word)
860{
861  struct RkContext	*cx;
862  int			i;
863
864  if ((cx = RkGetContext(cx_num)) && name) {
865    char        *prevname = (char *)0;
866
867    if (cx->dmprev)
868      prevname = cx->dmprev->dm_nickname;
869    if (cx->qmprev)
870      prevname = cx->qmprev->dm_nickname;
871
872    if (prevname && !STRCMP(prevname, name))
873      return(DST_CTL(cx->dmprev, cx->qmprev, DST_DoDelete, word,
874		     cx->gram->gramdic));
875    else {
876      for (i = 0; i < 4; i++)  {
877	struct MD	*mh = cx->md[i];
878	struct MD	*md, *nd;
879
880	for (md = mh->md_next; md != mh; md = nd) {
881	  struct DM	*dm = md->md_dic;
882	  struct DM	*qm = md->md_freq;
883	  char          *dname = (char *)0;
884
885	  if (dm)
886	    dname = dm->dm_nickname;
887	  if (qm)
888	    dname = qm->dm_nickname;
889
890	  if (dname) {
891	    if (!STRCMP(dname, name)) {
892	      cx->dmprev = dm;
893	      cx->qmprev = qm;
894	      return(DST_CTL(dm, qm, DST_DoDelete, word, cx->gram->gramdic));
895	    }
896	  }
897	  nd = md->md_next;
898	}
899      }
900    }
901  }
902  return(-1);
903}
904
905#ifdef STANDALONE /* The following code is as simulating the code in
906 lib/RKC API.  In case STANDALONE, it becomes possible for libRK to be
907 linked with libcanna directly. */
908
909
910int
911RkwSetAppName(int Context, char *name)
912{
913  return 0;
914}
915
916
917char *
918RkwGetServerName(void)
919{
920  return (char *)NULL;
921}
922
923
924int
925RkwGetProtocolVersion(int *majorp, int *minorp)
926{
927    *majorp = CANNA_MAJOR_MINOR / 1000;
928    *minorp = CANNA_MAJOR_MINOR % 1000;
929    return 0;
930}
931
932int RkwGetServerVersion(int *, int *);
933
934int
935RkwGetServerVersion(int *majorp, int *minorp)
936{
937  *majorp = CANNA_MAJOR_MINOR / 1000;
938  *minorp = CANNA_MAJOR_MINOR % 1000;
939  return 0;
940}
941
942int
943RkwSetUserInfo(char *user, char *group, char *topdir)
944{
945  return 1;
946}
947
948#endif /* STANDALONE */
949
950