1 /* vim:set ts=8 sts=4 sw=4 tw=0: */
2 /*
3  * mnode.c - mnode interfaces.
4  *
5  * Written By:  MURAOKA Taro <koron@tka.att.ne.jp>
6  * Last Change: 04-May-2004.
7  */
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 
14 #include "dbg.h"
15 #include "wordlist.h"
16 #include "wordbuf.h"
17 #include "mnode.h"
18 
19 #define MTREE_MNODE_N 1024
20 struct _mtree_t
21 {
22     mtree_p	active;
23     int		used;
24     mnode	nodes[MTREE_MNODE_N];
25     mtree_p	next;
26 };
27 
28 #define MNODE_BUFSIZE 16384
29 
30 #if defined(_MSC_VER) || defined(__GNUC__)
31 # define INLINE __inline
32 #else
33 # define INLINE
34 #endif
35 
36 int n_mnode_new = 0;
37 int n_mnode_delete = 0;
38 
39     INLINE static mnode*
mnode_new(mtree_p mtree)40 mnode_new(mtree_p mtree)
41 {
42     mtree_p active = mtree->active;
43 
44     if (active->used >= MTREE_MNODE_N)
45     {
46 	active->next = (mtree_p)calloc(1, sizeof(*active->next));
47 	/* TODO: �G���[���� */
48 	mtree->active = active->next;
49 	active = active->next;
50     }
51     ++n_mnode_new;
52     return &active->nodes[active->used++];
53 }
54 
55     static void
mnode_delete(mnode * p)56 mnode_delete(mnode* p)
57 {
58     while (p)
59     {
60 	mnode* child = p->child;
61 
62 	if (p->list)
63 	    wordlist_close(p->list);
64 	if (p->next)
65 	    mnode_delete(p->next);
66 	/*free(p);*/
67 	p = child;
68 	++n_mnode_delete;
69     }
70 }
71 
72 
73     void
mnode_print_stub(mnode * vp,unsigned char * p)74 mnode_print_stub(mnode* vp, unsigned char* p)
75 {
76     static unsigned char buf [256];
77 
78     if (!vp)
79 	return;
80     if (!p)
81 	p = &buf[0];
82     p[0] = MNODE_GET_CH(vp);
83     p[1] = '\0';
84     if (vp->list)
85 	printf("%s (list=%p)\n", buf, vp->list);
86     if (vp->child)
87 	mnode_print_stub(vp->child, p + 1);
88     if (vp->next)
89 	mnode_print_stub(vp->next, p);
90 }
91 
92     void
mnode_print(mtree_p mtree,unsigned char * p)93 mnode_print(mtree_p mtree, unsigned char* p)
94 {
95     if (mtree && mtree->used > 0)
96 	mnode_print_stub(&mtree->nodes[0], p);
97 }
98 
99     void
mnode_close(mtree_p mtree)100 mnode_close(mtree_p mtree)
101 {
102     if (mtree)
103     {
104 	mtree_p next;
105 
106 	if (mtree->used > 0)
107 	    mnode_delete(&mtree->nodes[0]);
108 
109 	while (mtree)
110 	{
111 	    next = mtree->next;
112 	    free(mtree);
113 	    mtree = next;
114 	}
115     }
116 }
117 
118     INLINE static mnode*
search_or_new_mnode(mtree_p mtree,wordbuf_p buf)119 search_or_new_mnode(mtree_p mtree, wordbuf_p buf)
120 {
121     /* ���x���P�ꂪ���肵���猟���؂ɒlj� */
122     int ch;
123     unsigned char *word;
124     mnode **ppnext;
125     mnode **res = NULL; /* To suppress warning for GCC */
126     mnode *root;
127 
128     word = WORDBUF_GET(buf);
129     root = mtree->used > 0 ? &mtree->nodes[0] : NULL;
130     ppnext = &root;
131     while ((ch = *word) != 0)
132     {
133 	res = ppnext;
134 	if (! *res)
135 	{
136 	    *res = mnode_new(mtree);
137 	    MNODE_SET_CH(*res, ch);
138 	}
139 	else if (MNODE_GET_CH(*res) != ch)
140 	{
141 	    ppnext = &(*res)->next;
142 	    continue;
143 	}
144 	ppnext = &(*res)->child;
145 	++word;
146     }
147 
148     _ASSERT(*res != NULL);
149     return *res;
150 }
151 
152 /*
153  * �����̃m�[�h�Ƀt�@�C������f�[�^���܂Ƃ߂Ēlj�����B
154  */
155     mtree_p
mnode_load(mtree_p mtree,FILE * fp)156 mnode_load(mtree_p mtree, FILE* fp)
157 {
158     mnode *pp = NULL;
159     int mode = 0;
160     int ch;
161     wordbuf_p buf;
162     wordbuf_p prevlabel;
163     wordlist_p *ppword = NULL; /* To suppress warning for GCC */
164     /* �ǂݍ��݃o�b�t�@�p�ϐ� */
165     unsigned char cache[MNODE_BUFSIZE];
166     unsigned char *cache_ptr = cache;
167     unsigned char *cache_tail = cache;
168 
169     buf = wordbuf_open();
170     prevlabel = wordbuf_open();
171     if (!fp || !buf || !prevlabel)
172     {
173 	goto END_MNODE_LOAD;
174     }
175 
176     /*
177      * EOF�̏������B���B�s���Ȍ`���̃t�@�C�����������ꍇ���l�����Ă��Ȃ��B�e
178      * ���[�h����EOF�̓���p�ӂ��Ȃ��Ɛ������Ȃ����c�ʓ|�Ȃ̂ł��Ȃ��B�f�[
179      * �^�t�@�C���͐�΂ɊԈ���Ă��Ȃ��Ƃ����O���u���B
180      */
181     do
182     {
183 	if (cache_ptr >= cache_tail)
184 	{
185 	    cache_ptr = cache;
186 	    cache_tail = cache + fread(cache, 1, MNODE_BUFSIZE, fp);
187 	    ch = (cache_tail <= cache && feof(fp)) ? EOF : *cache_ptr;
188 	}
189 	else
190 	    ch = *cache_ptr;
191 	++cache_ptr;
192 
193 	/* ���:mode�̃I�[�g�}�g�� */
194 	switch (mode)
195 	{
196 	    case 0: /* ���x���P�ꌟ�����[�h */
197 		/* ���̓��x���P��ɂȂ肦�܂��� */
198 		if (isspace(ch) || ch == EOF)
199 		    continue;
200 		/* �R�����g���C���`�F�b�N */
201 		else if (ch == ';')
202 		{
203 		    mode = 2; /* �s���܂ŐH���ׂ����[�h �ֈڍs */
204 		    continue;
205 		}
206 		else
207 		{
208 		    mode = 1; /* ���x���P��̓Ǎ����[�h �ֈڍs*/
209 		    wordbuf_reset(buf);
210 		    wordbuf_add(buf, (unsigned char)ch);
211 		}
212 		break;
213 
214 	    case 1: /* ���x���P��̓Ǎ����[�h */
215 		/* ���x���̏I�������o */
216 		switch (ch)
217 		{
218 		    default:
219 			wordbuf_add(buf, (unsigned char)ch);
220 			break;
221 		    case '\t':
222 			pp = search_or_new_mnode(mtree, buf);
223 			wordbuf_reset(buf);
224 			mode = 3; /* �P��O���ǔ�΂����[�h �ֈڍs */
225 			break;
226 		}
227 		break;
228 
229 	    case 2: /* �s���܂ŐH���ׂ����[�h */
230 		if (ch == '\n')
231 		{
232 		    wordbuf_reset(buf);
233 		    mode = 0; /* ���x���P�ꌟ�����[�h �֖߂� */
234 		}
235 		break;
236 
237 	    case 3: /* �P��O���ǂݔ�΂����[�h */
238 		if (ch == '\n')
239 		{
240 		    wordbuf_reset(buf);
241 		    mode = 0; /* ���x���P�ꌟ�����[�h �֖߂� */
242 		}
243 		else if (ch != '\t')
244 		{
245 		    /* �P��o�b�t�@���Z�b�g */
246 		    wordbuf_reset(buf);
247 		    wordbuf_add(buf, (unsigned char)ch);
248 		    /* �P�ꃊ�X�g�̍Ō������(���ꃉ�x����������) */
249 		    ppword = &pp->list;
250 		    while (*ppword)
251 			ppword = &(*ppword)->next;
252 		    mode = 4; /* �P��̓ǂݍ��݃��[�h �ֈڍs */
253 		}
254 		break;
255 
256 	    case 4: /* �P��̓ǂݍ��݃��[�h */
257 		switch (ch)
258 		{
259 		    case '\t':
260 		    case '\n':
261 			/* �P����L�� */
262 			*ppword = wordlist_open_len(WORDBUF_GET(buf),
263 				WORDBUF_LEN(buf));
264 			wordbuf_reset(buf);
265 
266 			if (ch == '\t')
267 			{
268 			    ppword = &(*ppword)->next;
269 			    mode = 3; /* �P��O���ǂݔ�΂����[�h �֖߂� */
270 			}
271 			else
272 			{
273 			    ppword = NULL;
274 			    mode = 0; /* ���x���P�ꌟ�����[�h �֖߂� */
275 			}
276 			break;
277 		    default:
278 			wordbuf_add(buf, (unsigned char)ch);
279 			break;
280 		}
281 		break;
282 	}
283     }
284     while (ch != EOF);
285 
286 END_MNODE_LOAD:
287     wordbuf_close(buf);
288     wordbuf_close(prevlabel);
289     return mtree;
290 }
291 
292     mtree_p
mnode_open(FILE * fp)293 mnode_open(FILE* fp)
294 {
295     mtree_p mtree;
296 
297     mtree = (mtree_p)calloc(1, sizeof(*mtree));
298     mtree->active = mtree;
299     if (mtree && fp)
300 	mnode_load(mtree, fp);
301 
302     return mtree;
303 }
304 
305 #if 0
306     static int
307 mnode_size(mnode* p)
308 {
309     return p ? mnode_size(p->child) + mnode_size(p->next) + 1 : 0;
310 }
311 #endif
312 
313     static mnode*
mnode_query_stub(mnode * node,const unsigned char * query)314 mnode_query_stub(mnode* node, const unsigned char* query)
315 {
316     while (1)
317     {
318 	if (*query == MNODE_GET_CH(node))
319 	    return (*++query == '\0') ? node :
320 		(node->child ? mnode_query_stub(node->child, query) : NULL);
321 	if (!(node = node->next))
322 	    break;
323     }
324     return NULL;
325 }
326 
327     mnode*
mnode_query(mtree_p mtree,const unsigned char * query)328 mnode_query(mtree_p mtree, const unsigned char* query)
329 {
330     return (query && *query != '\0' && mtree)
331 	? mnode_query_stub(&mtree->nodes[0], query) : 0;
332 }
333 
334     static void
mnode_traverse_stub(mnode * node,MNODE_TRAVERSE_PROC proc,void * data)335 mnode_traverse_stub(mnode* node, MNODE_TRAVERSE_PROC proc, void* data)
336 {
337     while (1)
338     {
339 	if (node->child)
340 	    mnode_traverse_stub(node->child, proc, data);
341 	proc(node, data);
342 	if (!(node = node->next))
343 	    break;
344     }
345 }
346 
347     void
mnode_traverse(mnode * node,MNODE_TRAVERSE_PROC proc,void * data)348 mnode_traverse(mnode *node, MNODE_TRAVERSE_PROC proc, void* data)
349 {
350     if (node && proc)
351     {
352 	proc(node, data);
353 	if (node->child)
354 	    mnode_traverse_stub(node->child, proc, data);
355     }
356 }
357