2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2004 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.0 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_0.txt. |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Adam Dickmeiss <adam@indexdata.dk> |
16 +----------------------------------------------------------------------+
19 /* $Id: php_yaz.c,v 1.115 2008/02/20 10:08:15 dickmeiss Exp $ */
30 #include "ext/standard/info.h"
33 #include <yaz/yaz-version.h>
36 #error YAZ version 4.0 or later must be used.
37 #elif YAZ_VERSIONL < 0x040000
38 #error YAZ version 4.0 or later must be used.
46 #include <yaz/proto.h>
47 #include <yaz/marcdisp.h>
48 #include <yaz/yaz-util.h>
49 #include <yaz/yaz-ccl.h>
50 #include <yaz/oid_db.h>
55 typedef struct Yaz_AssociationInfo *Yaz_Association;
57 struct Yaz_AssociationInfo {
59 ZOOM_connection zoom_conn;
60 ZOOM_resultset zoom_set;
61 ZOOM_scanset zoom_scan;
62 ZOOM_package zoom_package;
71 static Yaz_Association yaz_association_mk()
73 Yaz_Association p = xmalloc (sizeof(*p));
75 p->zoom_conn = ZOOM_connection_create (0);
79 ZOOM_connection_option_set(p->zoom_conn, "implementationName", "PHP");
80 ZOOM_connection_option_set(p->zoom_conn, "async", "1");
85 p->bibset = ccl_qual_mk();
90 static void yaz_association_destroy (Yaz_Association p)
96 ZOOM_resultset_destroy(p->zoom_set);
97 ZOOM_scanset_destroy(p->zoom_scan);
98 ZOOM_package_destroy(p->zoom_package);
99 ZOOM_connection_destroy(p->zoom_conn);
100 xfree(p->sort_criteria);
101 ccl_qual_rm(&p->bibset);
105 static MUTEX_T yaz_mutex;
108 ZEND_DECLARE_MODULE_GLOBALS(yaz);
110 static Yaz_Association *shared_associations;
111 static int order_associations;
115 #ifdef COMPILE_DL_YAZ
119 #ifdef ZEND_BEGIN_ARG_INFO
120 ZEND_BEGIN_ARG_INFO(first_argument_force_ref, 0)
121 ZEND_ARG_PASS_INFO(1)
124 ZEND_BEGIN_ARG_INFO(second_argument_force_ref, 0)
125 ZEND_ARG_PASS_INFO(0)
126 ZEND_ARG_PASS_INFO(1)
129 ZEND_BEGIN_ARG_INFO(third_argument_force_ref, 0)
130 ZEND_ARG_PASS_INFO(0)
131 ZEND_ARG_PASS_INFO(0)
132 ZEND_ARG_PASS_INFO(1)
135 static unsigned char first_argument_force_ref[] = {
137 static unsigned char second_argument_force_ref[] = {
138 2, BYREF_NONE, BYREF_FORCE };
139 static unsigned char third_argument_force_ref[] = {
140 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
144 function_entry yaz_functions [] = {
145 PHP_FE(yaz_connect, NULL)
146 PHP_FE(yaz_close, NULL)
147 PHP_FE(yaz_search, NULL)
148 PHP_FE(yaz_wait, first_argument_force_ref)
149 PHP_FE(yaz_errno, NULL)
150 PHP_FE(yaz_error, NULL)
151 PHP_FE(yaz_addinfo, NULL)
152 PHP_FE(yaz_hits, second_argument_force_ref)
153 PHP_FE(yaz_record, NULL)
154 PHP_FE(yaz_syntax, NULL)
155 PHP_FE(yaz_element, NULL)
156 PHP_FE(yaz_range, NULL)
157 PHP_FE(yaz_itemorder, NULL)
158 PHP_FE(yaz_es_result, NULL)
159 PHP_FE(yaz_scan, NULL)
160 PHP_FE(yaz_scan_result, second_argument_force_ref)
161 PHP_FE(yaz_present, NULL)
162 PHP_FE(yaz_ccl_conf, NULL)
163 PHP_FE(yaz_ccl_parse, third_argument_force_ref)
164 PHP_FE(yaz_database, NULL)
165 PHP_FE(yaz_sort, NULL)
166 PHP_FE(yaz_schema, NULL)
167 PHP_FE(yaz_set_option, NULL)
168 PHP_FE(yaz_get_option, NULL)
173 static void get_assoc(INTERNAL_FUNCTION_PARAMETERS, pval **id, Yaz_Association *assocp)
175 Yaz_Association *as = 0;
179 tsrm_mutex_lock (yaz_mutex);
182 ZEND_FETCH_RESOURCE(as, Yaz_Association *, id, -1, "YAZ link", le_link);
184 if (as && *as && (*as)->order == YAZSG(assoc_seq) && (*as)->in_use) {
188 tsrm_mutex_unlock (yaz_mutex);
190 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid YAZ handle");
194 static void release_assoc(Yaz_Association assoc)
198 tsrm_mutex_unlock(yaz_mutex);
203 static const char *array_lookup_string(HashTable *ht, const char *idx)
207 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
208 SEPARATE_ZVAL(pvalue);
209 convert_to_string(*pvalue);
210 return (*pvalue)->value.str.val;
215 static long *array_lookup_long(HashTable *ht, const char *idx)
219 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
220 SEPARATE_ZVAL(pvalue);
221 convert_to_long(*pvalue);
222 return &(*pvalue)->value.lval;
227 static long *array_lookup_bool(HashTable *ht, const char *idx)
231 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
232 SEPARATE_ZVAL(pvalue);
233 convert_to_boolean(*pvalue);
234 return &(*pvalue)->value.lval;
239 static const char *option_get(Yaz_Association as, const char *name)
244 return ZOOM_connection_option_get(as->zoom_conn, name);
247 static int option_get_int(Yaz_Association as, const char *name, int def)
251 v = ZOOM_connection_option_get(as->zoom_conn, name);
260 static void option_set(Yaz_Association as, const char *name, const char *value)
263 ZOOM_connection_option_set(as->zoom_conn, name, value);
267 static void option_set_int(Yaz_Association as, const char *name, int v)
272 sprintf (s, "%d", v);
273 ZOOM_connection_option_set(as->zoom_conn, name, s);
277 static int strcmp_null(const char *s1, const char *s2)
279 if (s1 == 0 && s2 == 0) {
282 if (s1 == 0 || s2 == 0) {
285 return strcmp(s1, s2);
288 /* {{{ proto resource yaz_connect(string zurl [, array options])
289 Create target with given zurl. Returns positive id if successful. */
290 PHP_FUNCTION(yaz_connect)
295 const char *sru_str = 0, *sru_version_str = 0;
296 const char *user_str = 0, *group_str = 0, *pass_str = 0;
297 const char *cookie_str = 0, *proxy_str = 0;
298 const char *charset_str = 0;
299 const char *client_IP = 0;
300 const char *otherInfo[3];
301 const char *maximumRecordSize = 0;
302 const char *preferredMessageSize = 0;
305 pval **zurl, **user = 0;
307 int max_links = YAZSG(max_links);
309 otherInfo[0] = otherInfo[1] = otherInfo[2] = 0;
311 if (ZEND_NUM_ARGS() == 1) {
312 if (zend_get_parameters_ex (1, &zurl) == FAILURE) {
315 } else if (ZEND_NUM_ARGS() == 2) {
316 if (zend_get_parameters_ex (2, &zurl, &user) == FAILURE) {
320 if (Z_TYPE_PP(user) == IS_ARRAY) {
321 long *persistent_val;
323 HashTable *ht = Z_ARRVAL_PP(user);
325 sru_str = array_lookup_string(ht, "sru");
326 sru_version_str = array_lookup_string(ht, "sru_version");
327 user_str = array_lookup_string(ht, "user");
328 group_str = array_lookup_string(ht, "group");
329 pass_str = array_lookup_string(ht, "password");
330 cookie_str = array_lookup_string(ht, "cookie");
331 proxy_str = array_lookup_string(ht, "proxy");
332 charset_str = array_lookup_string(ht, "charset");
333 persistent_val = array_lookup_bool(ht, "persistent");
334 if (persistent_val) {
335 persistent = *persistent_val;
337 piggyback_val = array_lookup_bool(ht, "piggyback");
339 piggyback = *piggyback_val;
342 array_lookup_string(ht, "maximumRecordSize");
343 preferredMessageSize =
344 array_lookup_string(ht, "preferredMessageSize");
345 otherInfo[0] = array_lookup_string(ht, "otherInfo0");
346 otherInfo[1] = array_lookup_string(ht, "otherInfo1");
347 otherInfo[2] = array_lookup_string(ht, "otherInfo2");
348 } else if (Z_TYPE_PP(user) == IS_STRING) {
349 convert_to_string_ex(user);
350 if (*(*user)->value.str.val)
351 user_str = (*user)->value.str.val;
356 convert_to_string_ex(zurl);
357 zurl_str = (*zurl)->value.str.val;
358 for (cp = zurl_str; *cp && strchr("\t\n ", *cp); cp++);
360 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty zurl");
363 /* see if we have it already ... */
365 tsrm_mutex_lock(yaz_mutex);
367 for (i = 0; i < max_links; i++) {
368 as = shared_associations[i];
369 if (persistent && as && !as->in_use &&
370 !strcmp_null(option_get(as, "host"), zurl_str) &&
371 !strcmp_null(option_get(as, "proxy"), proxy_str) &&
372 !strcmp_null(option_get(as, "sru"), sru_str) &&
373 !strcmp_null(option_get(as, "sru_version"), sru_version_str) &&
374 !strcmp_null(option_get(as, "user"), user_str) &&
375 !strcmp_null(option_get(as, "group"), group_str) &&
376 !strcmp_null(option_get(as, "pass"), pass_str) &&
377 !strcmp_null(option_get(as, "cookie"), cookie_str) &&
378 !strcmp_null(option_get(as, "charset"), charset_str))
381 if (i == max_links) {
382 /* we didn't have it (or already in use) */
384 int min_order = 2000000000;
386 /* find completely free slot or the oldest one */
387 for (i = 0; i < max_links && shared_associations[i]; i++) {
388 as = shared_associations[i];
389 if (persistent && !as->in_use && as->order < min_order) {
390 min_order = as->order;
395 if (i == max_links) {
400 tsrm_mutex_unlock (yaz_mutex);
402 sprintf(msg, "No YAZ handles available. max_links=%d",
404 php_error_docref(NULL TSRMLS_CC, E_WARNING,
405 "No YAZ handles available. max_links=%ld",
407 RETURN_LONG(0); /* no free slot */
408 } else { /* "best" free slot */
409 yaz_association_destroy(shared_associations[i]);
412 shared_associations[i] = as = yaz_association_mk ();
414 option_set(as, "proxy", proxy_str);
415 option_set(as, "sru", sru_str);
416 option_set(as, "sru_version", sru_version_str);
417 option_set(as, "user", user_str);
418 option_set(as, "group", group_str);
419 option_set(as, "pass", pass_str);
420 option_set(as, "cookie", cookie_str);
421 option_set(as, "charset", charset_str);
423 if (maximumRecordSize)
424 option_set(as, "maximumRecordSize", maximumRecordSize);
425 if (preferredMessageSize)
426 option_set(as, "preferredMessageSize", preferredMessageSize);
427 option_set(as, "otherInfo0", otherInfo[0]);
428 option_set(as, "otherInfo1", otherInfo[1]);
429 option_set(as, "otherInfo2", otherInfo[2]);
430 option_set(as, "clientIP", client_IP);
431 option_set(as, "piggyback", piggyback ? "1" : "0");
432 option_set_int(as, "start", 0);
433 option_set_int(as, "count", 0);
434 ZOOM_connection_connect(as->zoom_conn, zurl_str, 0);
436 as->persistent = persistent;
437 as->order = YAZSG(assoc_seq);
438 as->time_stamp = time(0);
442 ZOOM_resultset_destroy(as->zoom_set);
446 tsrm_mutex_unlock (yaz_mutex);
449 ZEND_REGISTER_RESOURCE(return_value, &shared_associations[i], le_link);
450 as->zval_resource = Z_LVAL_P(return_value);
454 /* {{{ proto bool yaz_close(resource id)
455 Destory and close target */
456 PHP_FUNCTION(yaz_close)
461 if (ZEND_NUM_ARGS() != 1) {
464 if (zend_get_parameters_ex (1, &id) == FAILURE) {
467 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
472 zend_list_delete((*id)->value.lval);
478 /* {{{ proto bool yaz_search(resource id, string type, string query)
479 Specify query of type for search - returns true if successful */
480 PHP_FUNCTION(yaz_search)
482 char *query_str, *type_str;
483 pval **id, **type, **query;
486 if (ZEND_NUM_ARGS() == 3) {
487 if (zend_get_parameters_ex(3, &id, &type, &query) == FAILURE) {
494 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
499 convert_to_string_ex(type);
500 type_str = (*type)->value.str.val;
501 convert_to_string_ex(query);
502 query_str = (*query)->value.str.val;
504 ZOOM_resultset_destroy(p->zoom_set);
509 if (!strcmp(type_str, "rpn")) {
510 ZOOM_query q = ZOOM_query_create();
511 if (ZOOM_query_prefix(q, query_str) == 0)
513 if (p->sort_criteria) {
514 ZOOM_query_sortby(q, p->sort_criteria);
516 xfree(p->sort_criteria);
517 p->sort_criteria = 0;
518 p->zoom_set = ZOOM_connection_search(p->zoom_conn, q);
521 ZOOM_query_destroy(q);
523 else if (!strcmp(type_str, "cql")) {
524 ZOOM_query q = ZOOM_query_create();
525 if (ZOOM_query_cql(q, query_str) == 0)
527 if (p->sort_criteria) {
528 ZOOM_query_sortby(q, p->sort_criteria);
530 xfree (p->sort_criteria);
531 p->sort_criteria = 0;
532 p->zoom_set = ZOOM_connection_search(p->zoom_conn, q);
535 ZOOM_query_destroy(q);
539 php_error_docref(NULL TSRMLS_CC, E_WARNING,
540 "Invalid query type %s", type_str);
546 /* {{{ proto bool yaz_present(resource id)
548 PHP_FUNCTION(yaz_present)
553 if (ZEND_NUM_ARGS() != 1) {
556 if (zend_get_parameters_ex(1, &id) == FAILURE) {
560 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
566 size_t start = option_get_int(p, "start", 0);
567 size_t count = option_get_int(p, "count", 0);
569 ZOOM_resultset_records(p->zoom_set, 0 /* recs */, start, count);
577 /* {{{ proto bool yaz_wait([array options])
579 PHP_FUNCTION(yaz_wait)
581 pval **pval_options = 0;
584 ZOOM_connection conn_ar[MAX_ASSOC];
585 Yaz_Association conn_as[MAX_ASSOC];
588 if (ZEND_NUM_ARGS() == 1) {
590 long *event_bool = 0;
591 HashTable *options_ht = 0;
592 if (zend_get_parameters_ex(1, &pval_options) == FAILURE) {
595 if (Z_TYPE_PP(pval_options) != IS_ARRAY) {
596 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array parameter");
599 options_ht = Z_ARRVAL_PP(pval_options);
600 val = array_lookup_long(options_ht, "timeout");
604 event_bool = array_lookup_bool(options_ht, "event");
605 if (event_bool && *event_bool)
609 tsrm_mutex_lock(yaz_mutex);
611 for (i = 0; i<YAZSG(max_links); i++) {
612 Yaz_Association p = shared_associations[i];
613 if (p && p->order == YAZSG(assoc_seq)) {
616 sprintf(str, "%d", timeout);
617 ZOOM_connection_option_set(p->zoom_conn, "timeout", str);
619 conn_ar[no++] = p->zoom_conn;
623 tsrm_mutex_unlock(yaz_mutex);
626 long ev = ZOOM_event(no, conn_ar);
630 Yaz_Association p = conn_as[ev-1];
631 int event_code = ZOOM_connection_last_event(p->zoom_conn);
633 add_assoc_long(*pval_options, "connid", ev);
635 add_assoc_long(*pval_options, "eventcode", event_code);
637 zend_list_addref(p->zval_resource);
638 Z_LVAL_P(return_value) = p->zval_resource;
639 Z_TYPE_P(return_value) = IS_RESOURCE;
645 while (ZOOM_event (no, conn_ar))
652 /* {{{ proto int yaz_errno(resource id)
653 Return last error number (>0 for bib-1 diagnostic, <0 for other error, 0 for no error */
654 PHP_FUNCTION(yaz_errno)
659 if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &id) == FAILURE) {
662 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
666 RETVAL_LONG(ZOOM_connection_errcode(p->zoom_conn));
671 /* {{{ proto string yaz_error(resource id)
672 Return last error message */
673 PHP_FUNCTION(yaz_error)
678 if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &id) == FAILURE) {
682 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
684 int code = ZOOM_connection_errcode(p->zoom_conn);
685 const char *msg = ZOOM_connection_errmsg(p->zoom_conn);
690 return_value->value.str.len = strlen(msg);
691 return_value->value.str.val = estrndup(msg, return_value->value.str.len);
692 return_value->type = IS_STRING;
698 /* {{{ proto string yaz_addinfo(resource id)
699 Return additional info for last error (empty string if none) */
700 PHP_FUNCTION(yaz_addinfo)
705 if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &id) == FAILURE) {
709 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
711 const char *addinfo = ZOOM_connection_addinfo(p->zoom_conn);
713 return_value->value.str.len = strlen(addinfo);
714 return_value->value.str.val = estrndup(addinfo, return_value->value.str.len);
715 return_value->type = IS_STRING;
721 /* {{{ proto int yaz_hits(resource id [, array searchresult])
722 Return number of hits (result count) for last search */
723 PHP_FUNCTION(yaz_hits)
725 pval **id, **searchresult = 0;
728 if (ZEND_NUM_ARGS() == 1) {
729 if (zend_get_parameters_ex(1, &id) == FAILURE) {
732 } else if (ZEND_NUM_ARGS() == 2) {
733 if (zend_get_parameters_ex(2, &id, &searchresult) == FAILURE) {
736 if (array_init(*searchresult) == FAILURE) {
737 php_error_docref(NULL TSRMLS_CC, E_WARNING,
738 "Could not initialize search result array");
745 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
746 if (p && p->zoom_set) {
747 RETVAL_LONG(ZOOM_resultset_size(p->zoom_set));
751 ZOOM_resultset_option_get(p->zoom_set, "resultSetStatus");
753 add_assoc_string(*searchresult, "resultSetStatus",
759 ZOOM_resultset_option_get(p->zoom_set, "searchresult.size");
763 if (sz_str && *sz_str)
765 for (i = 0; i<sz; i++)
768 const char *opt_value;
771 MAKE_STD_ZVAL(zval_element);
772 array_init(zval_element);
773 add_next_index_zval(*searchresult, zval_element);
775 sprintf(opt_name, "searchresult.%d.id", i);
776 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
778 add_assoc_string(zval_element, "id",
779 (char *) opt_value, 1);
781 sprintf(opt_name, "searchresult.%d.count", i);
782 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
784 add_assoc_long(zval_element, "count", atoi(opt_value));
786 sprintf(opt_name, "searchresult.%d.subquery.term", i);
787 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
789 add_assoc_string(zval_element, "subquery.term",
790 (char *) opt_value, 1);
792 sprintf(opt_name, "searchresult.%d.interpretation.term", i);
793 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
795 add_assoc_string(zval_element, "interpretation.term",
796 (char *) opt_value, 1);
798 sprintf(opt_name, "searchresult.%d.recommendation.term", i);
799 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
801 add_assoc_string(zval_element, "recommendation.term",
802 (char *) opt_value, 1);
813 static Z_GenericRecord *marc_to_grs1(const char *buf, ODR o)
817 int indicator_length;
818 int identifier_length;
820 int length_data_entry;
822 int length_implementation;
823 int max_elements = 256;
824 Z_GenericRecord *r = odr_malloc (o, sizeof(*r));
825 r->elements = odr_malloc (o, sizeof(*r->elements) * max_elements);
828 record_length = atoi_n(buf, 5);
829 if (record_length < 25) {
832 indicator_length = atoi_n(buf + 10, 1);
833 identifier_length = atoi_n(buf + 11, 1);
834 base_address = atoi_n(buf + 12, 5);
836 length_data_entry = atoi_n(buf + 20, 1);
837 length_starting = atoi_n(buf + 21, 1);
838 length_implementation = atoi_n(buf + 22, 1);
840 for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) {
841 entry_p += 3 + length_data_entry + length_starting;
842 if (entry_p >= record_length) {
848 Z_TaggedElement *tag;
849 tag = r->elements[r->num_elements++] = odr_malloc(o, sizeof(*tag));
850 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
852 tag->tagOccurrence = 0;
854 tag->appliedVariant = 0;
855 tag->tagValue = odr_malloc (o, sizeof(*tag->tagValue));
856 tag->tagValue->which = Z_StringOrNumeric_string;
857 tag->tagValue->u.string = odr_strdup(o, "leader");
859 tag->content = odr_malloc(o, sizeof(*tag->content));
860 tag->content->which = Z_ElementData_string;
861 tag->content->u.string = odr_strdupn(o, buf, 24);
863 base_address = entry_p + 1;
864 for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) {
865 Z_TaggedElement *tag;
871 int identifier_flag = 1;
873 memcpy(tag_str, buf+entry_p, 3);
877 if ((r->num_elements + 1) >= max_elements) {
878 Z_TaggedElement **tmp = r->elements;
880 /* double array space, throw away old buffer (nibble memory) */
881 r->elements = odr_malloc(o, sizeof(*r->elements) * (max_elements *= 2));
882 memcpy(r->elements, tmp, r->num_elements * sizeof(*tmp));
884 tag = r->elements[r->num_elements++] = odr_malloc(o, sizeof(*tag));
885 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
887 tag->tagOccurrence = 0;
889 tag->appliedVariant = 0;
890 tag->tagValue = odr_malloc (o, sizeof(*tag->tagValue));
891 tag->tagValue->which = Z_StringOrNumeric_string;
892 tag->tagValue->u.string = odr_strdup(o, tag_str);
894 tag->content = odr_malloc(o, sizeof(*tag->content));
895 tag->content->which = Z_ElementData_subtree;
897 tag->content->u.subtree = odr_malloc(o, sizeof(*tag->content->u.subtree));
898 tag->content->u.subtree->elements = odr_malloc(o, sizeof(*r->elements));
899 tag->content->u.subtree->num_elements = 1;
901 tag = tag->content->u.subtree->elements[0] = odr_malloc(o, sizeof(**tag->content->u.subtree->elements));
903 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
905 tag->tagOccurrence = 0;
907 tag->appliedVariant = 0;
908 tag->tagValue = odr_malloc(o, sizeof(*tag->tagValue));
909 tag->tagValue->which = Z_StringOrNumeric_string;
910 tag->content = odr_malloc(o, sizeof(*tag->content));
912 data_length = atoi_n(buf + entry_p, length_data_entry);
913 entry_p += length_data_entry;
914 data_offset = atoi_n(buf + entry_p, length_starting);
915 entry_p += length_starting;
916 i = data_offset + base_address;
917 end_offset = i + data_length - 1;
919 if (indicator_length > 0 && indicator_length < 5) {
920 if (buf[i + indicator_length] != ISO2709_IDFS) {
923 } else if (!memcmp (tag_str, "00", 2)) {
927 if (identifier_flag && indicator_length) {
929 tag->tagValue->u.string = odr_malloc(o, indicator_length + 1);
930 memcpy(tag->tagValue->u.string, buf + i, indicator_length);
931 tag->tagValue->u.string[indicator_length] = '\0';
932 i += indicator_length;
934 tag->content->which = Z_ElementData_subtree;
936 tag->content->u.subtree = odr_malloc(o, sizeof(*tag->content->u.subtree));
937 tag->content->u.subtree->elements = odr_malloc(o, 256 * sizeof(*r->elements));
938 tag->content->u.subtree->num_elements = 0;
940 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset) {
943 Z_TaggedElement *parent_tag = tag;
944 Z_TaggedElement *tag = odr_malloc (o, sizeof(*tag));
946 if (parent_tag->content->u.subtree->num_elements < 256) {
947 parent_tag->content->u.subtree->elements[
948 parent_tag->content->u.subtree->num_elements++] = tag;
951 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
953 tag->tagOccurrence = 0;
955 tag->appliedVariant = 0;
956 tag->tagValue = odr_malloc (o, sizeof(*tag->tagValue));
957 tag->tagValue->which = Z_StringOrNumeric_string;
960 tag->tagValue->u.string = odr_malloc(o, identifier_length);
961 memcpy(tag->tagValue->u.string, buf + i + 1, identifier_length - 1);
962 tag->tagValue->u.string[identifier_length - 1] = '\0';
963 i += identifier_length;
966 tag->content = odr_malloc(o, sizeof(*tag->content));
967 tag->content->which = Z_ElementData_string;
970 while ( buf[i] != ISO2709_RS &&
971 buf[i] != ISO2709_IDFS &&
972 buf[i] != ISO2709_FS && i < end_offset) {
976 tag->content->u.string = odr_malloc(o, i - i0 + 1);
977 memcpy(tag->content->u.string, buf + i0, i - i0);
978 tag->content->u.string[i - i0] = '\0';
983 tag->tagValue->u.string = "@";
984 tag->content->which = Z_ElementData_string;
986 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset) {
989 tag->content->u.string = odr_malloc(o, i - i0 +1);
990 memcpy(tag->content->u.string, buf + i0, i - i0);
991 tag->content->u.string[i-i0] = '\0';
1004 static struct cvt_handle *cvt_open(const char *to, const char *from)
1006 ODR o = odr_createmem(ODR_ENCODE);
1008 struct cvt_handle *cvt = odr_malloc(o, sizeof(*cvt));
1011 cvt->buf = odr_malloc(o, cvt->size);
1014 cvt->cd = yaz_iconv_open(to, from);
1018 static void cvt_close(struct cvt_handle *cvt)
1021 yaz_iconv_close(cvt->cd);
1022 odr_destroy(cvt->odr);
1025 static const char *cvt_string(const char *input, struct cvt_handle *cvt)
1030 size_t inbytesleft = strlen(input);
1031 const char *inp = input;
1032 size_t outbytesleft = cvt->size - 1;
1033 char *outp = cvt->buf;
1034 size_t r = yaz_iconv(cvt->cd, (char**) &inp, &inbytesleft,
1035 &outp, &outbytesleft);
1036 if (r == (size_t) (-1)) {
1037 int e = yaz_iconv_error(cvt->cd);
1038 if (e != YAZ_ICONV_E2BIG || cvt->size > 200000)
1043 cvt->size = cvt->size * 2 + 30;
1044 cvt->buf = (char*) odr_malloc(cvt->odr, cvt->size);
1046 cvt->buf[outp - cvt->buf] = '\0';
1053 static void retval_array3_grs1(zval *return_value, Z_GenericRecord *p,
1054 struct cvt_handle *cvt)
1060 struct tag_list *next;
1062 NMEM nmem = nmem_create();
1064 array_init(return_value);
1065 for (i = 0; i<p->num_elements; i++)
1067 struct tag_list *tl;
1070 Z_TaggedElement *e = p->elements[i];
1071 char tagstr[32], *tag = 0;
1073 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1075 sprintf(tagstr, "%d", *e->tagValue->u.numeric);
1078 else if (e->tagValue->which == Z_StringOrNumeric_string)
1079 tag = e->tagValue->u.string, zval_element;
1084 for (tl = all_tags; tl; tl = tl->next)
1085 if (!strcmp(tl->tag, tag))
1088 zval_list = tl->zval_list;
1091 MAKE_STD_ZVAL(zval_list);
1092 array_init(zval_list);
1093 add_assoc_zval(return_value, tag, zval_list);
1095 tl = nmem_malloc(nmem, sizeof(*tl));
1096 tl->tag = nmem_strdup(nmem, tag);
1097 tl->zval_list = zval_list;
1098 tl->next = all_tags;
1101 MAKE_STD_ZVAL(zval_element);
1102 array_init(zval_element);
1103 add_next_index_zval(zval_list, zval_element);
1104 if (e->content->which == Z_ElementData_subtree)
1106 /* we have a subtree. Move to first child */
1107 Z_GenericRecord *sub = e->content->u.subtree;
1108 if (sub->num_elements >= 1)
1109 e = sub->elements[0];
1115 const char *tag = 0;
1116 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1118 sprintf(tagstr, "%d", *e->tagValue->u.numeric);
1121 else if (e->tagValue->which == Z_StringOrNumeric_string)
1122 tag = e->tagValue->u.string;
1123 if (tag && e->content->which == Z_ElementData_subtree)
1126 Z_GenericRecord *sub = e->content->u.subtree;
1128 for (i = 0; tag[i]; i++)
1133 sprintf(ind_idx, "ind%d", i+1);
1134 ind_val[0] = tag[i];
1137 add_assoc_string(zval_element, ind_idx, ind_val, 1);
1139 for (i = 0; i<sub->num_elements; i++)
1141 Z_TaggedElement *e = sub->elements[i];
1142 const char *tag = 0;
1143 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1145 sprintf(tagstr, "%d", *e->tagValue->u.numeric);
1148 else if (e->tagValue->which == Z_StringOrNumeric_string)
1149 tag = e->tagValue->u.string, zval_element;
1151 if (tag && e->content->which == Z_ElementData_string)
1153 const char *v = cvt_string(e->content->u.string, cvt);
1154 add_assoc_string(zval_element, (char*) tag, (char*) v,
1159 else if (tag && e->content->which == Z_ElementData_string)
1161 /* Leader or control field */
1162 const char *v = cvt_string(e->content->u.string, cvt);
1163 ZVAL_STRING(zval_element, (char*) v, 1);
1170 static void retval_array2_grs1(zval *return_value, Z_GenericRecord *p,
1171 struct cvt_handle *cvt)
1175 array_init(return_value);
1177 for (i = 0; i<p->num_elements; i++)
1181 Z_TaggedElement *e = p->elements[i];
1183 MAKE_STD_ZVAL(zval_element);
1184 array_init(zval_element);
1187 add_assoc_long(zval_element, "tagType", *e->tagType);
1189 if (e->tagValue->which == Z_StringOrNumeric_string)
1190 add_assoc_string(zval_element, "tag", e->tagValue->u.string, 1);
1191 else if (e->tagValue->which == Z_StringOrNumeric_numeric)
1192 add_assoc_long(zval_element, "tag", *e->tagValue->u.numeric);
1194 switch (e->content->which) {
1195 case Z_ElementData_string:
1198 const char *v = cvt_string(e->content->u.string, cvt);
1199 add_assoc_string(zval_element, "content", (char*) v, 1);
1202 case Z_ElementData_numeric:
1203 add_assoc_long(zval_element, "content",*e->content->u.numeric);
1205 case Z_ElementData_trueOrFalse:
1206 add_assoc_bool(zval_element, "content",*e->content->u.trueOrFalse);
1208 case Z_ElementData_subtree:
1209 MAKE_STD_ZVAL(zval_sub);
1210 retval_array2_grs1(zval_sub, e->content->u.subtree, cvt);
1211 add_assoc_zval(zval_element, "content", zval_sub);
1213 add_next_index_zval(return_value, zval_element);
1217 static void retval_array1_grs1(zval *return_value, Z_GenericRecord *p,
1218 struct cvt_handle *cvt)
1220 Z_GenericRecord *grs[20];
1224 array_init(return_value);
1228 while (level >= 0) {
1230 Z_TaggedElement *e = 0;
1231 Z_GenericRecord *p = grs[level];
1236 if (eno[level] >= p->num_elements) {
1243 for (i = 0; i <= level; i++) {
1245 e = grs[i]->elements[eno[i]];
1248 tag_type = *e->tagType;
1250 taglen = strlen(tag);
1251 sprintf(tag + taglen, "(%d,", tag_type);
1252 taglen = strlen(tag);
1254 if (e->tagValue->which == Z_StringOrNumeric_string) {
1255 int len = strlen(e->tagValue->u.string);
1257 memcpy(tag + taglen, e->tagValue->u.string, len);
1258 tag[taglen+len] = '\0';
1259 } else if (e->tagValue->which == Z_StringOrNumeric_numeric) {
1260 sprintf(tag + taglen, "%d", *e->tagValue->u.numeric);
1262 taglen = strlen(tag);
1263 strcpy(tag + taglen, ")");
1266 ALLOC_ZVAL(my_zval);
1267 array_init(my_zval);
1268 INIT_PZVAL(my_zval);
1270 add_next_index_string(my_zval, tag, 1);
1272 switch (e->content->which) {
1273 case Z_ElementData_string:
1276 const char *v = cvt_string(e->content->u.string, cvt);
1277 add_next_index_string(my_zval, (char*) v, 1);
1280 case Z_ElementData_numeric:
1281 add_next_index_long(my_zval, *e->content->u.numeric);
1283 case Z_ElementData_trueOrFalse:
1284 add_next_index_long(my_zval, *e->content->u.trueOrFalse);
1286 case Z_ElementData_subtree:
1289 grs[level] = e->content->u.subtree;
1293 zend_hash_next_index_insert(return_value->value.ht, (void *) &my_zval, sizeof(zval *), NULL);
1298 static void ext_grs1(zval *return_value, char type_args[][60],
1300 void (*array_func)(zval *, Z_GenericRecord *,
1301 struct cvt_handle *))
1303 Z_External *ext = (Z_External *) ZOOM_record_get(r, "ext", 0);
1304 if (ext && ext->which == Z_External_OPAC)
1305 ext = ext->u.opac->bibliographicRecord;
1307 struct cvt_handle *cvt = 0;
1308 if (type_args[2][0])
1309 cvt = cvt_open(type_args[3], type_args[2]);
1311 cvt = cvt_open(0, 0);
1313 if (ext->which == Z_External_grs1) {
1314 retval_array1_grs1(return_value, ext->u.grs1, cvt);
1315 } else if (ext->which == Z_External_octet) {
1316 Z_GenericRecord *rec = 0;
1317 if (yaz_oid_is_iso2709(ext->direct_reference))
1319 char *buf = (char *) (ext->u.octet_aligned->buf);
1320 rec = marc_to_grs1(buf, cvt->odr);
1323 (*array_func)(return_value, rec, cvt);
1331 /* {{{ proto string yaz_record(resource id, int pos, string type)
1332 Return record information at given result set position */
1333 PHP_FUNCTION(yaz_record)
1335 pval **pval_id, **pval_pos, **pval_type;
1340 if (ZEND_NUM_ARGS() != 3) {
1343 if (zend_get_parameters_ex(3, &pval_id, &pval_pos, &pval_type) == FAILURE) {
1347 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1349 convert_to_long_ex(pval_pos);
1350 pos = (*pval_pos)->value.lval;
1351 convert_to_string_ex(pval_type);
1352 type = (*pval_type)->value.str.val;
1354 if (p && p->zoom_set) {
1356 char type_args[4][60]; /* 0; 1=2,3 (1 is assumed charset) */
1357 type_args[0][0] = 0;
1358 type_args[1][0] = 0;
1359 type_args[2][0] = 0;
1360 type_args[3][0] = 0;
1361 sscanf(type, "%59[^;];%59[^=]=%59[^,],%59[^,]", type_args[0],
1362 type_args[1], type_args[2], type_args[3]);
1363 r = ZOOM_resultset_record(p->zoom_set, pos-1);
1364 if (!strcmp(type_args[0], "string")) {
1368 if (!strcmp(type_args[0], "array") ||
1369 !strcmp(type_args[0], "array1"))
1371 ext_grs1(return_value, type_args, r, retval_array1_grs1);
1372 } else if (!strcmp(type_args[0], "array2")) {
1373 ext_grs1(return_value, type_args, r, retval_array2_grs1);
1374 } else if (!strcmp(type_args[0], "array3")) {
1375 ext_grs1(return_value, type_args, r, retval_array3_grs1);
1378 const char *info = ZOOM_record_get(r, type, &rlen);
1380 return_value->value.str.len = (rlen > 0) ? rlen : 0;
1381 return_value->value.str.val =
1382 estrndup(info, return_value->value.str.len);
1383 return_value->type = IS_STRING;
1387 php_error_docref(NULL TSRMLS_CC, E_WARNING,
1388 "Bad yaz_record type %s - or unable "
1389 "to return record with type given", type);
1398 /* {{{ proto void yaz_syntax(resource id, string syntax)
1399 Set record syntax for retrieval */
1400 PHP_FUNCTION(yaz_syntax)
1402 pval **pval_id, **pval_syntax;
1405 if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_syntax) == FAILURE) {
1409 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1410 convert_to_string_ex(pval_syntax);
1411 option_set(p, "preferredRecordSyntax", (*pval_syntax)->value.str.val);
1416 /* {{{ proto void yaz_element(resource id, string elementsetname)
1417 Set Element-Set-Name for retrieval */
1418 PHP_FUNCTION(yaz_element)
1420 pval **pval_id, **pval_element;
1423 if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_element) == FAILURE) {
1427 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1429 convert_to_string_ex(pval_element);
1430 option_set(p, "elementSetName", (*pval_element)->value.str.val);
1435 /* {{{ proto void yaz_schema(resource id, string schema)
1436 Set Schema for retrieval */
1437 PHP_FUNCTION(yaz_schema)
1439 pval **pval_id, **pval_element;
1442 if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_element) == FAILURE) {
1446 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1447 convert_to_string_ex(pval_element);
1448 option_set(p, "schema", (*pval_element)->value.str.val);
1453 /* {{{ proto void yaz_set_option(resource id, mixed options)
1454 Set Option(s) for connection */
1455 PHP_FUNCTION(yaz_set_option)
1457 pval **pval_ar, **pval_name, **pval_val, **pval_id;
1460 if (ZEND_NUM_ARGS() == 2) {
1461 if (zend_get_parameters_ex(2, &pval_id, &pval_ar) == FAILURE) {
1464 if (Z_TYPE_PP(pval_ar) != IS_ARRAY) {
1467 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1473 ht = Z_ARRVAL_PP(pval_ar);
1474 for(zend_hash_internal_pointer_reset_ex(ht, &pos);
1475 zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
1476 zend_hash_move_forward_ex(ht, &pos)
1480 #if PHP_API_VERSION > 20010101
1481 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
1483 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
1485 if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
1488 option_set(p, key, (*ent)->value.str.val);
1492 } else if (ZEND_NUM_ARGS() == 3) {
1493 if (zend_get_parameters_ex(3, &pval_id, &pval_name, &pval_val) == FAILURE) {
1496 get_assoc (INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1497 convert_to_string_ex(pval_name);
1498 convert_to_string_ex(pval_val);
1499 option_set(p, (*pval_name)->value.str.val, (*pval_val)->value.str.val);
1508 /* {{{ proto string yaz_get_option(resource id, string name)
1509 Set Option(s) for connection */
1510 PHP_FUNCTION(yaz_get_option)
1512 pval **pval_id, **pval_name;
1515 if (ZEND_NUM_ARGS() != 2) {
1518 if (zend_get_parameters_ex(2, &pval_id, &pval_name) == FAILURE) {
1522 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1524 const char *name_str, *v;
1525 convert_to_string_ex (pval_name);
1526 name_str = (*pval_name)->value.str.val;
1528 v = option_get(p, name_str);
1532 return_value->value.str.len = strlen(v);
1533 return_value->value.str.val = estrndup(v, return_value->value.str.len);
1534 return_value->type = IS_STRING;
1542 /* {{{ proto void yaz_range(resource id, int start, int number)
1543 Set result set start point and number of records to request */
1544 PHP_FUNCTION(yaz_range)
1546 pval **pval_id, **pval_start, **pval_number;
1549 if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &pval_id, &pval_start, &pval_number) == FAILURE) {
1553 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1554 convert_to_long_ex(pval_start);
1555 convert_to_long_ex(pval_number);
1556 option_set_int(p, "start", (*pval_start)->value.lval - 1);
1557 option_set_int(p, "count", (*pval_number)->value.lval);
1562 /* {{{ proto void yaz_sort(resource id, string sortspec)
1563 Set result set sorting criteria */
1564 PHP_FUNCTION(yaz_sort)
1566 pval **pval_id, **pval_criteria;
1569 if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_criteria) == FAILURE) {
1573 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1575 convert_to_string_ex(pval_criteria);
1576 xfree(p->sort_criteria);
1577 p->sort_criteria = xstrdup((*pval_criteria)->value.str.val);
1579 ZOOM_resultset_sort(p->zoom_set, "yaz",
1580 (*pval_criteria)->value.str.val);
1586 const char *ill_array_lookup (void *handle, const char *name)
1588 return array_lookup_string((HashTable *) handle, name);
1591 /* {{{ proto void yaz_itemorder(resource id, array package)
1592 Sends Item Order request */
1593 PHP_FUNCTION(yaz_itemorder)
1595 pval **pval_id, **pval_package;
1598 if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_package) == FAILURE) {
1601 if (Z_TYPE_PP(pval_package) != IS_ARRAY) {
1602 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array parameter");
1606 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1608 ZOOM_options options = ZOOM_options_create();
1610 ZOOM_options_set_callback(options, ill_array_lookup, Z_ARRVAL_PP(pval_package));
1611 ZOOM_package_destroy(p->zoom_package);
1612 p->zoom_package = ZOOM_connection_package(p->zoom_conn, options);
1613 ZOOM_package_send(p->zoom_package, "itemorder");
1614 ZOOM_options_set_callback(options, 0, 0);
1615 ZOOM_options_destroy (options);
1621 /* {{{ proto void yaz_es(resource id, string type, array package)
1622 Sends Extended Services Request */
1623 PHP_FUNCTION(yaz_es)
1625 pval **pval_id, **pval_type, **pval_package;
1628 if (ZEND_NUM_ARGS() != 3 ||
1629 zend_get_parameters_ex(3, &pval_id, &pval_type,
1630 &pval_package) == FAILURE) {
1633 if (Z_TYPE_PP(pval_type) != IS_STRING) {
1634 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected string parameter");
1638 if (Z_TYPE_PP(pval_package) != IS_ARRAY) {
1639 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array parameter");
1643 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1645 ZOOM_options options = ZOOM_options_create();
1647 ZOOM_options_set_callback(options, ill_array_lookup, Z_ARRVAL_PP(pval_package));
1648 ZOOM_package_destroy(p->zoom_package);
1649 p->zoom_package = ZOOM_connection_package(p->zoom_conn, options);
1650 ZOOM_package_send(p->zoom_package, (*pval_type)->value.str.val);
1651 ZOOM_options_set_callback(options, 0, 0);
1652 ZOOM_options_destroy (options);
1658 /* {{{ proto void yaz_scan(resource id, type, query [, flags])
1659 Sends Scan Request */
1660 PHP_FUNCTION(yaz_scan)
1662 pval **pval_id, **pval_type, **pval_query, **pval_flags = 0;
1663 HashTable *flags_ht = 0;
1666 if (ZEND_NUM_ARGS() == 3) {
1667 if (zend_get_parameters_ex(3, &pval_id, &pval_type, &pval_query) == FAILURE) {
1670 } else if (ZEND_NUM_ARGS() == 4) {
1671 if (zend_get_parameters_ex(4, &pval_id, &pval_type, &pval_query, &pval_flags) == FAILURE) {
1674 if (Z_TYPE_PP(pval_flags) != IS_ARRAY) {
1675 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad flags parameter");
1678 flags_ht = Z_ARRVAL_PP(pval_flags);
1683 convert_to_string_ex(pval_type);
1684 convert_to_string_ex(pval_query);
1686 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1687 ZOOM_scanset_destroy(p->zoom_scan);
1690 option_set(p, "number", array_lookup_string(flags_ht, "number"));
1691 option_set(p, "position", array_lookup_string(flags_ht, "position"));
1692 option_set(p, "stepSize", array_lookup_string(flags_ht, "stepsize"));
1693 p->zoom_scan = ZOOM_connection_scan(p->zoom_conn, Z_STRVAL_PP(pval_query));
1699 /* {{{ proto array yaz_es_result(resource id)
1700 Inspects Extended Services Result */
1701 PHP_FUNCTION(yaz_es_result)
1706 if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &pval_id) == FAILURE) {
1710 array_init(return_value);
1712 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1713 if (p && p->zoom_package) {
1714 const char *str = ZOOM_package_option_get(p->zoom_package,
1718 add_assoc_string(return_value, "targetReference", (char *) str, 1);
1720 str = ZOOM_package_option_get(p->zoom_package,
1723 add_assoc_string(return_value, "xmlUpdateDoc", (char *) str, 1);
1730 /* {{{ proto array yaz_scan_result(resource id [, array options])
1731 Inspects Scan Result */
1732 PHP_FUNCTION(yaz_scan_result)
1734 pval **pval_id, **pval_opt = 0;
1737 if (ZEND_NUM_ARGS() == 2) {
1738 if (zend_get_parameters_ex(2, &pval_id, &pval_opt) == FAILURE) {
1741 } else if (ZEND_NUM_ARGS() == 1) {
1742 if (zend_get_parameters_ex(1, &pval_id) == FAILURE) {
1749 array_init(return_value);
1751 if (pval_opt && array_init(*pval_opt) == FAILURE) {
1755 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1756 if (p && p->zoom_scan) {
1759 int size = ZOOM_scanset_size(p->zoom_scan);
1761 for (pos = 0; pos < size; pos++) {
1762 const char *term = ZOOM_scanset_term(p->zoom_scan, pos, &occ, &len);
1765 ALLOC_ZVAL(my_zval);
1766 array_init(my_zval);
1767 INIT_PZVAL(my_zval);
1769 add_next_index_string(my_zval, "term", 1);
1772 add_next_index_stringl(my_zval, (char*) term, len, 1);
1774 add_next_index_string(my_zval, "?", 1);
1776 add_next_index_long(my_zval, occ);
1778 term = ZOOM_scanset_display_term(p->zoom_scan, pos, &occ, &len);
1781 add_next_index_stringl(my_zval, (char*) term, len, 1);
1783 add_next_index_string(my_zval, "?", 1);
1786 zend_hash_next_index_insert(return_value->value.ht, (void *) &my_zval, sizeof(zval *), NULL);
1792 add_assoc_long(*pval_opt, "number", size);
1794 v = ZOOM_scanset_option_get(p->zoom_scan, "stepSize");
1796 add_assoc_long(*pval_opt, "stepsize", atoi(v));
1798 v = ZOOM_scanset_option_get(p->zoom_scan, "position");
1800 add_assoc_long(*pval_opt, "position", atoi(v));
1802 v = ZOOM_scanset_option_get(p->zoom_scan, "scanStatus");
1804 add_assoc_long(*pval_opt, "status", atoi(v));
1812 /* {{{ proto void yaz_ccl_conf(resource id, array package)
1813 Configure CCL package */
1814 PHP_FUNCTION(yaz_ccl_conf)
1816 pval **pval_id, **pval_package;
1819 if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_package) == FAILURE) {
1823 if (Z_TYPE_PP(pval_package) != IS_ARRAY) {
1824 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array parameter");
1828 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1830 HashTable *ht = Z_ARRVAL_PP(pval_package);
1835 ccl_qual_rm(&p->bibset);
1836 p->bibset = ccl_qual_mk();
1838 for(zend_hash_internal_pointer_reset_ex(ht, &pos);
1839 zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
1840 zend_hash_move_forward_ex(ht, &pos)
1843 #if PHP_API_VERSION > 20010101
1844 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
1846 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
1848 if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
1851 ccl_qual_fitem(p->bibset, (*ent)->value.str.val, key);
1858 /* {{{ proto bool yaz_ccl_parse(resource id, string query, array res)
1859 Parse a CCL query */
1860 PHP_FUNCTION(yaz_ccl_parse)
1862 pval **pval_id, **pval_query, **pval_res = 0;
1865 if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &pval_id, &pval_query, &pval_res) == FAILURE) {
1869 pval_destructor(*pval_res);
1870 array_init(*pval_res);
1871 convert_to_string_ex (pval_query);
1873 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1875 const char *query_str = (*pval_query)->value.str.val;
1876 struct ccl_rpn_node *rpn;
1879 CCL_parser ccl_parser = ccl_parser_create(p->bibset);
1881 rpn = ccl_parser_find_str(ccl_parser, query_str);
1883 error_code = ccl_parser_get_error(ccl_parser, &error_pos);
1884 add_assoc_long(*pval_res, "errorcode", error_code);
1888 add_assoc_string(*pval_res, "errorstring",
1889 (char *) ccl_err_msg(error_code), 1);
1890 add_assoc_long(*pval_res, "errorpos", error_pos);
1895 WRBUF wrbuf_pqf = wrbuf_alloc();
1896 ccl_stop_words_t csw = ccl_stop_words_create();
1897 int r = ccl_stop_words_tree(csw, p->bibset, &rpn);
1901 /* stop words were removed. Return stopwords info */
1902 zval *zval_stopwords;
1905 MAKE_STD_ZVAL(zval_stopwords);
1906 array_init(zval_stopwords);
1907 for (idx = 0; ; idx++)
1909 zval *zval_stopword;
1913 if (!ccl_stop_words_info(csw, idx, &qname, &term))
1916 MAKE_STD_ZVAL(zval_stopword);
1917 array_init(zval_stopword);
1919 add_assoc_string(zval_stopword, "field", (char *) qname, 1);
1920 add_assoc_string(zval_stopword, "term", (char *) term, 1);
1921 add_next_index_zval(zval_stopwords, zval_stopword);
1923 add_assoc_zval(*pval_res, "stopwords", zval_stopwords);
1925 ccl_pquery(wrbuf_pqf, rpn);
1926 add_assoc_stringl(*pval_res, "rpn",
1927 wrbuf_buf(wrbuf_pqf), wrbuf_len(wrbuf_pqf), 1);
1928 wrbuf_destroy(wrbuf_pqf);
1929 ccl_stop_words_destroy(csw);
1932 ccl_rpn_delete(rpn);
1940 /* {{{ proto bool yaz_database (resource id, string databases)
1941 Specify the databases within a session */
1942 PHP_FUNCTION(yaz_database)
1944 pval **pval_id, **pval_database;
1947 if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_database) == FAILURE) {
1951 convert_to_string_ex(pval_database);
1952 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1953 option_set(p, "databaseName", (*pval_database)->value.str.val);
1959 /* {{{ php_yaz_init_globals
1961 static void php_yaz_init_globals(zend_yaz_globals *yaz_globals)
1963 yaz_globals->assoc_seq = 0;
1964 yaz_globals->max_links = 100;
1965 yaz_globals->keepalive = 120;
1966 yaz_globals->log_file = NULL;
1967 yaz_globals->log_mask = NULL;
1971 static void yaz_close_session(Yaz_Association *as TSRMLS_DC)
1973 if (*as && (*as)->order == YAZSG(assoc_seq)) {
1974 if ((*as)->persistent) {
1977 yaz_association_destroy(*as);
1983 static void yaz_close_link (zend_rsrc_list_entry *rsrc TSRMLS_DC)
1985 Yaz_Association *as = (Yaz_Association *) rsrc->ptr;
1986 yaz_close_session(as TSRMLS_CC);
1989 /* {{{ PHP_INI_BEGIN
1992 #if PHP_MAJOR_VERSION >= 5
1993 STD_PHP_INI_ENTRY("yaz.max_links", "100", PHP_INI_ALL, OnUpdateLong, max_links, zend_yaz_globals, yaz_globals)
1995 STD_PHP_INI_ENTRY("yaz.max_links", "100", PHP_INI_ALL, OnUpdateInt, max_links, zend_yaz_globals, yaz_globals)
1997 #if PHP_MAJOR_VERSION >= 5
1998 STD_PHP_INI_ENTRY("yaz.keepalive", "120", PHP_INI_ALL, OnUpdateLong, keepalive, zend_yaz_globals, yaz_globals)
2000 STD_PHP_INI_ENTRY("yaz.keepalive", "120", PHP_INI_ALL, OnUpdateInt, keepalive, zend_yaz_globals, yaz_globals)
2002 STD_PHP_INI_ENTRY("yaz.log_file", NULL, PHP_INI_ALL, OnUpdateString, log_file, zend_yaz_globals, yaz_globals)
2003 STD_PHP_INI_ENTRY("yaz.log_mask", NULL, PHP_INI_ALL, OnUpdateString, log_mask, zend_yaz_globals, yaz_globals)
2007 PHP_MINIT_FUNCTION(yaz)
2013 yaz_mutex = tsrm_mutex_alloc();
2016 ZEND_INIT_MODULE_GLOBALS(yaz, php_yaz_init_globals, NULL);
2018 REGISTER_INI_ENTRIES();
2020 REGISTER_LONG_CONSTANT("ZOOM_EVENT_NONE", ZOOM_EVENT_NONE,
2021 CONST_CS|CONST_PERSISTENT);
2022 REGISTER_LONG_CONSTANT("ZOOM_EVENT_CONNECT", ZOOM_EVENT_CONNECT,
2023 CONST_CS|CONST_PERSISTENT);
2024 REGISTER_LONG_CONSTANT("ZOOM_EVENT_SEND_DATA", ZOOM_EVENT_SEND_DATA,
2025 CONST_CS|CONST_PERSISTENT);
2026 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_DATA", ZOOM_EVENT_RECV_DATA,
2027 CONST_CS|CONST_PERSISTENT);
2028 REGISTER_LONG_CONSTANT("ZOOM_EVENT_TIMEOUT", ZOOM_EVENT_TIMEOUT,
2029 CONST_CS|CONST_PERSISTENT);
2030 REGISTER_LONG_CONSTANT("ZOOM_EVENT_UNKNOWN", ZOOM_EVENT_UNKNOWN,
2031 CONST_CS|CONST_PERSISTENT);
2032 REGISTER_LONG_CONSTANT("ZOOM_EVENT_SEND_APDU", ZOOM_EVENT_SEND_APDU,
2033 CONST_CS|CONST_PERSISTENT);
2034 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_APDU", ZOOM_EVENT_RECV_APDU,
2035 CONST_CS|CONST_PERSISTENT);
2036 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_RECORD", ZOOM_EVENT_RECV_RECORD,
2037 CONST_CS|CONST_PERSISTENT);
2038 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_SEARCH", ZOOM_EVENT_RECV_SEARCH,
2039 CONST_CS|CONST_PERSISTENT);
2041 fname = YAZSG(log_file);
2042 mask = YAZSG(log_mask);
2043 if (fname && *fname)
2045 yaz_log_init_file(fname);
2048 yaz_log_init_level(yaz_log_mask_str(mask));
2051 yaz_log_init_level(0);
2053 le_link = zend_register_list_destructors_ex (yaz_close_link, 0, "YAZ link", module_number);
2055 order_associations = 1;
2056 shared_associations = xmalloc(sizeof(*shared_associations) * MAX_ASSOC);
2057 for (i = 0; i < MAX_ASSOC; i++) {
2058 shared_associations[i] = 0;
2063 PHP_MSHUTDOWN_FUNCTION(yaz)
2067 if (shared_associations) {
2068 for (i = 0; i < MAX_ASSOC; i++) {
2069 yaz_association_destroy (shared_associations[i]);
2071 xfree(shared_associations);
2072 shared_associations = 0;
2075 tsrm_mutex_free (yaz_mutex);
2078 yaz_log_init_file(0);
2080 UNREGISTER_INI_ENTRIES();
2085 PHP_MINFO_FUNCTION(yaz)
2087 char version_str[20];
2089 strcpy(version_str, "unknown");
2090 yaz_version(version_str, 0);
2091 php_info_print_table_start();
2092 php_info_print_table_row(2, "YAZ Support", "enabled");
2093 php_info_print_table_row(2, "PHP/YAZ Version", PHP_YAZ_VERSION);
2094 php_info_print_table_row(2, "YAZ Version", version_str);
2095 php_info_print_table_row(2, "Compiled with YAZ version", YAZ_VERSION);
2096 php_info_print_table_end();
2099 PHP_RSHUTDOWN_FUNCTION(yaz)
2105 tsrm_mutex_lock(yaz_mutex);
2107 for (i = 0; i < YAZSG(max_links); i++) {
2108 Yaz_Association *as = shared_associations + i;
2111 if (now - (*as)->time_stamp > YAZSG(keepalive))
2113 yaz_association_destroy(*as);
2119 tsrm_mutex_unlock(yaz_mutex);
2124 PHP_RINIT_FUNCTION(yaz)
2128 sprintf(pidstr, "%ld", (long) getpid());
2130 tsrm_mutex_lock(yaz_mutex);
2132 YAZSG(assoc_seq) = order_associations++;
2134 tsrm_mutex_unlock(yaz_mutex);
2136 yaz_log_init_prefix(pidstr);
2140 zend_module_entry yaz_module_entry = {
2141 #if ZEND_MODULE_API_NO >= 20010901
2142 STANDARD_MODULE_HEADER,
2151 #if ZEND_MODULE_API_NO >= 20010901
2154 STANDARD_MODULE_PROPERTIES
2165 * vim600: sw=4 ts=4 fdm=marker
2166 * vim<600: sw=4 ts=4