1 /* $Id: perlread.c,v 1.8.2.1 2004-09-03 09:31:21 adam Exp $
2 Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002
5 This file is part of the Zebra server.
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
33 #include <yaz/tpath.h>
39 #define GRS_PERL_MODULE_NAME_MAXLEN 255
41 /* Context information for the filter */
43 PerlInterpreter *perli;
44 PerlInterpreter *origi;
46 char filterClass[GRS_PERL_MODULE_NAME_MAXLEN];
49 int (*readf)(void *, char *, size_t);
50 off_t (*seekf)(void *, off_t);
51 off_t (*tellf)(void *);
52 void (*endf)(void *, off_t);
60 /* Constructor call for the filter object */
61 void Filter_create (struct perl_context *context)
67 XPUSHs(sv_2mortal(newSVpv(context->filterClass,
68 strlen(context->filterClass)))) ;
70 sv_setref_pv(msv, "_p_perl_context", (void*)context);
73 call_method("new", G_EVAL);
76 context->filterRef = POPs;
81 Execute the process call on the filter. This is a bit dirty.
82 The perl code is going to get dh and nmem from the context trough callbacks,
83 then call readf, to get the stream, and then set the res (d1 node)
84 in the context. However, it's safer, to let swig do as much of wrapping
87 int Filter_process (struct perl_context *context)
99 XPUSHs(context->filterRef);
101 call_method("_process", 0);
113 This one is called to transfer the results of a readf. It's going to create
114 a temporary variable there...
116 So the call stack is something like:
119 ->Filter_process(context) [C]
120 -> _process($context) [Perl]
121 -> grs_perl_get_dh($context) [Perl]
122 -> grs_perl_get_dh(context) [C]
123 -> grs_perl_get_mem($context) [Perl]
124 -> grs_perl_get_mem(context) [C]
127 -> grs_perl_readf($context,$len) [Perl]
128 -> grs_perl_readf(context, len) [C]
129 ->(*context->readf)(context->fh, buf, len) [C]
130 -> Filter_store_buff(context, buf, r) [C]
131 -> _store_buff($buff) [Perl]
132 [... returns buff and length ...]
134 [... returns d1 node ...]
135 -> grs_perl_set_res($context, $node) [Perl]
136 -> grs_perl_set_res(context, node) [C]
138 [... The result is in context->res ...]
140 Dirty, isn't it? It may become nicer, if I'll have some more time to work on
141 it. However, these changes are not going to hurt the filter api, as
142 Filter.pm, which is inherited into all specific filter implementations
143 can hide this whole compexity behind.
146 void Filter_store_buff (struct perl_context *context, char *buff, size_t len) {
153 XPUSHs(context->filterRef);
154 XPUSHs(sv_2mortal(newSVpv(buff, len)));
156 call_method("_store_buff", 0);
163 /* The "file" manipulation function wrappers */
164 int grs_perl_readf(struct perl_context *context, size_t len) {
166 char *buf = (char *) xmalloc (len+1);
167 r = (*context->readf)(context->fh, buf, len);
168 if (r > 0) Filter_store_buff (context, buf, r);
173 int grs_perl_readline(struct perl_context *context) {
175 char *buf = (char *) xmalloc (4096);
178 while ((r = (*context->readf)(context->fh,p,1)) && (p-buf < 4095)) {
180 if (*(p-1) == 10) break;
185 if (p != buf) Filter_store_buff (context, buf, p - buf);
190 char grs_perl_getc(struct perl_context *context) {
193 if ((r = (*context->readf)(context->fh,p,1))) {
200 off_t grs_perl_seekf(struct perl_context *context, off_t offset) {
201 return ((*context->seekf)(context->fh, offset));
204 off_t grs_perl_tellf(struct perl_context *context) {
205 return ((*context->tellf)(context->fh));
208 void grs_perl_endf(struct perl_context *context, off_t offset) {
209 (*context->endf)(context->fh, offset);
212 /* Get pointers from the context. Easyer to wrap this by SWIG */
213 data1_handle *grs_perl_get_dh(struct perl_context *context) {
214 return(&context->dh);
217 NMEM *grs_perl_get_mem(struct perl_context *context) {
218 return(&context->mem);
221 /* Set the result in the context */
222 void grs_perl_set_res(struct perl_context *context, data1_node *n) {
226 /* The filter handlers (init, destroy, read) */
227 static void *grs_init_perl(void)
229 struct perl_context *context =
230 (struct perl_context *) xmalloc (sizeof(*context));
232 /* If there is an interpreter (context) running, - we are calling
233 indexing and retrieval from the perl API - we don't create a new one. */
234 context->origi = PERL_GET_CONTEXT;
235 /* with Perl 5.8 context may be non-NULL even though it's not there! */
236 if (context->origi && !PL_stack_sp) /* dirty, but it seems to work */
238 if (context->origi == NULL) {
239 context->perli = perl_alloc();
240 PERL_SET_CONTEXT(context->perli);
241 logf (LOG_LOG, "Initializing new perl interpreter context (%p)",context->perli);
243 logf (LOG_LOG, "Using existing perl interpreter context (%p)",context->origi);
245 context->perli_ready = 0;
246 strcpy(context->filterClass, "");
250 void grs_destroy_perl(void *clientData)
252 struct perl_context *context = (struct perl_context *) clientData;
254 logf (LOG_LOG, "Destroying perl interpreter context");
255 if (context->perli_ready) {
260 if (context->origi == NULL) perl_destruct(context->perli);
262 if (context->origi == NULL) perl_free(context->perli);
266 static data1_node *grs_read_perl (struct grs_read_info *p)
268 struct perl_context *context = (struct perl_context *) p->clientData;
269 char *filterClass = p->type;
271 /* The "file" manipulation function wrappers */
272 context->readf = p->readf;
273 context->seekf = p->seekf;
274 context->tellf = p->tellf;
275 context->endf = p->endf;
277 /* The "file", data1 and NMEM handles */
280 context->mem = p->mem;
282 /* If the class was not interpreted before... */
283 /* This is not too efficient, when indexing with many different filters... */
284 if (strcmp(context->filterClass,filterClass)) {
286 char modarg[GRS_PERL_MODULE_NAME_MAXLEN + 2];
287 char initarg[GRS_PERL_MODULE_NAME_MAXLEN + 2];
288 char *arglist[6] = { "", "-I", "", "-M", "-e", "" };
290 if (context->perli_ready) {
295 if (context->origi == NULL) {
296 perl_destruct(context->perli);
299 if (context->origi == NULL) {
300 perl_construct(context->perli);
308 context->perli_ready = 1;
310 /* parse, and run the init call */
311 if (context->origi == NULL) {
312 logf (LOG_LOG, "Interpreting filter class:%s", filterClass);
314 arglist[2] = (char *) data1_get_tabpath(p->dh);
315 sprintf(modarg,"-M%s",filterClass);
316 arglist[3] = (char *) &modarg;
317 sprintf(initarg,"%s->init;",filterClass);
318 arglist[5] = (char *) &initarg;
320 perl_parse(context->perli, PERL_XS_INIT, 6, arglist, NULL);
321 perl_run(context->perli);
324 strcpy(context->filterClass, filterClass);
326 /* create the filter object as a filterClass blessed reference */
327 Filter_create(context);
330 /* Wow... if calling with individual update_record calls from perl,
331 the filter object reference may go out of scope... */
332 if (!sv_isa(context->filterRef, context->filterClass)) {
333 Filter_create(context);
334 logf (LOG_DEBUG,"Filter recreated");
337 if (!SvTRUE(context->filterRef)) {
338 logf (LOG_WARN,"Failed to initialize perl filter %s",context->filterClass);
342 /* call the process method */
343 Filter_process(context);
345 /* return the created data1 node */
346 return (context->res);
349 static struct recTypeGrs perl_type = {
356 RecTypeGrs recTypeGrs_perl = &perl_type;