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