The public functions simply use char instead of Dict_char to represent
[idzebra-moved-to-github.git] / dict / lookgrep.c
1 /*
2  * Copyright (C) 1994, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: lookgrep.c,v $
7  * Revision 1.14  1996-02-02 13:43:51  adam
8  * The public functions simply use char instead of Dict_char to represent
9  * search strings. Dict_char is used internally only.
10  *
11  * Revision 1.13  1996/01/08  09:09:30  adam
12  * Function dfa_parse got 'const' string argument.
13  *
14  * Revision 1.12  1995/12/11  09:04:48  adam
15  * Bug fix: the lookup/scan/lookgrep didn't handle empty dictionary.
16  *
17  * Revision 1.11  1995/12/06  14:43:02  adam
18  * New function: dict_delete.
19  *
20  * Revision 1.10  1995/11/16  17:00:44  adam
21  * Changed stupid log.
22  *
23  * Revision 1.9  1995/10/27  13:58:09  adam
24  * Makes 'Database unavailable' diagnostic.
25  *
26  * Revision 1.8  1995/10/19  14:57:21  adam
27  * New feature: grep lookup saves length of longest prefix match.
28  *
29  * Revision 1.7  1995/10/17  18:01:22  adam
30  * Userfunc may return non-zero in which case the the grepping stops
31  * immediately.
32  *
33  * Revision 1.6  1995/10/09  16:18:32  adam
34  * Function dict_lookup_grep got extra client data parameter.
35  *
36  * Revision 1.5  1995/09/14  11:52:59  adam
37  * Grep handle function parameter info is const now.
38  *
39  * Revision 1.4  1995/01/24  16:01:02  adam
40  * Added -ansi to CFLAGS.
41  * Use new API of dfa module.
42  *
43  * Revision 1.3  1994/10/05  12:16:50  adam
44  * Pagesize is a resource now.
45  *
46  * Revision 1.2  1994/10/04  12:08:07  adam
47  * Some bug fixes and some optimizations.
48  *
49  * Revision 1.1  1994/10/03  17:23:04  adam
50  * First version of dictionary lookup with regular expressions and errors.
51  *
52  */
53
54 #include <stdlib.h>
55 #include <string.h>
56 #include <stdio.h>
57 #include <assert.h>
58
59 #include <dfa.h>
60 #include <dict.h>
61
62 typedef unsigned MatchWord;
63 #define WORD_BITS 32
64 #define MAX_LENGTH 1024
65
66 typedef struct {
67   int n;                 /* no of MatchWord needed */
68   int range;             /* max no. of errors */
69   int fact;              /* (range+1)*n */
70   MatchWord *match_mask; /* match_mask */
71 } MatchContext;
72
73 #define INLINE 
74
75 static INLINE void set_bit (MatchContext *mc, MatchWord *m, int ch, int state)
76 {
77     int off = state & (WORD_BITS-1);
78     int wno = state / WORD_BITS;
79   
80     m[mc->n * ch + wno] |= 1<<off;
81 }
82
83 static INLINE MatchWord get_bit (MatchContext *mc, MatchWord *m, int ch,
84                                  int state)
85 {
86     int off = state & (WORD_BITS-1);
87     int wno = state / WORD_BITS;
88
89     return m[mc->n * ch + wno] & (1<<off);
90 }
91
92 static MatchContext *mk_MatchContext (struct DFA *dfa, int range)
93 {
94     MatchContext *mc = xmalloc (sizeof(*mc));
95     int s;
96
97     mc->n = (dfa->no_states+WORD_BITS) / WORD_BITS;
98     mc->range = range;
99     mc->fact = (range+1)*mc->n;
100     mc->match_mask = xcalloc (mc->n, sizeof(*mc->match_mask));
101
102     for (s = 0; s<dfa->no_states; s++)
103         if (dfa->states[s]->rule_no)
104             set_bit (mc, mc->match_mask, 0, s);
105     return mc;
106 }
107
108 static void rm_MatchContext (MatchContext **mc)
109 {
110     xfree ((*mc)->match_mask);
111     xfree (*mc);
112     *mc = NULL;
113 }
114
115 static void mask_shift (MatchContext *mc, MatchWord *Rdst, MatchWord *Rsrc,
116                    struct DFA *dfa, int ch)
117 {
118     int j, s = 0;
119     MatchWord *Rsrc_p = Rsrc, mask;
120
121     for (j = 0; j<mc->n; j++)
122         Rdst[j] = 0;
123     while (1)
124     {
125         mask = *Rsrc_p++;
126         for (j = 0; j<WORD_BITS/4; j++)
127         {
128             if (mask & 15)
129             {
130                 if (mask & 1)
131                 {
132                     struct DFA_state *state = dfa->states[s];
133                     int i = state->tran_no;
134                     while (--i >= 0)
135                         if (ch >= state->trans[i].ch[0] &&
136                             ch <= state->trans[i].ch[1])
137                             set_bit (mc, Rdst, 0, state->trans[i].to);
138                 }
139                 if (mask & 2)
140                 {
141                     struct DFA_state *state = dfa->states[s+1];
142                     int i = state->tran_no;
143                     while (--i >= 0)
144                         if (ch >= state->trans[i].ch[0] &&
145                             ch <= state->trans[i].ch[1])
146                             set_bit (mc, Rdst, 0, state->trans[i].to);
147                 }
148                 if (mask & 4)
149                 {
150                     struct DFA_state *state = dfa->states[s+2];
151                     int i = state->tran_no;
152                     while (--i >= 0)
153                         if (ch >= state->trans[i].ch[0] &&
154                             ch <= state->trans[i].ch[1])
155                             set_bit (mc, Rdst, 0, state->trans[i].to);
156                 }
157                 if (mask & 8)
158                 {
159                     struct DFA_state *state = dfa->states[s+3];
160                     int i = state->tran_no;
161                     while (--i >= 0)
162                         if (ch >= state->trans[i].ch[0] &&
163                             ch <= state->trans[i].ch[1])
164                             set_bit (mc, Rdst, 0, state->trans[i].to);
165                 }
166             }
167             s += 4;
168             if (s >= dfa->no_states)
169                 return;
170             mask >>= 4;
171         }
172     }
173 }
174
175 static void shift (MatchContext *mc, MatchWord *Rdst, MatchWord *Rsrc,
176                    struct DFA *dfa)
177 {
178     int j, s = 0;
179     MatchWord *Rsrc_p = Rsrc, mask;
180     for (j = 0; j<mc->n; j++)
181         Rdst[j] = 0;
182     while (1)
183     {
184         mask = *Rsrc_p++;
185         for (j = 0; j<WORD_BITS/4; j++)
186         {
187             if (mask & 15)
188             {
189                 if (mask & 1)
190                 {
191                     struct DFA_state *state = dfa->states[s];
192                     int i = state->tran_no;
193                     while (--i >= 0)
194                         set_bit (mc, Rdst, 0, state->trans[i].to);
195                 }
196                 if (mask & 2)
197                 {
198                     struct DFA_state *state = dfa->states[s+1];
199                     int i = state->tran_no;
200                     while (--i >= 0)
201                         set_bit (mc, Rdst, 0, state->trans[i].to);
202                 }
203                 if (mask & 4)
204                 {
205                     struct DFA_state *state = dfa->states[s+2];
206                     int i = state->tran_no;
207                     while (--i >= 0)
208                         set_bit (mc, Rdst, 0, state->trans[i].to);
209                 }
210                 if (mask & 8)
211                 {
212                     struct DFA_state *state = dfa->states[s+3];
213                     int i = state->tran_no;
214                     while (--i >= 0)
215                         set_bit (mc, Rdst, 0, state->trans[i].to);
216                 }
217             }
218             s += 4;
219             if (s >= dfa->no_states)
220                 return;
221             mask >>= 4;
222         }
223     }
224 }
225
226 static void or (MatchContext *mc, MatchWord *Rdst,
227                 MatchWord *Rsrc1, MatchWord *Rsrc2)
228 {
229     int i;
230     for (i = 0; i<mc->n; i++)
231         Rdst[i] = Rsrc1[i] | Rsrc2[i];
232 }
233
234 static INLINE int move (MatchContext *mc, MatchWord *Rj1, MatchWord *Rj,
235                  Dict_char ch, struct DFA *dfa, MatchWord *Rtmp)
236 {
237     int d;
238     MatchWord *Rtmp_2 = Rtmp + mc->n;
239
240     mask_shift (mc, Rj1, Rj, dfa, ch);
241     for (d = 1; d <= mc->range; d++)
242     {
243         or (mc, Rtmp, Rj, Rj1);                         /* 2,3 */
244         
245         shift (mc, Rtmp_2, Rtmp, dfa);
246
247         mask_shift (mc, Rtmp, Rj+mc->n, dfa, ch);      /* 1 */
248                 
249         or (mc, Rtmp, Rtmp_2, Rtmp);                    /* 1,2,3*/
250
251         Rj1 += mc->n;
252         
253         or (mc, Rj1, Rtmp, Rj);                         /* 1,2,3,4 */
254
255         Rj += mc->n;
256     }
257     return 1;
258
259 }
260
261
262 static int dict_grep (Dict dict, Dict_ptr ptr, MatchContext *mc,
263                       MatchWord *Rj, int pos, void *client,
264                       int (*userfunc)(char *, const char *, void *),
265                       Dict_char *prefix, struct DFA *dfa,
266                       int *max_pos)
267 {
268     int lo, hi, d;
269     void *p;
270     short *indxp;
271     char *info;
272
273     dict_bf_readp (dict->dbf, ptr, &p);
274     lo = 0;
275     hi = DICT_nodir(p)-1;
276     indxp = (short*) ((char*) p+DICT_pagesize(dict)-sizeof(short));    
277
278     while (lo <= hi)
279     {
280         if (indxp[-lo] > 0)
281         {
282             /* string (Dict_char *) DICT_EOS terminated */
283             /* unsigned char        length of information */
284             /* char *               information */
285             int j;
286             int was_match = 0;
287             info = (char*)p + indxp[-lo];
288             for (j=0; ; j++)
289             {
290                 Dict_char ch;
291                 MatchWord *Rj0 =    Rj + j    *mc->fact;
292                 MatchWord *Rj1 =    Rj + (j+1)*mc->fact;
293                 MatchWord *Rj_tmp = Rj + (j+2)*mc->fact;
294
295                 memcpy (&ch, info+j*sizeof(Dict_char), sizeof(Dict_char));
296                 prefix[pos+j] = ch;
297                 if (pos+j > *max_pos)
298                     *max_pos = pos+j;
299                 if (ch == DICT_EOS)
300                 {
301                     if (was_match)
302                         if ((*userfunc)((char*) prefix,
303                                         info+(j+1)*sizeof(Dict_char), client))
304                             return 1;
305                     break;
306                 }
307                 move (mc, Rj1, Rj0, ch, dfa, Rj_tmp);
308                 for (d = mc->n; --d >= 0; )
309                     if (Rj1[mc->range*mc->n + d])
310                         break;
311                 if (d < 0)
312                     break;
313                 was_match = 0;
314                 for (d = mc->n; --d >= 0; )
315                     if (Rj1[mc->range*mc->n + d] & mc->match_mask[d])
316                     {
317                         was_match = 1;
318                         break;
319                     }
320             }
321         }
322         else
323         {
324             MatchWord *Rj1 =    Rj+  mc->fact;
325             MatchWord *Rj_tmp = Rj+2*mc->fact;
326             Dict_char ch;
327
328             /* Dict_ptr             subptr */
329             /* Dict_char            sub char */
330             /* unsigned char        length of information */
331             /* char *               information */
332             info = (char*)p - indxp[-lo];
333             memcpy (&ch, info+sizeof(Dict_ptr), sizeof(Dict_char));
334             prefix[pos] = ch;
335             
336             if (pos > *max_pos)
337                 *max_pos = pos;
338             move (mc, Rj1, Rj, ch, dfa, Rj_tmp);
339             for (d = mc->n; --d >= 0; )
340                 if (Rj1[mc->range*mc->n + d])
341                     break;
342             if (d >= 0)
343             {
344                 Dict_ptr subptr;
345                 if (info[sizeof(Dict_ptr)+sizeof(Dict_char)])
346                 {
347                     for (d = mc->n; --d >= 0; )
348                         if (Rj1[mc->range*mc->n + d] & mc->match_mask[d])
349                         {
350                             prefix[pos+1] = DICT_EOS;
351                             if ((*userfunc)((char*) prefix,
352                                             info+sizeof(Dict_ptr)+
353                                             sizeof(Dict_char), client))
354                                 return 1;
355                             break;
356                         }
357                 }
358                 memcpy (&subptr, info, sizeof(Dict_ptr));
359                 if (subptr)
360                 {
361                     if (dict_grep (dict, subptr, mc, Rj1, pos+1,
362                                    client, userfunc, prefix, dfa, max_pos))
363                         return 1;
364                     dict_bf_readp (dict->dbf, ptr, &p);
365                     indxp = (short*) ((char*) p+DICT_pagesize(dict)
366                                       -sizeof(short));
367                 }
368             }
369         }
370         lo++;
371     }
372     return 0;
373 }
374
375 int dict_lookup_grep (Dict dict, const char *pattern, int range, void *client,
376                       int *max_pos,
377                       int (*userfunc)(char *name, const char *info,
378                                       void *client))
379 {
380     MatchWord *Rj;
381     Dict_char prefix[MAX_LENGTH+1];
382     const char *this_pattern = pattern;
383     MatchContext *mc;
384     struct DFA *dfa = dfa_init();
385     int i, d;
386
387     logf (LOG_DEBUG, "dict_lookup_grep '%s' range=%d", pattern, range);
388     i = dfa_parse (dfa, &this_pattern);
389     if (i || *this_pattern)
390     {
391         dfa_delete (&dfa);
392         return -1;
393     }
394     dfa_mkstate (dfa);
395
396     mc = mk_MatchContext (dfa, range);
397
398     Rj = xcalloc ((MAX_LENGTH+1) * mc->n, sizeof(*Rj));
399
400     set_bit (mc, Rj, 0, 0);
401     for (d = 1; d<=mc->range; d++)
402     {
403         int s;
404         memcpy (Rj + mc->n * d, Rj + mc->n * (d-1), mc->n * sizeof(*Rj));
405         for (s = 0; s<dfa->no_states; s++)
406         {
407             if (get_bit (mc, Rj, d-1, s))
408             {
409                 struct DFA_state *state = dfa->states[s];
410                 int i = state->tran_no;
411                 while (--i >= 0)
412                     set_bit (mc, Rj, d, state->trans[i].to);
413             }
414         }
415     }
416     *max_pos = 0;
417     if (dict->head.last > 1)
418         i = dict_grep (dict, 1, mc, Rj, 0, client, userfunc, prefix,
419                        dfa, max_pos);
420     else
421         i = 0;
422     logf (LOG_DEBUG, "max_pos = %d", *max_pos);
423     dfa_delete (&dfa);
424     xfree (Rj);
425     rm_MatchContext (&mc);
426     return i;
427 }