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