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 #if PHP_API_VERSION >= 20150101
54 #define ADD_ASSOC_STRING(x, y, z) add_assoc_string(x, y, z)
55 #define ADD_NEXT_INDEX_STRING(x, y) add_next_index_string(x, y)
56 #define ADD_NEXT_INDEX_STRINGl(x, y, z) add_next_index_stringl(x, y, z)
58 #define ADD_ASSOC_STRING(x, y, z) add_assoc_string(x, y, z, 1)
59 #define ADD_NEXT_INDEX_STRING(x, y) add_next_index_string(x, y, 1)
60 #define ADD_NEXT_INDEX_STRINGl(x, y, z) add_next_index_stringl(x, y, z, 1)
63 struct Yaz_AssociationInfo {
65 #if YAZ_VERSIONL >= 0x050100
68 ZOOM_connection zoom_conn;
69 ZOOM_resultset zoom_set;
70 ZOOM_scanset zoom_scan;
71 ZOOM_package zoom_package;
80 static Yaz_Association yaz_association_mk()
82 Yaz_Association p = xmalloc(sizeof(*p));
84 p->zoom_conn = ZOOM_connection_create(0);
88 ZOOM_connection_option_set(p->zoom_conn, "implementationName", "PHP");
89 ZOOM_connection_option_set(p->zoom_conn, "async", "1");
94 p->bibset = ccl_qual_mk();
95 #if YAZ_VERSIONL >= 0x050100
96 p->ct = cql_transform_create();
102 static void yaz_association_destroy(Yaz_Association p)
108 #if YAZ_VERSIONL >= 0x050100
109 cql_transform_close(p->ct);
111 ZOOM_resultset_destroy(p->zoom_set);
112 ZOOM_scanset_destroy(p->zoom_scan);
113 ZOOM_package_destroy(p->zoom_package);
114 ZOOM_connection_destroy(p->zoom_conn);
115 xfree(p->sort_criteria);
116 ccl_qual_rm(&p->bibset);
120 static MUTEX_T yaz_mutex;
123 ZEND_DECLARE_MODULE_GLOBALS(yaz);
125 static Yaz_Association *shared_associations;
126 static int order_associations;
130 #ifdef COMPILE_DL_YAZ
134 #ifdef ZEND_BEGIN_ARG_INFO
135 ZEND_BEGIN_ARG_INFO(first_argument_force_ref, 0)
136 ZEND_ARG_PASS_INFO(1)
139 ZEND_BEGIN_ARG_INFO(second_argument_force_ref, 0)
140 ZEND_ARG_PASS_INFO(0)
141 ZEND_ARG_PASS_INFO(1)
144 ZEND_BEGIN_ARG_INFO(third_argument_force_ref, 0)
145 ZEND_ARG_PASS_INFO(0)
146 ZEND_ARG_PASS_INFO(0)
147 ZEND_ARG_PASS_INFO(1)
150 static unsigned char first_argument_force_ref[] = {
152 static unsigned char second_argument_force_ref[] = {
153 2, BYREF_NONE, BYREF_FORCE };
154 static unsigned char third_argument_force_ref[] = {
155 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
159 zend_function_entry yaz_functions [] = {
160 PHP_FE(yaz_connect, NULL)
161 PHP_FE(yaz_close, NULL)
162 PHP_FE(yaz_search, NULL)
163 PHP_FE(yaz_wait, first_argument_force_ref)
164 PHP_FE(yaz_errno, NULL)
165 PHP_FE(yaz_error, NULL)
166 PHP_FE(yaz_addinfo, NULL)
167 PHP_FE(yaz_hits, second_argument_force_ref)
168 PHP_FE(yaz_record, NULL)
169 PHP_FE(yaz_syntax, NULL)
170 PHP_FE(yaz_element, NULL)
171 PHP_FE(yaz_range, NULL)
172 PHP_FE(yaz_itemorder, NULL)
173 PHP_FE(yaz_es_result, NULL)
174 PHP_FE(yaz_scan, NULL)
175 PHP_FE(yaz_scan_result, second_argument_force_ref)
176 PHP_FE(yaz_present, NULL)
177 PHP_FE(yaz_ccl_conf, NULL)
178 PHP_FE(yaz_ccl_parse, third_argument_force_ref)
179 #if YAZ_VERSIONL >= 0x050100
180 PHP_FE(yaz_cql_parse, third_argument_force_ref)
181 PHP_FE(yaz_cql_conf, NULL)
183 PHP_FE(yaz_database, NULL)
184 PHP_FE(yaz_sort, NULL)
185 PHP_FE(yaz_schema, NULL)
186 PHP_FE(yaz_set_option, NULL)
187 PHP_FE(yaz_get_option, NULL)
192 static void get_assoc(INTERNAL_FUNCTION_PARAMETERS, zval *id, Yaz_Association *assocp)
194 Yaz_Association *as = 0;
199 tsrm_mutex_lock(yaz_mutex);
202 #if PHP_API_VERSION >= 20150101
203 as = (Yaz_Association *) zend_fetch_resource(Z_RES_P(pv_res),
204 "YAZ link", le_link);
206 ZEND_FETCH_RESOURCE(as, Yaz_Association *, &id, -1, "YAZ link", le_link);
208 if (as && *as && (*as)->order == YAZSG(assoc_seq) && (*as)->in_use) {
212 tsrm_mutex_unlock(yaz_mutex);
214 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid YAZ handle");
218 static void release_assoc(Yaz_Association assoc)
222 tsrm_mutex_unlock(yaz_mutex);
227 static const char *array_lookup_string(HashTable *ht, const char *idx)
229 #if PHP_API_VERSION >= 20150101
232 zend_string *str = zend_string_init(idx, strlen(idx), 0);
233 zv = zend_hash_find(ht, str);
234 zend_string_release(str);
236 convert_to_string(zv);
237 if (Z_TYPE_P(zv) == IS_STRING)
238 return ZSTR_VAL(zv->value.str);
243 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
244 SEPARATE_ZVAL(pvalue);
245 convert_to_string(*pvalue);
246 return (*pvalue)->value.str.val;
253 #if PHP_API_VERSION >= 20150101
258 *array_lookup_long(HashTable *ht, const char *idx)
260 #if PHP_API_VERSION >= 20150101
263 zend_string *str = zend_string_init(idx, strlen(idx), 0);
264 zv = zend_hash_find(ht, str);
265 zend_string_release(str);
268 if (Z_TYPE_P(zv) == IS_LONG)
269 return &zv->value.lval;
274 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
275 SEPARATE_ZVAL(pvalue);
276 convert_to_long(*pvalue);
277 return &(*pvalue)->value.lval;
283 static long *array_lookup_bool(HashTable *ht, const char *idx)
285 #if PHP_API_VERSION >= 20150101
287 static long l_true = 1;
288 static long l_false = 0;
290 zend_string *str = zend_string_init(idx, strlen(idx), 0);
291 zv = zend_hash_find(ht, str);
292 zend_string_release(str);
295 if (Z_TYPE_P(zv) == IS_TRUE)
297 if (Z_TYPE_P(zv) == IS_FALSE)
303 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
304 SEPARATE_ZVAL(pvalue);
305 convert_to_boolean(*pvalue);
306 return &(*pvalue)->value.lval;
312 static const char *option_get(Yaz_Association as, const char *name)
317 return ZOOM_connection_option_get(as->zoom_conn, name);
320 static int option_get_int(Yaz_Association as, const char *name, int def)
324 v = ZOOM_connection_option_get(as->zoom_conn, name);
333 static void option_set(Yaz_Association as, const char *name, const char *value)
336 ZOOM_connection_option_set(as->zoom_conn, name, value);
340 static void option_set_int(Yaz_Association as, const char *name, int v)
346 ZOOM_connection_option_set(as->zoom_conn, name, s);
350 static int strcmp_null(const char *s1, const char *s2)
352 if (s1 == 0 && s2 == 0) {
355 if (s1 == 0 || s2 == 0) {
358 return strcmp(s1, s2);
361 /* {{{ proto resource yaz_connect(string zurl [, array options])
362 Create target with given zurl. Returns positive id if successful. */
363 PHP_FUNCTION(yaz_connect)
369 const char *sru_str = 0, *sru_version_str = 0;
370 const char *user_str = 0, *group_str = 0, *pass_str = 0;
371 const char *cookie_str = 0, *proxy_str = 0;
372 const char *charset_str = 0;
373 const char *client_IP = 0;
374 const char *otherInfo[3];
375 const char *maximumRecordSize = 0;
376 const char *preferredMessageSize = 0;
379 Yaz_Association as = 0;
380 int max_links = YAZSG(max_links);
382 otherInfo[0] = otherInfo[1] = otherInfo[2] = 0;
384 if (ZEND_NUM_ARGS() == 1) {
385 if (zend_parse_parameters(1 TSRMLS_CC, "s", &zurl_str, &zurl_len)
389 } else if (ZEND_NUM_ARGS() == 2) {
391 if (zend_parse_parameters(2 TSRMLS_CC, "sz", &zurl_str, &zurl_len,
396 if (Z_TYPE_PP(&user) == IS_ARRAY) {
397 long *persistent_val;
399 HashTable *ht = Z_ARRVAL_PP(&user);
401 sru_str = array_lookup_string(ht, "sru");
402 sru_version_str = array_lookup_string(ht, "sru_version");
403 user_str = array_lookup_string(ht, "user");
404 group_str = array_lookup_string(ht, "group");
405 pass_str = array_lookup_string(ht, "password");
406 cookie_str = array_lookup_string(ht, "cookie");
407 proxy_str = array_lookup_string(ht, "proxy");
408 charset_str = array_lookup_string(ht, "charset");
409 persistent_val = array_lookup_bool(ht, "persistent");
410 if (persistent_val) {
411 persistent = *persistent_val;
413 piggyback_val = array_lookup_bool(ht, "piggyback");
415 piggyback = *piggyback_val;
418 array_lookup_string(ht, "maximumRecordSize");
419 preferredMessageSize =
420 array_lookup_string(ht, "preferredMessageSize");
421 otherInfo[0] = array_lookup_string(ht, "otherInfo0");
422 otherInfo[1] = array_lookup_string(ht, "otherInfo1");
423 otherInfo[2] = array_lookup_string(ht, "otherInfo2");
424 } else if (Z_TYPE_PP(&user) == IS_STRING) {
425 convert_to_string_ex(&user);
426 if (*user->value.str.val)
427 user_str = user->value.str.val;
432 for (cp = zurl_str; *cp && strchr("\t\n ", *cp); cp++);
434 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty zurl");
437 /* see if we have it already ... */
439 tsrm_mutex_lock(yaz_mutex);
441 for (i = 0; i < max_links; i++) {
442 as = shared_associations[i];
443 if (persistent && as && !as->in_use &&
444 !strcmp_null(option_get(as, "host"), zurl_str) &&
445 !strcmp_null(option_get(as, "proxy"), proxy_str) &&
446 !strcmp_null(option_get(as, "sru"), sru_str) &&
447 !strcmp_null(option_get(as, "sru_version"), sru_version_str) &&
448 !strcmp_null(option_get(as, "user"), user_str) &&
449 !strcmp_null(option_get(as, "group"), group_str) &&
450 !strcmp_null(option_get(as, "pass"), pass_str) &&
451 !strcmp_null(option_get(as, "cookie"), cookie_str) &&
452 !strcmp_null(option_get(as, "charset"), charset_str))
455 if (i == max_links) {
456 /* we didn't have it (or already in use) */
458 int min_order = 2000000000;
460 /* find completely free slot or the oldest one */
461 for (i = 0; i < max_links && shared_associations[i]; i++) {
462 as = shared_associations[i];
463 if (persistent && !as->in_use && as->order < min_order) {
464 min_order = as->order;
469 if (i == max_links) {
474 tsrm_mutex_unlock(yaz_mutex);
476 sprintf(msg, "No YAZ handles available. max_links=%d",
478 php_error_docref(NULL TSRMLS_CC, E_WARNING,
479 "No YAZ handles available. max_links=%ld",
481 RETURN_LONG(0); /* no free slot */
482 } else { /* "best" free slot */
483 yaz_association_destroy(shared_associations[i]);
486 shared_associations[i] = as = yaz_association_mk();
488 option_set(as, "proxy", proxy_str);
489 option_set(as, "sru", sru_str);
490 option_set(as, "sru_version", sru_version_str);
491 option_set(as, "user", user_str);
492 option_set(as, "group", group_str);
493 option_set(as, "pass", pass_str);
494 option_set(as, "cookie", cookie_str);
495 option_set(as, "charset", charset_str);
497 if (maximumRecordSize)
498 option_set(as, "maximumRecordSize", maximumRecordSize);
499 if (preferredMessageSize)
500 option_set(as, "preferredMessageSize", preferredMessageSize);
501 option_set(as, "otherInfo0", otherInfo[0]);
502 option_set(as, "otherInfo1", otherInfo[1]);
503 option_set(as, "otherInfo2", otherInfo[2]);
504 option_set(as, "clientIP", client_IP);
505 option_set(as, "piggyback", piggyback ? "1" : "0");
506 option_set_int(as, "start", 0);
507 option_set_int(as, "count", 0);
508 ZOOM_connection_connect(as->zoom_conn, zurl_str, 0);
510 as->persistent = persistent;
511 as->order = YAZSG(assoc_seq);
512 as->time_stamp = time(0);
516 ZOOM_resultset_destroy(as->zoom_set);
520 tsrm_mutex_unlock(yaz_mutex);
523 ZEND_REGISTER_RESOURCE(return_value, &shared_associations[i], le_link);
524 as->zval_resource = Z_LVAL_P(return_value);
528 /* {{{ proto bool yaz_close(resource id)
529 Destory and close target */
530 PHP_FUNCTION(yaz_close)
535 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters(1 TSRMLS_CC, "z", &id)
539 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
544 zend_list_delete(id->value.lval);
550 /* {{{ proto bool yaz_search(resource id, string type, string query)
551 Specify query of type for search - returns true if successful */
552 PHP_FUNCTION(yaz_search)
554 char *query_str, *type_str;
555 int query_len, type_len;
559 if (ZEND_NUM_ARGS() != 3 ||
560 zend_parse_parameters(3 TSRMLS_CC, "zss", &id,
561 &type_str, &type_len,
562 &query_str, &query_len) == FAILURE) {
565 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
570 ZOOM_resultset_destroy(p->zoom_set);
575 if (!strcmp(type_str, "rpn")) {
576 ZOOM_query q = ZOOM_query_create();
577 if (ZOOM_query_prefix(q, query_str) == 0)
579 if (p->sort_criteria) {
580 ZOOM_query_sortby(q, p->sort_criteria);
582 xfree(p->sort_criteria);
583 p->sort_criteria = 0;
584 p->zoom_set = ZOOM_connection_search(p->zoom_conn, q);
587 ZOOM_query_destroy(q);
589 else if (!strcmp(type_str, "cql")) {
590 ZOOM_query q = ZOOM_query_create();
591 if (ZOOM_query_cql(q, query_str) == 0)
593 if (p->sort_criteria) {
594 ZOOM_query_sortby(q, p->sort_criteria);
596 xfree(p->sort_criteria);
597 p->sort_criteria = 0;
598 p->zoom_set = ZOOM_connection_search(p->zoom_conn, q);
601 ZOOM_query_destroy(q);
605 php_error_docref(NULL TSRMLS_CC, E_WARNING,
606 "Invalid query type %s", type_str);
612 /* {{{ proto bool yaz_present(resource id)
614 PHP_FUNCTION(yaz_present)
619 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters(1 TSRMLS_CC, "z", &id)
623 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
629 size_t start = option_get_int(p, "start", 0);
630 size_t count = option_get_int(p, "count", 0);
632 ZOOM_resultset_records(p->zoom_set, 0 /* recs */, start, count);
640 /* {{{ proto bool yaz_wait([array options])
642 PHP_FUNCTION(yaz_wait)
644 zval *pval_options = 0;
647 ZOOM_connection conn_ar[MAX_ASSOC];
648 Yaz_Association conn_as[MAX_ASSOC];
651 if (ZEND_NUM_ARGS() == 1) {
653 long *event_bool = 0;
654 HashTable *options_ht = 0;
655 if (zend_parse_parameters(1 TSRMLS_CC, "a", &pval_options) ==
659 options_ht = Z_ARRVAL_PP(&pval_options);
660 val = array_lookup_long(options_ht, "timeout");
664 event_bool = array_lookup_bool(options_ht, "event");
665 if (event_bool && *event_bool)
668 else if (ZEND_NUM_ARGS() > 1) {
672 tsrm_mutex_lock(yaz_mutex);
674 for (i = 0; i<YAZSG(max_links); i++) {
675 Yaz_Association p = shared_associations[i];
676 if (p && p->order == YAZSG(assoc_seq)) {
679 sprintf(str, "%d", timeout);
680 ZOOM_connection_option_set(p->zoom_conn, "timeout", str);
682 conn_ar[no++] = p->zoom_conn;
686 tsrm_mutex_unlock(yaz_mutex);
689 long ev = ZOOM_event(no, conn_ar);
693 Yaz_Association p = conn_as[ev-1];
694 int event_code = ZOOM_connection_last_event(p->zoom_conn);
697 add_assoc_long(pval_options, "connid", ev);
698 add_assoc_long(pval_options, "eventcode", event_code);
701 zend_list_addref(p->zval_resource);
702 Z_LVAL_P(return_value) = p->zval_resource;
703 Z_TYPE_P(return_value) = IS_RESOURCE;
709 while (ZOOM_event(no, conn_ar))
716 /* {{{ proto int yaz_errno(resource id)
717 Return last error number (>0 for bib-1 diagnostic, <0 for other error, 0 for no error */
718 PHP_FUNCTION(yaz_errno)
723 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters(1 TSRMLS_CC, "z", &id)
727 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
731 RETVAL_LONG(ZOOM_connection_errcode(p->zoom_conn));
736 /* {{{ proto string yaz_error(resource id)
737 Return last error message */
738 PHP_FUNCTION(yaz_error)
743 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters(1 TSRMLS_CC, "z", &id)
747 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
749 int code = ZOOM_connection_errcode(p->zoom_conn);
750 const char *msg = ZOOM_connection_errmsg(p->zoom_conn);
755 return_value->value.str.len = strlen(msg);
756 return_value->value.str.val = estrndup(msg, return_value->value.str.len);
757 return_value->type = IS_STRING;
763 /* {{{ proto string yaz_addinfo(resource id)
764 Return additional info for last error (empty string if none) */
765 PHP_FUNCTION(yaz_addinfo)
770 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters(1 TSRMLS_CC, "z", &id)
774 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
776 const char *addinfo = ZOOM_connection_addinfo(p->zoom_conn);
778 return_value->value.str.len = strlen(addinfo);
779 return_value->value.str.val = estrndup(addinfo, return_value->value.str.len);
780 return_value->type = IS_STRING;
786 /* {{{ proto int yaz_hits(resource id [, array searchresult])
787 Return number of hits (result count) for last search */
788 PHP_FUNCTION(yaz_hits)
790 zval *id, *searchresult = 0;
793 if (ZEND_NUM_ARGS() == 1) {
794 if (zend_parse_parameters(1 TSRMLS_CC, "z", &id) == FAILURE) {
797 } else if (ZEND_NUM_ARGS() == 2) {
798 if (zend_parse_parameters(2 TSRMLS_CC, "za", &id, &searchresult)
806 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
807 if (p && p->zoom_set) {
808 RETVAL_LONG(ZOOM_resultset_size(p->zoom_set));
812 ZOOM_resultset_option_get(p->zoom_set, "resultSetStatus");
814 ADD_ASSOC_STRING(searchresult, "resultSetStatus",
820 ZOOM_resultset_option_get(p->zoom_set, "searchresult.size");
823 if (sz_str && *sz_str)
825 for (i = 0; i<sz; i++)
828 const char *opt_value;
831 MAKE_STD_ZVAL(zval_element);
832 array_init(zval_element);
833 add_next_index_zval(searchresult, zval_element);
835 sprintf(opt_name, "searchresult.%d.id", i);
836 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
838 ADD_ASSOC_STRING(zval_element, "id", (char *) opt_value);
840 sprintf(opt_name, "searchresult.%d.count", i);
841 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
843 add_assoc_long(zval_element, "count", atoi(opt_value));
845 sprintf(opt_name, "searchresult.%d.subquery.term", i);
846 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
848 ADD_ASSOC_STRING(zval_element, "subquery.term",
851 sprintf(opt_name, "searchresult.%d.interpretation.term", i);
852 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
854 ADD_ASSOC_STRING(zval_element, "interpretation.term",
857 sprintf(opt_name, "searchresult.%d.recommendation.term", i);
858 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
860 ADD_ASSOC_STRING(zval_element, "recommendation.term",
872 static Z_GenericRecord *marc_to_grs1(const char *buf, ODR o)
876 int indicator_length;
877 int identifier_length;
879 int length_data_entry;
881 int max_elements = 256;
882 Z_GenericRecord *r = odr_malloc(o, sizeof(*r));
883 r->elements = odr_malloc(o, sizeof(*r->elements) * max_elements);
886 record_length = atoi_n(buf, 5);
887 if (record_length < 25) {
890 indicator_length = atoi_n(buf + 10, 1);
891 identifier_length = atoi_n(buf + 11, 1);
892 base_address = atoi_n(buf + 12, 5);
894 length_data_entry = atoi_n(buf + 20, 1);
895 length_starting = atoi_n(buf + 21, 1);
897 for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) {
898 entry_p += 3 + length_data_entry + length_starting;
899 if (entry_p >= record_length) {
905 Z_TaggedElement *tag;
906 tag = r->elements[r->num_elements++] = odr_malloc(o, sizeof(*tag));
907 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
909 tag->tagOccurrence = 0;
911 tag->appliedVariant = 0;
912 tag->tagValue = odr_malloc(o, sizeof(*tag->tagValue));
913 tag->tagValue->which = Z_StringOrNumeric_string;
914 tag->tagValue->u.string = odr_strdup(o, "leader");
916 tag->content = odr_malloc(o, sizeof(*tag->content));
917 tag->content->which = Z_ElementData_string;
918 tag->content->u.string = odr_strdupn(o, buf, 24);
920 base_address = entry_p + 1;
921 for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) {
922 Z_TaggedElement *tag;
928 int identifier_flag = 1;
930 memcpy(tag_str, buf+entry_p, 3);
934 if ((r->num_elements + 1) >= max_elements) {
935 Z_TaggedElement **tmp = r->elements;
937 /* double array space, throw away old buffer (nibble memory) */
938 r->elements = odr_malloc(o, sizeof(*r->elements) * (max_elements *= 2));
939 memcpy(r->elements, tmp, r->num_elements * sizeof(*tmp));
941 tag = r->elements[r->num_elements++] = odr_malloc(o, sizeof(*tag));
942 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
944 tag->tagOccurrence = 0;
946 tag->appliedVariant = 0;
947 tag->tagValue = odr_malloc(o, sizeof(*tag->tagValue));
948 tag->tagValue->which = Z_StringOrNumeric_string;
949 tag->tagValue->u.string = odr_strdup(o, tag_str);
951 tag->content = odr_malloc(o, sizeof(*tag->content));
952 tag->content->which = Z_ElementData_subtree;
954 tag->content->u.subtree = odr_malloc(o, sizeof(*tag->content->u.subtree));
955 tag->content->u.subtree->elements = odr_malloc(o, sizeof(*r->elements));
956 tag->content->u.subtree->num_elements = 1;
958 tag = tag->content->u.subtree->elements[0] = odr_malloc(o, sizeof(**tag->content->u.subtree->elements));
960 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
962 tag->tagOccurrence = 0;
964 tag->appliedVariant = 0;
965 tag->tagValue = odr_malloc(o, sizeof(*tag->tagValue));
966 tag->tagValue->which = Z_StringOrNumeric_string;
967 tag->content = odr_malloc(o, sizeof(*tag->content));
969 data_length = atoi_n(buf + entry_p, length_data_entry);
970 entry_p += length_data_entry;
971 data_offset = atoi_n(buf + entry_p, length_starting);
972 entry_p += length_starting;
973 i = data_offset + base_address;
974 end_offset = i + data_length - 1;
976 if (indicator_length > 0 && indicator_length < 5) {
977 if (buf[i + indicator_length] != ISO2709_IDFS) {
980 } else if (!memcmp(tag_str, "00", 2)) {
984 if (identifier_flag && indicator_length) {
986 tag->tagValue->u.string = odr_malloc(o, indicator_length + 1);
987 memcpy(tag->tagValue->u.string, buf + i, indicator_length);
988 tag->tagValue->u.string[indicator_length] = '\0';
989 i += indicator_length;
991 tag->content->which = Z_ElementData_subtree;
993 tag->content->u.subtree = odr_malloc(o, sizeof(*tag->content->u.subtree));
994 tag->content->u.subtree->elements = odr_malloc(o, 256 * sizeof(*r->elements));
995 tag->content->u.subtree->num_elements = 0;
997 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset) {
1000 Z_TaggedElement *parent_tag = tag;
1001 Z_TaggedElement *tag = odr_malloc(o, sizeof(*tag));
1003 if (parent_tag->content->u.subtree->num_elements < 256) {
1004 parent_tag->content->u.subtree->elements[
1005 parent_tag->content->u.subtree->num_elements++] = tag;
1008 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
1010 tag->tagOccurrence = 0;
1012 tag->appliedVariant = 0;
1013 tag->tagValue = odr_malloc(o, sizeof(*tag->tagValue));
1014 tag->tagValue->which = Z_StringOrNumeric_string;
1017 tag->tagValue->u.string = odr_malloc(o, identifier_length);
1018 memcpy(tag->tagValue->u.string, buf + i + 1, identifier_length - 1);
1019 tag->tagValue->u.string[identifier_length - 1] = '\0';
1020 i += identifier_length;
1023 tag->content = odr_malloc(o, sizeof(*tag->content));
1024 tag->content->which = Z_ElementData_string;
1027 while ( buf[i] != ISO2709_RS &&
1028 buf[i] != ISO2709_IDFS &&
1029 buf[i] != ISO2709_FS && i < end_offset) {
1033 tag->content->u.string = odr_malloc(o, i - i0 + 1);
1034 memcpy(tag->content->u.string, buf + i0, i - i0);
1035 tag->content->u.string[i - i0] = '\0';
1040 tag->tagValue->u.string = "@";
1041 tag->content->which = Z_ElementData_string;
1043 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset) {
1046 tag->content->u.string = odr_malloc(o, i - i0 +1);
1047 memcpy(tag->content->u.string, buf + i0, i - i0);
1048 tag->content->u.string[i-i0] = '\0';
1061 static struct cvt_handle *cvt_open(const char *to, const char *from)
1063 ODR o = odr_createmem(ODR_ENCODE);
1065 struct cvt_handle *cvt = odr_malloc(o, sizeof(*cvt));
1068 cvt->buf = odr_malloc(o, cvt->size);
1071 cvt->cd = yaz_iconv_open(to, from);
1075 static void cvt_close(struct cvt_handle *cvt)
1078 yaz_iconv_close(cvt->cd);
1079 odr_destroy(cvt->odr);
1082 static const char *cvt_string(const char *input, struct cvt_handle *cvt)
1087 size_t inbytesleft = strlen(input);
1088 const char *inp = input;
1089 size_t outbytesleft = cvt->size - 1;
1090 char *outp = cvt->buf;
1091 size_t r = yaz_iconv(cvt->cd, (char**) &inp, &inbytesleft,
1092 &outp, &outbytesleft);
1093 if (r == (size_t) (-1)) {
1094 int e = yaz_iconv_error(cvt->cd);
1095 if (e != YAZ_ICONV_E2BIG || cvt->size > 200000)
1100 cvt->size = cvt->size * 2 + 30;
1101 cvt->buf = (char*) odr_malloc(cvt->odr, cvt->size);
1103 cvt->buf[outp - cvt->buf] = '\0';
1110 static void retval_array3_grs1(zval *return_value, Z_GenericRecord *p,
1111 struct cvt_handle *cvt)
1117 struct tag_list *next;
1119 NMEM nmem = nmem_create();
1121 array_init(return_value);
1122 for (i = 0; i<p->num_elements; i++)
1124 struct tag_list *tl;
1127 Z_TaggedElement *e = p->elements[i];
1128 char tagstr[32], *tag = 0;
1130 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1132 sprintf(tagstr, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1135 else if (e->tagValue->which == Z_StringOrNumeric_string)
1136 tag = e->tagValue->u.string, zval_element;
1141 for (tl = all_tags; tl; tl = tl->next)
1142 if (!strcmp(tl->tag, tag))
1145 zval_list = tl->zval_list;
1148 MAKE_STD_ZVAL(zval_list);
1149 array_init(zval_list);
1150 add_assoc_zval(return_value, tag, zval_list);
1152 tl = nmem_malloc(nmem, sizeof(*tl));
1153 tl->tag = nmem_strdup(nmem, tag);
1154 tl->zval_list = zval_list;
1155 tl->next = all_tags;
1158 MAKE_STD_ZVAL(zval_element);
1159 array_init(zval_element);
1160 add_next_index_zval(zval_list, zval_element);
1161 if (e->content->which == Z_ElementData_subtree)
1163 /* we have a subtree. Move to first child */
1164 Z_GenericRecord *sub = e->content->u.subtree;
1165 if (sub->num_elements >= 1)
1166 e = sub->elements[0];
1172 const char *tag = 0;
1173 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1175 sprintf(tagstr, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1178 else if (e->tagValue->which == Z_StringOrNumeric_string)
1179 tag = e->tagValue->u.string;
1180 if (tag && e->content->which == Z_ElementData_subtree)
1183 Z_GenericRecord *sub = e->content->u.subtree;
1185 for (i = 0; tag[i]; i++)
1190 sprintf(ind_idx, "ind%d", i+1);
1191 ind_val[0] = tag[i];
1194 ADD_ASSOC_STRING(zval_element, ind_idx, ind_val);
1196 for (i = 0; i<sub->num_elements; i++)
1198 Z_TaggedElement *e = sub->elements[i];
1199 const char *tag = 0;
1200 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1202 sprintf(tagstr, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1205 else if (e->tagValue->which == Z_StringOrNumeric_string)
1206 tag = e->tagValue->u.string, zval_element;
1208 if (tag && e->content->which == Z_ElementData_string)
1210 const char *v = cvt_string(e->content->u.string, cvt);
1211 ADD_ASSOC_STRING(zval_element, (char*) tag, (char*) v);
1215 else if (tag && e->content->which == Z_ElementData_string)
1217 /* Leader or control field */
1218 const char *v = cvt_string(e->content->u.string, cvt);
1219 ZVAL_STRING(zval_element, (char*) v, 1);
1226 static void retval_array2_grs1(zval *return_value, Z_GenericRecord *p,
1227 struct cvt_handle *cvt)
1231 array_init(return_value);
1233 for (i = 0; i<p->num_elements; i++)
1237 Z_TaggedElement *e = p->elements[i];
1239 MAKE_STD_ZVAL(zval_element);
1240 array_init(zval_element);
1243 add_assoc_long(zval_element, "tagType", (long) *e->tagType);
1245 if (e->tagValue->which == Z_StringOrNumeric_string)
1246 ADD_ASSOC_STRING(zval_element, "tag", e->tagValue->u.string);
1247 else if (e->tagValue->which == Z_StringOrNumeric_numeric)
1248 add_assoc_long(zval_element, "tag", (long) *e->tagValue->u.numeric);
1250 switch (e->content->which) {
1251 case Z_ElementData_string:
1254 const char *v = cvt_string(e->content->u.string, cvt);
1255 ADD_ASSOC_STRING(zval_element, "content", (char*) v);
1258 case Z_ElementData_numeric:
1259 add_assoc_long(zval_element, "content", (long) *e->content->u.numeric);
1261 case Z_ElementData_trueOrFalse:
1262 add_assoc_bool(zval_element, "content",*e->content->u.trueOrFalse);
1264 case Z_ElementData_subtree:
1265 MAKE_STD_ZVAL(zval_sub);
1266 retval_array2_grs1(zval_sub, e->content->u.subtree, cvt);
1267 add_assoc_zval(zval_element, "content", zval_sub);
1269 add_next_index_zval(return_value, zval_element);
1273 static void retval_array1_grs1(zval *return_value, Z_GenericRecord *p,
1274 struct cvt_handle *cvt)
1276 Z_GenericRecord *grs[20];
1280 array_init(return_value);
1284 while (level >= 0) {
1286 Z_TaggedElement *e = 0;
1287 Z_GenericRecord *p = grs[level];
1292 if (eno[level] >= p->num_elements) {
1299 for (i = 0; i <= level; i++) {
1301 e = grs[i]->elements[eno[i]];
1304 tag_type = (long) *e->tagType;
1306 taglen = strlen(tag);
1307 sprintf(tag + taglen, "(%ld,", tag_type);
1308 taglen = strlen(tag);
1310 if (e->tagValue->which == Z_StringOrNumeric_string) {
1311 int len = strlen(e->tagValue->u.string);
1313 memcpy(tag + taglen, e->tagValue->u.string, len);
1314 tag[taglen+len] = '\0';
1315 } else if (e->tagValue->which == Z_StringOrNumeric_numeric) {
1316 sprintf(tag + taglen, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1318 taglen = strlen(tag);
1319 strcpy(tag + taglen, ")");
1322 ALLOC_ZVAL(my_zval);
1323 array_init(my_zval);
1324 INIT_PZVAL(my_zval);
1326 ADD_NEXT_INDEX_STRING(my_zval, tag);
1328 switch (e->content->which) {
1329 case Z_ElementData_string:
1332 const char *v = cvt_string(e->content->u.string, cvt);
1333 ADD_NEXT_INDEX_STRING(my_zval, (char*) v);
1336 case Z_ElementData_numeric:
1337 add_next_index_long(my_zval, (long) *e->content->u.numeric);
1339 case Z_ElementData_trueOrFalse:
1340 add_next_index_long(my_zval, *e->content->u.trueOrFalse);
1342 case Z_ElementData_subtree:
1345 grs[level] = e->content->u.subtree;
1349 zend_hash_next_index_insert(return_value->value.ht, (void *) &my_zval, sizeof(zval *), NULL);
1354 static void ext_grs1(zval *return_value, char type_args[][60],
1356 void (*array_func)(zval *, Z_GenericRecord *,
1357 struct cvt_handle *))
1359 Z_External *ext = (Z_External *) ZOOM_record_get(r, "ext", 0);
1360 if (ext && ext->which == Z_External_OPAC)
1361 ext = ext->u.opac->bibliographicRecord;
1363 struct cvt_handle *cvt = 0;
1364 if (type_args[2][0])
1365 cvt = cvt_open(type_args[3], type_args[2]);
1367 cvt = cvt_open(0, 0);
1369 if (ext->which == Z_External_grs1) {
1370 retval_array1_grs1(return_value, ext->u.grs1, cvt);
1371 } else if (ext->which == Z_External_octet) {
1372 Z_GenericRecord *rec = 0;
1373 if (yaz_oid_is_iso2709(ext->direct_reference))
1375 char *buf = (char *) (ext->u.octet_aligned->buf);
1376 rec = marc_to_grs1(buf, cvt->odr);
1379 (*array_func)(return_value, rec, cvt);
1387 /* {{{ proto string yaz_record(resource id, int pos, string type)
1388 Return record information at given result set position */
1389 PHP_FUNCTION(yaz_record)
1397 if (ZEND_NUM_ARGS() != 3) {
1401 if (zend_parse_parameters(3 TSRMLS_CC, "zls", &pval_id, &pos,
1402 &type, &type_len) == FAILURE) {
1406 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1408 if (p && p->zoom_set) {
1410 r = ZOOM_resultset_record(p->zoom_set, pos-1);
1413 char type_args[4][60]; /* 0; 1=2,3 (1 is assumed charset) */
1414 type_args[0][0] = 0;
1415 type_args[1][0] = 0;
1416 type_args[2][0] = 0;
1417 type_args[3][0] = 0;
1418 sscanf(type, "%59[^;];%59[^=]=%59[^,],%59[^,]", type_args[0],
1419 type_args[1], type_args[2], type_args[3]);
1421 if (!strcmp(type_args[0], "string")) {
1422 type_tmp = xstrdup(type);
1423 strcpy(type_tmp, "render");
1424 strcat(type_tmp, type + 6);
1427 if (!strcmp(type_args[0], "array") ||
1428 !strcmp(type_args[0], "array1"))
1430 ext_grs1(return_value, type_args, r, retval_array1_grs1);
1431 } else if (!strcmp(type_args[0], "array2")) {
1432 ext_grs1(return_value, type_args, r, retval_array2_grs1);
1433 } else if (!strcmp(type_args[0], "array3")) {
1434 ext_grs1(return_value, type_args, r, retval_array3_grs1);
1437 const char *info = ZOOM_record_get(r, type, &rlen);
1439 return_value->value.str.len = (rlen > 0) ? rlen : 0;
1440 return_value->value.str.val =
1441 estrndup(info, return_value->value.str.len);
1442 return_value->type = IS_STRING;
1446 php_error_docref(NULL TSRMLS_CC, E_WARNING,
1447 "Bad yaz_record type %s - or unable "
1448 "to return record with type given", type);
1458 /* {{{ proto void yaz_syntax(resource id, string syntax)
1459 Set record syntax for retrieval */
1460 PHP_FUNCTION(yaz_syntax)
1467 if (ZEND_NUM_ARGS() != 2 ||
1468 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id,
1469 &syntax, &syntax_len) == FAILURE) {
1473 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1474 option_set(p, "preferredRecordSyntax", syntax);
1479 /* {{{ proto void yaz_element(resource id, string elementsetname)
1480 Set Element-Set-Name for retrieval */
1481 PHP_FUNCTION(yaz_element)
1484 const char *element;
1488 if (ZEND_NUM_ARGS() != 2 ||
1489 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id,
1490 &element, &element_len) == FAILURE) {
1493 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1495 option_set(p, "elementSetName", element);
1500 /* {{{ proto void yaz_schema(resource id, string schema)
1501 Set Schema for retrieval */
1502 PHP_FUNCTION(yaz_schema)
1509 if (ZEND_NUM_ARGS() != 2 ||
1510 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id,
1511 &schema, &schema_len) == FAILURE) {
1515 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1516 option_set(p, "schema", schema);
1521 /* {{{ proto void yaz_set_option(resource id, mixed options)
1522 Set Option(s) for connection */
1523 PHP_FUNCTION(yaz_set_option)
1527 if (ZEND_NUM_ARGS() == 2) {
1528 zval *pval_ar, *pval_id;
1529 if (zend_parse_parameters(2 TSRMLS_CC, "za",
1530 &pval_id, &pval_ar) == FAILURE) {
1533 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1539 ht = Z_ARRVAL_PP(&pval_ar);
1540 for(zend_hash_internal_pointer_reset_ex(ht, &pos);
1541 zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
1542 zend_hash_move_forward_ex(ht, &pos)
1546 #if PHP_API_VERSION > 20010101
1547 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
1549 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
1551 if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
1554 option_set(p, key, (*ent)->value.str.val);
1558 } else if (ZEND_NUM_ARGS() == 3) {
1561 int name_len, value_len;
1562 if (zend_parse_parameters(3 TSRMLS_CC, "zss",
1563 &pval_id, &name, &name_len,
1564 &value, &value_len) == FAILURE) {
1567 get_assoc (INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1568 option_set(p, name, value);
1576 /* {{{ proto string yaz_get_option(resource id, string name)
1577 Set Option(s) for connection */
1578 PHP_FUNCTION(yaz_get_option)
1585 if (ZEND_NUM_ARGS() != 2 ||
1586 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id, &name, &name_len)
1590 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1593 v = option_get(p, name);
1597 return_value->value.str.len = strlen(v);
1598 return_value->value.str.val = estrndup(v, return_value->value.str.len);
1599 return_value->type = IS_STRING;
1607 /* {{{ proto void yaz_range(resource id, int start, int number)
1608 Set result set start point and number of records to request */
1609 PHP_FUNCTION(yaz_range)
1615 if (ZEND_NUM_ARGS() != 3 ||
1616 zend_parse_parameters(3 TSRMLS_CC, "zll", &pval_id, &start, &number)
1621 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1622 option_set_int(p, "start", start > 0 ? start - 1 : 0);
1623 option_set_int(p, "count", number);
1628 /* {{{ proto void yaz_sort(resource id, string sortspec)
1629 Set result set sorting criteria */
1630 PHP_FUNCTION(yaz_sort)
1633 const char *criteria;
1637 if (ZEND_NUM_ARGS() != 2 ||
1638 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id, &criteria,
1639 &criteria_len) == FAILURE) {
1643 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1645 xfree(p->sort_criteria);
1646 p->sort_criteria = xstrdup(criteria);
1648 ZOOM_resultset_sort(p->zoom_set, "yaz", criteria);
1654 const char *ill_array_lookup(void *handle, const char *name)
1656 return array_lookup_string((HashTable *) handle, name);
1659 /* {{{ proto void yaz_itemorder(resource id, array package)
1660 Sends Item Order request */
1661 PHP_FUNCTION(yaz_itemorder)
1663 zval *pval_id, *pval_package;
1666 if (ZEND_NUM_ARGS() != 2 ||
1667 zend_parse_parameters(2 TSRMLS_CC, "za", &pval_id, &pval_package) ==
1671 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1673 ZOOM_options options = ZOOM_options_create();
1675 ZOOM_options_set_callback(options,
1676 ill_array_lookup, Z_ARRVAL_PP(&pval_package));
1677 ZOOM_package_destroy(p->zoom_package);
1678 p->zoom_package = ZOOM_connection_package(p->zoom_conn, options);
1679 ZOOM_package_send(p->zoom_package, "itemorder");
1680 ZOOM_options_set_callback(options, 0, 0);
1681 ZOOM_options_destroy(options);
1687 /* {{{ proto void yaz_es(resource id, string type, array package)
1688 Sends Extended Services Request */
1689 PHP_FUNCTION(yaz_es)
1691 zval *pval_id, *pval_package;
1696 if (ZEND_NUM_ARGS() != 3 ||
1697 zend_parse_parameters(3 TSRMLS_CC, "zsa", &pval_id,
1698 &type, &type_len, &pval_package) == FAILURE) {
1701 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1703 ZOOM_options options = ZOOM_options_create();
1705 ZOOM_options_set_callback(options, ill_array_lookup,
1706 Z_ARRVAL_PP(&pval_package));
1707 ZOOM_package_destroy(p->zoom_package);
1708 p->zoom_package = ZOOM_connection_package(p->zoom_conn, options);
1709 ZOOM_package_send(p->zoom_package, type);
1710 ZOOM_options_set_callback(options, 0, 0);
1711 ZOOM_options_destroy(options);
1717 /* {{{ proto void yaz_scan(resource id, type, query [, flags])
1718 Sends Scan Request */
1719 PHP_FUNCTION(yaz_scan)
1721 zval *pval_id, *pval_flags;
1723 int type_len, query_len;
1724 HashTable *flags_ht = 0;
1727 if (ZEND_NUM_ARGS() == 3) {
1728 if (zend_parse_parameters(3 TSRMLS_CC, "zss",
1729 &pval_id, &type, &type_len,
1730 &query, &query_len) == FAILURE) {
1733 } else if (ZEND_NUM_ARGS() == 4) {
1734 if (zend_parse_parameters(4 TSRMLS_CC, "zssa",
1735 &pval_id, &type, &type_len,
1736 &query, &query_len, &pval_flags) == FAILURE) {
1739 flags_ht = Z_ARRVAL_PP(&pval_flags);
1743 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1744 ZOOM_scanset_destroy(p->zoom_scan);
1747 option_set(p, "number", array_lookup_string(flags_ht, "number"));
1748 option_set(p, "position", array_lookup_string(flags_ht, "position"));
1749 option_set(p, "stepSize", array_lookup_string(flags_ht, "stepsize"));
1750 p->zoom_scan = ZOOM_connection_scan(p->zoom_conn, query);
1756 /* {{{ proto array yaz_es_result(resource id)
1757 Inspects Extended Services Result */
1758 PHP_FUNCTION(yaz_es_result)
1763 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters(1 TSRMLS_CC, "z",
1764 &pval_id) == FAILURE) {
1768 array_init(return_value);
1770 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1771 if (p && p->zoom_package) {
1772 const char *str = ZOOM_package_option_get(p->zoom_package,
1776 ADD_ASSOC_STRING(return_value, "targetReference", (char *) str);
1778 str = ZOOM_package_option_get(p->zoom_package,
1781 ADD_ASSOC_STRING(return_value, "xmlUpdateDoc", (char *) str);
1788 /* {{{ proto array yaz_scan_result(resource id [, array options])
1789 Inspects Scan Result */
1790 PHP_FUNCTION(yaz_scan_result)
1792 zval *pval_id, *pval_opt = 0;
1795 if (ZEND_NUM_ARGS() == 2) {
1796 if (zend_parse_parameters(2 TSRMLS_CC, "zz",
1797 &pval_id, &pval_opt) == FAILURE) {
1800 } else if (ZEND_NUM_ARGS() == 1) {
1801 if (zend_parse_parameters(1 TSRMLS_CC, "z",
1802 &pval_id) == FAILURE) {
1809 array_init(return_value);
1811 if (pval_opt && array_init(pval_opt) == FAILURE) {
1815 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1816 if (p && p->zoom_scan) {
1818 /* ZOOM_scanset_term changed from YAZ 3 to YAZ 4 */
1819 #if YAZ_VERSIONL >= 0x040000
1824 int size = ZOOM_scanset_size(p->zoom_scan);
1826 for (pos = 0; pos < size; pos++) {
1827 const char *term = ZOOM_scanset_term(p->zoom_scan, pos, &occ, &len);
1830 ALLOC_ZVAL(my_zval);
1831 array_init(my_zval);
1832 INIT_PZVAL(my_zval);
1834 ADD_NEXT_INDEX_STRING(my_zval, "term");
1837 ADD_NEXT_INDEX_STRINGl(my_zval, (char*) term, len);
1839 ADD_NEXT_INDEX_STRING(my_zval, "?");
1841 add_next_index_long(my_zval, occ);
1843 term = ZOOM_scanset_display_term(p->zoom_scan, pos, &occ, &len);
1846 ADD_NEXT_INDEX_STRINGl(my_zval, (char*) term, len);
1848 ADD_NEXT_INDEX_STRING(my_zval, "?");
1851 zend_hash_next_index_insert(return_value->value.ht, (void *) &my_zval, sizeof(zval *), NULL);
1857 add_assoc_long(pval_opt, "number", size);
1859 v = ZOOM_scanset_option_get(p->zoom_scan, "stepSize");
1861 add_assoc_long(pval_opt, "stepsize", atoi(v));
1863 v = ZOOM_scanset_option_get(p->zoom_scan, "position");
1865 add_assoc_long(pval_opt, "position", atoi(v));
1867 v = ZOOM_scanset_option_get(p->zoom_scan, "scanStatus");
1869 add_assoc_long(pval_opt, "status", atoi(v));
1877 /* {{{ proto void yaz_ccl_conf(resource id, array package)
1878 Configure CCL package */
1879 PHP_FUNCTION(yaz_ccl_conf)
1881 zval *pval_id, *pval_package;
1884 if (ZEND_NUM_ARGS() != 2 ||
1885 zend_parse_parameters(2 TSRMLS_CC, "za", &pval_id, &pval_package)
1889 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1891 HashTable *ht = Z_ARRVAL_PP(&pval_package);
1896 ccl_qual_rm(&p->bibset);
1897 p->bibset = ccl_qual_mk();
1899 for (zend_hash_internal_pointer_reset_ex(ht, &pos);
1900 zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
1901 zend_hash_move_forward_ex(ht, &pos)
1904 #if PHP_API_VERSION > 20010101
1905 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
1907 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
1909 if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
1912 ccl_qual_fitem(p->bibset, (*ent)->value.str.val, key);
1919 /* {{{ proto bool yaz_ccl_parse(resource id, string query, array res)
1920 Parse a CCL query */
1921 PHP_FUNCTION(yaz_ccl_parse)
1923 zval *pval_id, *pval_res = 0;
1928 if (ZEND_NUM_ARGS() != 3 ||
1929 zend_parse_parameters(3 TSRMLS_CC, "zsz",
1930 &pval_id, &query, &query_len, &pval_res)
1935 zval_dtor(pval_res);
1936 array_init(pval_res);
1937 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1939 struct ccl_rpn_node *rpn;
1942 CCL_parser ccl_parser = ccl_parser_create(p->bibset);
1944 rpn = ccl_parser_find_str(ccl_parser, query);
1946 error_code = ccl_parser_get_error(ccl_parser, &error_pos);
1947 add_assoc_long(pval_res, "errorcode", error_code);
1951 ADD_ASSOC_STRING(pval_res, "errorstring",
1952 (char *) ccl_err_msg(error_code));
1953 add_assoc_long(pval_res, "errorpos", error_pos);
1958 WRBUF wrbuf_pqf = wrbuf_alloc();
1959 ccl_stop_words_t csw = ccl_stop_words_create();
1960 int r = ccl_stop_words_tree(csw, p->bibset, &rpn);
1964 /* stop words were removed. Return stopwords info */
1965 zval *zval_stopwords;
1968 MAKE_STD_ZVAL(zval_stopwords);
1969 array_init(zval_stopwords);
1970 for (idx = 0; ; idx++)
1972 zval *zval_stopword;
1976 if (!ccl_stop_words_info(csw, idx, &qname, &term))
1979 MAKE_STD_ZVAL(zval_stopword);
1980 array_init(zval_stopword);
1982 ADD_ASSOC_STRING(zval_stopword, "field", (char *) qname);
1983 ADD_ASSOC_STRING(zval_stopword, "term", (char *) term);
1984 add_next_index_zval(zval_stopwords, zval_stopword);
1986 add_assoc_zval(pval_res, "stopwords", zval_stopwords);
1988 ccl_pquery(wrbuf_pqf, rpn);
1989 ADD_ASSOC_STRINGl(pval_res, "rpn",
1990 wrbuf_buf(wrbuf_pqf), wrbuf_len(wrbuf_pqf));
1991 wrbuf_destroy(wrbuf_pqf);
1992 ccl_stop_words_destroy(csw);
1995 ccl_rpn_delete(rpn);
2004 #if YAZ_VERSIONL >= 0x050100
2006 /* {{{ proto bool yaz_cql_parse(resource id, string cql, array res, bool rev)
2007 Parse a CQL query */
2008 PHP_FUNCTION(yaz_cql_parse)
2010 zval *pval_id, *pval_res = 0;
2014 zend_bool reverse = 0;
2016 if (ZEND_NUM_ARGS() != 4 ||
2017 zend_parse_parameters(4 TSRMLS_CC, "zszb",
2018 &pval_id, &query, &query_len, &pval_res, &reverse)
2023 zval_dtor(pval_res);
2024 array_init(pval_res);
2025 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
2028 ODR odr = odr_createmem(ODR_ENCODE);
2029 YAZ_PQF_Parser pp = yaz_pqf_create();
2030 Z_RPNQuery *rpn = yaz_pqf_parse(pp, odr, query);
2031 WRBUF wrbuf_cql = wrbuf_alloc();
2034 add_assoc_long(pval_res, "errorcode", 0);
2035 ADD_ASSOC_STRING(pval_res, "addinfo",
2036 (char *) "PQF syntax error");
2038 } else if ((r = cql_transform_rpn2cql_stream(p->ct, wrbuf_vp_puts,
2040 add_assoc_long(pval_res, "errorcode", r);
2043 ADD_ASSOC_STRING(pval_res, "cql",
2044 (char *) wrbuf_cstr(wrbuf_cql));
2047 wrbuf_destroy(wrbuf_cql);
2048 yaz_pqf_destroy(pp);
2051 CQL_parser cp = cql_parser_create();
2052 int r = cql_parser_string(cp, query);
2054 add_assoc_long(pval_res, "errorcode", 0);
2055 ADD_ASSOC_STRING(pval_res, "addinfo",
2056 (char *) "syntax error");
2059 WRBUF wrbuf_addinfo = wrbuf_alloc();
2060 WRBUF wrbuf_pqf = wrbuf_alloc();
2061 r = cql_transform_r(p->ct, cql_parser_result(cp), wrbuf_addinfo,
2062 wrbuf_vp_puts, wrbuf_pqf);
2064 add_assoc_long(pval_res, "errorcode", r);
2065 if (wrbuf_len(wrbuf_addinfo))
2066 ADD_ASSOC_STRING(pval_res, "addinfo",
2067 (char *) wrbuf_cstr(wrbuf_addinfo));
2070 wrbuf_chop_right(wrbuf_pqf);
2071 ADD_ASSOC_STRING(pval_res, "rpn",
2072 (char *) wrbuf_cstr(wrbuf_pqf));
2075 wrbuf_destroy(wrbuf_pqf);
2076 wrbuf_destroy(wrbuf_addinfo);
2078 cql_parser_destroy(cp);
2089 #if YAZ_VERSIONL >= 0x050100
2090 /* {{{ proto void yaz_cql_conf(resource id, array package)
2091 Configure CQL package */
2092 PHP_FUNCTION(yaz_cql_conf)
2094 zval *pval_id, *pval_package;
2097 if (ZEND_NUM_ARGS() != 2 ||
2098 zend_parse_parameters(2 TSRMLS_CC, "za", &pval_id, &pval_package)
2102 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
2104 HashTable *ht = Z_ARRVAL_PP(&pval_package);
2109 cql_transform_close(p->ct);
2110 p->ct = cql_transform_create();
2112 for (zend_hash_internal_pointer_reset_ex(ht, &pos);
2113 zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
2114 zend_hash_move_forward_ex(ht, &pos)
2117 #if PHP_API_VERSION > 20010101
2118 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
2120 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
2122 if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
2126 cql_transform_define_pattern(p->ct, key, (*ent)->value.str.val);
2134 /* {{{ proto bool yaz_database (resource id, string databases)
2135 Specify the databases within a session */
2136 PHP_FUNCTION(yaz_database)
2143 if (ZEND_NUM_ARGS() != 2 ||
2144 zend_parse_parameters(2 TSRMLS_CC, "zs", &pval_id,
2145 &database, &database_len) == FAILURE) {
2149 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
2150 option_set(p, "databaseName", database);
2156 /* {{{ php_yaz_init_globals
2158 static void php_yaz_init_globals(zend_yaz_globals *yaz_globals)
2160 yaz_globals->assoc_seq = 0;
2161 yaz_globals->max_links = 100;
2162 yaz_globals->keepalive = 120;
2163 yaz_globals->log_file = NULL;
2164 yaz_globals->log_mask = NULL;
2168 static void yaz_close_session(Yaz_Association *as TSRMLS_DC)
2170 if (*as && (*as)->order == YAZSG(assoc_seq)) {
2171 if ((*as)->persistent) {
2174 yaz_association_destroy(*as);
2180 static void yaz_close_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
2182 Yaz_Association *as = (Yaz_Association *) rsrc->ptr;
2183 yaz_close_session(as TSRMLS_CC);
2186 /* {{{ PHP_INI_BEGIN
2189 #if PHP_MAJOR_VERSION >= 5
2190 STD_PHP_INI_ENTRY("yaz.max_links", "100", PHP_INI_ALL, OnUpdateLong, max_links, zend_yaz_globals, yaz_globals)
2192 STD_PHP_INI_ENTRY("yaz.max_links", "100", PHP_INI_ALL, OnUpdateInt, max_links, zend_yaz_globals, yaz_globals)
2194 #if PHP_MAJOR_VERSION >= 5
2195 STD_PHP_INI_ENTRY("yaz.keepalive", "120", PHP_INI_ALL, OnUpdateLong, keepalive, zend_yaz_globals, yaz_globals)
2197 STD_PHP_INI_ENTRY("yaz.keepalive", "120", PHP_INI_ALL, OnUpdateInt, keepalive, zend_yaz_globals, yaz_globals)
2199 STD_PHP_INI_ENTRY("yaz.log_file", NULL, PHP_INI_ALL, OnUpdateString, log_file, zend_yaz_globals, yaz_globals)
2200 STD_PHP_INI_ENTRY("yaz.log_mask", NULL, PHP_INI_ALL, OnUpdateString, log_mask, zend_yaz_globals, yaz_globals)
2204 PHP_MINIT_FUNCTION(yaz)
2210 yaz_mutex = tsrm_mutex_alloc();
2213 ZEND_INIT_MODULE_GLOBALS(yaz, php_yaz_init_globals, NULL);
2215 REGISTER_INI_ENTRIES();
2217 REGISTER_LONG_CONSTANT("ZOOM_EVENT_NONE", ZOOM_EVENT_NONE,
2218 CONST_CS|CONST_PERSISTENT);
2219 REGISTER_LONG_CONSTANT("ZOOM_EVENT_CONNECT", ZOOM_EVENT_CONNECT,
2220 CONST_CS|CONST_PERSISTENT);
2221 REGISTER_LONG_CONSTANT("ZOOM_EVENT_SEND_DATA", ZOOM_EVENT_SEND_DATA,
2222 CONST_CS|CONST_PERSISTENT);
2223 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_DATA", ZOOM_EVENT_RECV_DATA,
2224 CONST_CS|CONST_PERSISTENT);
2225 REGISTER_LONG_CONSTANT("ZOOM_EVENT_TIMEOUT", ZOOM_EVENT_TIMEOUT,
2226 CONST_CS|CONST_PERSISTENT);
2227 REGISTER_LONG_CONSTANT("ZOOM_EVENT_UNKNOWN", ZOOM_EVENT_UNKNOWN,
2228 CONST_CS|CONST_PERSISTENT);
2229 REGISTER_LONG_CONSTANT("ZOOM_EVENT_SEND_APDU", ZOOM_EVENT_SEND_APDU,
2230 CONST_CS|CONST_PERSISTENT);
2231 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_APDU", ZOOM_EVENT_RECV_APDU,
2232 CONST_CS|CONST_PERSISTENT);
2233 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_RECORD", ZOOM_EVENT_RECV_RECORD,
2234 CONST_CS|CONST_PERSISTENT);
2235 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_SEARCH", ZOOM_EVENT_RECV_SEARCH,
2236 CONST_CS|CONST_PERSISTENT);
2238 fname = YAZSG(log_file);
2239 mask = YAZSG(log_mask);
2240 if (fname && *fname)
2242 yaz_log_init_file(fname);
2245 yaz_log_init_level(yaz_log_mask_str(mask));
2248 yaz_log_init_level(0);
2250 le_link = zend_register_list_destructors_ex(yaz_close_link, 0, "YAZ link", module_number);
2252 order_associations = 1;
2253 shared_associations = xmalloc(sizeof(*shared_associations) * MAX_ASSOC);
2254 for (i = 0; i < MAX_ASSOC; i++) {
2255 shared_associations[i] = 0;
2260 PHP_MSHUTDOWN_FUNCTION(yaz)
2264 if (shared_associations) {
2265 for (i = 0; i < MAX_ASSOC; i++) {
2266 yaz_association_destroy (shared_associations[i]);
2268 xfree(shared_associations);
2269 shared_associations = 0;
2272 tsrm_mutex_free(yaz_mutex);
2275 yaz_log_init_file(0);
2277 UNREGISTER_INI_ENTRIES();
2282 PHP_MINFO_FUNCTION(yaz)
2284 char version_str[20];
2286 strcpy(version_str, "unknown");
2287 yaz_version(version_str, 0);
2288 php_info_print_table_start();
2289 php_info_print_table_row(2, "YAZ Support", "enabled");
2290 php_info_print_table_row(2, "PHP/YAZ Version", PHP_YAZ_VERSION);
2291 php_info_print_table_row(2, "YAZ Version", version_str);
2292 php_info_print_table_row(2, "Compiled with YAZ version", YAZ_VERSION);
2293 php_info_print_table_end();
2296 PHP_RSHUTDOWN_FUNCTION(yaz)
2302 tsrm_mutex_lock(yaz_mutex);
2304 for (i = 0; i < YAZSG(max_links); i++) {
2305 Yaz_Association *as = shared_associations + i;
2308 if (now - (*as)->time_stamp > YAZSG(keepalive))
2310 yaz_association_destroy(*as);
2316 tsrm_mutex_unlock(yaz_mutex);
2321 PHP_RINIT_FUNCTION(yaz)
2325 sprintf(pidstr, "%ld", (long) getpid());
2327 tsrm_mutex_lock(yaz_mutex);
2329 YAZSG(assoc_seq) = order_associations++;
2331 tsrm_mutex_unlock(yaz_mutex);
2333 yaz_log_init_prefix(pidstr);
2337 zend_module_entry yaz_module_entry = {
2338 #if ZEND_MODULE_API_NO >= 20010901
2339 STANDARD_MODULE_HEADER,
2348 #if ZEND_MODULE_API_NO >= 20010901
2351 STANDARD_MODULE_PROPERTIES
2362 * vim600: sw=4 ts=4 fdm=marker
2363 * vim<600: sw=4 ts=4