First work on Z39.50 persistence.
[egate.git] / kernel / persist.c
1 /* Gateway kernel - Z39.50 Persistence
2  * Europagate, 1995
3  *
4  * $Log: persist.c,v $
5  * Revision 1.1  1995/04/19 07:31:10  adam
6  * First work on Z39.50 persistence.
7  *
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <assert.h>
13 #include <ctype.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17
18 #include "kernel.h"
19
20 static int set_change;
21
22 static int obtain_set (ZASS zass, struct gw_user_set *set)
23 {
24     const struct zass_searchent *p;
25
26     p = zass_search (zass, set->rpn, set->name, set->database);
27     if (!p)
28         return 2;
29     if (p->errcode != -1)
30         return 3;
31     if (p->num != set->hits)
32         set_change = 1;
33     set->present_flag = 1;
34     set->hits = p->num;
35     return 0;
36 }
37
38 static int obtain_sets (ZASS zass, struct ccl_rpn_node *rpn, 
39                         struct gw_user_set *sets)
40 {
41     struct gw_user_set *set;
42     int r;
43
44     switch (rpn->kind)
45     {
46     case CCL_RPN_AND:
47     case CCL_RPN_OR:
48     case CCL_RPN_NOT:
49     case CCL_RPN_PROX:
50         if ((r=obtain_sets (zass, rpn->u.p[0], sets)))
51             return r;
52         return obtain_sets (zass, rpn->u.p[1], sets);
53     case CCL_RPN_TERM:
54         return 0;
55     case CCL_RPN_SET:
56         set = user_set_search (rpn->u.setname);
57         if (!set)
58             return 1;
59         if (set->present_flag)
60             return 0;
61     }
62     return obtain_set (zass, set);
63 }
64
65 const struct zass_searchent *zass_p_search (ZASS zass, 
66                         struct ccl_rpn_node *rpn, 
67                         const char *result_set,
68                         const char *database,
69                         struct gw_user_set *sets)
70 {
71     int r;
72
73     set_change = 0;
74     r = obtain_sets (zass, rpn, sets);
75     if (r)
76         return NULL;
77     return zass_search (zass, rpn, (char*) result_set, (char*) database);
78 }
79
80 const struct zass_presentent *zass_p_present (ZASS zass,
81                         const char *result_set, int offset, int number)
82 {
83     struct gw_user_set *set;
84
85     set = user_set_search (result_set);
86     if (!set)
87         return NULL;
88     if (!set->present_flag)
89     {
90         int r = obtain_set (zass, set);
91         if (r)
92             return NULL;
93     }
94     return zass_present (zass, (char*) result_set, offset, number);
95 }
96
97 struct ccl_rpn_node *load_rpn (char *buf, FILE *inf)
98 {
99     struct ccl_rpn_node *rpn;
100     struct ccl_rpn_attr **attrp;
101     char *cp;
102     int type, value, no_read;
103
104     if (!fgets (buf, 1024, inf))
105         return NULL;
106     if ((cp = strchr (buf, '\n')))
107         *cp = '\0';
108     switch (*buf)
109     {
110     case 'A':
111         rpn = malloc (sizeof (*rpn));
112         if (!rpn)
113             return NULL;
114         rpn->kind = CCL_RPN_AND;
115         rpn->u.p[0] = load_rpn (buf, inf);
116         rpn->u.p[1] = load_rpn (buf, inf);
117         break;
118     case 'O':
119         rpn = malloc (sizeof (*rpn));
120         if (!rpn)
121             return NULL;
122         rpn->kind = CCL_RPN_OR;
123         rpn->u.p[0] = load_rpn (buf, inf);
124         rpn->u.p[1] = load_rpn (buf, inf);
125         break;
126     case 'N':
127         rpn = malloc (sizeof (*rpn));
128         if (!rpn)
129             return NULL;
130         rpn->kind = CCL_RPN_NOT;
131         rpn->u.p[0] = load_rpn (buf, inf);
132         rpn->u.p[1] = load_rpn (buf, inf);
133         break;
134     case 'P':
135         rpn = malloc (sizeof (*rpn));
136         if (!rpn)
137             return NULL;
138         rpn->kind = CCL_RPN_PROX;
139         rpn->u.p[0] = load_rpn (buf, inf);
140         rpn->u.p[1] = load_rpn (buf, inf);
141         break;
142     case 'T':
143         rpn = malloc (sizeof (*rpn));
144         if (!rpn)
145             return NULL;
146         rpn->kind = CCL_RPN_TERM;
147
148         rpn->u.t.term = gw_strdup (buf+2);
149         attrp = &rpn->u.t.attr_list;
150         if (!fgets (buf, 1024, inf))
151             return NULL;
152         cp = buf;
153         while (sscanf (cp, "%d %d%n", &type, &value, &no_read) > 1)
154         {
155             *attrp = malloc (sizeof(**attrp));
156             (*attrp)->type = type;
157             (*attrp)->value = value;
158             attrp = &(*attrp)->next;
159             cp += no_read; 
160         }
161         *attrp = NULL;
162         break;
163     case 'S':
164         rpn = malloc (sizeof (*rpn));
165         if (!rpn)
166             return NULL;
167         rpn->kind = CCL_RPN_SET;
168         rpn->u.setname = gw_strdup (buf+2);
169     }
170     return rpn;
171 }
172
173 int load_p_state (int userid)
174 {
175     FILE *inf;
176     char fname[128];
177     char fline[1025];
178     char database[1024];
179     char resultname[32];
180     int hits;
181     struct gw_user_set *set;
182
183     sprintf (fname, "persist.%d", userid);
184
185     inf = fopen (fname, "r");
186     if (!inf)
187     {
188         gw_log (GW_LOG_WARN|GW_LOG_ERRNO, KERNEL_LOG, 
189                 "Couldn't open %s", fname);
190         return -1;
191     }
192     gw_log (GW_LOG_FATAL, KERNEL_LOG, 
193        "Reading persistence file %s", fname);
194     if (!fgets (fline, 1024, inf))
195         return -1;
196     if (sscanf (fline, "%s", info.target) != 1)
197         *info.target = '\0';
198     gw_log (GW_LOG_FATAL, KERNEL_LOG, 
199            "Reading persistence file %s (2)", fname);
200     read_kernel_res ();
201     gw_log (GW_LOG_FATAL, KERNEL_LOG, "reopen_target start");
202     reopen_target ();
203     gw_log (GW_LOG_FATAL, KERNEL_LOG, "reopen_target end");
204     while (fgets (fline, 1024, inf))
205     {
206         gw_log (GW_LOG_FATAL, KERNEL_LOG, 
207               "Reading persistence file %s (3)", fname);
208         if (sscanf (fline, "%s %d %s", resultname, &hits, database) != 3)
209             return -1;
210         gw_log (GW_LOG_FATAL, KERNEL_LOG,
211                 "Adding %s, %d hits, database %s",
212                 resultname, hits, database);
213         set = user_set_add (resultname, hits, database, NULL, 0);
214         set->rpn = load_rpn (fline, inf);
215         ccl_pr_tree (set->rpn, stderr);
216         fgets (fline, 1024, inf);
217     }
218     fclose (inf);
219     return 0;
220 }
221
222 static void save_rpn (struct ccl_rpn_node *rpn, FILE *of)
223 {
224     struct ccl_rpn_attr *attr;
225
226     switch (rpn->kind)
227     {
228     case CCL_RPN_AND:
229         fprintf (of, "A\n");
230         save_rpn (rpn->u.p[0], of);
231         save_rpn (rpn->u.p[1], of);
232         break;
233     case CCL_RPN_OR:
234         fprintf (of, "O\n");
235         save_rpn (rpn->u.p[0], of);
236         save_rpn (rpn->u.p[1], of);
237         break;
238     case CCL_RPN_NOT:
239         fprintf (of, "N\n");
240         save_rpn (rpn->u.p[0], of);
241         save_rpn (rpn->u.p[1], of);
242         break;
243     case CCL_RPN_PROX:
244         fprintf (of, "P\n");
245         save_rpn (rpn->u.p[0], of);
246         save_rpn (rpn->u.p[1], of);
247         break;
248     case CCL_RPN_TERM:
249         fprintf (of, "T %s\n", rpn->u.t.term);
250         for (attr = rpn->u.t.attr_list; attr; attr = attr->next)
251             fprintf (of, "%d %d ", attr->type, attr->value);
252         fprintf (of, "\n");
253         break;
254     case CCL_RPN_SET:
255         fprintf (of, "S %s\n", rpn->u.setname); 
256     }
257 }
258
259 int save_p_state (int userid)
260 {
261     FILE *of;
262     char fname[128];
263     struct gw_user_set *sp;
264
265     sprintf (fname, "persist.%d", userid);
266
267     of = fopen (fname, "w");
268     if (!of)
269     {
270         gw_log (GW_LOG_WARN|GW_LOG_ERRNO, KERNEL_LOG, 
271                 "Couldn't open %s", fname);
272         return -1;
273     }
274     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Writing persistence file %s", fname);
275     fprintf (of, "%s\n", info.target);
276     for (sp = info.sets; sp; sp = sp->prev)
277     {
278         fprintf (of, "%s %d %s\n", sp->name, sp->hits, sp->database);
279         save_rpn (sp->rpn, of);
280         fprintf (of, "X\n");
281     }
282     fclose (of);
283     return 0;
284 }
285