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__)
29	static char rcsid[]="$Id: dd.c 10525 2004-12-23 21:23:50Z korli $";
30#endif
31/*LINTLIBRARY*/
32
33#include	"RKintern.h"
34
35#include <string.h>
36#include <unistd.h>
37#include <ctype.h>
38
39#include <stdio.h>
40#include <time.h>
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <fcntl.h>
44
45#define cx_gwt		cx_extdata.ptr
46#define	STRCMP(d, s)	strcmp((char *)(d), (char *)(s))
47
48#define RK_READABLE 'r'
49#define RK_WRITABLE 'w'
50
51static void _RkFreeDM(struct DM *dm);
52static struct DM *_RkAllocDM(struct DF *df, unsigned char *dicname, unsigned char *nickname, int iclass);
53static struct DF *_RkCreateDF(struct DD *dd, unsigned char *lnk, int type);
54static void _RkFreeDF(struct DF *df);
55static struct DF *_RkAllocDF(struct DD *dd, unsigned char *lnk, int type);
56static int _RkParseDicsDir(char *line, char *lnk, char *member, char *nickname, int *dftype, int *dmclass, int *r_return, int *w_return);
57static void _RkFreeDD(struct DD *dd);
58
59/*
60* DM
61*/
62inline
63struct DM	*
64_RkCreateDM(struct DF *df, unsigned char *dicname, unsigned char *nickname, int iclass)
65{
66	struct DM	*dm;
67
68	dm = (struct DM *)calloc(1, sizeof(struct DM));
69	if (dm) {
70		dm->dm_next = dm->dm_prev = dm;
71		dm->dm_file = df;
72		dm->dm_dicname  = strdup((char *)dicname);
73		if (dm->dm_dicname) {
74			dm->dm_nickname = strdup((char *)nickname);
75			if (dm->dm_nickname) {
76				dm->dm_class = iclass;
77				dm->dm_flags = dm->dm_packbyte = dm->dm_rcount = 0;
78				dm->dm_gram = (struct RkGram *)0;
79				dm->dm_extdata.ptr = (pointer)0;
80				dm->dm_rut = (struct RUT *)0;
81				dm->dm_nv = (struct NV *)0;
82				return dm;
83			}
84			free(dm->dm_dicname);
85		}
86		free(dm);
87	}
88	return 0;
89}
90
91static
92void
93_RkFreeDM(struct DM *dm)
94{
95if (dm) {
96	dm->dm_next->dm_prev = dm->dm_prev;
97	dm->dm_prev->dm_next = dm->dm_next;
98	if (dm->dm_dicname)
99		free(dm->dm_dicname);
100	if (dm->dm_nickname)
101		free(dm->dm_nickname);
102	free(dm);
103};
104}
105
106inline
107struct DM *
108_RkAllocDM(struct DF *df, unsigned char *dicname, unsigned char *nickname, int iclass)
109{
110	struct DM	*m, *mh = &df->df_members;
111
112	for (m = mh->dm_next; m != mh; m = m->dm_next) {
113	if (!STRCMP(m->dm_dicname,  dicname)) {
114		return m;
115	}
116	}
117	m = _RkCreateDM(df, dicname, nickname, iclass);
118	if (m) {
119		m->dm_next = mh;
120		m->dm_prev = mh->dm_prev;
121		mh->dm_prev = m;
122		m->dm_prev->dm_next = m;
123	}
124	return(m);
125}
126
127/*
128* DF
129*/
130inline
131struct DF *
132_RkCreateDF(struct DD *dd, unsigned char *lnk, int type)
133{
134	struct DF	*df;
135
136	df = (struct DF *)calloc(1, sizeof(struct DF));
137	if (df) {
138		struct DM	*dm = &df->df_members;
139
140		df->df_next = df->df_prev = df;
141		df->df_direct = dd;
142		dm->dm_next = dm->dm_prev = dm;
143
144		if (!(df->df_link = strdup((char *)lnk))) {
145			free(df);
146			return(0);
147		};
148		df->df_rcount = 0;
149		df->df_type  = type;
150		df->df_extdata.ptr = (pointer)0;
151	};
152	return(df);
153}
154
155static
156void
157_RkFreeDF(struct DF *df)
158{
159	struct DM	*m, *n;
160
161	if (df) {
162		struct DM	*mh = &df->df_members;
163
164		/* remove all members in this file */
165		for (m = mh->dm_next; m != mh; m = n) {
166			n = m->dm_next;
167			_RkFreeDM(m);
168		};
169		/* unlink from directory list */
170		df->df_next->df_prev = df->df_prev;
171		df->df_prev->df_next = df->df_next;
172		if (df->df_link)
173			free(df->df_link);
174		free(df);
175	};
176}
177
178static
179struct DF	*
180_RkAllocDF(struct DD *dd, unsigned char *lnk, int type)
181{
182	struct DF	*f;
183	struct DF	*fh = &dd->dd_files;
184
185	for (f = fh->df_next; f != fh; f = f->df_next) {
186	if (!STRCMP(f->df_link,  lnk)) {
187		return(f);
188	}
189	}
190	f = _RkCreateDF(dd, lnk, type);
191	if (f) {
192		f->df_next = fh;
193		f->df_prev = fh->df_prev;
194		fh->df_prev = f;
195		f->df_prev->df_next = f;
196	};
197	return(f);
198}
199
200int
201_RkRealizeDF(struct DF *df)
202{
203	struct DD	*dd = df->df_direct;
204	char		*pathname;
205#ifdef WIN
206	int oldmask;
207#else
208	unsigned long oldmask;
209#endif
210	int t;
211
212	_RkRealizeDD(dd);
213	/* create path filename */
214	pathname = _RkCreatePath(df->df_direct, df->df_link);
215	if (pathname) {
216		oldmask = umask(2);
217		/* create a file */
218#ifdef WIN
219{
220	HANDLE fd;
221	fd = CreateFile(pathname, GENERIC_WRITE,
222		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
223		CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
224	if (fd == INVALID_HANDLE_VALUE) {
225		t = -1;
226		}else{
227		CloseHandle(fd);
228		t = 0;
229	}
230}
231#else
232		t = close(creat(pathname, CREAT_MODE));
233#endif
234		free(pathname);
235		(void)umask(oldmask);
236		if (t >= 0) {
237			return 0;
238		}
239	}
240	return -1;
241}
242
243static int
244_RkParseDicsDir(char *line, char *lnk, char *member, char *nickname, int *dftype, int *dmclass, int *r_return, int *w_return) /* ¥¢¥¯¥»¥¹¸¢¤òÊÖ¤¹½ê */
245{
246	char	*s, *d, *t, par, ch;
247	int	count;
248
249	*dftype  = -1;
250	*dmclass = -1;
251	*r_return = *w_return = 0; /* ¸¢Íø̵¤· */
252	if (!isalpha(line[0]))
253		return -1;
254
255	/* parse line %s.s(%s.%s)   -%s--%c%c- */
256
257	for (s = line; *s && isspace(*s);) {
258		s++;
259	}
260	if (!*s)
261		return -1;
262
263	/* link name */
264	for (d = lnk, count = 0; *s && *s != '('; count++) {
265	if (count < RK_LINK_BMAX) {
266		*d++ = *s++;
267		} else {
268		return -1;
269	}
270	}
271	if (!count)
272		return -1;
273		if (count++ < RK_LINK_BMAX) {
274			*d = 0;
275		}
276	if (!*s++)
277		return -1;
278	if (count > RK_LINK_BMAX)
279		return -1;
280	if (!(t = (char *)strrchr(lnk, '.')))
281		return -1;
282	if (!STRCMP(t, ".d") || !STRCMP(t, ".cbd"))
283		*dftype = DF_PERMDIC;
284	else if (!STRCMP(t, ".t") || !STRCMP(t, ".ctd"))
285		*dftype = DF_TEMPDIC;
286	else if (!STRCMP(t, ".fq") || !STRCMP(t, ".cld"))
287		*dftype = DF_FREQDIC;
288	else if (!STRCMP(t, ".ruc"))
289		*dftype = DF_RUCDIC;
290	else
291		return -1;
292	/* member name */
293	for (d = member, count = 0; *s && *s != ')'; count++) {
294	if (count < RK_MEMBER_BMAX) {
295		*d++ = *s++;
296		} else {
297		return -1;
298	}
299	}
300	if (!count)
301		return -1;
302	if (count++ < RK_MEMBER_BMAX)
303		*d = 0;
304	if (!*s++)
305		return -1;
306	if (count > RK_MEMBER_BMAX)
307		return -1;
308	if (!(t = (char *)strrchr(member, '.')))
309		return -1;
310	if (!STRCMP(t, ".mwd"))
311		*dmclass = ND_MWD;
312	else if (!STRCMP(t, ".swd"))
313		*dmclass = ND_SWD;
314	else if (!STRCMP(t, ".pre"))
315		*dmclass = ND_PRE;
316	else if (!STRCMP(t, ".suc"))
317		*dmclass = ND_SUC;
318	else
319		return -1;
320	/* nickname */
321	for (; *s && isspace(*s);) {
322		s++;
323	}
324	if (!(par = *s++))
325		return -1;
326
327	for (d = nickname, count = 0; *s && *s != par; count++) {
328	if (count < RK_NICK_BMAX) {
329		*d++ = *s++;
330		} else {
331		return -1;
332	}
333	}
334	if (!count)
335		return -1;
336	if (count++ < RK_NICK_BMAX)
337		*d = 0;
338	if (!*s++)
339		return -1;
340	if (count > RK_NICK_BMAX)
341		return -1;
342
343	*w_return = 1; /* ²¼°Ì¸ß´¹¤Î¤¿¤á¤³¤³¤Þ¤Ç¤·¤«¤Ê¤¤¾ì¹ç¤Ï writable ¤Ë¤¹¤ë */
344
345	while ((ch = *s) && ch != par) {
346		s++;/* 1 ¥Õ¥£¡¼¥ë¥ÉÆɤßÈô¤Ð¤· */
347	}
348
349	if (*s++ /* == par ¤Ë¤Ê¤Ã¤Æ¤¤¤ë¤ï¤± */) {
350		/* ¥¢¥¯¥»¥¹¸¢´ØÏ¢ */
351		*w_return = 0;
352	while ((ch = *s) && ch != par) {
353	if (ch == RK_READABLE) {
354		*r_return = 1;
355	}
356else if (ch == RK_WRITABLE) {
357	*w_return = 1;
358	} else {
359	return -1;
360}
361		s++;
362	}
363	}
364
365	return 0;
366}
367
368/*
369* DD - dictonary directory record
370*/
371inline
372struct DD	*
373_RkCreateDD(unsigned char *path, unsigned char *name)
374{
375	struct DD	*dd;
376
377	dd = (struct DD *)calloc(1, sizeof(struct DD));
378	if (dd) {
379		dd->dd_next = dd->dd_prev = dd;
380		dd->dd_path = strdup((char *)path);
381		if (dd->dd_path) {
382			dd->dd_name = strdup((char *)name);
383			if (dd->dd_name) {
384				dd->dd_rcount = 0;
385				dd->dd_files.df_next = dd->dd_files.df_prev = &dd->dd_files;
386				dd->dd_flags = 0;
387				dd->dd_text.ddt_next = dd->dd_text.ddt_prev = &dd->dd_text;
388				return dd;
389			}
390			free(dd->dd_path);
391		}
392		free(dd);
393	}
394	return (struct DD *)0;
395}
396
397static
398void
399_RkFreeDD(struct DD *dd)
400{
401	struct DF	*f, *g;
402	struct DF	*fh = &dd->dd_files;
403	struct DDT	*ddLines;
404	struct DDT	*p, *q;
405
406	if (dd) {
407	for (f = fh->df_next; f != fh; f = g) {
408		g = f->df_next;
409		_RkFreeDF(f);
410	};
411		dd->dd_next->dd_prev = dd->dd_prev;
412		dd->dd_prev->dd_next = dd->dd_next;
413		if (dd->dd_path)
414			free(dd->dd_path);
415		if (dd->dd_name)
416			free(dd->dd_name);
417
418		ddLines = &dd->dd_text;
419		for (p = ddLines->ddt_next; p != ddLines; p = q) {
420			q = p->ddt_next;
421			p->ddt_next->ddt_prev = p->ddt_prev;
422			p->ddt_prev->ddt_next = p->ddt_next;
423			if (p->ddt_spec)
424				free(p->ddt_spec);
425			free(p);
426		};
427		free(dd);
428	};
429}
430
431inline struct DD	*
432_RkLookupDD(struct DD *dd, unsigned char *name)
433{
434	struct DD		*d;
435
436	for (d = dd->dd_next; d != dd; d = d->dd_next)
437		if (!STRCMP(d->dd_name,  name))
438			return d;
439	return (struct DD *)0;
440}
441
442/* _RkReadDD
443*	read a DD directory using dics.dir file.
444*/
445inline struct DD	*
446_RkReadDD(char *name)
447{
448	char		*dics_dir = "/dics.dir";
449	struct DD *dd = (struct DD *)0;
450	struct DF		*df;
451	struct DM		*dm;
452	struct DDT		*ddLines;
453	struct DDT		*ddt;
454	struct RkParam	*sx = RkGetSystem();
455	int r, w;
456	int fdes;
457	FILE		*fp;
458
459#ifndef USE_MALLOC_FOR_BIG_ARRAY
460	char		direct[RK_PATH_BMAX];
461	char		file[RK_PATH_BMAX];
462	char		path[RK_PATH_BMAX];
463	unsigned char	line[RK_LINE_BMAX];
464	unsigned char	lnk[RK_LINK_BMAX+1];
465	unsigned char	member[RK_MEMBER_BMAX+1];
466	unsigned char	nickname[RK_NICK_BMAX+1];
467#else
468	char *direct, *file, *path;
469	unsigned char *line, *lnk, *member, *nickname;
470	direct = (char *)malloc(RK_PATH_BMAX);
471	file = (char *)malloc(RK_PATH_BMAX);
472	path = (char *)malloc(RK_PATH_BMAX);
473	line = (unsigned char *)malloc(RK_LINE_BMAX);
474	lnk = (unsigned char *)malloc(RK_LINK_BMAX + 1);
475	member = (unsigned char *)malloc(RK_MEMBER_BMAX + 1);
476	nickname = (unsigned char *)malloc(RK_NICK_BMAX + 1);
477	if (!direct || !file || !path || !line || !lnk || !member || !nickname) {
478		if (direct) free(direct);
479		if (file) free(file);
480		if (path) free(path);
481		if (line) free(line);
482		if (lnk) free(lnk);
483		if (member) free(member);
484		if (nickname) free(nickname);
485		return dd;
486	}
487#endif
488
489	/* create dd even if there is no directory or dics.dir file */
490	sprintf(path, "%s/%s", sx->ddhome, name);
491	dd = _RkCreateDD((unsigned char *)path, (unsigned char *)name);
492	if (!dd) {
493		goto return_dd;
494	}
495	/* jisho table ga aruka ? */
496	if (strlen(path) + strlen(dics_dir) + 1 >= RK_PATH_BMAX) {
497		dd = (struct DD *)0;
498		goto return_dd;
499	}
500	sprintf(direct, "%s%s", path, dics_dir);
501
502	/* check for accessing right */
503	if ((fdes = open(direct, 0)) < 0) { /* no file? */
504		dd->dd_flags |= DD_WRITEOK;
505	}
506else {
507	struct stat buf;
508
509	if (fstat(fdes, &buf) == 0) {
510	if (buf.st_mode & 004) { /* if readable for others */
511		dd->dd_flags |= DD_READOK;
512	}
513	}
514	close(fdes);
515	if (!close(open(direct, 2))) {
516		dd->dd_flags |= DD_WRITEOK;
517	}
518}
519
520	fp = fopen(direct, "r");
521if (!fp) {
522	goto return_dd;
523}
524	ddLines = &dd->dd_text;
525	/* read dics_dir lines */
526	while (fgets((char *)line, RK_LINE_BMAX, fp))
527{
528	int		dftype, dmclass;
529
530	ddt = (struct DDT *)malloc(sizeof(struct DDT));
531	if (!ddt)
532		continue;
533
534	ddt->ddt_spec = (char *)malloc(strlen((char *)line) + 2); /* 2 for \n\0 */
535	if (!ddt->ddt_spec)
536	{
537		free(ddt);
538		continue;
539	};
540{
541	int len = strlen((char *)line);
542	if (line[len - 1] == '\n') {
543		line[len - 1] = '\0';
544	}
545}
546	strcpy(ddt->ddt_spec, (char *)line);
547	ddt->ddt_next = ddLines;
548	ddt->ddt_prev = ddLines->ddt_prev;
549	ddt->ddt_status = 1;
550	ddLines->ddt_prev = ddt;
551	ddt->ddt_prev->ddt_next = ddt;
552
553	if (_RkParseDicsDir(ddt->ddt_spec, (char *)lnk, (char *)member,
554	(char *)nickname, &dftype, &dmclass, &r, &w) < 0) {
555		continue;
556	}
557
558	if (strlen((char *)path) + strlen((char *)lnk) + 1 >= RK_PATH_BMAX)
559		continue;
560	sprintf(file, "%s/%s", path, (char *)lnk);
561	if (close(open(file, 0)) < 0)
562		continue;
563	df = _RkAllocDF(dd, lnk, dftype);
564	if (df) {
565		dm = _RkAllocDM(df, member, nickname, dmclass);
566		if (dm) {
567			dm->dm_line = ddt;
568			if (r) {
569				dm->dm_flags |= DM_READOK;
570			}
571			if (w) {
572				dm->dm_flags |= DM_WRITEOK;
573			}
574			ddt->ddt_status = 0;
575		};
576	};
577};
578	(void)fclose(fp);
579
580return_dd:
581#ifdef USE_MALLOC_FOR_BIG_ARRAY
582	free(direct);
583	free(file);
584	free(path);
585	free(line);
586	free(lnk);
587	free(member);
588	free(nickname);
589#endif
590	return dd;
591}
592
593inline
594struct DD	*
595_RkOpenDD(char *name)
596{
597	struct RkParam	*sx = RkGetSystem();
598	struct DD		*dd;
599	struct DD		*knownDD = &sx->dd;
600
601	dd = _RkLookupDD(knownDD, (unsigned char *)name);
602	if (dd)
603		return dd;
604	dd = _RkReadDD(name);
605	/* link to the known list */
606	if (dd) {
607		dd->dd_next = knownDD;
608		dd->dd_prev = knownDD->dd_prev;
609		knownDD->dd_prev = dd;
610		dd->dd_prev->dd_next = dd;
611	};
612	return dd;
613}
614
615char *
616_RkCreatePath(struct DD *dd, char *name)
617{
618	unsigned 	sz;
619	char        *ddname;
620
621	if (!dd || !dd->dd_path || !name)
622		return (char *)0;
623	sz = strlen(dd->dd_path) + strlen(name) + 2;
624	ddname = (char *)malloc(sz);
625	if (ddname)  {
626		sprintf(ddname, "%s/%s", dd->dd_path, name);
627	};
628	return ddname;
629}
630
631char *
632_RkCreateUniquePath(struct DD *dd, char *proto)
633{
634	static char	newLinkName[RK_LINK_BMAX];
635	unsigned 	i;
636
637	/* now checking ... */
638	if (!dd || !dd->dd_path || !proto)
639		return (char *)0;
640	/* create directory */
641	if (_RkRealizeDD(dd) < 0)
642		return (char *)0;
643	/* try at most 100 times */
644	for (i = 1; i < 100; i++) {
645		int		count;
646		struct DF		*f;
647		struct DF		*fh = &dd->dd_files;
648		unsigned long       oldmask;
649		char		*filename;
650
651		count = 0;
652		sprintf(newLinkName, proto, i);
653		for (f = fh->df_next; f != fh; f = f->df_next)
654			if (!STRCMP(f->df_link,  newLinkName))
655				count++;
656		if (count)
657			continue;
658		filename = _RkCreatePath(dd, newLinkName);
659		if (filename) {
660			oldmask = umask(2);
661
662			if (close(creat(filename, CREAT_MODE)) < 0)
663				count++;
664			free(filename);
665			(void)umask(oldmask);
666			if (!count)
667				return newLinkName;
668		};
669	};
670	return (char *)0;
671}
672
673char	*
674_RkMakePath(struct DF *df)
675{
676	if (df)
677		return _RkCreatePath(df->df_direct, df->df_link);
678	else
679		return (char *)0;
680}
681
682int
683_RkRealizeDD(struct DD	*dd)
684{
685	struct DDT		*ddLines;
686	struct DDT		*ddt;
687	int			n;
688	int ret = -1;
689	int tmpres;
690	int			fdes;
691	long		tloc;
692
693	char *whattime, *header, *dicsdir, *backup;
694	whattime = (char *)malloc(RK_LINE_BMAX);
695	header = (char *)malloc(RK_LINE_BMAX);
696	dicsdir = (char *)malloc(RK_PATH_BMAX);
697	backup = (char *)malloc(RK_PATH_BMAX);
698	if (!whattime || !header || !dicsdir || !backup) {
699		if (whattime) free(whattime);
700		if (header) free(header);
701		if (dicsdir) free(dicsdir);
702		if (backup) free(backup);
703		return ret;
704	}
705	/* create directory if needed */
706	if (close(open(dd->dd_path, 0, 0664)) < 0) {
707	if (mkdir(dd->dd_path, MKDIR_MODE) < 0) {
708		goto return_ret;
709	}
710		/* change owner
711		if (pw)
712			chown(dd->dd_path, getuid(), pw->pw_gid);
713		*/
714	}
715
716	/* dics.dir */
717	sprintf(dicsdir, "%s/dics.dir", dd->dd_path);
718	backup[0] = 0;
719	tmpres = close(open(dicsdir, 0));
720	if (tmpres >= 0) {
721		sprintf(backup, "%s/#dics.dir", dd->dd_path);
722		if (rename(dicsdir, backup)) {
723			goto return_ret;
724		}
725	};
726	/* create dics.dir */
727
728	if ((fdes = creat(dicsdir, CREAT_MODE)) < 0)
729	{
730	if (backup[0]) {
731		rename(backup, dicsdir);
732	}
733		goto return_ret;
734	};
735	/* header */
736	tloc = time(0);
737	strcpy(whattime, ctime(&tloc));
738	whattime[strlen(whattime)-1] = 0;
739	n = sprintf(header, "#CANNA dics.dir [%s] %s\n", whattime, dd->dd_name);
740	//  n = strlen(header);
741	tmpres = write(fdes, header, n);
742	if (tmpres != n) {
743	if (backup[0]) {
744		rename(backup, dicsdir);
745	}
746		else
747			unlink(dicsdir);
748		close(fdes);
749		goto return_ret;
750	};
751	/* fill up bodies */
752	ddLines = &dd->dd_text;
753	for (ddt = ddLines->ddt_next; ddt != ddLines; ddt = ddt->ddt_next)
754		if (strncmp(ddt->ddt_spec, "#CANNA ",  7)) {
755			n = strlen(ddt->ddt_spec);
756			ddt->ddt_spec[n] = '\n';
757			tmpres = write(fdes, ddt->ddt_spec, n + 1);
758			if (tmpres > 0) {
759				tmpres--; /* for \n */
760			}
761
762
763			ddt->ddt_spec[n] = '\0';
764
765			if (tmpres != n) {
766			if (backup[0]) {
767				rename(backup, dicsdir);
768			}
769				else
770					unlink(dicsdir);
771				close(fdes);
772				goto return_ret;
773			};
774		};
775	close(fdes);
776	/* change owner
777	if (pw)
778		chown(dicsdir, getuid(), pw->pw_gid);
779	*/
780	ret = 0;
781
782return_ret:
783	free(whattime);
784	free(header);
785	free(dicsdir);
786	free(backup);
787	return ret;
788}
789
790/*
791* DDP
792*/
793int
794_RkIsInDDP(struct DD	**ddp, struct DD	*dd)
795{
796	while (*ddp)
797		if (*ddp++ == dd)
798			return 1;
799	return 0;
800}
801
802static
803int
804_RkCountDDP(
805	struct DD	**ddp)
806{
807	int	count = 0;
808
809	if (ddp)
810		while (ddp[count])  count++;
811	return count;
812}
813
814struct DD	**
815_RkCopyDDP(
816	struct DD	**ddp)
817{
818	struct DD	**newc = (struct DD **)0;
819	int		i;
820	struct DD	*dd;
821
822	if (ddp) {
823		int	count = _RkCountDDP(ddp);
824
825		newc = (struct DD **)calloc(count + 1, (unsigned)sizeof(struct DD *));
826		if (newc)
827			for (i = 0; (dd = newc[i] = ddp[i]) != (struct DD *)0 ; i++)
828				dd->dd_rcount++;
829	};
830	return newc;
831}
832
833inline
834struct DD	**
835_RkAppendDDP(
836	struct DD	**ddp,
837	struct DD	*dd)
838{
839	struct DD	**newc;
840	int		i;
841	int		count = _RkCountDDP(ddp);
842
843	newc = (struct DD **)calloc(count + 2, (unsigned)sizeof(struct DD *));
844	if (newc) {
845	if (ddp) {
846		for (i = 0; i < count; i++) newc[i] = ddp[i];
847		free(ddp);
848	};
849		newc[count++] = dd;
850		newc[count] = (struct DD *)0;
851		dd->dd_rcount++;
852	} else
853	newc = ddp;
854	return newc;
855}
856
857struct DD	**
858_RkCreateDDP(
859	char		*ddpath)
860{
861	char		*d, *s;
862	struct DD 	*dd;
863	struct DD	**ddp  = (struct DD **)0;
864#ifndef USE_MALLOC_FOR_BIG_ARRAY
865	char dir[RK_PATH_BMAX + 1];
866#else
867	char *dir = (char *)malloc(RK_PATH_BMAX + 1);
868	if (!dir) {
869		return ddp;
870	}
871#endif
872
873	for (s = ddpath; *s; ) {
874		int		count;
875
876		for (;*s && isspace(*s);) {
877			s++;
878		}
879		if (!*s)
880			break;
881		for (d = dir, count = 0; *s; count++)
882			if (*s == ':') {
883				s++;
884				break;
885				} else {
886				if (count < RK_PATH_BMAX)
887					*d++ = *s;
888				s++;
889			};
890		*d = 0;
891		dd = _RkOpenDD(dir);
892		if (dd)
893			ddp = _RkAppendDDP(ddp, dd);
894	};
895#ifdef USE_MALLOC_FOR_BIG_ARRAY
896	free(dir);
897#endif
898	return ddp;
899}
900
901void
902_RkFreeDDP(
903	struct DD	**ddp)
904{
905	struct DD	*dd;
906	int		i;
907
908	if (ddp) {
909		for (i = 0; (dd = ddp[i]) != (struct DD *)0 ; i++)
910			if (--dd->dd_rcount == 0) {
911				_RkFreeDD(dd);
912			};
913		free(ddp);
914	};
915}
916
917/* _RkSearchDDP/Q
918*	search dictionary file by nickname
919*/
920struct DM	*
921_RkSearchDDP(
922	struct DD	**ddp,
923	char	*name)
924{
925	struct DD	*dd;
926	struct DF	*f, *fh;
927	struct DM	*m, *mh;
928	int		i;
929
930	if (ddp) {
931	for (i = 0; (dd = ddp[i]) != (struct DD *)0 ; i++) {
932		fh = &dd->dd_files;
933		for (f = fh->df_next; f && (f != fh); f = f->df_next) {
934		if (f->df_type == DF_FREQDIC) {
935			/* Ʊ¤¸¥Ç¥£¥ì¥¯¥È¥ê³¬ÁØ¤Ç¤Ï .fq ¤«¤éõ¤¹ */
936			mh = &f->df_members;
937			for (m = mh->dm_next; m != mh; m = m->dm_next) {
938			if (!STRCMP(m->dm_nickname, name)) {
939				return m;
940			}
941			}
942		}
943		}
944		fh = &dd->dd_files;
945		for (f = fh->df_next; f && (f != fh); f = f->df_next) {
946		if (f->df_type != DF_RUCDIC && f->df_type != DF_FREQDIC) {
947			mh = &f->df_members;
948			for (m = mh->dm_next ; m != mh; m = m->dm_next) {
949			if (!STRCMP(m->dm_nickname, name)) {
950				return m;
951			}
952			}
953		}
954		}
955	}
956	}
957	return (struct DM *)0;
958}
959
960/* _RkSearchDDQ
961¤¢¤ë¥¿¥¤¥×¤Î¼­½ñ¤À¤±Ãµ¤·¤ÆÊÖ¤¹
962*/
963
964struct DM	*
965_RkSearchDDQ(
966	struct DD	**ddp,
967	char	*name,
968	int	type)
969{
970	struct DD	*dd;
971	struct DF	*f, *fh;
972	struct DM	*m, *mh;
973	int		i;
974
975	if (ddp) {
976	for (i = 0; (dd = ddp[i]) != (struct DD *)0 ; i++) {
977		fh = &dd->dd_files;
978		for (f = fh->df_next; f && (f != fh); f = f->df_next)
979			if (f->df_type == (unsigned)type) {
980				mh = &f->df_members;
981				for (m = mh->dm_next; m != mh; m = m->dm_next) {
982					if (!STRCMP(m->dm_nickname, name))
983						return(m);
984				};
985			};
986	};
987	};
988	return((struct DM *)0);
989}
990
991/*
992_RkSearchUDDP()
993	ºÇ½é¤Ë¸«ÉÕ¤«¤ë¤Î¤¬¥·¥¹¥Æ¥à¼­½ñ¤Ë¤¢¤ë¤ä¤Ä¤«¤É¤¦¤«¤òȽÃǤ·¤Ê¤¬¤éÊÖ¤¹
994*/
995
996struct DM	*
997_RkSearchUDDP(
998	struct DD		**ddp,
999	unsigned char	*name)
1000{
1001	struct DM	*dm = _RkSearchDDP(ddp, (char *)name);
1002
1003	if (dm && STRCMP(dm->dm_file->df_direct->dd_name, SYSTEM_DDHOME_NAME)) {
1004		return dm;
1005	}
1006	return((struct DM *)0);
1007}
1008
1009/* ¼­½ñ¥á¥ó¥Ð̾¤Ç¼­½ñ¤òõ¤¹
1010
1011³Ø½¬¥Õ¥¡¥¤¥ë¤Ï½ü³°¤·¤Æõ¤¹
1012*/
1013
1014struct DM	*
1015_RkSearchDDMEM(
1016	struct DD	**ddp,
1017	char	*name)
1018{
1019	struct DD	*dd;
1020	struct DF	*f, *fh;
1021	struct DM	*m, *mh;
1022	int		i;
1023
1024	if (ddp) {
1025	for (i = 0; (dd = ddp[i]) != (struct DD *)0 ; i++) {
1026		fh = &dd->dd_files;
1027		for (f = fh->df_next; f && (f != fh); f = f->df_next) {
1028		if (f->df_type != DF_FREQDIC && f->df_type != DF_RUCDIC) {
1029			mh = &f->df_members;
1030			for (m = mh->dm_next; m != mh; m = m->dm_next) {
1031			if (!STRCMP(m->dm_dicname, name)) {
1032				return m;
1033			}
1034			}
1035		}
1036		}
1037	}
1038	}
1039	return (struct DM *)0;
1040}
1041
1042/*
1043_RkSearchDicWithFreq -- ¼­½ñ(³Ø½¬¼­½ñ¤ò´Þ¤à)¤òõ¤·ÊÖ¤¹¡£
1044
1045ddpath ¤ÎÀèƬ¤«¤é½ç¤Ë³Ø½¬¥Õ¥¡¥¤¥ë¤¢¤ë¤¤¤Ï¼­½ñ¤ò¤µ¤¬¤·¡¢¤ß¤Ä¤«¤Ã¤¿¤Î
1046¤òÊÖ¤¹¡£³Ø½¬¥Õ¥¡¥¤¥ë¤¬¤ß¤Ä¤«¤Ã¤¿¾ì¹ç¤Ë¤Ï³Ø½¬¥Õ¥¡¥¤¥ë¤Î¸µ¼­½ñ¤òõ¤·¤Æ
1047¤½¤ì¤ò dm ¤ËÊÖ¤·¡¢³Ø½¬¥Õ¥¡¥¤¥ë¼«¿È¤Ï qmp ¤ÎÀè¤Ë³ÊǼ¤·¤ÆÊÖ¤¹¡£
1048
1049*/
1050
1051struct DM *
1052_RkSearchDicWithFreq(
1053	struct DD **ddpath,
1054	char *name,
1055	struct DM **qmp)
1056{
1057	struct DD *udd[2];
1058	struct DM *dm, *qm;
1059
1060	udd[1] = (struct DD *)0;
1061
1062	*qmp = (struct DM *)0;
1063	while (*ddpath) {
1064		udd[0] = *ddpath;
1065		qm = _RkSearchDDQ(udd, name, DF_FREQDIC);
1066		if (qm) {
1067			*qmp = qm;
1068			return _RkSearchDDMEM(ddpath, qm->dm_dicname);
1069		}
1070		dm = _RkSearchDDP(udd, name);
1071		if (dm) {
1072			return dm;
1073		}
1074		ddpath++;
1075	}
1076	return (struct DM *)0;
1077}
1078
1079/* DMcheck
1080
1081DMcreate ¤Ç name ¤òÂ裳°ú¿ô¤ËÉÕ¤±¤Æ¤¤¤¿»þ¤Î¥Á¥§¥Ã¥¯¤òÆÈΩ¤µ¤»¤¿¡£
1082
1083return value;
10841: OK
10850: bad
1086*/
1087
1088int
1089DMcheck(char *spec, char *name)
1090{
1091	int dftype, dmclass;
1092	int r, w, ret;
1093#ifndef USE_MALLOC_FOR_BIG_ARRAY
1094	char lnk[RK_LINK_BMAX+1];
1095	char member[RK_MEMBER_BMAX+1];
1096	char nickname[RK_NICK_BMAX+1];
1097#else
1098	char *lnk, *member, *nickname;
1099	lnk = (char *)malloc(RK_LINK_BMAX + 1);
1100	member = (char *)malloc(RK_MEMBER_BMAX + 1);
1101	nickname = (char *)malloc(RK_NICK_BMAX + 1);
1102	if (!lnk || !member || !nickname) {
1103		if (lnk) free(lnk);
1104		if (member) free(member);
1105		if (nickname) free(nickname);
1106		return 0;
1107	}
1108#endif
1109
1110	if (_RkParseDicsDir(spec, lnk, member, nickname, &dftype, &dmclass,
1111		&r, &w) < 0 ||
1112	STRCMP(nickname, name)) {
1113		ret = 0;
1114	}
1115else {
1116	ret = 1;
1117}
1118#ifdef USE_MALLOC_FOR_BIG_ARRAY
1119	free(lnk);
1120	free(member);
1121	free(nickname);
1122#endif
1123	return ret;
1124}
1125
1126/* DMcreate
1127*	create a newc member under dd
1128*	DMcreate does not create an actual dictionary file.
1129*/
1130struct DM	*
1131DMcreate(
1132	struct DD		*dd,
1133	char		*spec)
1134{
1135	int		dftype, dmclass;
1136	struct DF	*df;
1137	struct DM	*dm = (struct DM *)0;
1138	struct DDT	*ddt;
1139	struct DDT	*ddLines = &dd->dd_text;
1140	int r, w;
1141#ifndef USE_MALLOC_FOR_BIG_ARRAY
1142	char		lnk[RK_LINK_BMAX+1];
1143	char		member[RK_MEMBER_BMAX+1];
1144	char		nickname[RK_NICK_BMAX+1];
1145#else
1146	char *lnk, *member, *nickname;
1147	lnk = (char *)malloc(RK_LINK_BMAX + 1);
1148	member = (char *)malloc(RK_MEMBER_BMAX + 1);
1149	nickname = (char *)malloc(RK_NICK_BMAX + 1);
1150	if (!lnk || !member || !nickname) {
1151		if (lnk) free(lnk);
1152		if (member) free(member);
1153		if (nickname) free(nickname);
1154		return dm;
1155	}
1156#endif
1157
1158	if (_RkParseDicsDir(spec, lnk, member, nickname, &dftype, &dmclass,
1159	&r, &w) >= 0) {
1160		int len = strlen(spec);
1161		if (spec[len - 1] == '\n') {
1162			spec[len - 1] = '\0';
1163		}
1164
1165		ddt = (struct DDT *)malloc(sizeof(struct DDT));
1166		if (ddt) {
1167			ddt->ddt_spec = (char *)malloc(strlen(spec) + 3); /* 3 for \r\n\0 */
1168			if (ddt->ddt_spec) {
1169				strcpy(ddt->ddt_spec, spec);
1170				df = _RkAllocDF(dd, (unsigned char *)lnk, dftype);
1171				if (df) {
1172					dm = _RkAllocDM(df, (unsigned char *)member,
1173						(unsigned char *)nickname, dmclass);
1174					if (dm) {
1175						ddt->ddt_next = ddLines;
1176						ddt->ddt_prev = ddLines->ddt_prev;
1177						ddLines->ddt_prev = ddt;
1178						ddt->ddt_prev->ddt_next = ddt;
1179						ddt->ddt_status = 0;
1180						dm->dm_line = ddt;
1181						dm->dm_flags |= DM_WRITEOK; /* default access right */
1182						goto return_dm;
1183					}
1184					_RkFreeDF(df);
1185				}
1186				free(ddt->ddt_spec);
1187			}
1188			free(ddt);
1189		}
1190	}
1191return_dm:
1192#ifdef USE_MALLOC_FOR_BIG_ARRAY
1193	free(lnk);
1194	free(member);
1195	free(nickname);
1196#endif
1197	return(dm);
1198}
1199
1200int
1201DMremove(
1202	struct DM	*dm)
1203{
1204	struct DF	*df = dm->dm_file;
1205	struct DDT	*ddt = dm->dm_line;
1206
1207
1208	/* free up dirs.dic line */
1209	if (ddt) {
1210		ddt->ddt_next->ddt_prev = ddt->ddt_prev;
1211		ddt->ddt_prev->ddt_next = ddt->ddt_next;
1212		if (ddt->ddt_spec)
1213			free(ddt->ddt_spec);
1214		free(ddt);
1215	};
1216	/* free dm itself */
1217	_RkFreeDM(dm);
1218	if (df) {
1219		struct DM	*mh = &df->df_members;
1220
1221		if (mh == mh->dm_next)
1222			_RkFreeDF(df);
1223	};
1224	return 0;
1225}
1226
1227int
1228DMrename(
1229	struct DM		*dm,
1230	unsigned char	*nickname)
1231{
1232	struct DF	*df = dm->dm_file;
1233	struct DDT	*ddt = dm->dm_line;
1234	char		*new_spec;
1235	char		*new_nick;
1236	char		member[5];
1237	char *dicname = (char *)0;
1238	int ret = -1;
1239#ifndef USE_MALLOC_FOR_BIG_ARRAY
1240	char		spec[RK_LINE_BMAX];
1241#else
1242	char *spec = (char *)malloc(RK_LINE_BMAX);
1243	if (!spec) {
1244		return ret;
1245	}
1246#endif
1247
1248	if (!df || !df->df_link || !dm->dm_file || !ddt || !ddt->ddt_spec)
1249		goto return_ret;
1250		if (df->df_type == DF_FREQDIC) {
1251			dicname = dm->dm_dicname;
1252		}
1253		switch (dm->dm_class) {
1254		default:
1255		case ND_MWD:
1256			(void)strcpy(member, ".mwd");
1257			break;
1258		case ND_SWD:
1259			(void)strcpy(member, ".swd");
1260			break;
1261		case ND_PRE:
1262			(void)strcpy(member, ".pre");
1263			break;
1264		case ND_SUC:
1265			(void)strcpy(member, ".suc");
1266			break;
1267		};
1268	(void)sprintf(spec, "%s(%s) -%s--%s%s-", df->df_link,
1269		dicname ? dicname : member, nickname,
1270		(dm->dm_flags & DM_READOK) ? "r" : "",
1271		(dm->dm_flags & DM_WRITEOK) ? "w" : "");
1272	new_spec = (char *)malloc(strlen(spec) + 3); /* 3 for \r\n\0 */
1273	if (!new_spec) {
1274		goto return_ret;
1275	}
1276	strcpy(new_spec, spec);
1277	if (!(new_nick = strdup((char *)nickname))) {
1278		free(new_spec);
1279		goto return_ret;
1280	};
1281	free(ddt->ddt_spec);
1282	ddt->ddt_spec = new_spec;
1283	free(dm->dm_nickname);
1284	dm->dm_nickname = new_nick;
1285	ret = 0;
1286
1287return_ret:
1288#ifdef USE_MALLOC_FOR_BIG_ARRAY
1289	free(spec);
1290#endif
1291	return ret;
1292}
1293
1294int
1295DMchmod(struct DM *dm, int mode)
1296{
1297	struct DF	*df = dm->dm_file;
1298	struct DDT	*ddt = dm->dm_line;
1299	char		*new_spec;
1300	unsigned newflags = dm->dm_flags;
1301	int ret = -1;
1302#ifndef USE_MALLOC_FOR_BIG_ARRAY
1303	char		spec[RK_LINE_BMAX];
1304#else
1305	char *spec = (char *)malloc(RK_LINE_BMAX);
1306	if (!spec) {
1307		return ret;
1308	}
1309#endif
1310
1311	if (!df || !df->df_link || !ddt || !ddt->ddt_spec)
1312		goto return_ret;
1313
1314	/* READ ¥Ñ¡¼¥ß¥Ã¥·¥ç¥ó¤ÎÁàºî */
1315	if ((mode & (RK_ENABLE_READ | RK_DISABLE_READ)) == RK_ENABLE_READ) {
1316		newflags |= DM_READOK;
1317	}
1318else if ((mode & (RK_ENABLE_READ | RK_DISABLE_READ)) == RK_DISABLE_READ) {
1319	newflags &= ~DM_READOK;
1320}
1321
1322	/* WRITE ¥Ñ¡¼¥ß¥Ã¥·¥ç¥ó¤ÎÁàºî */
1323	if ((mode & (RK_ENABLE_WRITE | RK_DISABLE_WRITE)) == RK_ENABLE_WRITE) {
1324		newflags |= DM_WRITEOK;
1325	}
1326else if ((mode & (RK_ENABLE_WRITE | RK_DISABLE_WRITE)) == RK_DISABLE_WRITE) {
1327	newflags &= ~DM_WRITEOK;
1328}
1329
1330	if (newflags != dm->dm_flags) {
1331	if (df->df_direct->dd_flags & DD_WRITEOK) {
1332		dm->dm_flags = newflags;
1333		(void)sprintf(spec, "%s(%s) -%s--%s%s-",
1334			df->df_link, dm->dm_dicname, dm->dm_nickname,
1335			(dm->dm_flags & DM_READOK) ? "r" : "",
1336			(dm->dm_flags & DM_WRITEOK) ? "w" : "");
1337		new_spec = (char *)malloc(strlen(spec) + 3); /* 3 for \r\n\0 */
1338		if (!new_spec) {
1339			ret = NOTALC;
1340			goto return_ret;
1341		}
1342		strcpy(new_spec, spec);
1343		free(ddt->ddt_spec);
1344		ddt->ddt_spec = new_spec;
1345	}
1346	}
1347	ret = (((dm->dm_flags & DM_WRITEOK) ? RK_ENABLE_WRITE : RK_DISABLE_WRITE) |
1348		((dm->dm_flags & DM_READOK) ? RK_ENABLE_READ : RK_DISABLE_READ));
1349
1350return_ret:
1351#ifdef USE_MALLOC_FOR_BIG_ARRAY
1352	free(spec);
1353#endif
1354	return ret;
1355}
1356
1357int
1358DDchmod(struct DD *dd, int mode)
1359{
1360	char *dicsdir;
1361	unsigned newflags = dd->dd_flags;
1362
1363	/* READ ¥Ñ¡¼¥ß¥Ã¥·¥ç¥ó¤ÎÁàºî */
1364	if ((mode & (RK_ENABLE_READ | RK_DISABLE_READ)) == RK_ENABLE_READ) {
1365		newflags |= DD_READOK;
1366	}
1367else if ((mode & (RK_ENABLE_READ | RK_DISABLE_READ)) == RK_DISABLE_READ) {
1368	newflags &= ~DD_READOK;
1369}
1370
1371	/* WRITE ¥Ñ¡¼¥ß¥Ã¥·¥ç¥ó¤ÎÁàºî */
1372	if ((mode & (RK_ENABLE_WRITE | RK_DISABLE_WRITE)) == RK_ENABLE_WRITE) {
1373		newflags |= DD_WRITEOK;
1374	}
1375else if ((mode & (RK_ENABLE_WRITE | RK_DISABLE_WRITE)) == RK_DISABLE_WRITE) {
1376	newflags &= ~DD_WRITEOK;
1377}
1378
1379	if (newflags != dd->dd_flags) {
1380		dicsdir = (char *)malloc(strlen(dd->dd_path) + strlen("/dics.dir") + 1);
1381		if (dicsdir) {
1382			int filemode;
1383
1384			sprintf(dicsdir, "%s/dics.dir", dd->dd_path);
1385
1386			filemode = ((newflags & DD_WRITEOK) ? 0640 : 0440)
1387				| ((newflags & DD_READOK) ? 04 : 0);
1388
1389			if (chmod(dicsdir, filemode) == 0) {
1390				dd->dd_flags = newflags;
1391			}
1392			free(dicsdir);
1393		}
1394	}
1395	newflags = dd->dd_flags;
1396	return (((newflags & DD_WRITEOK) ? RK_ENABLE_WRITE : RK_DISABLE_WRITE) |
1397		((newflags & DD_READOK) ? RK_ENABLE_READ : RK_DISABLE_READ));
1398}
1399
1400int
1401_RkMountMD(
1402	struct RkContext	*cx,
1403	struct DM		*dm,
1404	struct DM		*qm,
1405	int		mode,
1406	int		firsttime)
1407{
1408	struct MD	*md, *head;
1409	struct DF	*df;
1410	struct DD	*dd;
1411	char		*file;
1412	int		status;
1413
1414	if (!dm || !(md = (struct MD *)calloc(1, sizeof(struct MD))))
1415		return -1;
1416	/* increment the reference counter */
1417	if (dm->dm_rcount == 0) {
1418		df = dm->dm_file;
1419		dd = df->df_direct;
1420		if (!(file = _RkCreatePath(dd, df->df_link))) {
1421			free(md);
1422			return -1;
1423		};
1424		status = DST_OPEN(dm, file,  DM_WRITABLE, cx->gram->gramdic);
1425		free(file);
1426		if (status) {
1427			free(md);
1428			return -1;
1429		};
1430	};
1431	if (qm && qm->dm_rcount == 0) {
1432		df = qm->dm_file;
1433		dd = df->df_direct;
1434		if (!(file = _RkCreatePath(dd, df->df_link))) {
1435			free(md);
1436			return -1;
1437		};
1438		status = FQopen(dm, qm, file, DM_WRITABLE);
1439		free(file);
1440		if (status) {
1441			free(md);
1442			return -1;
1443		};
1444	};
1445	/* use the dic as the default grammatical dic if it contains */
1446	if (firsttime && DM2TYPE(dm) == DF_PERMDIC && dm->dm_gram) {
1447		cx->gram = dm->dm_gram;
1448		cx->gram->refcount++;
1449	}
1450	/* increment the reference counter */
1451	dm->dm_rcount++;
1452	if (qm) {
1453		qm->dm_rcount++;
1454		if (!cx->nv && qm->dm_nv)
1455			cx->nv = qm->dm_nv;
1456	}
1457	/* put it at the end of the mount list */
1458	head = cx->md[dm->dm_class];
1459	md->md_next = head;
1460	md->md_prev = head->md_prev;
1461	head->md_prev = md;
1462	md->md_prev->md_next = md;
1463	md->md_dic = dm;
1464	md->md_freq = qm;
1465	md->md_flags = mode&MD_WRITE;
1466	/* wait for the translation to finish */
1467	if (IS_XFERCTX(cx))
1468		md->md_flags |= MD_MPEND;
1469	return 0;
1470}
1471
1472void
1473_RkUmountMD(
1474	struct RkContext	*cx,
1475	struct MD		*md)
1476{
1477	struct DM	*dm = md->md_dic;
1478	struct DM	*qm = md->md_freq;
1479	struct DF	*df;
1480	struct DD	*dd;
1481	char		*file;
1482
1483	cx->dmprev = (struct DM *)0;
1484	cx->qmprev = (struct DM *)0;
1485	if (IS_XFERCTX(cx))
1486		md->md_flags |= MD_UPEND;
1487	else {
1488		md->md_prev->md_next = md->md_next;
1489		md->md_next->md_prev = md->md_prev;
1490		free(md);
1491		if (qm) {
1492			df = qm->dm_file;
1493			dd = df->df_direct;
1494			if (cx->nv == qm->dm_nv)
1495				cx->nv = (struct NV *)0;
1496				if (qm->dm_rcount > 0 && --qm->dm_rcount == 0) {
1497					file = _RkCreatePath(dd, df->df_link);
1498					if (file) {
1499						FQclose(cx, dm, qm, file);
1500						if (!df->df_rcount) {
1501							if (dd->dd_rcount > 0 && --dd->dd_rcount == 0)
1502								_RkFreeDD(dd);
1503						};
1504						free(file);
1505					};
1506				};
1507		};
1508		if (dm->dm_rcount > 0 && --dm->dm_rcount == 0) {
1509			df = dm->dm_file;
1510			dd = df->df_direct;
1511			file  = _RkCreatePath(dd, df->df_link);
1512			if (file) {
1513				(void)DST_CLOSE(dm, file, cx->gram->gramdic);
1514				if (df->df_rcount == 0) {
1515					if (dd->dd_rcount > 0 && --dd->dd_rcount == 0)
1516						_RkFreeDD(dd);
1517				};
1518				free(file);
1519			};
1520		};
1521	};
1522}
1523