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