Bug fix: the lookup/scan/lookgrep didn't handle empty dictionary.
[idzebra-moved-to-github.git] / dict / scan.c
1 /*
2  * Copyright (C) 1994, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: scan.c,v $
7  * Revision 1.7  1995-12-11 09:04:50  adam
8  * Bug fix: the lookup/scan/lookgrep didn't handle empty dictionary.
9  *
10  * Revision 1.6  1995/11/20  11:58:04  adam
11  * Support for YAZ in standard located directories, such as /usr/local/..
12  *
13  * Revision 1.5  1995/10/09  16:18:32  adam
14  * Function dict_lookup_grep got extra client data parameter.
15  *
16  * Revision 1.4  1995/10/06  13:52:00  adam
17  * Bug fixes. Handler may abort further scanning.
18  *
19  * Revision 1.3  1995/10/06  11:06:07  adam
20  * Bug fixes.
21  *
22  * Revision 1.2  1995/10/06  10:43:16  adam
23  * Minor changes.
24  *
25  * Revision 1.1  1995/10/06  09:04:18  adam
26  * First version of scan.
27  *
28  */
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <assert.h>
33
34 #include <dict.h>
35
36 int dict_scan_trav (Dict dict, Dict_ptr ptr, int pos, Dict_char *str, 
37                     int start, int *count, void *client,
38                     int (*userfunc)(Dict_char *, const char *, int, void *),
39                     int dir)
40 {
41     int lo, hi, j;
42     void *p;
43     short *indxp;
44     char *info;
45
46     dict_bf_readp (dict->dbf, ptr, &p);
47     hi = DICT_nodir(p)-1;
48     if (start == 0 && dir == -1)
49         lo = hi;
50     else
51         lo = start;
52     indxp = (short*) ((char*) p+DICT_pagesize(dict)-sizeof(short)); 
53
54     while (lo <= hi && lo >= 0 && *count > 0)
55     {
56         if (indxp[-lo] > 0)
57         {
58             /* string (Dict_char *) DICT_EOS terminated */
59             /* unsigned char        length of information */
60             /* char *               information */
61
62             info = (char*)p + indxp[-lo];
63             for (j = 0; info[j] != DICT_EOS; j++)
64                 str[pos+j] = info[j];
65             str[pos+j] = DICT_EOS;
66             if ((*userfunc)(str, info+(j+1)*sizeof(Dict_char), *count * dir,
67                             client))
68                 return 1;
69             --(*count);
70         }
71         else
72         {
73             Dict_char dc;
74             Dict_ptr subptr;
75
76             /* Dict_ptr             subptr */
77             /* Dict_char            sub char */
78             /* unsigned char        length of information */
79             /* char *               information */
80
81             info = (char*)p - indxp[-lo];
82             memcpy (&dc, info+sizeof(Dict_ptr), sizeof(Dict_char));
83             str[pos] = dc;
84             memcpy (&subptr, info, sizeof(Dict_ptr));
85             if (info[sizeof(Dict_ptr)+sizeof(Dict_char)])
86             {
87                  str[pos+1] = DICT_EOS;
88                  if ((*userfunc)(str, info+sizeof(Dict_ptr)+sizeof(Dict_char),
89                                  *count * dir, client))
90                      return 1;
91                  --(*count);
92             }
93             if (*count > 0 && subptr)
94                  dict_scan_trav (dict, subptr, pos+1, str, 0, count, 
95                                  client, userfunc, dir);
96         }
97         lo += dir;
98     }
99     return 0;
100 }
101     
102 int dict_scan_r (Dict dict, Dict_ptr ptr, int pos, Dict_char *str, 
103                  int *before, int *after, void *client,
104                  int (*userfunc)(Dict_char *, const char *, int, void *))
105 {
106     int cmp = 0, mid, lo, hi;
107     void *p;
108     short *indxp;
109     char *info;
110
111     dict_bf_readp (dict->dbf, ptr, &p);
112     if (!p)
113         return 0;
114     mid = lo = 0;
115     hi = DICT_nodir(p)-1;
116     indxp = (short*) ((char*) p+DICT_pagesize(dict)-sizeof(short));    
117     while (lo <= hi)
118     {
119         mid = (lo+hi)/2;
120         if (indxp[-mid] > 0)
121         {
122             /* string (Dict_char *) DICT_EOS terminated */
123             /* unsigned char        length of information */
124             /* char *               information */
125             info = (char*)p + indxp[-mid];
126             cmp = dict_strcmp ((Dict_char*) info, str + pos);
127             if (!cmp)
128             {
129                 if (*after)
130                 {
131                     (*userfunc)(str, info+
132                                 (dict_strlen(info)+1)*sizeof(Dict_char), 
133                                 *after, client);
134                     --(*after);
135                 }
136                 break;
137             }
138         }
139         else
140         {
141             Dict_char dc;
142             Dict_ptr subptr;
143
144             /* Dict_ptr             subptr */
145             /* Dict_char            sub char */
146             /* unsigned char        length of information */
147             /* char *               information */
148             info = (char*)p - indxp[-mid];
149             memcpy (&dc, info+sizeof(Dict_ptr), sizeof(Dict_char));
150             cmp = dc - str[pos];
151             if (!cmp)
152             {
153                 memcpy (&subptr, info, sizeof(Dict_ptr));
154                 if (str[pos+1] == DICT_EOS)
155                 {
156                     if (info[sizeof(Dict_ptr)+sizeof(Dict_char)])
157                     {
158                         if (*after)
159                         {
160                             (*userfunc)(str, 
161                                         info+sizeof(Dict_ptr)+
162                                         sizeof(Dict_char),
163                                         *after, client);
164                             --(*after);
165                         }
166                     }
167                     if (*after && subptr)
168                         if (dict_scan_trav (dict, subptr, pos+1, str, 0, 
169                                             after, client, userfunc, 1))
170                             return 1;
171                 }
172                 else if (subptr)
173                     if (dict_scan_r (dict, subptr, pos+1, str, before, after,
174                                      client, userfunc))
175                         return 1;
176                 break;
177             }
178         }
179         if (cmp < 0)
180             lo = mid+1;
181         else
182             hi = mid-1;
183     }
184     if (lo>hi && cmp < 0)
185         ++mid;
186     if (*after)
187         if (dict_scan_trav (dict, ptr, pos, str, cmp ? mid : mid+1, after,
188                             client, userfunc, 1))
189             return 1;
190     if (*before && mid > 1)
191         if (dict_scan_trav (dict, ptr, pos, str, mid-1, before, 
192                             client, userfunc, -1))
193             return 1;
194     return 0;
195 }
196
197 int dict_scan (Dict dict, Dict_char *str, int *before, int *after,
198                void *client,
199                int (*f)(Dict_char *name, const char *info, int pos,
200                         void *client))
201 {
202     if (dict->head.last <= 1)
203         return 0;
204     return dict_scan_r (dict, 1, 0, str, before, after, client, f);
205 }
206