Updated WIN32 code specific sections. Changed header.
[idzebra-moved-to-github.git] / dict / scan.c
1 /*
2  * Copyright (C) 1994-1999, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: scan.c,v $
7  * Revision 1.12  1999-02-02 14:50:28  adam
8  * Updated WIN32 code specific sections. Changed header.
9  *
10  * Revision 1.11  1998/06/22 11:34:45  adam
11  * Changed scan callback function so it doesn't stop further scanning.
12  *
13  * Revision 1.10  1998/03/06 16:58:04  adam
14  * Fixed bug which related to scanning of large indexes.
15  *
16  * Revision 1.9  1997/10/27 14:33:04  adam
17  * Moved towards generic character mapping depending on "structure"
18  * field in abstract syntax file. Fixed a few memory leaks. Fixed
19  * bug with negative integers when doing searches with relational
20  * operators.
21  *
22  * Revision 1.8  1996/02/02 13:43:52  adam
23  * The public functions simply use char instead of Dict_char to represent
24  * search strings. Dict_char is used internally only.
25  *
26  * Revision 1.7  1995/12/11  09:04:50  adam
27  * Bug fix: the lookup/scan/lookgrep didn't handle empty dictionary.
28  *
29  * Revision 1.6  1995/11/20  11:58:04  adam
30  * Support for YAZ in standard located directories, such as /usr/local/..
31  *
32  * Revision 1.5  1995/10/09  16:18:32  adam
33  * Function dict_lookup_grep got extra client data parameter.
34  *
35  * Revision 1.4  1995/10/06  13:52:00  adam
36  * Bug fixes. Handler may abort further scanning.
37  *
38  * Revision 1.3  1995/10/06  11:06:07  adam
39  * Bug fixes.
40  *
41  * Revision 1.2  1995/10/06  10:43:16  adam
42  * Minor changes.
43  *
44  * Revision 1.1  1995/10/06  09:04:18  adam
45  * First version of scan.
46  *
47  */
48 #include <stdlib.h>
49 #include <string.h>
50 #include <stdio.h>
51 #include <assert.h>
52
53 #include <dict.h>
54
55 int dict_scan_trav (Dict dict, Dict_ptr ptr, int pos, Dict_char *str, 
56                     int start, int *count, void *client,
57                     int (*userfunc)(char *, const char *, int, void *),
58                     int dir)
59 {
60     int lo, hi, j;
61     void *p;
62     short *indxp;
63     char *info;
64
65     dict_bf_readp (dict->dbf, ptr, &p);
66     hi = DICT_nodir(p)-1;
67     if (start == 0 && dir == -1)
68         lo = hi;
69     else
70         lo = start;
71     indxp = (short*) ((char*) p+DICT_pagesize(dict)-sizeof(short)); 
72
73     while (lo <= hi && lo >= 0 && *count > 0)
74     {
75         if (indxp[-lo] > 0)
76         {
77             /* string (Dict_char *) DICT_EOS terminated */
78             /* unsigned char        length of information */
79             /* char *               information */
80
81             info = (char*)p + indxp[-lo];
82             for (j = 0; info[j] != DICT_EOS; j++)
83                 str[pos+j] = info[j];
84             str[pos+j] = DICT_EOS;
85             (*userfunc)((char*) str, info+(j+1)*sizeof(Dict_char),
86                             *count * dir, client);
87             --(*count);
88         }
89         else
90         {
91             Dict_char dc;
92             Dict_ptr subptr;
93
94             /* Dict_ptr             subptr */
95             /* Dict_char            sub char */
96             /* unsigned char        length of information */
97             /* char *               information */
98
99             info = (char*)p - indxp[-lo];
100             memcpy (&dc, info+sizeof(Dict_ptr), sizeof(Dict_char));
101             str[pos] = dc;
102             memcpy (&subptr, info, sizeof(Dict_ptr));
103             if (info[sizeof(Dict_ptr)+sizeof(Dict_char)])
104             {
105                  str[pos+1] = DICT_EOS;
106                  if ((*userfunc)((char*) str,
107                                  info+sizeof(Dict_ptr)+sizeof(Dict_char),
108                                  *count * dir, client))
109                      return 1;
110                  --(*count);
111             }
112             if (*count > 0 && subptr)
113             {
114                 dict_scan_trav (dict, subptr, pos+1, str, 0, count, 
115                                 client, userfunc, dir);
116                 dict_bf_readp (dict->dbf, ptr, &p);
117                 indxp = (short*) ((char*) p+DICT_pagesize(dict)-sizeof(short)); 
118             }
119         }
120         lo += dir;
121     }
122     return 0;
123 }
124
125 int dict_scan_r (Dict dict, Dict_ptr ptr, int pos, Dict_char *str, 
126                  int *before, int *after, void *client,
127                  int (*userfunc)(char *, const char *, int, void *))
128 {
129     int cmp = 0, mid, lo, hi;
130     void *p;
131     short *indxp;
132     char *info;
133
134     dict_bf_readp (dict->dbf, ptr, &p);
135     if (!p)
136         return 0;
137     mid = lo = 0;
138     hi = DICT_nodir(p)-1;
139     indxp = (short*) ((char*) p+DICT_pagesize(dict)-sizeof(short));    
140     while (lo <= hi)
141     {
142         mid = (lo+hi)/2;
143         if (indxp[-mid] > 0)
144         {
145             /* string (Dict_char *) DICT_EOS terminated */
146             /* unsigned char        length of information */
147             /* char *               information */
148             info = (char*)p + indxp[-mid];
149             cmp = dict_strcmp ((Dict_char*) info, str + pos);
150             if (!cmp)
151             {
152                 if (*after)
153                 {
154                     (*userfunc)((char *) str, info+
155                                 (dict_strlen((Dict_char*) info)+1)
156                                 *sizeof(Dict_char), 
157                                 *after, client);
158                     --(*after);
159                 }
160                 break;
161             }
162         }
163         else
164         {
165             Dict_char dc;
166             Dict_ptr subptr;
167
168             /* Dict_ptr             subptr */
169             /* Dict_char            sub char */
170             /* unsigned char        length of information */
171             /* char *               information */
172             info = (char*)p - indxp[-mid];
173             memcpy (&dc, info+sizeof(Dict_ptr), sizeof(Dict_char));
174             cmp = dc - str[pos];
175             if (!cmp)
176             {
177                 memcpy (&subptr, info, sizeof(Dict_ptr));
178                 if (str[pos+1] == DICT_EOS)
179                 {
180                     if (info[sizeof(Dict_ptr)+sizeof(Dict_char)])
181                     {
182                         if (*after)
183                         {
184                             (*userfunc)((char*) str,
185                                         info+sizeof(Dict_ptr)+
186                                         sizeof(Dict_char),
187                                         *after, client);
188                             --(*after);
189                         }
190                     }
191                     if (*after && subptr)
192                         if (dict_scan_trav (dict, subptr, pos+1, str, 0, 
193                                             after, client, userfunc, 1))
194                             return 1;
195                 }
196                 else if (subptr)
197                 {
198                     if (dict_scan_r (dict, subptr, pos+1, str, before, after,
199                                      client, userfunc))
200                         return 1;
201                 }
202                 break;
203             }
204         }
205         if (cmp < 0)
206             lo = mid+1;
207         else
208             hi = mid-1;
209     }
210     if (lo>hi && cmp < 0)
211         ++mid;
212     if (*after)
213         if (dict_scan_trav (dict, ptr, pos, str, cmp ? mid : mid+1, after,
214                             client, userfunc, 1))
215             return 1;
216     if (*before && mid > 1)
217         if (dict_scan_trav (dict, ptr, pos, str, mid-1, before, 
218                             client, userfunc, -1))
219             return 1;
220     return 0;
221 }
222
223 int dict_scan (Dict dict, char *str, int *before, int *after, void *client,
224                int (*f)(char *name, const char *info, int pos, void *client))
225 {
226     int i;
227
228     logf (LOG_DEBUG, "dict_scan");
229     for (i = 0; str[i]; i++)
230     {
231         logf (LOG_DEBUG, " %3d  %c", str[i],
232               (str[i] > ' ' && str[i] < 127) ? str[i] : '?');
233     }
234     if (dict->head.last <= 1)
235         return 0;
236     return dict_scan_r (dict, 1, 0, (Dict_char *) str, before, after, client,
237                         f);
238 }
239