1 /* This file is part of PHP YAZ.
2 * Copyright (C) Index Data 2004-2014
3 * See the file LICENSE for details.
15 #include "ext/standard/info.h"
17 #include <yaz/yaz-version.h>
22 #error YAZ version 3.0.2 or later must be used.
23 #elif YAZ_VERSIONL < 0x030020
24 #error YAZ version 3.0.2 or later must be used.
32 #include <yaz/proto.h>
33 #include <yaz/marcdisp.h>
34 #include <yaz/yaz-util.h>
35 #include <yaz/yaz-ccl.h>
37 #include <yaz/oid_db.h>
39 #include <yaz/pquery.h>
41 #if YAZ_VERSIONL >= 0x050100
42 #include <yaz/rpn2cql.h>
45 #ifndef ODR_INT_PRINTF
46 #define ODR_INT_PRINTF "%d"
51 typedef struct Yaz_AssociationInfo *Yaz_Association;
53 struct Yaz_AssociationInfo {
55 #if YAZ_VERSIONL >= 0x050100
58 ZOOM_connection zoom_conn;
59 ZOOM_resultset zoom_set;
60 ZOOM_scanset zoom_scan;
61 ZOOM_package zoom_package;
70 static Yaz_Association yaz_association_mk()
72 Yaz_Association p = xmalloc(sizeof(*p));
74 p->zoom_conn = ZOOM_connection_create(0);
78 ZOOM_connection_option_set(p->zoom_conn, "implementationName", "PHP");
79 ZOOM_connection_option_set(p->zoom_conn, "async", "1");
84 p->bibset = ccl_qual_mk();
85 #if YAZ_VERSIONL >= 0x050100
86 p->ct = cql_transform_create();
92 static void yaz_association_destroy(Yaz_Association p)
98 #if YAZ_VERSIONL >= 0x050100
99 cql_transform_close(p->ct);
101 ZOOM_resultset_destroy(p->zoom_set);
102 ZOOM_scanset_destroy(p->zoom_scan);
103 ZOOM_package_destroy(p->zoom_package);
104 ZOOM_connection_destroy(p->zoom_conn);
105 xfree(p->sort_criteria);
106 ccl_qual_rm(&p->bibset);
110 static MUTEX_T yaz_mutex;
113 ZEND_DECLARE_MODULE_GLOBALS(yaz);
115 static Yaz_Association *shared_associations;
116 static int order_associations;
120 #ifdef COMPILE_DL_YAZ
124 #ifdef ZEND_BEGIN_ARG_INFO
125 ZEND_BEGIN_ARG_INFO(first_argument_force_ref, 0)
126 ZEND_ARG_PASS_INFO(1)
129 ZEND_BEGIN_ARG_INFO(second_argument_force_ref, 0)
130 ZEND_ARG_PASS_INFO(0)
131 ZEND_ARG_PASS_INFO(1)
134 ZEND_BEGIN_ARG_INFO(third_argument_force_ref, 0)
135 ZEND_ARG_PASS_INFO(0)
136 ZEND_ARG_PASS_INFO(0)
137 ZEND_ARG_PASS_INFO(1)
140 static unsigned char first_argument_force_ref[] = {
142 static unsigned char second_argument_force_ref[] = {
143 2, BYREF_NONE, BYREF_FORCE };
144 static unsigned char third_argument_force_ref[] = {
145 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
149 zend_function_entry yaz_functions [] = {
150 PHP_FE(yaz_connect, NULL)
151 PHP_FE(yaz_close, NULL)
152 PHP_FE(yaz_search, NULL)
153 PHP_FE(yaz_wait, first_argument_force_ref)
154 PHP_FE(yaz_errno, NULL)
155 PHP_FE(yaz_error, NULL)
156 PHP_FE(yaz_addinfo, NULL)
157 PHP_FE(yaz_hits, second_argument_force_ref)
158 PHP_FE(yaz_record, NULL)
159 PHP_FE(yaz_syntax, NULL)
160 PHP_FE(yaz_element, NULL)
161 PHP_FE(yaz_range, NULL)
162 PHP_FE(yaz_itemorder, NULL)
163 PHP_FE(yaz_es_result, NULL)
164 PHP_FE(yaz_scan, NULL)
165 PHP_FE(yaz_scan_result, second_argument_force_ref)
166 PHP_FE(yaz_present, NULL)
167 PHP_FE(yaz_ccl_conf, NULL)
168 PHP_FE(yaz_ccl_parse, third_argument_force_ref)
169 #if YAZ_VERSIONL >= 0x050100
170 PHP_FE(yaz_cql_parse, third_argument_force_ref)
171 PHP_FE(yaz_cql_conf, NULL)
173 PHP_FE(yaz_database, NULL)
174 PHP_FE(yaz_sort, NULL)
175 PHP_FE(yaz_schema, NULL)
176 PHP_FE(yaz_set_option, NULL)
177 PHP_FE(yaz_get_option, NULL)
182 static void get_assoc(INTERNAL_FUNCTION_PARAMETERS, zval *id, Yaz_Association *assocp)
184 Yaz_Association *as = 0;
188 tsrm_mutex_lock(yaz_mutex);
191 ZEND_FETCH_RESOURCE(as, Yaz_Association *, &id, -1, "YAZ link", le_link);
193 if (as && *as && (*as)->order == YAZSG(assoc_seq) && (*as)->in_use) {
197 tsrm_mutex_unlock(yaz_mutex);
199 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid YAZ handle");
203 static void release_assoc(Yaz_Association assoc)
207 tsrm_mutex_unlock(yaz_mutex);
212 static const char *array_lookup_string(HashTable *ht, const char *idx)
216 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
217 SEPARATE_ZVAL(pvalue);
218 convert_to_string(*pvalue);
219 return (*pvalue)->value.str.val;
224 static long *array_lookup_long(HashTable *ht, const char *idx)
228 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
229 SEPARATE_ZVAL(pvalue);
230 convert_to_long(*pvalue);
231 return &(*pvalue)->value.lval;
236 static long *array_lookup_bool(HashTable *ht, const char *idx)
240 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
241 SEPARATE_ZVAL(pvalue);
242 convert_to_boolean(*pvalue);
243 return &(*pvalue)->value.lval;
248 static const char *option_get(Yaz_Association as, const char *name)
253 return ZOOM_connection_option_get(as->zoom_conn, name);
256 static int option_get_int(Yaz_Association as, const char *name, int def)
260 v = ZOOM_connection_option_get(as->zoom_conn, name);
269 static void option_set(Yaz_Association as, const char *name, const char *value)
272 ZOOM_connection_option_set(as->zoom_conn, name, value);
276 static void option_set_int(Yaz_Association as, const char *name, int v)
282 ZOOM_connection_option_set(as->zoom_conn, name, s);
286 static int strcmp_null(const char *s1, const char *s2)
288 if (s1 == 0 && s2 == 0) {
291 if (s1 == 0 || s2 == 0) {
294 return strcmp(s1, s2);
297 /* {{{ proto resource yaz_connect(string zurl [, array options])
298 Create target with given zurl. Returns positive id if successful. */
299 PHP_FUNCTION(yaz_connect)
305 const char *sru_str = 0, *sru_version_str = 0;
306 const char *user_str = 0, *group_str = 0, *pass_str = 0;
307 const char *cookie_str = 0, *proxy_str = 0;
308 const char *charset_str = 0;
309 const char *client_IP = 0;
310 const char *otherInfo[3];
311 const char *maximumRecordSize = 0;
312 const char *preferredMessageSize = 0;
315 Yaz_Association as = 0;
316 int max_links = YAZSG(max_links);
318 otherInfo[0] = otherInfo[1] = otherInfo[2] = 0;
320 if (ZEND_NUM_ARGS() == 1) {
321 if (zend_parse_parameters(1 TSRMLS_CC, "s", &zurl_str, &zurl_len)
325 } else if (ZEND_NUM_ARGS() == 2) {
327 if (zend_parse_parameters(2 TSRMLS_CC, "sz", &zurl_str, &zurl_len,
332 if (Z_TYPE_PP(&user) == IS_ARRAY) {
333 long *persistent_val;
335 HashTable *ht = Z_ARRVAL_PP(&user);
337 sru_str = array_lookup_string(ht, "sru");
338 sru_version_str = array_lookup_string(ht, "sru_version");
339 user_str = array_lookup_string(ht, "user");
340 group_str = array_lookup_string(ht, "group");
341 pass_str = array_lookup_string(ht, "password");
342 cookie_str = array_lookup_string(ht, "cookie");
343 proxy_str = array_lookup_string(ht, "proxy");
344 charset_str = array_lookup_string(ht, "charset");
345 persistent_val = array_lookup_bool(ht, "persistent");
346 if (persistent_val) {
347 persistent = *persistent_val;
349 piggyback_val = array_lookup_bool(ht, "piggyback");
351 piggyback = *piggyback_val;
354 array_lookup_string(ht, "maximumRecordSize");
355 preferredMessageSize =
356 array_lookup_string(ht, "preferredMessageSize");
357 otherInfo[0] = array_lookup_string(ht, "otherInfo0");
358 otherInfo[1] = array_lookup_string(ht, "otherInfo1");
359 otherInfo[2] = array_lookup_string(ht, "otherInfo2");
360 } else if (Z_TYPE_PP(&user) == IS_STRING) {
361 convert_to_string_ex(&user);
362 if (*user->value.str.val)
363 user_str = user->value.str.val;
368 for (cp = zurl_str; *cp && strchr("\t\n ", *cp); cp++);
370 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty zurl");
373 /* see if we have it already ... */
375 tsrm_mutex_lock(yaz_mutex);
377 for (i = 0; i < max_links; i++) {
378 as = shared_associations[i];
379 if (persistent && as && !as->in_use &&
380 !strcmp_null(option_get(as, "host"), zurl_str) &&
381 !strcmp_null(option_get(as, "proxy"), proxy_str) &&
382 !strcmp_null(option_get(as, "sru"), sru_str) &&
383 !strcmp_null(option_get(as, "sru_version"), sru_version_str) &&
384 !strcmp_null(option_get(as, "user"), user_str) &&
385 !strcmp_null(option_get(as, "group"), group_str) &&
386 !strcmp_null(option_get(as, "pass"), pass_str) &&
387 !strcmp_null(option_get(as, "cookie"), cookie_str) &&
388 !strcmp_null(option_get(as, "charset"), charset_str))
391 if (i == max_links) {
392 /* we didn't have it (or already in use) */
394 int min_order = 2000000000;
396 /* find completely free slot or the oldest one */
397 for (i = 0; i < max_links && shared_associations[i]; i++) {
398 as = shared_associations[i];
399 if (persistent && !as->in_use && as->order < min_order) {
400 min_order = as->order;
405 if (i == max_links) {
410 tsrm_mutex_unlock(yaz_mutex);
412 sprintf(msg, "No YAZ handles available. max_links=%d",
414 php_error_docref(NULL TSRMLS_CC, E_WARNING,
415 "No YAZ handles available. max_links=%ld",
417 RETURN_LONG(0); /* no free slot */
418 } else { /* "best" free slot */
419 yaz_association_destroy(shared_associations[i]);
422 shared_associations[i] = as = yaz_association_mk();
424 option_set(as, "proxy", proxy_str);
425 option_set(as, "sru", sru_str);
426 option_set(as, "sru_version", sru_version_str);
427 option_set(as, "user", user_str);
428 option_set(as, "group", group_str);
429 option_set(as, "pass", pass_str);
430 option_set(as, "cookie", cookie_str);
431 option_set(as, "charset", charset_str);
433 if (maximumRecordSize)
434 option_set(as, "maximumRecordSize", maximumRecordSize);
435 if (preferredMessageSize)
436 option_set(as, "preferredMessageSize", preferredMessageSize);
437 option_set(as, "otherInfo0", otherInfo[0]);
438 option_set(as, "otherInfo1", otherInfo[1]);
439 option_set(as, "otherInfo2", otherInfo[2]);
440 option_set(as, "clientIP", client_IP);
441 option_set(as, "piggyback", piggyback ? "1" : "0");
442 option_set_int(as, "start", 0);
443 option_set_int(as, "count", 0);
444 ZOOM_connection_connect(as->zoom_conn, zurl_str, 0);
446 as->persistent = persistent;
447 as->order = YAZSG(assoc_seq);
448 as->time_stamp = time(0);
452 ZOOM_resultset_destroy(as->zoom_set);
456 tsrm_mutex_unlock(yaz_mutex);
459 ZEND_REGISTER_RESOURCE(return_value, &shared_associations[i], le_link);
460 as->zval_resource = Z_LVAL_P(return_value);
464 /* {{{ proto bool yaz_close(resource id)
465 Destory and close target */
466 PHP_FUNCTION(yaz_close)
471 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters(1 TSRMLS_CC, "z", &id)
475 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
480 zend_list_delete(id->value.lval);
486 /* {{{ proto bool yaz_search(resource id, string type, string query)
487 Specify query of type for search - returns true if successful */
488 PHP_FUNCTION(yaz_search)
490 char *query_str, *type_str;
491 int query_len, type_len;
495 if (ZEND_NUM_ARGS() != 3 ||
496 zend_parse_parameters(3 TSRMLS_CC, "zss", &id,
497 &type_str, &type_len,
498 &query_str, &query_len) == FAILURE) {
501 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
506 ZOOM_resultset_destroy(p->zoom_set);
511 if (!strcmp(type_str, "rpn")) {
512 ZOOM_query q = ZOOM_query_create();
513 if (ZOOM_query_prefix(q, query_str) == 0)
515 if (p->sort_criteria) {
516 ZOOM_query_sortby(q, p->sort_criteria);
518 xfree(p->sort_criteria);
519 p->sort_criteria = 0;
520 p->zoom_set = ZOOM_connection_search(p->zoom_conn, q);
523 ZOOM_query_destroy(q);
525 else if (!strcmp(type_str, "cql")) {
526 ZOOM_query q = ZOOM_query_create();
527 if (ZOOM_query_cql(q, query_str) == 0)
529 if (p->sort_criteria) {
530 ZOOM_query_sortby(q, p->sort_criteria);
532 xfree(p->sort_criteria);
533 p->sort_criteria = 0;
534 p->zoom_set = ZOOM_connection_search(p->zoom_conn, q);
537 ZOOM_query_destroy(q);
541 php_error_docref(NULL TSRMLS_CC, E_WARNING,
542 "Invalid query type %s", type_str);
548 /* {{{ proto bool yaz_present(resource id)
550 PHP_FUNCTION(yaz_present)
555 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters(1 TSRMLS_CC, "z", &id)
559 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
565 size_t start = option_get_int(p, "start", 0);
566 size_t count = option_get_int(p, "count", 0);
568 ZOOM_resultset_records(p->zoom_set, 0 /* recs */, start, count);
576 /* {{{ proto bool yaz_wait([array options])
578 PHP_FUNCTION(yaz_wait)
580 zval *pval_options = 0;
583 ZOOM_connection conn_ar[MAX_ASSOC];
584 Yaz_Association conn_as[MAX_ASSOC];
587 if (ZEND_NUM_ARGS() == 1) {
589 long *event_bool = 0;
590 HashTable *options_ht = 0;
591 if (zend_parse_parameters(1 TSRMLS_CC, "a", &pval_options) ==
595 options_ht = Z_ARRVAL_PP(&pval_options);
596 val = array_lookup_long(options_ht, "timeout");
600 event_bool = array_lookup_bool(options_ht, "event");
601 if (event_bool && *event_bool)
604 else if (ZEND_NUM_ARGS() > 1) {
608 tsrm_mutex_lock(yaz_mutex);
610 for (i = 0; i<YAZSG(max_links); i++) {
611 Yaz_Association p = shared_associations[i];
612 if (p && p->order == YAZSG(assoc_seq)) {
615 sprintf(str, "%d", timeout);
616 ZOOM_connection_option_set(p->zoom_conn, "timeout", str);
618 conn_ar[no++] = p->zoom_conn;
622 tsrm_mutex_unlock(yaz_mutex);
625 long ev = ZOOM_event(no, conn_ar);
629 Yaz_Association p = conn_as[ev-1];
630 int event_code = ZOOM_connection_last_event(p->zoom_conn);
633 add_assoc_long(pval_options, "connid", ev);
634 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_parse_parameters(1 TSRMLS_CC, "z", &id)
663 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
667 RETVAL_LONG(ZOOM_connection_errcode(p->zoom_conn));
672 /* {{{ proto string yaz_error(resource id)
673 Return last error message */
674 PHP_FUNCTION(yaz_error)
679 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters(1 TSRMLS_CC, "z", &id)
683 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
685 int code = ZOOM_connection_errcode(p->zoom_conn);
686 const char *msg = ZOOM_connection_errmsg(p->zoom_conn);
691 return_value->value.str.len = strlen(msg);
692 return_value->value.str.val = estrndup(msg, return_value->value.str.len);
693 return_value->type = IS_STRING;
699 /* {{{ proto string yaz_addinfo(resource id)
700 Return additional info for last error (empty string if none) */
701 PHP_FUNCTION(yaz_addinfo)
706 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters(1 TSRMLS_CC, "z", &id)
710 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
712 const char *addinfo = ZOOM_connection_addinfo(p->zoom_conn);
714 return_value->value.str.len = strlen(addinfo);
715 return_value->value.str.val = estrndup(addinfo, return_value->value.str.len);
716 return_value->type = IS_STRING;
722 /* {{{ proto int yaz_hits(resource id [, array searchresult])
723 Return number of hits (result count) for last search */
724 PHP_FUNCTION(yaz_hits)
726 zval *id, *searchresult = 0;
729 if (ZEND_NUM_ARGS() == 1) {
730 if (zend_parse_parameters(1 TSRMLS_CC, "z", &id) == FAILURE) {
733 } else if (ZEND_NUM_ARGS() == 2) {
734 if (zend_parse_parameters(2 TSRMLS_CC, "za", &id, &searchresult)
742 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
743 if (p && p->zoom_set) {
744 RETVAL_LONG(ZOOM_resultset_size(p->zoom_set));
748 ZOOM_resultset_option_get(p->zoom_set, "resultSetStatus");
750 add_assoc_string(searchresult, "resultSetStatus",
756 ZOOM_resultset_option_get(p->zoom_set, "searchresult.size");
759 if (sz_str && *sz_str)
761 for (i = 0; i<sz; i++)
764 const char *opt_value;
767 MAKE_STD_ZVAL(zval_element);
768 array_init(zval_element);
769 add_next_index_zval(searchresult, zval_element);
771 sprintf(opt_name, "searchresult.%d.id", i);
772 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
774 add_assoc_string(zval_element, "id",
775 (char *) opt_value, 1);
777 sprintf(opt_name, "searchresult.%d.count", i);
778 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
780 add_assoc_long(zval_element, "count", atoi(opt_value));
782 sprintf(opt_name, "searchresult.%d.subquery.term", i);
783 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
785 add_assoc_string(zval_element, "subquery.term",
786 (char *) opt_value, 1);
788 sprintf(opt_name, "searchresult.%d.interpretation.term", i);
789 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
791 add_assoc_string(zval_element, "interpretation.term",
792 (char *) opt_value, 1);
794 sprintf(opt_name, "searchresult.%d.recommendation.term", i);
795 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
797 add_assoc_string(zval_element, "recommendation.term",
798 (char *) opt_value, 1);
809 static Z_GenericRecord *marc_to_grs1(const char *buf, ODR o)
813 int indicator_length;
814 int identifier_length;
816 int length_data_entry;
818 int max_elements = 256;
819 Z_GenericRecord *r = odr_malloc(o, sizeof(*r));
820 r->elements = odr_malloc(o, sizeof(*r->elements) * max_elements);
823 record_length = atoi_n(buf, 5);
824 if (record_length < 25) {
827 indicator_length = atoi_n(buf + 10, 1);
828 identifier_length = atoi_n(buf + 11, 1);
829 base_address = atoi_n(buf + 12, 5);
831 length_data_entry = atoi_n(buf + 20, 1);
832 length_starting = atoi_n(buf + 21, 1);
834 for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) {
835 entry_p += 3 + length_data_entry + length_starting;
836 if (entry_p >= record_length) {
842 Z_TaggedElement *tag;
843 tag = r->elements[r->num_elements++] = odr_malloc(o, sizeof(*tag));
844 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
846 tag->tagOccurrence = 0;
848 tag->appliedVariant = 0;
849 tag->tagValue = odr_malloc(o, sizeof(*tag->tagValue));
850 tag->tagValue->which = Z_StringOrNumeric_string;
851 tag->tagValue->u.string = odr_strdup(o, "leader");
853 tag->content = odr_malloc(o, sizeof(*tag->content));
854 tag->content->which = Z_ElementData_string;
855 tag->content->u.string = odr_strdupn(o, buf, 24);
857 base_address = entry_p + 1;
858 for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) {
859 Z_TaggedElement *tag;
865 int identifier_flag = 1;
867 memcpy(tag_str, buf+entry_p, 3);
871 if ((r->num_elements + 1) >= max_elements) {
872 Z_TaggedElement **tmp = r->elements;
874 /* double array space, throw away old buffer (nibble memory) */
875 r->elements = odr_malloc(o, sizeof(*r->elements) * (max_elements *= 2));
876 memcpy(r->elements, tmp, r->num_elements * sizeof(*tmp));
878 tag = r->elements[r->num_elements++] = odr_malloc(o, sizeof(*tag));
879 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
881 tag->tagOccurrence = 0;
883 tag->appliedVariant = 0;
884 tag->tagValue = odr_malloc(o, sizeof(*tag->tagValue));
885 tag->tagValue->which = Z_StringOrNumeric_string;
886 tag->tagValue->u.string = odr_strdup(o, tag_str);
888 tag->content = odr_malloc(o, sizeof(*tag->content));
889 tag->content->which = Z_ElementData_subtree;
891 tag->content->u.subtree = odr_malloc(o, sizeof(*tag->content->u.subtree));
892 tag->content->u.subtree->elements = odr_malloc(o, sizeof(*r->elements));
893 tag->content->u.subtree->num_elements = 1;
895 tag = tag->content->u.subtree->elements[0] = odr_malloc(o, sizeof(**tag->content->u.subtree->elements));
897 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
899 tag->tagOccurrence = 0;
901 tag->appliedVariant = 0;
902 tag->tagValue = odr_malloc(o, sizeof(*tag->tagValue));
903 tag->tagValue->which = Z_StringOrNumeric_string;
904 tag->content = odr_malloc(o, sizeof(*tag->content));
906 data_length = atoi_n(buf + entry_p, length_data_entry);
907 entry_p += length_data_entry;
908 data_offset = atoi_n(buf + entry_p, length_starting);
909 entry_p += length_starting;
910 i = data_offset + base_address;
911 end_offset = i + data_length - 1;
913 if (indicator_length > 0 && indicator_length < 5) {
914 if (buf[i + indicator_length] != ISO2709_IDFS) {
917 } else if (!memcmp(tag_str, "00", 2)) {
921 if (identifier_flag && indicator_length) {
923 tag->tagValue->u.string = odr_malloc(o, indicator_length + 1);
924 memcpy(tag->tagValue->u.string, buf + i, indicator_length);
925 tag->tagValue->u.string[indicator_length] = '\0';
926 i += indicator_length;
928 tag->content->which = Z_ElementData_subtree;
930 tag->content->u.subtree = odr_malloc(o, sizeof(*tag->content->u.subtree));
931 tag->content->u.subtree->elements = odr_malloc(o, 256 * sizeof(*r->elements));
932 tag->content->u.subtree->num_elements = 0;
934 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset) {
937 Z_TaggedElement *parent_tag = tag;
938 Z_TaggedElement *tag = odr_malloc(o, sizeof(*tag));
940 if (parent_tag->content->u.subtree->num_elements < 256) {
941 parent_tag->content->u.subtree->elements[
942 parent_tag->content->u.subtree->num_elements++] = tag;
945 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
947 tag->tagOccurrence = 0;
949 tag->appliedVariant = 0;
950 tag->tagValue = odr_malloc(o, sizeof(*tag->tagValue));
951 tag->tagValue->which = Z_StringOrNumeric_string;
954 tag->tagValue->u.string = odr_malloc(o, identifier_length);
955 memcpy(tag->tagValue->u.string, buf + i + 1, identifier_length - 1);
956 tag->tagValue->u.string[identifier_length - 1] = '\0';
957 i += identifier_length;
960 tag->content = odr_malloc(o, sizeof(*tag->content));
961 tag->content->which = Z_ElementData_string;
964 while ( buf[i] != ISO2709_RS &&
965 buf[i] != ISO2709_IDFS &&
966 buf[i] != ISO2709_FS && i < end_offset) {
970 tag->content->u.string = odr_malloc(o, i - i0 + 1);
971 memcpy(tag->content->u.string, buf + i0, i - i0);
972 tag->content->u.string[i - i0] = '\0';
977 tag->tagValue->u.string = "@";
978 tag->content->which = Z_ElementData_string;
980 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset) {
983 tag->content->u.string = odr_malloc(o, i - i0 +1);
984 memcpy(tag->content->u.string, buf + i0, i - i0);
985 tag->content->u.string[i-i0] = '\0';
998 static struct cvt_handle *cvt_open(const char *to, const char *from)
1000 ODR o = odr_createmem(ODR_ENCODE);
1002 struct cvt_handle *cvt = odr_malloc(o, sizeof(*cvt));
1005 cvt->buf = odr_malloc(o, cvt->size);
1008 cvt->cd = yaz_iconv_open(to, from);
1012 static void cvt_close(struct cvt_handle *cvt)
1015 yaz_iconv_close(cvt->cd);
1016 odr_destroy(cvt->odr);
1019 static const char *cvt_string(const char *input, struct cvt_handle *cvt)
1024 size_t inbytesleft = strlen(input);
1025 const char *inp = input;
1026 size_t outbytesleft = cvt->size - 1;
1027 char *outp = cvt->buf;
1028 size_t r = yaz_iconv(cvt->cd, (char**) &inp, &inbytesleft,
1029 &outp, &outbytesleft);
1030 if (r == (size_t) (-1)) {
1031 int e = yaz_iconv_error(cvt->cd);
1032 if (e != YAZ_ICONV_E2BIG || cvt->size > 200000)
1037 cvt->size = cvt->size * 2 + 30;
1038 cvt->buf = (char*) odr_malloc(cvt->odr, cvt->size);
1040 cvt->buf[outp - cvt->buf] = '\0';
1047 static void retval_array3_grs1(zval *return_value, Z_GenericRecord *p,
1048 struct cvt_handle *cvt)
1054 struct tag_list *next;
1056 NMEM nmem = nmem_create();
1058 array_init(return_value);
1059 for (i = 0; i<p->num_elements; i++)
1061 struct tag_list *tl;
1064 Z_TaggedElement *e = p->elements[i];
1065 char tagstr[32], *tag = 0;
1067 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1069 sprintf(tagstr, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1072 else if (e->tagValue->which == Z_StringOrNumeric_string)
1073 tag = e->tagValue->u.string, zval_element;
1078 for (tl = all_tags; tl; tl = tl->next)
1079 if (!strcmp(tl->tag, tag))
1082 zval_list = tl->zval_list;
1085 MAKE_STD_ZVAL(zval_list);
1086 array_init(zval_list);
1087 add_assoc_zval(return_value, tag, zval_list);
1089 tl = nmem_malloc(nmem, sizeof(*tl));
1090 tl->tag = nmem_strdup(nmem, tag);
1091 tl->zval_list = zval_list;
1092 tl->next = all_tags;
1095 MAKE_STD_ZVAL(zval_element);
1096 array_init(zval_element);
1097 add_next_index_zval(zval_list, zval_element);
1098 if (e->content->which == Z_ElementData_subtree)
1100 /* we have a subtree. Move to first child */
1101 Z_GenericRecord *sub = e->content->u.subtree;
1102 if (sub->num_elements >= 1)
1103 e = sub->elements[0];
1109 const char *tag = 0;
1110 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1112 sprintf(tagstr, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1115 else if (e->tagValue->which == Z_StringOrNumeric_string)
1116 tag = e->tagValue->u.string;
1117 if (tag && e->content->which == Z_ElementData_subtree)
1120 Z_GenericRecord *sub = e->content->u.subtree;
1122 for (i = 0; tag[i]; i++)
1127 sprintf(ind_idx, "ind%d", i+1);
1128 ind_val[0] = tag[i];
1131 add_assoc_string(zval_element, ind_idx, ind_val, 1);
1133 for (i = 0; i<sub->num_elements; i++)
1135 Z_TaggedElement *e = sub->elements[i];
1136 const char *tag = 0;
1137 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1139 sprintf(tagstr, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1142 else if (e->tagValue->which == Z_StringOrNumeric_string)
1143 tag = e->tagValue->u.string, zval_element;
1145 if (tag && e->content->which == Z_ElementData_string)
1147 const char *v = cvt_string(e->content->u.string, cvt);
1148 add_assoc_string(zval_element, (char*) tag, (char*) v,
1153 else if (tag && e->content->which == Z_ElementData_string)
1155 /* Leader or control field */
1156 const char *v = cvt_string(e->content->u.string, cvt);
1157 ZVAL_STRING(zval_element, (char*) v, 1);
1164 static void retval_array2_grs1(zval *return_value, Z_GenericRecord *p,
1165 struct cvt_handle *cvt)
1169 array_init(return_value);
1171 for (i = 0; i<p->num_elements; i++)
1175 Z_TaggedElement *e = p->elements[i];
1177 MAKE_STD_ZVAL(zval_element);
1178 array_init(zval_element);
1181 add_assoc_long(zval_element, "tagType", (long) *e->tagType);
1183 if (e->tagValue->which == Z_StringOrNumeric_string)
1184 add_assoc_string(zval_element, "tag", e->tagValue->u.string, 1);
1185 else if (e->tagValue->which == Z_StringOrNumeric_numeric)
1186 add_assoc_long(zval_element, "tag", (long) *e->tagValue->u.numeric);
1188 switch (e->content->which) {
1189 case Z_ElementData_string:
1192 const char *v = cvt_string(e->content->u.string, cvt);
1193 add_assoc_string(zval_element, "content", (char*) v, 1);
1196 case Z_ElementData_numeric:
1197 add_assoc_long(zval_element, "content", (long) *e->content->u.numeric);
1199 case Z_ElementData_trueOrFalse:
1200 add_assoc_bool(zval_element, "content",*e->content->u.trueOrFalse);
1202 case Z_ElementData_subtree:
1203 MAKE_STD_ZVAL(zval_sub);
1204 retval_array2_grs1(zval_sub, e->content->u.subtree, cvt);
1205 add_assoc_zval(zval_element, "content", zval_sub);
1207 add_next_index_zval(return_value, zval_element);
1211 static void retval_array1_grs1(zval *return_value, Z_GenericRecord *p,
1212 struct cvt_handle *cvt)
1214 Z_GenericRecord *grs[20];
1218 array_init(return_value);
1222 while (level >= 0) {
1224 Z_TaggedElement *e = 0;
1225 Z_GenericRecord *p = grs[level];
1230 if (eno[level] >= p->num_elements) {
1237 for (i = 0; i <= level; i++) {
1239 e = grs[i]->elements[eno[i]];
1242 tag_type = (long) *e->tagType;
1244 taglen = strlen(tag);
1245 sprintf(tag + taglen, "(%ld,", tag_type);
1246 taglen = strlen(tag);
1248 if (e->tagValue->which == Z_StringOrNumeric_string) {
1249 int len = strlen(e->tagValue->u.string);
1251 memcpy(tag + taglen, e->tagValue->u.string, len);
1252 tag[taglen+len] = '\0';
1253 } else if (e->tagValue->which == Z_StringOrNumeric_numeric) {
1254 sprintf(tag + taglen, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1256 taglen = strlen(tag);
1257 strcpy(tag + taglen, ")");
1260 ALLOC_ZVAL(my_zval);
1261 array_init(my_zval);
1262 INIT_PZVAL(my_zval);
1264 add_next_index_string(my_zval, tag, 1);
1266 switch (e->content->which) {
1267 case Z_ElementData_string:
1270 const char *v = cvt_string(e->content->u.string, cvt);
1271 add_next_index_string(my_zval, (char*) v, 1);
1274 case Z_ElementData_numeric:
1275 add_next_index_long(my_zval, (long) *e->content->u.numeric);
1277 case Z_ElementData_trueOrFalse:
1278 add_next_index_long(my_zval, *e->content->u.trueOrFalse);
1280 case Z_ElementData_subtree:
1283 grs[level] = e->content->u.subtree;
1287 zend_hash_next_index_insert(return_value->value.ht, (void *) &my_zval, sizeof(zval *), NULL);
1292 static void ext_grs1(zval *return_value, char type_args[][60],
1294 void (*array_func)(zval *, Z_GenericRecord *,
1295 struct cvt_handle *))
1297 Z_External *ext = (Z_External *) ZOOM_record_get(r, "ext", 0);
1298 if (ext && ext->which == Z_External_OPAC)
1299 ext = ext->u.opac->bibliographicRecord;
1301 struct cvt_handle *cvt = 0;
1302 if (type_args[2][0])
1303 cvt = cvt_open(type_args[3], type_args[2]);
1305 cvt = cvt_open(0, 0);
1307 if (ext->which == Z_External_grs1) {
1308 retval_array1_grs1(return_value, ext->u.grs1, cvt);
1309 } else if (ext->which == Z_External_octet) {
1310 Z_GenericRecord *rec = 0;
1311 if (yaz_oid_is_iso2709(ext->direct_reference))
1313 char *buf = (char *) (ext->u.octet_aligned->buf);
1314 rec = marc_to_grs1(buf, cvt->odr);
1317 (*array_func)(return_value, rec, cvt);
1325 /* {{{ proto string yaz_record(resource id, int pos, string type)
1326 Return record information at given result set position */
1327 PHP_FUNCTION(yaz_record)
1335 if (ZEND_NUM_ARGS() != 3) {
1339 if (zend_parse_parameters(3 TSRMLS_CC, "zls", &pval_id, &pos,
1340 &type, &type_len) == FAILURE) {
1344 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1346 if (p && p->zoom_set) {
1348 r = ZOOM_resultset_record(p->zoom_set, pos-1);
1351 char type_args[4][60]; /* 0; 1=2,3 (1 is assumed charset) */
1352 type_args[0][0] = 0;
1353 type_args[1][0] = 0;
1354 type_args[2][0] = 0;
1355 type_args[3][0] = 0;
1356 sscanf(type, "%59[^;];%59[^=]=%59[^,],%59[^,]", type_args[0],
1357 type_args[1], type_args[2], type_args[3]);
1359 if (!strcmp(type_args[0], "string")) {
1360 type_tmp = xstrdup(type);
1361 strcpy(type_tmp, "render");
1362 strcat(type_tmp, type + 6);
1365 if (!strcmp(type_args[0], "array") ||
1366 !strcmp(type_args[0], "array1"))
1368 ext_grs1(return_value, type_args, r, retval_array1_grs1);
1369 } else if (!strcmp(type_args[0], "array2")) {
1370 ext_grs1(return_value, type_args, r, retval_array2_grs1);
1371 } else if (!strcmp(type_args[0], "array3")) {
1372 ext_grs1(return_value, type_args, r, retval_array3_grs1);
1375 const char *info = ZOOM_record_get(r, type, &rlen);
1377 return_value->value.str.len = (rlen > 0) ? rlen : 0;
1378 return_value->value.str.val =
1379 estrndup(info, return_value->value.str.len);
1380 return_value->type = IS_STRING;
1384 php_error_docref(NULL TSRMLS_CC, E_WARNING,
1385 "Bad yaz_record type %s - or unable "
1386 "to return record with type given", type);
1396 /* {{{ proto void yaz_syntax(resource id, string syntax)
1397 Set record syntax for retrieval */
1398 PHP_FUNCTION(yaz_syntax)
1405 if (ZEND_NUM_ARGS() != 2 ||
1406 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id,
1407 &syntax, &syntax_len) == FAILURE) {
1411 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1412 option_set(p, "preferredRecordSyntax", syntax);
1417 /* {{{ proto void yaz_element(resource id, string elementsetname)
1418 Set Element-Set-Name for retrieval */
1419 PHP_FUNCTION(yaz_element)
1422 const char *element;
1426 if (ZEND_NUM_ARGS() != 2 ||
1427 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id,
1428 &element, &element_len) == FAILURE) {
1431 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1433 option_set(p, "elementSetName", element);
1438 /* {{{ proto void yaz_schema(resource id, string schema)
1439 Set Schema for retrieval */
1440 PHP_FUNCTION(yaz_schema)
1447 if (ZEND_NUM_ARGS() != 2 ||
1448 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id,
1449 &schema, &schema_len) == FAILURE) {
1453 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1454 option_set(p, "schema", schema);
1459 /* {{{ proto void yaz_set_option(resource id, mixed options)
1460 Set Option(s) for connection */
1461 PHP_FUNCTION(yaz_set_option)
1465 if (ZEND_NUM_ARGS() == 2) {
1466 zval *pval_ar, *pval_id;
1467 if (zend_parse_parameters(2 TSRMLS_CC, "za",
1468 &pval_id, &pval_ar) == FAILURE) {
1471 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1477 ht = Z_ARRVAL_PP(&pval_ar);
1478 for(zend_hash_internal_pointer_reset_ex(ht, &pos);
1479 zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
1480 zend_hash_move_forward_ex(ht, &pos)
1484 #if PHP_API_VERSION > 20010101
1485 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
1487 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
1489 if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
1492 option_set(p, key, (*ent)->value.str.val);
1496 } else if (ZEND_NUM_ARGS() == 3) {
1499 int name_len, value_len;
1500 if (zend_parse_parameters(3 TSRMLS_CC, "zss",
1501 &pval_id, &name, &name_len,
1502 &value, &value_len) == FAILURE) {
1505 get_assoc (INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1506 option_set(p, name, value);
1514 /* {{{ proto string yaz_get_option(resource id, string name)
1515 Set Option(s) for connection */
1516 PHP_FUNCTION(yaz_get_option)
1523 if (ZEND_NUM_ARGS() != 2 ||
1524 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id, &name, &name_len)
1528 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1531 v = option_get(p, name);
1535 return_value->value.str.len = strlen(v);
1536 return_value->value.str.val = estrndup(v, return_value->value.str.len);
1537 return_value->type = IS_STRING;
1545 /* {{{ proto void yaz_range(resource id, int start, int number)
1546 Set result set start point and number of records to request */
1547 PHP_FUNCTION(yaz_range)
1553 if (ZEND_NUM_ARGS() != 3 ||
1554 zend_parse_parameters(3 TSRMLS_CC, "zll", &pval_id, &start, &number)
1559 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1560 option_set_int(p, "start", start > 0 ? start - 1 : 0);
1561 option_set_int(p, "count", number);
1566 /* {{{ proto void yaz_sort(resource id, string sortspec)
1567 Set result set sorting criteria */
1568 PHP_FUNCTION(yaz_sort)
1571 const char *criteria;
1575 if (ZEND_NUM_ARGS() != 2 ||
1576 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id, &criteria,
1577 &criteria_len) == FAILURE) {
1581 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1583 xfree(p->sort_criteria);
1584 p->sort_criteria = xstrdup(criteria);
1586 ZOOM_resultset_sort(p->zoom_set, "yaz", criteria);
1592 const char *ill_array_lookup(void *handle, const char *name)
1594 return array_lookup_string((HashTable *) handle, name);
1597 /* {{{ proto void yaz_itemorder(resource id, array package)
1598 Sends Item Order request */
1599 PHP_FUNCTION(yaz_itemorder)
1601 zval *pval_id, *pval_package;
1604 if (ZEND_NUM_ARGS() != 2 ||
1605 zend_parse_parameters(2 TSRMLS_CC, "za", &pval_id, &pval_package) ==
1609 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1611 ZOOM_options options = ZOOM_options_create();
1613 ZOOM_options_set_callback(options,
1614 ill_array_lookup, Z_ARRVAL_PP(&pval_package));
1615 ZOOM_package_destroy(p->zoom_package);
1616 p->zoom_package = ZOOM_connection_package(p->zoom_conn, options);
1617 ZOOM_package_send(p->zoom_package, "itemorder");
1618 ZOOM_options_set_callback(options, 0, 0);
1619 ZOOM_options_destroy(options);
1625 /* {{{ proto void yaz_es(resource id, string type, array package)
1626 Sends Extended Services Request */
1627 PHP_FUNCTION(yaz_es)
1629 zval *pval_id, *pval_package;
1634 if (ZEND_NUM_ARGS() != 3 ||
1635 zend_parse_parameters(3 TSRMLS_CC, "zsa", &pval_id,
1636 &type, &type_len, &pval_package) == FAILURE) {
1639 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1641 ZOOM_options options = ZOOM_options_create();
1643 ZOOM_options_set_callback(options, ill_array_lookup,
1644 Z_ARRVAL_PP(&pval_package));
1645 ZOOM_package_destroy(p->zoom_package);
1646 p->zoom_package = ZOOM_connection_package(p->zoom_conn, options);
1647 ZOOM_package_send(p->zoom_package, type);
1648 ZOOM_options_set_callback(options, 0, 0);
1649 ZOOM_options_destroy(options);
1655 /* {{{ proto void yaz_scan(resource id, type, query [, flags])
1656 Sends Scan Request */
1657 PHP_FUNCTION(yaz_scan)
1659 zval *pval_id, *pval_flags;
1661 int type_len, query_len;
1662 HashTable *flags_ht = 0;
1665 if (ZEND_NUM_ARGS() == 3) {
1666 if (zend_parse_parameters(3 TSRMLS_CC, "zss",
1667 &pval_id, &type, &type_len,
1668 &query, &query_len) == FAILURE) {
1671 } else if (ZEND_NUM_ARGS() == 4) {
1672 if (zend_parse_parameters(4 TSRMLS_CC, "zssa",
1673 &pval_id, &type, &type_len,
1674 &query, &query_len, &pval_flags) == FAILURE) {
1677 flags_ht = Z_ARRVAL_PP(&pval_flags);
1681 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1682 ZOOM_scanset_destroy(p->zoom_scan);
1685 option_set(p, "number", array_lookup_string(flags_ht, "number"));
1686 option_set(p, "position", array_lookup_string(flags_ht, "position"));
1687 option_set(p, "stepSize", array_lookup_string(flags_ht, "stepsize"));
1688 p->zoom_scan = ZOOM_connection_scan(p->zoom_conn, query);
1694 /* {{{ proto array yaz_es_result(resource id)
1695 Inspects Extended Services Result */
1696 PHP_FUNCTION(yaz_es_result)
1701 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters(1 TSRMLS_CC, "z",
1702 &pval_id) == FAILURE) {
1706 array_init(return_value);
1708 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1709 if (p && p->zoom_package) {
1710 const char *str = ZOOM_package_option_get(p->zoom_package,
1714 add_assoc_string(return_value, "targetReference", (char *) str, 1);
1716 str = ZOOM_package_option_get(p->zoom_package,
1719 add_assoc_string(return_value, "xmlUpdateDoc", (char *) str, 1);
1726 /* {{{ proto array yaz_scan_result(resource id [, array options])
1727 Inspects Scan Result */
1728 PHP_FUNCTION(yaz_scan_result)
1730 zval *pval_id, *pval_opt = 0;
1733 if (ZEND_NUM_ARGS() == 2) {
1734 if (zend_parse_parameters(2 TSRMLS_CC, "zz",
1735 &pval_id, &pval_opt) == FAILURE) {
1738 } else if (ZEND_NUM_ARGS() == 1) {
1739 if (zend_parse_parameters(1 TSRMLS_CC, "z",
1740 &pval_id) == FAILURE) {
1747 array_init(return_value);
1749 if (pval_opt && array_init(pval_opt) == FAILURE) {
1753 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1754 if (p && p->zoom_scan) {
1756 /* ZOOM_scanset_term changed from YAZ 3 to YAZ 4 */
1757 #if YAZ_VERSIONL >= 0x040000
1762 int size = ZOOM_scanset_size(p->zoom_scan);
1764 for (pos = 0; pos < size; pos++) {
1765 const char *term = ZOOM_scanset_term(p->zoom_scan, pos, &occ, &len);
1768 ALLOC_ZVAL(my_zval);
1769 array_init(my_zval);
1770 INIT_PZVAL(my_zval);
1772 add_next_index_string(my_zval, "term", 1);
1775 add_next_index_stringl(my_zval, (char*) term, len, 1);
1777 add_next_index_string(my_zval, "?", 1);
1779 add_next_index_long(my_zval, occ);
1781 term = ZOOM_scanset_display_term(p->zoom_scan, pos, &occ, &len);
1784 add_next_index_stringl(my_zval, (char*) term, len, 1);
1786 add_next_index_string(my_zval, "?", 1);
1789 zend_hash_next_index_insert(return_value->value.ht, (void *) &my_zval, sizeof(zval *), NULL);
1795 add_assoc_long(pval_opt, "number", size);
1797 v = ZOOM_scanset_option_get(p->zoom_scan, "stepSize");
1799 add_assoc_long(pval_opt, "stepsize", atoi(v));
1801 v = ZOOM_scanset_option_get(p->zoom_scan, "position");
1803 add_assoc_long(pval_opt, "position", atoi(v));
1805 v = ZOOM_scanset_option_get(p->zoom_scan, "scanStatus");
1807 add_assoc_long(pval_opt, "status", atoi(v));
1815 /* {{{ proto void yaz_ccl_conf(resource id, array package)
1816 Configure CCL package */
1817 PHP_FUNCTION(yaz_ccl_conf)
1819 zval *pval_id, *pval_package;
1822 if (ZEND_NUM_ARGS() != 2 ||
1823 zend_parse_parameters(2 TSRMLS_CC, "za", &pval_id, &pval_package)
1827 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1829 HashTable *ht = Z_ARRVAL_PP(&pval_package);
1834 ccl_qual_rm(&p->bibset);
1835 p->bibset = ccl_qual_mk();
1837 for (zend_hash_internal_pointer_reset_ex(ht, &pos);
1838 zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
1839 zend_hash_move_forward_ex(ht, &pos)
1842 #if PHP_API_VERSION > 20010101
1843 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
1845 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
1847 if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
1850 ccl_qual_fitem(p->bibset, (*ent)->value.str.val, key);
1857 /* {{{ proto bool yaz_ccl_parse(resource id, string query, array res)
1858 Parse a CCL query */
1859 PHP_FUNCTION(yaz_ccl_parse)
1861 zval *pval_id, *pval_res = 0;
1866 if (ZEND_NUM_ARGS() != 3 ||
1867 zend_parse_parameters(3 TSRMLS_CC, "zsz",
1868 &pval_id, &query, &query_len, &pval_res)
1873 zval_dtor(pval_res);
1874 array_init(pval_res);
1875 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1877 struct ccl_rpn_node *rpn;
1880 CCL_parser ccl_parser = ccl_parser_create(p->bibset);
1882 rpn = ccl_parser_find_str(ccl_parser, query);
1884 error_code = ccl_parser_get_error(ccl_parser, &error_pos);
1885 add_assoc_long(pval_res, "errorcode", error_code);
1889 add_assoc_string(pval_res, "errorstring",
1890 (char *) ccl_err_msg(error_code), 1);
1891 add_assoc_long(pval_res, "errorpos", error_pos);
1896 WRBUF wrbuf_pqf = wrbuf_alloc();
1897 ccl_stop_words_t csw = ccl_stop_words_create();
1898 int r = ccl_stop_words_tree(csw, p->bibset, &rpn);
1902 /* stop words were removed. Return stopwords info */
1903 zval *zval_stopwords;
1906 MAKE_STD_ZVAL(zval_stopwords);
1907 array_init(zval_stopwords);
1908 for (idx = 0; ; idx++)
1910 zval *zval_stopword;
1914 if (!ccl_stop_words_info(csw, idx, &qname, &term))
1917 MAKE_STD_ZVAL(zval_stopword);
1918 array_init(zval_stopword);
1920 add_assoc_string(zval_stopword, "field", (char *) qname, 1);
1921 add_assoc_string(zval_stopword, "term", (char *) term, 1);
1922 add_next_index_zval(zval_stopwords, zval_stopword);
1924 add_assoc_zval(pval_res, "stopwords", zval_stopwords);
1926 ccl_pquery(wrbuf_pqf, rpn);
1927 add_assoc_stringl(pval_res, "rpn",
1928 wrbuf_buf(wrbuf_pqf), wrbuf_len(wrbuf_pqf), 1);
1929 wrbuf_destroy(wrbuf_pqf);
1930 ccl_stop_words_destroy(csw);
1933 ccl_rpn_delete(rpn);
1942 #if YAZ_VERSIONL >= 0x050100
1944 /* {{{ proto bool yaz_cql_parse(resource id, string cql, array res, bool rev)
1945 Parse a CQL query */
1946 PHP_FUNCTION(yaz_cql_parse)
1948 zval *pval_id, *pval_res = 0;
1952 zend_bool reverse = 0;
1954 if (ZEND_NUM_ARGS() != 4 ||
1955 zend_parse_parameters(4 TSRMLS_CC, "zszb",
1956 &pval_id, &query, &query_len, &pval_res, &reverse)
1961 zval_dtor(pval_res);
1962 array_init(pval_res);
1963 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1966 ODR odr = odr_createmem(ODR_ENCODE);
1967 YAZ_PQF_Parser pp = yaz_pqf_create();
1968 Z_RPNQuery *rpn = yaz_pqf_parse(pp, odr, query);
1969 WRBUF wrbuf_cql = wrbuf_alloc();
1972 add_assoc_long(pval_res, "errorcode", 0);
1973 add_assoc_string(pval_res, "addinfo",
1974 (char *) "PQF syntax error", 1);
1976 } else if ((r = cql_transform_rpn2cql_stream(p->ct, wrbuf_vp_puts,
1978 add_assoc_long(pval_res, "errorcode", r);
1981 add_assoc_string(pval_res, "cql",
1982 (char *) wrbuf_cstr(wrbuf_cql), 1);
1985 wrbuf_destroy(wrbuf_cql);
1986 yaz_pqf_destroy(pp);
1989 CQL_parser cp = cql_parser_create();
1990 int r = cql_parser_string(cp, query);
1992 add_assoc_long(pval_res, "errorcode", 0);
1993 add_assoc_string(pval_res, "addinfo",
1994 (char *) "syntax error", 1);
1997 WRBUF wrbuf_addinfo = wrbuf_alloc();
1998 WRBUF wrbuf_pqf = wrbuf_alloc();
1999 r = cql_transform_r(p->ct, cql_parser_result(cp), wrbuf_addinfo,
2000 wrbuf_vp_puts, wrbuf_pqf);
2002 add_assoc_long(pval_res, "errorcode", r);
2003 if (wrbuf_len(wrbuf_addinfo))
2004 add_assoc_string(pval_res, "addinfo",
2005 (char *) wrbuf_cstr(wrbuf_addinfo), 1);
2008 wrbuf_chop_right(wrbuf_pqf);
2009 add_assoc_string(pval_res, "rpn",
2010 (char *) wrbuf_cstr(wrbuf_pqf), 1);
2013 wrbuf_destroy(wrbuf_pqf);
2014 wrbuf_destroy(wrbuf_addinfo);
2016 cql_parser_destroy(cp);
2027 #if YAZ_VERSIONL >= 0x050100
2028 /* {{{ proto void yaz_cql_conf(resource id, array package)
2029 Configure CQL package */
2030 PHP_FUNCTION(yaz_cql_conf)
2032 zval *pval_id, *pval_package;
2035 if (ZEND_NUM_ARGS() != 2 ||
2036 zend_parse_parameters(2 TSRMLS_CC, "za", &pval_id, &pval_package)
2040 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
2042 HashTable *ht = Z_ARRVAL_PP(&pval_package);
2047 cql_transform_close(p->ct);
2048 p->ct = cql_transform_create();
2050 for (zend_hash_internal_pointer_reset_ex(ht, &pos);
2051 zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
2052 zend_hash_move_forward_ex(ht, &pos)
2055 #if PHP_API_VERSION > 20010101
2056 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
2058 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
2060 if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
2064 cql_transform_define_pattern(p->ct, key, (*ent)->value.str.val);
2072 /* {{{ proto bool yaz_database (resource id, string databases)
2073 Specify the databases within a session */
2074 PHP_FUNCTION(yaz_database)
2081 if (ZEND_NUM_ARGS() != 2 ||
2082 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id,
2083 &database, &database_len) == FAILURE) {
2087 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
2088 option_set(p, "databaseName", database);
2094 /* {{{ php_yaz_init_globals
2096 static void php_yaz_init_globals(zend_yaz_globals *yaz_globals)
2098 yaz_globals->assoc_seq = 0;
2099 yaz_globals->max_links = 100;
2100 yaz_globals->keepalive = 120;
2101 yaz_globals->log_file = NULL;
2102 yaz_globals->log_mask = NULL;
2106 static void yaz_close_session(Yaz_Association *as TSRMLS_DC)
2108 if (*as && (*as)->order == YAZSG(assoc_seq)) {
2109 if ((*as)->persistent) {
2112 yaz_association_destroy(*as);
2118 static void yaz_close_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
2120 Yaz_Association *as = (Yaz_Association *) rsrc->ptr;
2121 yaz_close_session(as TSRMLS_CC);
2124 /* {{{ PHP_INI_BEGIN
2127 #if PHP_MAJOR_VERSION >= 5
2128 STD_PHP_INI_ENTRY("yaz.max_links", "100", PHP_INI_ALL, OnUpdateLong, max_links, zend_yaz_globals, yaz_globals)
2130 STD_PHP_INI_ENTRY("yaz.max_links", "100", PHP_INI_ALL, OnUpdateInt, max_links, zend_yaz_globals, yaz_globals)
2132 #if PHP_MAJOR_VERSION >= 5
2133 STD_PHP_INI_ENTRY("yaz.keepalive", "120", PHP_INI_ALL, OnUpdateLong, keepalive, zend_yaz_globals, yaz_globals)
2135 STD_PHP_INI_ENTRY("yaz.keepalive", "120", PHP_INI_ALL, OnUpdateInt, keepalive, zend_yaz_globals, yaz_globals)
2137 STD_PHP_INI_ENTRY("yaz.log_file", NULL, PHP_INI_ALL, OnUpdateString, log_file, zend_yaz_globals, yaz_globals)
2138 STD_PHP_INI_ENTRY("yaz.log_mask", NULL, PHP_INI_ALL, OnUpdateString, log_mask, zend_yaz_globals, yaz_globals)
2142 PHP_MINIT_FUNCTION(yaz)
2148 yaz_mutex = tsrm_mutex_alloc();
2151 ZEND_INIT_MODULE_GLOBALS(yaz, php_yaz_init_globals, NULL);
2153 REGISTER_INI_ENTRIES();
2155 REGISTER_LONG_CONSTANT("ZOOM_EVENT_NONE", ZOOM_EVENT_NONE,
2156 CONST_CS|CONST_PERSISTENT);
2157 REGISTER_LONG_CONSTANT("ZOOM_EVENT_CONNECT", ZOOM_EVENT_CONNECT,
2158 CONST_CS|CONST_PERSISTENT);
2159 REGISTER_LONG_CONSTANT("ZOOM_EVENT_SEND_DATA", ZOOM_EVENT_SEND_DATA,
2160 CONST_CS|CONST_PERSISTENT);
2161 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_DATA", ZOOM_EVENT_RECV_DATA,
2162 CONST_CS|CONST_PERSISTENT);
2163 REGISTER_LONG_CONSTANT("ZOOM_EVENT_TIMEOUT", ZOOM_EVENT_TIMEOUT,
2164 CONST_CS|CONST_PERSISTENT);
2165 REGISTER_LONG_CONSTANT("ZOOM_EVENT_UNKNOWN", ZOOM_EVENT_UNKNOWN,
2166 CONST_CS|CONST_PERSISTENT);
2167 REGISTER_LONG_CONSTANT("ZOOM_EVENT_SEND_APDU", ZOOM_EVENT_SEND_APDU,
2168 CONST_CS|CONST_PERSISTENT);
2169 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_APDU", ZOOM_EVENT_RECV_APDU,
2170 CONST_CS|CONST_PERSISTENT);
2171 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_RECORD", ZOOM_EVENT_RECV_RECORD,
2172 CONST_CS|CONST_PERSISTENT);
2173 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_SEARCH", ZOOM_EVENT_RECV_SEARCH,
2174 CONST_CS|CONST_PERSISTENT);
2176 fname = YAZSG(log_file);
2177 mask = YAZSG(log_mask);
2178 if (fname && *fname)
2180 yaz_log_init_file(fname);
2183 yaz_log_init_level(yaz_log_mask_str(mask));
2186 yaz_log_init_level(0);
2188 le_link = zend_register_list_destructors_ex(yaz_close_link, 0, "YAZ link", module_number);
2190 order_associations = 1;
2191 shared_associations = xmalloc(sizeof(*shared_associations) * MAX_ASSOC);
2192 for (i = 0; i < MAX_ASSOC; i++) {
2193 shared_associations[i] = 0;
2198 PHP_MSHUTDOWN_FUNCTION(yaz)
2202 if (shared_associations) {
2203 for (i = 0; i < MAX_ASSOC; i++) {
2204 yaz_association_destroy (shared_associations[i]);
2206 xfree(shared_associations);
2207 shared_associations = 0;
2210 tsrm_mutex_free(yaz_mutex);
2213 yaz_log_init_file(0);
2215 UNREGISTER_INI_ENTRIES();
2220 PHP_MINFO_FUNCTION(yaz)
2222 char version_str[20];
2224 strcpy(version_str, "unknown");
2225 yaz_version(version_str, 0);
2226 php_info_print_table_start();
2227 php_info_print_table_row(2, "YAZ Support", "enabled");
2228 php_info_print_table_row(2, "PHP/YAZ Version", PHP_YAZ_VERSION);
2229 php_info_print_table_row(2, "YAZ Version", version_str);
2230 php_info_print_table_row(2, "Compiled with YAZ version", YAZ_VERSION);
2231 php_info_print_table_end();
2234 PHP_RSHUTDOWN_FUNCTION(yaz)
2240 tsrm_mutex_lock(yaz_mutex);
2242 for (i = 0; i < YAZSG(max_links); i++) {
2243 Yaz_Association *as = shared_associations + i;
2246 if (now - (*as)->time_stamp > YAZSG(keepalive))
2248 yaz_association_destroy(*as);
2254 tsrm_mutex_unlock(yaz_mutex);
2259 PHP_RINIT_FUNCTION(yaz)
2263 sprintf(pidstr, "%ld", (long) getpid());
2265 tsrm_mutex_lock(yaz_mutex);
2267 YAZSG(assoc_seq) = order_associations++;
2269 tsrm_mutex_unlock(yaz_mutex);
2271 yaz_log_init_prefix(pidstr);
2275 zend_module_entry yaz_module_entry = {
2276 #if ZEND_MODULE_API_NO >= 20010901
2277 STANDARD_MODULE_HEADER,
2286 #if ZEND_MODULE_API_NO >= 20010901
2289 STANDARD_MODULE_PROPERTIES
2300 * vim600: sw=4 ts=4 fdm=marker
2301 * vim<600: sw=4 ts=4