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