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