ZOOM_event() wrapper now works for arbitrarily many connection --
[ZOOM-Perl-moved-to-github.git] / ZOOM.xs
1 /* $Id: ZOOM.xs,v 1.47 2007-02-22 20:37:47 mike Exp $ */
2
3 #include "EXTERN.h"
4 #include "perl.h"
5 #include "XSUB.h"
6
7 #include <yaz/zoom.h>
8 #include <yaz/xmalloc.h>
9
10 /* Used by the *_setl() functions */
11 typedef char opaquechar;
12
13 /* Used as the return value of the *_getl() functions */
14 struct datachunk {
15         char *data;
16         int len;
17 };
18
19 /* Used to package Perl function-pointer and user-data together */
20 struct callback_block {
21         SV *function;
22         SV *handle;
23 };
24
25 /* The callback function used for ZOOM_options_set_callback().  I do
26  * not claim to fully understand all the stack-hacking magic, and less
27  * still the reference-counting/mortality stuff.  Accordingly, the
28  * memory management here is best characterised as What I Could Get To
29  * Work, More Or Less.
30  */
31 const char *__ZOOM_option_callback (void *handle, const char *name)
32 {
33         struct callback_block *cb = (struct callback_block*) handle;
34         int count;
35         SV *ret;
36         char *s;
37         char *res;
38
39         dSP;
40
41         ENTER;
42         SAVETMPS;
43
44         PUSHMARK(SP);
45         XPUSHs(cb->handle);
46         XPUSHs(sv_2mortal(newSVpv(name, 0)));
47         PUTBACK;
48         /* Perl_sv_dump(0, cb->function); */
49
50         count = call_sv(cb->function, G_SCALAR);
51
52         SPAGAIN;
53
54         if (count != 1)
55                 croak("callback function for ZOOM_options_get() returned %d values: should have returned exactly one", count);
56
57         ret = POPs;
58         if (SvPOK(ret)) {
59                 s = SvPV_nolen(ret);
60                 /* ### `res' never gets freed!  I think it is
61                  * impossible to solve this problem "correctly"
62                  * because the ZOOM-C option callback interface is
63                  * inadequate. */
64                 res = xstrdup(s);
65         } else {
66                 res = 0;
67         }
68
69         PUTBACK;
70         FREETMPS;
71         LEAVE;
72
73         return res;
74 }
75
76
77 MODULE = Net::Z3950::ZOOM               PACKAGE = Net::Z3950::ZOOM              PREFIX=ZOOM_
78
79 PROTOTYPES: ENABLE
80
81
82 ZOOM_connection
83 ZOOM_connection_new(host, portnum)
84         const char* host
85         int portnum
86
87 ZOOM_connection
88 ZOOM_connection_create(options)
89         ZOOM_options options
90
91 void
92 ZOOM_connection_connect(c, host, portnum)
93         ZOOM_connection c
94         const char* host
95         int portnum
96
97 void
98 ZOOM_connection_destroy(c)
99         ZOOM_connection c
100
101 const char *
102 ZOOM_connection_option_get(c, key)
103         ZOOM_connection c
104         const char *key
105
106 struct datachunk
107 ZOOM_connection_option_getl(c, key, len)
108         ZOOM_connection c
109         const char* key
110         int &len
111         CODE:
112                 RETVAL.data = (char*) ZOOM_connection_option_getl(c, key, &len);
113                 RETVAL.len = len;
114         OUTPUT:
115                 RETVAL
116                 len
117
118 void
119 ZOOM_connection_option_set(c, key, val)
120         ZOOM_connection c
121         const char *key
122         const char *val
123
124 # In ZOOM-C, the `val' parameter is const char*.  However, our typemap
125 # treats this as T_PV, i.e. it's "known" that it points to a
126 # NUL-terminated string.  Instead, then, I here use opaquechar*, which
127 # is an opaque pointer.  The underlying C function can then use this
128 # along with `len' to Do The Right Thing.
129 #
130 void
131 ZOOM_connection_option_setl(c, key, val, len)
132         ZOOM_connection c
133         const char* key
134         opaquechar* val
135         int len
136
137 # The reference parameters, `cp' and `addinfo', need to already have
138 # values when this function is called, otherwise an "uninitialised
139 # value" warning is generated.  As far as I can see, there is no way
140 # around this: no way to specify in a prototype that an argument is
141 # allowed to be undefined, for example.  Since these function will
142 # never be called directly by well-behaved client code, but only by
143 # our own wrapper classes, I think we can live with that.
144 #
145 # The poxing about with cpp and caddinfo is due to Perl XS's lack of
146 # support for const char**, but who can blame it?  If you ask me, the
147 # whole "const" thing was well-intentioned by ghastly mistake.
148 #
149 int
150 ZOOM_connection_error(c, cp, addinfo)
151         ZOOM_connection c
152         char* &cp
153         char* &addinfo
154         CODE:
155                 {
156                 const char *ccp, *caddinfo;
157                 RETVAL = ZOOM_connection_error(c, &ccp, &caddinfo);
158                 cp = (char*) ccp;
159                 addinfo = (char*) caddinfo;
160                 }
161         OUTPUT:
162                 RETVAL
163                 cp
164                 addinfo
165
166 # See comments for ZOOM_connection_error() above
167 int
168 ZOOM_connection_error_x(c, cp, addinfo, diagset)
169         ZOOM_connection c
170         const char * &cp
171         const char * &addinfo
172         const char * &diagset
173         CODE:
174                 {
175                 const char *ccp, *caddinfo, *cdset;
176                 RETVAL = ZOOM_connection_error_x(c, &ccp, &caddinfo, &cdset);
177                 cp = (char*) ccp;
178                 addinfo = (char*) caddinfo;
179                 diagset = (char*) cdset;
180                 }
181         OUTPUT:
182                 RETVAL
183                 cp
184                 addinfo
185                 diagset
186
187 int
188 ZOOM_connection_errcode(c)
189         ZOOM_connection c
190
191 const char *
192 ZOOM_connection_errmsg(c)
193         ZOOM_connection c
194
195 const char *
196 ZOOM_connection_addinfo(c)
197         ZOOM_connection c
198
199 const char *
200 ZOOM_connection_diagset(c)
201         ZOOM_connection c
202
203 const char *
204 ZOOM_diag_str(error)
205         int error
206
207 ZOOM_resultset
208 ZOOM_connection_search(arg0, q)
209         ZOOM_connection arg0
210         ZOOM_query q
211
212 ZOOM_resultset
213 ZOOM_connection_search_pqf(c, q)
214         ZOOM_connection c
215         const char *q
216
217 void
218 ZOOM_resultset_destroy(r)
219         ZOOM_resultset r
220
221 const char *
222 ZOOM_resultset_option_get(r, key)
223         ZOOM_resultset r
224         const char* key
225
226 void
227 ZOOM_resultset_option_set(r, key, val)
228         ZOOM_resultset r
229         const char* key
230         const char* val
231
232 size_t
233 ZOOM_resultset_size(r)
234         ZOOM_resultset r
235
236 SV *
237 ZOOM_resultset_records(r, start, count, return_records)
238         ZOOM_resultset r
239         size_t start
240         size_t count
241         int return_records
242         CODE:
243                 {
244                 ZOOM_record *recs = 0;
245                 if (return_records)
246                         recs = (ZOOM_record*) xmalloc(count * sizeof *recs);
247                 ZOOM_resultset_records(r, recs, start, count);
248                 if (return_records) {
249                         AV *av = newAV();
250                         int i;
251                         for (i = 0; i < count; i++) {
252                                 SV *tmp = newSV(0);
253                                 sv_setref_pv(tmp, "ZOOM_record", (void*) recs[i]);
254                                 av_push(av, tmp);
255                         }
256                         RETVAL = newRV((SV*) av);
257                 } else {
258                         RETVAL = &PL_sv_undef;
259                 }
260                 }
261         OUTPUT:
262                 RETVAL
263
264 ZOOM_record
265 ZOOM_resultset_record(s, pos)
266         ZOOM_resultset s
267         size_t pos
268
269 ZOOM_record
270 ZOOM_resultset_record_immediate(s, pos)
271         ZOOM_resultset s
272         size_t pos
273
274 void
275 ZOOM_resultset_cache_reset(r)
276         ZOOM_resultset r
277
278 # TESTED (but deprecated)
279 void
280 ZOOM_resultset_sort(r, sort_type, sort_spec)
281         ZOOM_resultset r
282         const char* sort_type
283         const char* sort_spec
284
285 int
286 ZOOM_resultset_sort1(r, sort_type, sort_spec)
287         ZOOM_resultset r
288         const char* sort_type
289         const char* sort_spec
290
291 # See comments for ZOOM_connection_error() above
292 int
293 ZOOM_record_error(rec, cp, addinfo, diagset)
294         ZOOM_record rec
295         const char* &cp
296         const char* &addinfo
297         const char* &diagset
298         CODE:
299                 {
300                 const char *ccp = "", *caddinfo = "", *cdset = "";
301                 RETVAL = ZOOM_record_error(rec, &ccp, &caddinfo, &cdset);
302                 cp = (char*) ccp;
303                 addinfo = (char*) caddinfo;
304                 diagset = (char*) cdset;
305                 }
306         OUTPUT:
307                 RETVAL
308                 cp
309                 addinfo
310                 diagset
311
312 # See "typemap" for discussion of the "const char *" return-type.
313 #
314 ### but should use datachunk for in some (not all!) cases.
315 const char *
316 ZOOM_record_get(rec, type, len)
317         ZOOM_record rec
318         const char* type
319         int &len
320         OUTPUT:
321                 RETVAL
322                 len
323
324 void
325 ZOOM_record_destroy(rec)
326         ZOOM_record rec
327
328 ZOOM_record
329 ZOOM_record_clone(srec)
330         ZOOM_record srec
331
332 ZOOM_query
333 ZOOM_query_create()
334
335 void
336 ZOOM_query_destroy(s)
337         ZOOM_query s
338
339 int
340 ZOOM_query_cql(s, str)
341         ZOOM_query s
342         const char* str
343
344 int
345 ZOOM_query_cql2rpn(s, str, conn)
346         ZOOM_query s
347         const char* str
348         ZOOM_connection conn
349
350 int
351 ZOOM_query_ccl2rpn(s, query_str, config, errcode, errstr, errpos)
352         ZOOM_query s
353         const char* query_str
354         const char* config
355         int &errcode
356         const char* &errstr
357         int &errpos
358         OUTPUT:
359                 RETVAL
360                 errcode
361                 errstr
362                 errpos
363
364 int
365 ZOOM_query_prefix(s, str)
366         ZOOM_query s
367         const char* str
368
369 int
370 ZOOM_query_sortby(s, criteria)
371         ZOOM_query      s
372         const char *    criteria
373
374 ZOOM_scanset
375 ZOOM_connection_scan(c, startterm)
376         ZOOM_connection c
377         const char* startterm
378
379 ZOOM_scanset
380 ZOOM_connection_scan1(c, startterm)
381         ZOOM_connection c
382         ZOOM_query startterm
383
384 const char *
385 ZOOM_scanset_term(scan, pos, occ, len)
386         ZOOM_scanset scan
387         size_t pos
388         int& occ
389         int& len
390         OUTPUT:
391                 RETVAL
392                 occ
393                 len
394
395 const char *
396 ZOOM_scanset_display_term(scan, pos, occ, len)
397         ZOOM_scanset scan
398         size_t pos
399         int& occ
400         int& len
401         OUTPUT:
402                 RETVAL
403                 occ
404                 len
405
406 size_t
407 ZOOM_scanset_size(scan)
408         ZOOM_scanset scan
409
410 void
411 ZOOM_scanset_destroy(scan)
412         ZOOM_scanset scan
413
414 const char *
415 ZOOM_scanset_option_get(scan, key)
416         ZOOM_scanset    scan
417         const char *    key
418
419 void
420 ZOOM_scanset_option_set(scan, key, val)
421         ZOOM_scanset    scan
422         const char *    key
423         const char *    val
424
425 # We ignore the return value of ZOOM_options_set_callback(), since it
426 # is always just the address of the __ZOOM_option_callback() function.
427 # The information that we actually want -- the address of the Perl
428 # function in the callback_block -- is unavailable to us, as the
429 # underlying C function doesn't give the block back.
430 #
431 void
432 ZOOM_options_set_callback(opt, function, handle)
433         ZOOM_options opt
434         SV* function;
435         SV* handle;
436         CODE:
437                 {
438                 /* The tiny amount of memory allocated here is never
439                  * released, as options_destroy() doesn't do anything
440                  * to the callback information.  Not a big deal.
441                  * Also, I have no idea how to drive the Perl "mortal"
442                  * reference-counting stuff, so I am just allocating
443                  * copies which also never get released.  Don't sue!
444                  */
445                 struct callback_block *block = (struct callback_block*)
446                         xmalloc(sizeof *block);
447                 block->function = function;
448                 block->handle = handle;
449                 SvREFCNT(block->function);
450                 SvREFCNT(block->handle);
451                 ZOOM_options_set_callback(opt, __ZOOM_option_callback,
452                                           (void*) block);
453                 }
454
455 ZOOM_options
456 ZOOM_options_create()
457
458 ZOOM_options
459 ZOOM_options_create_with_parent(parent)
460         ZOOM_options parent
461
462 ZOOM_options
463 ZOOM_options_create_with_parent2(parent1, parent2)
464         ZOOM_options parent1
465         ZOOM_options parent2
466
467 const char *
468 ZOOM_options_get(opt, name)
469         ZOOM_options opt
470         const char* name
471
472 struct datachunk
473 ZOOM_options_getl(opt, name, len)
474         ZOOM_options opt
475         const char* name
476         int &len
477         CODE:
478                 RETVAL.data = (char*) ZOOM_options_getl(opt, name, &len);
479                 RETVAL.len = len;
480         OUTPUT:
481                 RETVAL
482                 len
483
484 void
485 ZOOM_options_set(opt, name, v)
486         ZOOM_options opt
487         const char* name
488         const char* v
489
490 void
491 ZOOM_options_setl(opt, name, value, len)
492         ZOOM_options opt
493         const char* name
494         opaquechar* value
495         int len
496
497 void
498 ZOOM_options_destroy(opt)
499         ZOOM_options opt
500
501 int
502 ZOOM_options_get_bool(opt, name, defa)
503         ZOOM_options opt
504         const char* name
505         int defa
506
507 int
508 ZOOM_options_get_int(opt, name, defa)
509         ZOOM_options opt
510         const char* name
511         int defa
512
513 void
514 ZOOM_options_set_int(opt, name, value)
515         ZOOM_options opt
516         const char* name
517         int value
518
519 ZOOM_package
520 ZOOM_connection_package(c, options)
521         ZOOM_connection c
522         ZOOM_options    options
523
524 void
525 ZOOM_package_destroy(p)
526         ZOOM_package    p
527
528 void
529 ZOOM_package_send(p, type)
530         ZOOM_package    p
531         const char *    type
532
533 const char *
534 ZOOM_package_option_get(p, key)
535         ZOOM_package    p
536         const char *    key
537
538 void
539 ZOOM_package_option_set(p, key, val)
540         ZOOM_package    p
541         const char *    key
542         const char *    val
543
544 # This has to be called with a single argument which is a _reference_
545 # to an array -- rather than directly with an array, which is of
546 # course identical to passing arbitrarily many arguments.  This is
547 # because there doesn't seem to be a way to do varargs in an XS
548 # function.
549 #
550 int
551 ZOOM_event(conns)
552         SV* conns
553         INIT:
554                 SV *realconns;
555                 I32 n, i;
556                 int res;
557                 ZOOM_connection *cs;
558         CODE:
559                 /*printf("* in ZOOM_event(%p)\n", conns);*/
560                 if (!SvROK(conns)) {
561                         /*printf("* argument is not a reference\n");*/
562                         XSRETURN_IV(-1);
563                 }
564                 realconns = SvRV(conns);
565                 /*printf("* realconns = %p\n", realconns);*/
566                 if (SvTYPE(realconns) != SVt_PVAV) {
567                         /*printf("* reference is not to an array\n");*/
568                         XSRETURN_IV(-2);
569                 }
570                 n = av_len((AV*) realconns);
571                 n++; /* The av_len() return-value is zero-based */
572                 if (n == 0) {
573                         /*printf("* No connections in referenced array\n");*/
574                         XSRETURN_IV(-3);
575                 }
576
577                 /*printf("* n = %d\n", n);*/
578                 if ((cs = (ZOOM_connection*) malloc(n * sizeof *cs)) == 0) {
579                         /*printf("* Too many connections (%d)\n", (int) n);*/
580                         XSRETURN_IV(-4);
581                 }
582
583                 for (i = 0; i < n; i++) {
584                     SV **connp = av_fetch((AV*) realconns, i, (I32) 0);
585                     SV *conn, *sv;
586                     /*printf("* %d of %d: connp = %p\n", (int) i, (int) n,connp);*/
587                     assert(connp != 0);
588                     conn = *connp;
589                     /*printf("* conn = %p\n", conn);*/
590                     /*
591                      * From here on, the tests and assertions seem to
592                      * be ignored: if I pass in a reference to
593                      * something other than a ZOOM_connection, or even
594                      * if I pass a non-reference, the assertions still
595                      * pass and everything seems to work until the
596                      * segmentation fault bites.
597                      */
598                     assert(sv_derived_from(conn, "ZOOM_connection"));
599                     /*printf("* passed assert(isa(ZOOM_connection))\n");*/
600                     assert(SvROK(conn));
601                     /*printf("* passed assert SvROK()\n");*/
602                     sv = (SV*) SvRV(conn);
603                     /*printf("* sv = %p\n", sv);*/
604                     cs[i] = INT2PTR(ZOOM_connection, SvIV(sv));
605                     /*printf("got cs[%d] of %d = %p\n", (int) i, (int) n, cs[i]);*/
606                 }
607                 RETVAL = ZOOM_event((int) n, cs);
608                 free(cs);
609         OUTPUT:
610                 RETVAL
611
612 int
613 ZOOM_connection_last_event(cs)
614         ZOOM_connection cs
615
616 int
617 ZOOM_connection_is_idle(cs)
618         ZOOM_connection cs
619
620 int
621 ZOOM_connection_peek_event(cs)
622         ZOOM_connection cs
623
624
625 # ----------------------------------------------------------------------------
626 # What follows is the YAZ logging API.  This is not strictly part of
627 # ZOOM, but it's so useful that it would be silly to omit.
628
629 int
630 yaz_log_mask_str(str)
631         const char *str
632
633 int
634 yaz_log_module_level(name)
635         const char *name
636
637 void
638 yaz_log_init(level, prefix, name)
639         int level
640         const char *prefix
641         const char *name
642
643 void
644 yaz_log_init_file(fname)
645         const char *fname
646
647 void
648 yaz_log_init_level(level)
649         int level
650
651 void
652 yaz_log_init_prefix(prefix)
653         const char *prefix
654
655 void
656 yaz_log_time_format(fmt)
657         const char *fmt
658
659 void
660 yaz_log_init_max_size(mx)
661         int mx
662
663 # <stdarg.h> interfaces are horrible to code for a Perl-C interface
664 # layer.  Instead, we expect Perl applications to construct the
665 # message themselves, and pass it in as an opaque lump.
666 void
667 yaz_log(level, str)
668         int level
669         const char *str
670         CODE:
671                 yaz_log(level, "%s", str);
672
673 # This is also not strictly part of ZOOM
674 unsigned long
675 yaz_version(version_str, sys_str)
676         char *version_str
677         char *sys_str
678         OUTPUT:
679                 RETVAL
680                 version_str
681                 sys_str
682