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