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