Implemented loadable filters.
[idzebra-moved-to-github.git] / perl / zebra_perl.c
1 #if 0
2 #include "zebraapi.h"
3 #endif
4
5 #include "EXTERN.h"
6 #include "perl.h"
7 #include "XSUB.h"
8
9 #include <yaz/yaz-util.h>
10 #include <yaz/proto.h>
11 #include <yaz/log.h>
12 #include <yaz/cql.h>
13 #include <yaz/pquery.h>
14
15 #include "zebra_perl.h"
16 #include "../recctrl/perlread.h"
17 #include <data1.h>
18
19 NMEM handles;
20
21 void init (void) {
22   nmem_init ();
23   yaz_log_init_prefix ("ZebraPerl");
24   yaz_log (LOG_LOG, "Zebra API initialized");
25 }
26
27 void DESTROY (void) {
28   nmem_exit ();
29   yaz_log (LOG_LOG, "Zebra API destroyed");
30 }   
31
32 /* Logging facilities from yaz */
33 void logMsg (int level, const char *message) {
34   logf(level, "%s", message);
35 }
36
37 /* debug tool for data1... maybe should be moved to data1. 
38    perl can't really pass filehandles */
39 void data1_print_tree(data1_handle dh, data1_node *n) {
40   data1_pr_tree(dh, n, stdout);
41 }
42
43 /* ---------------------------------------------------------------------------
44   Record retrieval 
45   2 phase retrieval - I didn't manage to return array of blessed references
46   to wrapped structures... it's feasible, but I'll need some time 
47   / pop - 2002-11-17
48 */
49
50 void record_retrieve(RetrievalObj *ro,
51                      ODR stream,
52                      RetrievalRecord *res,
53                      int pos) 
54 {
55   int i = pos - 1;
56
57
58   RetrievalRecordBuf *buf = 
59     (RetrievalRecordBuf *) odr_malloc(stream, sizeof(*buf));  
60
61   res->errCode    = ro->records[i].errCode;
62   if (ro->records[i].errString) {
63     res->errString  = odr_strdup(stream, ro->records[i].errString);
64   } else {
65     res->errString = "";
66   }
67   res->position   = ro->records[i].position;
68   res->base       = odr_strdup(stream, ro->records[i].base);
69   res->format     = (char *) 
70     yaz_z3950_oid_value_to_str(ro->records[i].format, CLASS_RECSYN); 
71   res->buf        = buf;
72   res->buf->len   = ro->records[i].len;
73   res->buf->buf   = ro->records[i].buf;
74   res->score      = ro->records[i].score;
75   res->sysno      = ro->records[i].sysno;
76
77 }
78
79
80
81 /* most of the code here was copied from yaz-client */
82 void records_retrieve(ZebraHandle zh,
83                       ODR stream,
84                       const char *setname,
85                       const char *a_eset, 
86                       const char *a_schema,
87                       const char *a_format,
88                       int from,
89                       int to,
90                       RetrievalObj *res) 
91 {
92   static enum oid_value recordsyntax = VAL_SUTRS;
93   static enum oid_value schema = VAL_NONE;
94   static Z_ElementSetNames *elementSetNames = 0; 
95   static Z_RecordComposition compo;
96   static Z_ElementSetNames esn;
97   static char what[100];
98   int i;
99   int oid[OID_SIZE];
100
101   compo.which = -1;
102
103   if (from < 1) from = 1;
104   if (from > to) to = from;
105   res->noOfRecords = to - from + 1;
106
107   res->records = odr_malloc (stream, 
108                              sizeof(*res->records) * (res->noOfRecords));  
109
110   for (i = 0; i<res->noOfRecords; i++) res->records[i].position = from+i;
111
112   if (!a_eset || !*a_eset) {
113     elementSetNames = 0;
114   } else {
115     strcpy(what, a_eset);
116     esn.which = Z_ElementSetNames_generic;
117     esn.u.generic = what;
118     elementSetNames = &esn;
119   }
120
121   if (!a_schema || !*a_schema) {
122     schema = VAL_NONE;
123   } else {
124     schema = oid_getvalbyname (a_schema);
125     if (schema == VAL_NONE) {
126       logf(LOG_WARN,"unknown schema '%s'",a_schema);
127     }
128   }
129
130   
131   if (!a_format || !*a_format) {
132     recordsyntax = VAL_SUTRS;
133   } else {
134     recordsyntax = oid_getvalbyname (a_format);
135     if (recordsyntax == VAL_NONE) {
136       logf(LOG_WARN,"unknown record syntax '%s', using SUTRS",a_schema);
137       recordsyntax = VAL_SUTRS;
138     }
139   }
140
141   if (schema != VAL_NONE) {
142     oident prefschema;
143
144     prefschema.proto = PROTO_Z3950;
145     prefschema.oclass = CLASS_SCHEMA;
146     prefschema.value = schema;
147     
148     compo.which = Z_RecordComp_complex;
149     compo.u.complex = (Z_CompSpec *)
150       odr_malloc(stream, sizeof(*compo.u.complex));
151     compo.u.complex->selectAlternativeSyntax = (bool_t *) 
152       odr_malloc(stream, sizeof(bool_t));
153     *compo.u.complex->selectAlternativeSyntax = 0;
154     
155     compo.u.complex->generic = (Z_Specification *)
156       odr_malloc(stream, sizeof(*compo.u.complex->generic));
157     compo.u.complex->generic->which = Z_Schema_oid;
158     compo.u.complex->generic->schema.oid = (Odr_oid *)
159       odr_oiddup(stream, oid_ent_to_oid(&prefschema, oid));
160     if (!compo.u.complex->generic->schema.oid)
161       {
162         /* OID wasn't a schema! Try record syntax instead. */
163         prefschema.oclass = CLASS_RECSYN;
164         compo.u.complex->generic->schema.oid = (Odr_oid *)
165           odr_oiddup(stream, oid_ent_to_oid(&prefschema, oid));
166       }
167     if (!elementSetNames)
168       compo.u.complex->generic->elementSpec = 0;
169     else
170       {
171         compo.u.complex->generic->elementSpec = (Z_ElementSpec *)
172           odr_malloc(stream, sizeof(Z_ElementSpec));
173         compo.u.complex->generic->elementSpec->which =
174           Z_ElementSpec_elementSetName;
175         compo.u.complex->generic->elementSpec->u.elementSetName =
176           elementSetNames->u.generic;
177       }
178     compo.u.complex->num_dbSpecific = 0;
179     compo.u.complex->dbSpecific = 0;
180     compo.u.complex->num_recordSyntax = 0;
181     compo.u.complex->recordSyntax = 0;
182   } 
183   else if (elementSetNames) {
184     compo.which = Z_RecordComp_simple;
185     compo.u.simple = elementSetNames;
186   }
187
188   if (compo.which == -1) {
189     api_records_retrieve (zh, stream, setname, 
190                             NULL, 
191                             recordsyntax,
192                             res->noOfRecords, res->records);
193   } else {
194     api_records_retrieve (zh, stream, setname, 
195                             &compo,
196                             recordsyntax,
197                             res->noOfRecords, res->records);
198   }
199
200 }
201  
202 int zebra_cql2pqf (cql_transform_t ct, 
203                    const char *query, char *res, int len) {
204   
205   int status;
206   const char *addinfo = "";
207   CQL_parser cp = cql_parser_create();
208
209   if (status = cql_parser_string(cp, query)) {
210     cql_parser_destroy(cp);
211     return (status);
212   }
213
214   if (cql_transform_buf(ct, cql_parser_result(cp), res, len)) {
215     status = cql_transform_error(ct, &addinfo);
216     logf (LOG_WARN,"Transform error %d %s\n", status, addinfo ? addinfo : "");
217     cql_parser_destroy(cp);
218     return (status);
219   }
220
221   cql_parser_destroy(cp);
222   return (0);
223 }
224
225 void zebra_scan_PQF (ZebraHandle zh,
226                      ScanObj *so,
227                      ODR stream,
228                      const char *pqf_query)
229 {
230   Z_AttributesPlusTerm *zapt;
231   Odr_oid *attrsetid;
232   const char* oidname;
233   oid_value attributeset;
234   ZebraScanEntry *entries;
235   int i, class;
236
237   logf(LOG_DEBUG,  
238        "scan req: pos:%d, num:%d, partial:%d", 
239        so->position, so->num_entries, so->is_partial);
240
241   zapt = p_query_scan (stream, PROTO_Z3950, &attrsetid, pqf_query);
242
243   oidname = yaz_z3950oid_to_str (attrsetid, &class); 
244   logf (LOG_DEBUG, "Attributreset: %s", oidname);
245   attributeset = oid_getvalbyname(oidname);
246
247   if (!zapt) {
248     logf (LOG_WARN, "bad query %s\n", pqf_query);
249     odr_reset (stream);
250     return;
251   }
252
253   so->entries = (scanEntry *)
254     odr_malloc (stream, sizeof(so->entries) * (so->num_entries));
255
256
257   zebra_scan (zh, stream, zapt, attributeset, 
258               &so->position, &so->num_entries, 
259               (ZebraScanEntry **) &so->entries, &so->is_partial);
260
261   logf(LOG_DEBUG, 
262        "scan res: pos:%d, num:%d, partial:%d", 
263        so->position, so->num_entries, so->is_partial);
264 }
265
266 scanEntry *getScanEntry(ScanObj *so, int pos) {
267   return (&so->entries[pos-1]);
268 }
269
270 #if 1
271 void Filter_store_buff (struct perl_context *context, char *buff, size_t len)
272 {
273     dSP;
274     
275     ENTER;
276     SAVETMPS;
277     
278     PUSHMARK(SP) ;
279     XPUSHs(context->filterRef);
280     XPUSHs(sv_2mortal(newSVpv(buff, len)));  
281     PUTBACK ;
282     call_method("_store_buff", 0);
283     SPAGAIN ;
284     PUTBACK ;
285     
286     FREETMPS;
287     LEAVE;
288 }
289
290 /*  The "file" manipulation function wrappers */
291 int grs_perl_readf(struct perl_context *context, size_t len)
292 {
293     int r;
294     char *buf = (char *) xmalloc (len+1);
295     r = (*context->readf)(context->fh, buf, len);
296     if (r > 0) Filter_store_buff (context, buf, r);
297     xfree (buf);
298     return (r);
299 }
300
301 int grs_perl_readline(struct perl_context *context)
302 {
303     int r;
304     char *buf = (char *) xmalloc (4096);
305     char *p = buf;
306     
307     while ((r = (*context->readf)(context->fh,p,1)) && (p-buf < 4095)) {
308         p++;
309         if (*(p-1) == 10) break;
310     }
311     
312     *p = 0;
313     
314     if (p != buf) Filter_store_buff (context, buf, p - buf);
315     xfree (buf);
316     return (p - buf);
317 }
318
319 char grs_perl_getc(struct perl_context *context)
320 {
321     int r;
322     char *p;
323     if ((r = (*context->readf)(context->fh,p,1))) {
324         return (*p);
325     } else {
326         return (0);
327     }
328 }
329
330 off_t grs_perl_seekf(struct perl_context *context, off_t offset)
331 {
332     return ((*context->seekf)(context->fh, offset));
333 }
334
335 off_t grs_perl_tellf(struct perl_context *context)
336 {
337     return ((*context->tellf)(context->fh));
338 }
339
340 void grs_perl_endf(struct perl_context *context, off_t offset)
341 {
342     (*context->endf)(context->fh, offset);
343 }
344
345 /* Get pointers from the context. Easyer to wrap this by SWIG */
346 data1_handle *grs_perl_get_dh(struct perl_context *context)
347 {
348     return(&context->dh);
349 }
350
351 NMEM *grs_perl_get_mem(struct perl_context *context)
352 {
353     return(&context->mem);
354 }
355
356 /* Set the result in the context */
357 void grs_perl_set_res(struct perl_context *context, data1_node *n)
358 {
359     context->res = n;
360 }
361 #endif