2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2004 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.0 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_0.txt. |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Adam Dickmeiss <adam@indexdata.dk> |
16 +----------------------------------------------------------------------+
19 /* $Id: php_yaz.c,v 1.115 2008/02/20 10:08:15 dickmeiss Exp $ */
30 #include "ext/standard/info.h"
33 #include <yaz/yaz-version.h>
36 #error YAZ version 3.0 or later must be used.
37 #elif YAZ_VERSIONL < 0x030000
38 #error YAZ version 3.0 or later must be used.
46 #include <yaz/proto.h>
47 #include <yaz/marcdisp.h>
48 #include <yaz/yaz-util.h>
49 #include <yaz/yaz-ccl.h>
50 #include <yaz/oid_db.h>
53 #ifndef ODR_INT_PRINTF
54 #define ODR_INT_PRINTF %d
59 typedef struct Yaz_AssociationInfo *Yaz_Association;
61 struct Yaz_AssociationInfo {
63 ZOOM_connection zoom_conn;
64 ZOOM_resultset zoom_set;
65 ZOOM_scanset zoom_scan;
66 ZOOM_package zoom_package;
75 static Yaz_Association yaz_association_mk()
77 Yaz_Association p = xmalloc (sizeof(*p));
79 p->zoom_conn = ZOOM_connection_create (0);
83 ZOOM_connection_option_set(p->zoom_conn, "implementationName", "PHP");
84 ZOOM_connection_option_set(p->zoom_conn, "async", "1");
89 p->bibset = ccl_qual_mk();
94 static void yaz_association_destroy (Yaz_Association p)
100 ZOOM_resultset_destroy(p->zoom_set);
101 ZOOM_scanset_destroy(p->zoom_scan);
102 ZOOM_package_destroy(p->zoom_package);
103 ZOOM_connection_destroy(p->zoom_conn);
104 xfree(p->sort_criteria);
105 ccl_qual_rm(&p->bibset);
109 static MUTEX_T yaz_mutex;
112 ZEND_DECLARE_MODULE_GLOBALS(yaz);
114 static Yaz_Association *shared_associations;
115 static int order_associations;
119 #ifdef COMPILE_DL_YAZ
123 #ifdef ZEND_BEGIN_ARG_INFO
124 ZEND_BEGIN_ARG_INFO(first_argument_force_ref, 0)
125 ZEND_ARG_PASS_INFO(1)
128 ZEND_BEGIN_ARG_INFO(second_argument_force_ref, 0)
129 ZEND_ARG_PASS_INFO(0)
130 ZEND_ARG_PASS_INFO(1)
133 ZEND_BEGIN_ARG_INFO(third_argument_force_ref, 0)
134 ZEND_ARG_PASS_INFO(0)
135 ZEND_ARG_PASS_INFO(0)
136 ZEND_ARG_PASS_INFO(1)
139 static unsigned char first_argument_force_ref[] = {
141 static unsigned char second_argument_force_ref[] = {
142 2, BYREF_NONE, BYREF_FORCE };
143 static unsigned char third_argument_force_ref[] = {
144 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
148 function_entry yaz_functions [] = {
149 PHP_FE(yaz_connect, NULL)
150 PHP_FE(yaz_close, NULL)
151 PHP_FE(yaz_search, NULL)
152 PHP_FE(yaz_wait, first_argument_force_ref)
153 PHP_FE(yaz_errno, NULL)
154 PHP_FE(yaz_error, NULL)
155 PHP_FE(yaz_addinfo, NULL)
156 PHP_FE(yaz_hits, second_argument_force_ref)
157 PHP_FE(yaz_record, NULL)
158 PHP_FE(yaz_syntax, NULL)
159 PHP_FE(yaz_element, NULL)
160 PHP_FE(yaz_range, NULL)
161 PHP_FE(yaz_itemorder, NULL)
162 PHP_FE(yaz_es_result, NULL)
163 PHP_FE(yaz_scan, NULL)
164 PHP_FE(yaz_scan_result, second_argument_force_ref)
165 PHP_FE(yaz_present, NULL)
166 PHP_FE(yaz_ccl_conf, NULL)
167 PHP_FE(yaz_ccl_parse, third_argument_force_ref)
168 PHP_FE(yaz_database, NULL)
169 PHP_FE(yaz_sort, NULL)
170 PHP_FE(yaz_schema, NULL)
171 PHP_FE(yaz_set_option, NULL)
172 PHP_FE(yaz_get_option, NULL)
177 static void get_assoc(INTERNAL_FUNCTION_PARAMETERS, pval *id, Yaz_Association *assocp)
179 Yaz_Association *as = 0;
183 tsrm_mutex_lock (yaz_mutex);
186 ZEND_FETCH_RESOURCE(as, Yaz_Association *, &id, -1, "YAZ link", le_link);
188 if (as && *as && (*as)->order == YAZSG(assoc_seq) && (*as)->in_use) {
192 tsrm_mutex_unlock (yaz_mutex);
194 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid YAZ handle");
198 static void release_assoc(Yaz_Association assoc)
202 tsrm_mutex_unlock(yaz_mutex);
207 static const char *array_lookup_string(HashTable *ht, const char *idx)
211 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
212 SEPARATE_ZVAL(pvalue);
213 convert_to_string(*pvalue);
214 return (*pvalue)->value.str.val;
219 static long *array_lookup_long(HashTable *ht, const char *idx)
223 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
224 SEPARATE_ZVAL(pvalue);
225 convert_to_long(*pvalue);
226 return &(*pvalue)->value.lval;
231 static long *array_lookup_bool(HashTable *ht, const char *idx)
235 if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
236 SEPARATE_ZVAL(pvalue);
237 convert_to_boolean(*pvalue);
238 return &(*pvalue)->value.lval;
243 static const char *option_get(Yaz_Association as, const char *name)
248 return ZOOM_connection_option_get(as->zoom_conn, name);
251 static int option_get_int(Yaz_Association as, const char *name, int def)
255 v = ZOOM_connection_option_get(as->zoom_conn, name);
264 static void option_set(Yaz_Association as, const char *name, const char *value)
267 ZOOM_connection_option_set(as->zoom_conn, name, value);
271 static void option_set_int(Yaz_Association as, const char *name, int v)
276 sprintf (s, "%d", v);
277 ZOOM_connection_option_set(as->zoom_conn, name, s);
281 static int strcmp_null(const char *s1, const char *s2)
283 if (s1 == 0 && s2 == 0) {
286 if (s1 == 0 || s2 == 0) {
289 return strcmp(s1, s2);
292 /* {{{ proto resource yaz_connect(string zurl [, array options])
293 Create target with given zurl. Returns positive id if successful. */
294 PHP_FUNCTION(yaz_connect)
299 const char *sru_str = 0, *sru_version_str = 0;
300 const char *user_str = 0, *group_str = 0, *pass_str = 0;
301 const char *cookie_str = 0, *proxy_str = 0;
302 const char *charset_str = 0;
303 const char *client_IP = 0;
304 const char *otherInfo[3];
305 const char *maximumRecordSize = 0;
306 const char *preferredMessageSize = 0;
309 pval *zurl, *user = 0;
311 int max_links = YAZSG(max_links);
313 otherInfo[0] = otherInfo[1] = otherInfo[2] = 0;
315 if (ZEND_NUM_ARGS() == 1) {
316 if (zend_parse_parameters(1, "z", &zurl)
320 } else if (ZEND_NUM_ARGS() == 2) {
321 if (zend_parse_parameters(2, "zz", &zurl, &user)
326 if (Z_TYPE_PP(&user) == IS_ARRAY) {
327 long *persistent_val;
329 HashTable *ht = Z_ARRVAL_PP(&user);
331 sru_str = array_lookup_string(ht, "sru");
332 sru_version_str = array_lookup_string(ht, "sru_version");
333 user_str = array_lookup_string(ht, "user");
334 group_str = array_lookup_string(ht, "group");
335 pass_str = array_lookup_string(ht, "password");
336 cookie_str = array_lookup_string(ht, "cookie");
337 proxy_str = array_lookup_string(ht, "proxy");
338 charset_str = array_lookup_string(ht, "charset");
339 persistent_val = array_lookup_bool(ht, "persistent");
340 if (persistent_val) {
341 persistent = *persistent_val;
343 piggyback_val = array_lookup_bool(ht, "piggyback");
345 piggyback = *piggyback_val;
348 array_lookup_string(ht, "maximumRecordSize");
349 preferredMessageSize =
350 array_lookup_string(ht, "preferredMessageSize");
351 otherInfo[0] = array_lookup_string(ht, "otherInfo0");
352 otherInfo[1] = array_lookup_string(ht, "otherInfo1");
353 otherInfo[2] = array_lookup_string(ht, "otherInfo2");
354 } else if (Z_TYPE_PP(&user) == IS_STRING) {
355 convert_to_string_ex(&user);
356 if (*user->value.str.val)
357 user_str = user->value.str.val;
362 convert_to_string_ex(&zurl);
363 zurl_str = zurl->value.str.val;
364 for (cp = zurl_str; *cp && strchr("\t\n ", *cp); cp++);
366 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty zurl");
369 /* see if we have it already ... */
371 tsrm_mutex_lock(yaz_mutex);
373 for (i = 0; i < max_links; i++) {
374 as = shared_associations[i];
375 if (persistent && as && !as->in_use &&
376 !strcmp_null(option_get(as, "host"), zurl_str) &&
377 !strcmp_null(option_get(as, "proxy"), proxy_str) &&
378 !strcmp_null(option_get(as, "sru"), sru_str) &&
379 !strcmp_null(option_get(as, "sru_version"), sru_version_str) &&
380 !strcmp_null(option_get(as, "user"), user_str) &&
381 !strcmp_null(option_get(as, "group"), group_str) &&
382 !strcmp_null(option_get(as, "pass"), pass_str) &&
383 !strcmp_null(option_get(as, "cookie"), cookie_str) &&
384 !strcmp_null(option_get(as, "charset"), charset_str))
387 if (i == max_links) {
388 /* we didn't have it (or already in use) */
390 int min_order = 2000000000;
392 /* find completely free slot or the oldest one */
393 for (i = 0; i < max_links && shared_associations[i]; i++) {
394 as = shared_associations[i];
395 if (persistent && !as->in_use && as->order < min_order) {
396 min_order = as->order;
401 if (i == max_links) {
406 tsrm_mutex_unlock (yaz_mutex);
408 sprintf(msg, "No YAZ handles available. max_links=%d",
410 php_error_docref(NULL TSRMLS_CC, E_WARNING,
411 "No YAZ handles available. max_links=%ld",
413 RETURN_LONG(0); /* no free slot */
414 } else { /* "best" free slot */
415 yaz_association_destroy(shared_associations[i]);
418 shared_associations[i] = as = yaz_association_mk ();
420 option_set(as, "proxy", proxy_str);
421 option_set(as, "sru", sru_str);
422 option_set(as, "sru_version", sru_version_str);
423 option_set(as, "user", user_str);
424 option_set(as, "group", group_str);
425 option_set(as, "pass", pass_str);
426 option_set(as, "cookie", cookie_str);
427 option_set(as, "charset", charset_str);
429 if (maximumRecordSize)
430 option_set(as, "maximumRecordSize", maximumRecordSize);
431 if (preferredMessageSize)
432 option_set(as, "preferredMessageSize", preferredMessageSize);
433 option_set(as, "otherInfo0", otherInfo[0]);
434 option_set(as, "otherInfo1", otherInfo[1]);
435 option_set(as, "otherInfo2", otherInfo[2]);
436 option_set(as, "clientIP", client_IP);
437 option_set(as, "piggyback", piggyback ? "1" : "0");
438 option_set_int(as, "start", 0);
439 option_set_int(as, "count", 0);
440 ZOOM_connection_connect(as->zoom_conn, zurl_str, 0);
442 as->persistent = persistent;
443 as->order = YAZSG(assoc_seq);
444 as->time_stamp = time(0);
448 ZOOM_resultset_destroy(as->zoom_set);
452 tsrm_mutex_unlock (yaz_mutex);
455 ZEND_REGISTER_RESOURCE(return_value, &shared_associations[i], le_link);
456 as->zval_resource = Z_LVAL_P(return_value);
460 /* {{{ proto bool yaz_close(resource id)
461 Destory and close target */
462 PHP_FUNCTION(yaz_close)
467 if (ZEND_NUM_ARGS() != 1) {
470 if (zend_parse_parameters(1, "z", &id) == FAILURE) {
473 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
478 zend_list_delete(id->value.lval);
484 /* {{{ proto bool yaz_search(resource id, string type, string query)
485 Specify query of type for search - returns true if successful */
486 PHP_FUNCTION(yaz_search)
488 char *query_str, *type_str;
489 pval *id, *type, *query;
492 if (ZEND_NUM_ARGS() == 3) {
493 if (zend_parse_parameters(3, "zzz", &id, &type, &query)
501 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
506 convert_to_string_ex(&type);
507 type_str = type->value.str.val;
508 convert_to_string_ex(&query);
509 query_str = query->value.str.val;
511 ZOOM_resultset_destroy(p->zoom_set);
516 if (!strcmp(type_str, "rpn")) {
517 ZOOM_query q = ZOOM_query_create();
518 if (ZOOM_query_prefix(q, query_str) == 0)
520 if (p->sort_criteria) {
521 ZOOM_query_sortby(q, p->sort_criteria);
523 xfree(p->sort_criteria);
524 p->sort_criteria = 0;
525 p->zoom_set = ZOOM_connection_search(p->zoom_conn, q);
528 ZOOM_query_destroy(q);
530 else if (!strcmp(type_str, "cql")) {
531 ZOOM_query q = ZOOM_query_create();
532 if (ZOOM_query_cql(q, query_str) == 0)
534 if (p->sort_criteria) {
535 ZOOM_query_sortby(q, p->sort_criteria);
537 xfree (p->sort_criteria);
538 p->sort_criteria = 0;
539 p->zoom_set = ZOOM_connection_search(p->zoom_conn, q);
542 ZOOM_query_destroy(q);
546 php_error_docref(NULL TSRMLS_CC, E_WARNING,
547 "Invalid query type %s", type_str);
553 /* {{{ proto bool yaz_present(resource id)
555 PHP_FUNCTION(yaz_present)
560 if (ZEND_NUM_ARGS() != 1) {
563 if (zend_parse_parameters(1, "z", id) == FAILURE) {
567 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
573 size_t start = option_get_int(p, "start", 0);
574 size_t count = option_get_int(p, "count", 0);
576 ZOOM_resultset_records(p->zoom_set, 0 /* recs */, start, count);
584 /* {{{ proto bool yaz_wait([array options])
586 PHP_FUNCTION(yaz_wait)
588 pval *pval_options = 0;
591 ZOOM_connection conn_ar[MAX_ASSOC];
592 Yaz_Association conn_as[MAX_ASSOC];
595 if (ZEND_NUM_ARGS() == 1) {
597 long *event_bool = 0;
598 HashTable *options_ht = 0;
599 if (zend_parse_parameters(1, "z", &pval_options) == FAILURE) {
602 if (Z_TYPE_PP(&pval_options) != IS_ARRAY) {
603 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array parameter");
606 options_ht = Z_ARRVAL_PP(&pval_options);
607 val = array_lookup_long(options_ht, "timeout");
611 event_bool = array_lookup_bool(options_ht, "event");
612 if (event_bool && *event_bool)
616 tsrm_mutex_lock(yaz_mutex);
618 for (i = 0; i<YAZSG(max_links); i++) {
619 Yaz_Association p = shared_associations[i];
620 if (p && p->order == YAZSG(assoc_seq)) {
623 sprintf(str, "%d", timeout);
624 ZOOM_connection_option_set(p->zoom_conn, "timeout", str);
626 conn_ar[no++] = p->zoom_conn;
630 tsrm_mutex_unlock(yaz_mutex);
633 long ev = ZOOM_event(no, conn_ar);
637 Yaz_Association p = conn_as[ev-1];
638 int event_code = ZOOM_connection_last_event(p->zoom_conn);
640 add_assoc_long(pval_options, "connid", ev);
642 add_assoc_long(pval_options, "eventcode", event_code);
644 zend_list_addref(p->zval_resource);
645 Z_LVAL_P(return_value) = p->zval_resource;
646 Z_TYPE_P(return_value) = IS_RESOURCE;
652 while (ZOOM_event (no, conn_ar))
659 /* {{{ proto int yaz_errno(resource id)
660 Return last error number (>0 for bib-1 diagnostic, <0 for other error, 0 for no error */
661 PHP_FUNCTION(yaz_errno)
666 if (ZEND_NUM_ARGS() != 1 ||
667 zend_parse_parameters(1, "z", &id) == FAILURE) {
670 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
674 RETVAL_LONG(ZOOM_connection_errcode(p->zoom_conn));
679 /* {{{ proto string yaz_error(resource id)
680 Return last error message */
681 PHP_FUNCTION(yaz_error)
686 if (ZEND_NUM_ARGS() != 1 ||
687 zend_parse_parameters(1, "z", &id) == FAILURE) {
691 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
693 int code = ZOOM_connection_errcode(p->zoom_conn);
694 const char *msg = ZOOM_connection_errmsg(p->zoom_conn);
699 return_value->value.str.len = strlen(msg);
700 return_value->value.str.val = estrndup(msg, return_value->value.str.len);
701 return_value->type = IS_STRING;
707 /* {{{ proto string yaz_addinfo(resource id)
708 Return additional info for last error (empty string if none) */
709 PHP_FUNCTION(yaz_addinfo)
714 if (ZEND_NUM_ARGS() != 1 ||
715 zend_parse_parameters(ZEND_NUM_ARGS(), "z", &id) == FAILURE) {
719 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
721 const char *addinfo = ZOOM_connection_addinfo(p->zoom_conn);
723 return_value->value.str.len = strlen(addinfo);
724 return_value->value.str.val = estrndup(addinfo, return_value->value.str.len);
725 return_value->type = IS_STRING;
731 /* {{{ proto int yaz_hits(resource id [, array searchresult])
732 Return number of hits (result count) for last search */
733 PHP_FUNCTION(yaz_hits)
735 pval *id, *searchresult = 0;
738 if (ZEND_NUM_ARGS() == 1) {
739 if (zend_parse_parameters(1, "z", &id) == FAILURE) {
742 } else if (ZEND_NUM_ARGS() == 2) {
743 if (zend_parse_parameters(2, "zz", &id, &searchresult) == FAILURE) {
746 if (array_init(searchresult) == FAILURE) {
747 php_error_docref(NULL TSRMLS_CC, E_WARNING,
748 "Could not initialize search result array");
755 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
756 if (p && p->zoom_set) {
757 RETVAL_LONG(ZOOM_resultset_size(p->zoom_set));
761 ZOOM_resultset_option_get(p->zoom_set, "resultSetStatus");
763 add_assoc_string(searchresult, "resultSetStatus",
769 ZOOM_resultset_option_get(p->zoom_set, "searchresult.size");
773 if (sz_str && *sz_str)
775 for (i = 0; i<sz; i++)
778 const char *opt_value;
781 MAKE_STD_ZVAL(zval_element);
782 array_init(zval_element);
783 add_next_index_zval(searchresult, zval_element);
785 sprintf(opt_name, "searchresult.%d.id", i);
786 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
788 add_assoc_string(zval_element, "id",
789 (char *) opt_value, 1);
791 sprintf(opt_name, "searchresult.%d.count", i);
792 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
794 add_assoc_long(zval_element, "count", atoi(opt_value));
796 sprintf(opt_name, "searchresult.%d.subquery.term", i);
797 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
799 add_assoc_string(zval_element, "subquery.term",
800 (char *) opt_value, 1);
802 sprintf(opt_name, "searchresult.%d.interpretation.term", i);
803 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
805 add_assoc_string(zval_element, "interpretation.term",
806 (char *) opt_value, 1);
808 sprintf(opt_name, "searchresult.%d.recommendation.term", i);
809 opt_value = ZOOM_resultset_option_get(p->zoom_set, opt_name);
811 add_assoc_string(zval_element, "recommendation.term",
812 (char *) opt_value, 1);
823 static Z_GenericRecord *marc_to_grs1(const char *buf, ODR o)
827 int indicator_length;
828 int identifier_length;
830 int length_data_entry;
832 int length_implementation;
833 int max_elements = 256;
834 Z_GenericRecord *r = odr_malloc (o, sizeof(*r));
835 r->elements = odr_malloc (o, sizeof(*r->elements) * max_elements);
838 record_length = atoi_n(buf, 5);
839 if (record_length < 25) {
842 indicator_length = atoi_n(buf + 10, 1);
843 identifier_length = atoi_n(buf + 11, 1);
844 base_address = atoi_n(buf + 12, 5);
846 length_data_entry = atoi_n(buf + 20, 1);
847 length_starting = atoi_n(buf + 21, 1);
848 length_implementation = atoi_n(buf + 22, 1);
850 for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) {
851 entry_p += 3 + length_data_entry + length_starting;
852 if (entry_p >= record_length) {
858 Z_TaggedElement *tag;
859 tag = r->elements[r->num_elements++] = odr_malloc(o, sizeof(*tag));
860 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
862 tag->tagOccurrence = 0;
864 tag->appliedVariant = 0;
865 tag->tagValue = odr_malloc (o, sizeof(*tag->tagValue));
866 tag->tagValue->which = Z_StringOrNumeric_string;
867 tag->tagValue->u.string = odr_strdup(o, "leader");
869 tag->content = odr_malloc(o, sizeof(*tag->content));
870 tag->content->which = Z_ElementData_string;
871 tag->content->u.string = odr_strdupn(o, buf, 24);
873 base_address = entry_p + 1;
874 for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) {
875 Z_TaggedElement *tag;
881 int identifier_flag = 1;
883 memcpy(tag_str, buf+entry_p, 3);
887 if ((r->num_elements + 1) >= max_elements) {
888 Z_TaggedElement **tmp = r->elements;
890 /* double array space, throw away old buffer (nibble memory) */
891 r->elements = odr_malloc(o, sizeof(*r->elements) * (max_elements *= 2));
892 memcpy(r->elements, tmp, r->num_elements * sizeof(*tmp));
894 tag = r->elements[r->num_elements++] = odr_malloc(o, sizeof(*tag));
895 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
897 tag->tagOccurrence = 0;
899 tag->appliedVariant = 0;
900 tag->tagValue = odr_malloc (o, sizeof(*tag->tagValue));
901 tag->tagValue->which = Z_StringOrNumeric_string;
902 tag->tagValue->u.string = odr_strdup(o, tag_str);
904 tag->content = odr_malloc(o, sizeof(*tag->content));
905 tag->content->which = Z_ElementData_subtree;
907 tag->content->u.subtree = odr_malloc(o, sizeof(*tag->content->u.subtree));
908 tag->content->u.subtree->elements = odr_malloc(o, sizeof(*r->elements));
909 tag->content->u.subtree->num_elements = 1;
911 tag = tag->content->u.subtree->elements[0] = odr_malloc(o, sizeof(**tag->content->u.subtree->elements));
913 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
915 tag->tagOccurrence = 0;
917 tag->appliedVariant = 0;
918 tag->tagValue = odr_malloc(o, sizeof(*tag->tagValue));
919 tag->tagValue->which = Z_StringOrNumeric_string;
920 tag->content = odr_malloc(o, sizeof(*tag->content));
922 data_length = atoi_n(buf + entry_p, length_data_entry);
923 entry_p += length_data_entry;
924 data_offset = atoi_n(buf + entry_p, length_starting);
925 entry_p += length_starting;
926 i = data_offset + base_address;
927 end_offset = i + data_length - 1;
929 if (indicator_length > 0 && indicator_length < 5) {
930 if (buf[i + indicator_length] != ISO2709_IDFS) {
933 } else if (!memcmp (tag_str, "00", 2)) {
937 if (identifier_flag && indicator_length) {
939 tag->tagValue->u.string = odr_malloc(o, indicator_length + 1);
940 memcpy(tag->tagValue->u.string, buf + i, indicator_length);
941 tag->tagValue->u.string[indicator_length] = '\0';
942 i += indicator_length;
944 tag->content->which = Z_ElementData_subtree;
946 tag->content->u.subtree = odr_malloc(o, sizeof(*tag->content->u.subtree));
947 tag->content->u.subtree->elements = odr_malloc(o, 256 * sizeof(*r->elements));
948 tag->content->u.subtree->num_elements = 0;
950 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset) {
953 Z_TaggedElement *parent_tag = tag;
954 Z_TaggedElement *tag = odr_malloc (o, sizeof(*tag));
956 if (parent_tag->content->u.subtree->num_elements < 256) {
957 parent_tag->content->u.subtree->elements[
958 parent_tag->content->u.subtree->num_elements++] = tag;
961 tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
963 tag->tagOccurrence = 0;
965 tag->appliedVariant = 0;
966 tag->tagValue = odr_malloc (o, sizeof(*tag->tagValue));
967 tag->tagValue->which = Z_StringOrNumeric_string;
970 tag->tagValue->u.string = odr_malloc(o, identifier_length);
971 memcpy(tag->tagValue->u.string, buf + i + 1, identifier_length - 1);
972 tag->tagValue->u.string[identifier_length - 1] = '\0';
973 i += identifier_length;
976 tag->content = odr_malloc(o, sizeof(*tag->content));
977 tag->content->which = Z_ElementData_string;
980 while ( buf[i] != ISO2709_RS &&
981 buf[i] != ISO2709_IDFS &&
982 buf[i] != ISO2709_FS && i < end_offset) {
986 tag->content->u.string = odr_malloc(o, i - i0 + 1);
987 memcpy(tag->content->u.string, buf + i0, i - i0);
988 tag->content->u.string[i - i0] = '\0';
993 tag->tagValue->u.string = "@";
994 tag->content->which = Z_ElementData_string;
996 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset) {
999 tag->content->u.string = odr_malloc(o, i - i0 +1);
1000 memcpy(tag->content->u.string, buf + i0, i - i0);
1001 tag->content->u.string[i-i0] = '\0';
1014 static struct cvt_handle *cvt_open(const char *to, const char *from)
1016 ODR o = odr_createmem(ODR_ENCODE);
1018 struct cvt_handle *cvt = odr_malloc(o, sizeof(*cvt));
1021 cvt->buf = odr_malloc(o, cvt->size);
1024 cvt->cd = yaz_iconv_open(to, from);
1028 static void cvt_close(struct cvt_handle *cvt)
1031 yaz_iconv_close(cvt->cd);
1032 odr_destroy(cvt->odr);
1035 static const char *cvt_string(const char *input, struct cvt_handle *cvt)
1040 size_t inbytesleft = strlen(input);
1041 const char *inp = input;
1042 size_t outbytesleft = cvt->size - 1;
1043 char *outp = cvt->buf;
1044 size_t r = yaz_iconv(cvt->cd, (char**) &inp, &inbytesleft,
1045 &outp, &outbytesleft);
1046 if (r == (size_t) (-1)) {
1047 int e = yaz_iconv_error(cvt->cd);
1048 if (e != YAZ_ICONV_E2BIG || cvt->size > 200000)
1053 cvt->size = cvt->size * 2 + 30;
1054 cvt->buf = (char*) odr_malloc(cvt->odr, cvt->size);
1056 cvt->buf[outp - cvt->buf] = '\0';
1063 static void retval_array3_grs1(zval *return_value, Z_GenericRecord *p,
1064 struct cvt_handle *cvt)
1070 struct tag_list *next;
1072 NMEM nmem = nmem_create();
1074 array_init(return_value);
1075 for (i = 0; i<p->num_elements; i++)
1077 struct tag_list *tl;
1080 Z_TaggedElement *e = p->elements[i];
1081 char tagstr[32], *tag = 0;
1083 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1085 sprintf(tagstr, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1088 else if (e->tagValue->which == Z_StringOrNumeric_string)
1089 tag = e->tagValue->u.string, zval_element;
1094 for (tl = all_tags; tl; tl = tl->next)
1095 if (!strcmp(tl->tag, tag))
1098 zval_list = tl->zval_list;
1101 MAKE_STD_ZVAL(zval_list);
1102 array_init(zval_list);
1103 add_assoc_zval(return_value, tag, zval_list);
1105 tl = nmem_malloc(nmem, sizeof(*tl));
1106 tl->tag = nmem_strdup(nmem, tag);
1107 tl->zval_list = zval_list;
1108 tl->next = all_tags;
1111 MAKE_STD_ZVAL(zval_element);
1112 array_init(zval_element);
1113 add_next_index_zval(zval_list, zval_element);
1114 if (e->content->which == Z_ElementData_subtree)
1116 /* we have a subtree. Move to first child */
1117 Z_GenericRecord *sub = e->content->u.subtree;
1118 if (sub->num_elements >= 1)
1119 e = sub->elements[0];
1125 const char *tag = 0;
1126 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1128 sprintf(tagstr, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1131 else if (e->tagValue->which == Z_StringOrNumeric_string)
1132 tag = e->tagValue->u.string;
1133 if (tag && e->content->which == Z_ElementData_subtree)
1136 Z_GenericRecord *sub = e->content->u.subtree;
1138 for (i = 0; tag[i]; i++)
1143 sprintf(ind_idx, "ind%d", i+1);
1144 ind_val[0] = tag[i];
1147 add_assoc_string(zval_element, ind_idx, ind_val, 1);
1149 for (i = 0; i<sub->num_elements; i++)
1151 Z_TaggedElement *e = sub->elements[i];
1152 const char *tag = 0;
1153 if (e->tagValue->which == Z_StringOrNumeric_numeric)
1155 sprintf(tagstr, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1158 else if (e->tagValue->which == Z_StringOrNumeric_string)
1159 tag = e->tagValue->u.string, zval_element;
1161 if (tag && e->content->which == Z_ElementData_string)
1163 const char *v = cvt_string(e->content->u.string, cvt);
1164 add_assoc_string(zval_element, (char*) tag, (char*) v,
1169 else if (tag && e->content->which == Z_ElementData_string)
1171 /* Leader or control field */
1172 const char *v = cvt_string(e->content->u.string, cvt);
1173 ZVAL_STRING(zval_element, (char*) v, 1);
1180 static void retval_array2_grs1(zval *return_value, Z_GenericRecord *p,
1181 struct cvt_handle *cvt)
1185 array_init(return_value);
1187 for (i = 0; i<p->num_elements; i++)
1191 Z_TaggedElement *e = p->elements[i];
1193 MAKE_STD_ZVAL(zval_element);
1194 array_init(zval_element);
1197 add_assoc_long(zval_element, "tagType", *e->tagType);
1199 if (e->tagValue->which == Z_StringOrNumeric_string)
1200 add_assoc_string(zval_element, "tag", e->tagValue->u.string, 1);
1201 else if (e->tagValue->which == Z_StringOrNumeric_numeric)
1202 add_assoc_long(zval_element, "tag", *e->tagValue->u.numeric);
1204 switch (e->content->which) {
1205 case Z_ElementData_string:
1208 const char *v = cvt_string(e->content->u.string, cvt);
1209 add_assoc_string(zval_element, "content", (char*) v, 1);
1212 case Z_ElementData_numeric:
1213 add_assoc_long(zval_element, "content",*e->content->u.numeric);
1215 case Z_ElementData_trueOrFalse:
1216 add_assoc_bool(zval_element, "content",*e->content->u.trueOrFalse);
1218 case Z_ElementData_subtree:
1219 MAKE_STD_ZVAL(zval_sub);
1220 retval_array2_grs1(zval_sub, e->content->u.subtree, cvt);
1221 add_assoc_zval(zval_element, "content", zval_sub);
1223 add_next_index_zval(return_value, zval_element);
1227 static void retval_array1_grs1(zval *return_value, Z_GenericRecord *p,
1228 struct cvt_handle *cvt)
1230 Z_GenericRecord *grs[20];
1234 array_init(return_value);
1238 while (level >= 0) {
1240 Z_TaggedElement *e = 0;
1241 Z_GenericRecord *p = grs[level];
1246 if (eno[level] >= p->num_elements) {
1253 for (i = 0; i <= level; i++) {
1255 e = grs[i]->elements[eno[i]];
1258 tag_type = *e->tagType;
1260 taglen = strlen(tag);
1261 sprintf(tag + taglen, "(%d,", tag_type);
1262 taglen = strlen(tag);
1264 if (e->tagValue->which == Z_StringOrNumeric_string) {
1265 int len = strlen(e->tagValue->u.string);
1267 memcpy(tag + taglen, e->tagValue->u.string, len);
1268 tag[taglen+len] = '\0';
1269 } else if (e->tagValue->which == Z_StringOrNumeric_numeric) {
1270 sprintf(tag + taglen, ODR_INT_PRINTF, *e->tagValue->u.numeric);
1272 taglen = strlen(tag);
1273 strcpy(tag + taglen, ")");
1276 ALLOC_ZVAL(my_zval);
1277 array_init(my_zval);
1278 INIT_PZVAL(my_zval);
1280 add_next_index_string(my_zval, tag, 1);
1282 switch (e->content->which) {
1283 case Z_ElementData_string:
1286 const char *v = cvt_string(e->content->u.string, cvt);
1287 add_next_index_string(my_zval, (char*) v, 1);
1290 case Z_ElementData_numeric:
1291 add_next_index_long(my_zval, *e->content->u.numeric);
1293 case Z_ElementData_trueOrFalse:
1294 add_next_index_long(my_zval, *e->content->u.trueOrFalse);
1296 case Z_ElementData_subtree:
1299 grs[level] = e->content->u.subtree;
1303 zend_hash_next_index_insert(return_value->value.ht, (void *) &my_zval, sizeof(zval *), NULL);
1308 static void ext_grs1(zval *return_value, char type_args[][60],
1310 void (*array_func)(zval *, Z_GenericRecord *,
1311 struct cvt_handle *))
1313 Z_External *ext = (Z_External *) ZOOM_record_get(r, "ext", 0);
1314 if (ext && ext->which == Z_External_OPAC)
1315 ext = ext->u.opac->bibliographicRecord;
1317 struct cvt_handle *cvt = 0;
1318 if (type_args[2][0])
1319 cvt = cvt_open(type_args[3], type_args[2]);
1321 cvt = cvt_open(0, 0);
1323 if (ext->which == Z_External_grs1) {
1324 retval_array1_grs1(return_value, ext->u.grs1, cvt);
1325 } else if (ext->which == Z_External_octet) {
1326 Z_GenericRecord *rec = 0;
1327 if (yaz_oid_is_iso2709(ext->direct_reference))
1329 char *buf = (char *) (ext->u.octet_aligned->buf);
1330 rec = marc_to_grs1(buf, cvt->odr);
1333 (*array_func)(return_value, rec, cvt);
1341 /* {{{ proto string yaz_record(resource id, int pos, string type)
1342 Return record information at given result set position */
1343 PHP_FUNCTION(yaz_record)
1345 pval *pval_id, *pval_pos, *pval_type;
1350 if (ZEND_NUM_ARGS() != 3) {
1353 if (zend_parse_parameters(3, "zzz", &pval_id, &pval_pos, &pval_type)
1358 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1360 convert_to_long_ex(&pval_pos);
1361 pos = pval_pos->value.lval;
1362 convert_to_string_ex(&pval_type);
1363 type = pval_type->value.str.val;
1365 if (p && p->zoom_set) {
1367 char type_args[4][60]; /* 0; 1=2,3 (1 is assumed charset) */
1368 type_args[0][0] = 0;
1369 type_args[1][0] = 0;
1370 type_args[2][0] = 0;
1371 type_args[3][0] = 0;
1372 sscanf(type, "%59[^;];%59[^=]=%59[^,],%59[^,]", type_args[0],
1373 type_args[1], type_args[2], type_args[3]);
1374 r = ZOOM_resultset_record(p->zoom_set, pos-1);
1375 if (!strcmp(type_args[0], "string")) {
1379 if (!strcmp(type_args[0], "array") ||
1380 !strcmp(type_args[0], "array1"))
1382 ext_grs1(return_value, type_args, r, retval_array1_grs1);
1383 } else if (!strcmp(type_args[0], "array2")) {
1384 ext_grs1(return_value, type_args, r, retval_array2_grs1);
1385 } else if (!strcmp(type_args[0], "array3")) {
1386 ext_grs1(return_value, type_args, r, retval_array3_grs1);
1389 const char *info = ZOOM_record_get(r, type, &rlen);
1391 return_value->value.str.len = (rlen > 0) ? rlen : 0;
1392 return_value->value.str.val =
1393 estrndup(info, return_value->value.str.len);
1394 return_value->type = IS_STRING;
1398 php_error_docref(NULL TSRMLS_CC, E_WARNING,
1399 "Bad yaz_record type %s - or unable "
1400 "to return record with type given", type);
1409 /* {{{ proto void yaz_syntax(resource id, string syntax)
1410 Set record syntax for retrieval */
1411 PHP_FUNCTION(yaz_syntax)
1413 pval *pval_id, *pval_syntax;
1416 if (ZEND_NUM_ARGS() != 2 ||
1417 zend_parse_parameters(2, "zz", &pval_id, &pval_syntax) == FAILURE) {
1421 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1422 convert_to_string_ex(&pval_syntax);
1423 option_set(p, "preferredRecordSyntax", pval_syntax->value.str.val);
1428 /* {{{ proto void yaz_element(resource id, string elementsetname)
1429 Set Element-Set-Name for retrieval */
1430 PHP_FUNCTION(yaz_element)
1432 pval *pval_id, *pval_element;
1435 if (ZEND_NUM_ARGS() != 2 ||
1436 zend_parse_parameters(2, "zz", &pval_id, &pval_element) == FAILURE) {
1440 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1442 convert_to_string_ex(&pval_element);
1443 option_set(p, "elementSetName", pval_element->value.str.val);
1448 /* {{{ proto void yaz_schema(resource id, string schema)
1449 Set Schema for retrieval */
1450 PHP_FUNCTION(yaz_schema)
1452 pval *pval_id, *pval_element;
1455 if (ZEND_NUM_ARGS() != 2 ||
1456 zend_parse_parameters(2, "zz", &pval_id, &pval_element) == FAILURE) {
1460 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1461 convert_to_string_ex(&pval_element);
1462 option_set(p, "schema", pval_element->value.str.val);
1467 /* {{{ proto void yaz_set_option(resource id, mixed options)
1468 Set Option(s) for connection */
1469 PHP_FUNCTION(yaz_set_option)
1471 pval *pval_ar, *pval_name, *pval_val, *pval_id;
1474 if (ZEND_NUM_ARGS() == 2) {
1475 if (zend_parse_parameters(2, "zz", &pval_id, &pval_ar) == FAILURE) {
1478 if (Z_TYPE_PP(&pval_ar) != IS_ARRAY) {
1481 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1487 ht = Z_ARRVAL_PP(&pval_ar);
1488 for(zend_hash_internal_pointer_reset_ex(ht, &pos);
1489 zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
1490 zend_hash_move_forward_ex(ht, &pos)
1494 #if PHP_API_VERSION > 20010101
1495 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
1497 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
1499 if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
1502 option_set(p, key, (*ent)->value.str.val);
1506 } else if (ZEND_NUM_ARGS() == 3) {
1507 if (zend_parse_parameters(3, "zzz", &pval_id, &pval_name, &pval_val)
1511 get_assoc (INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1512 convert_to_string_ex(&pval_name);
1513 convert_to_string_ex(&pval_val);
1514 option_set(p, pval_name->value.str.val, pval_val->value.str.val);
1523 /* {{{ proto string yaz_get_option(resource id, string name)
1524 Set Option(s) for connection */
1525 PHP_FUNCTION(yaz_get_option)
1527 pval *pval_id, *pval_name;
1530 if (ZEND_NUM_ARGS() != 2) {
1533 if (zend_parse_parameters(2, "zz", &pval_id, &pval_name) == FAILURE) {
1537 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1539 const char *name_str, *v;
1540 convert_to_string_ex(&pval_name);
1541 name_str = pval_name->value.str.val;
1543 v = option_get(p, name_str);
1547 return_value->value.str.len = strlen(v);
1548 return_value->value.str.val = estrndup(v, return_value->value.str.len);
1549 return_value->type = IS_STRING;
1557 /* {{{ proto void yaz_range(resource id, int start, int number)
1558 Set result set start point and number of records to request */
1559 PHP_FUNCTION(yaz_range)
1561 pval *pval_id, *pval_start, *pval_number;
1564 if (ZEND_NUM_ARGS() != 3 ||
1565 zend_parse_parameters(3, "zzz", &pval_id, &pval_start, &pval_number)
1570 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1571 convert_to_long_ex(&pval_start);
1572 convert_to_long_ex(&pval_number);
1573 option_set_int(p, "start", pval_start->value.lval - 1);
1574 option_set_int(p, "count", pval_number->value.lval);
1579 /* {{{ proto void yaz_sort(resource id, string sortspec)
1580 Set result set sorting criteria */
1581 PHP_FUNCTION(yaz_sort)
1583 pval *pval_id, *pval_criteria;
1586 if (ZEND_NUM_ARGS() != 2 ||
1587 zend_parse_parameters(2, "zz", &pval_id, &pval_criteria) == FAILURE) {
1591 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1593 convert_to_string_ex(&pval_criteria);
1594 xfree(p->sort_criteria);
1595 p->sort_criteria = xstrdup(pval_criteria->value.str.val);
1597 ZOOM_resultset_sort(p->zoom_set, "yaz",
1598 pval_criteria->value.str.val);
1604 const char *ill_array_lookup (void *handle, const char *name)
1606 return array_lookup_string((HashTable *) handle, name);
1609 /* {{{ proto void yaz_itemorder(resource id, array package)
1610 Sends Item Order request */
1611 PHP_FUNCTION(yaz_itemorder)
1613 pval *pval_id, *pval_package;
1616 if (ZEND_NUM_ARGS() != 2 ||
1617 zend_parse_parameters(2, "zz", &pval_id, &pval_package) == FAILURE) {
1620 if (Z_TYPE_PP(&pval_package) != IS_ARRAY) {
1621 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array parameter");
1625 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1627 ZOOM_options options = ZOOM_options_create();
1629 ZOOM_options_set_callback(options,
1630 ill_array_lookup, Z_ARRVAL_PP(&pval_package));
1631 ZOOM_package_destroy(p->zoom_package);
1632 p->zoom_package = ZOOM_connection_package(p->zoom_conn, options);
1633 ZOOM_package_send(p->zoom_package, "itemorder");
1634 ZOOM_options_set_callback(options, 0, 0);
1635 ZOOM_options_destroy (options);
1641 /* {{{ proto void yaz_es(resource id, string type, array package)
1642 Sends Extended Services Request */
1643 PHP_FUNCTION(yaz_es)
1645 pval *pval_id, *pval_type, *pval_package;
1648 if (ZEND_NUM_ARGS() != 3 ||
1649 zend_parse_parameters(3, "zzz", &pval_id, &pval_type,
1650 &pval_package) == FAILURE) {
1653 if (Z_TYPE_PP(&pval_type) != IS_STRING) {
1654 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected string parameter");
1658 if (Z_TYPE_PP(&pval_package) != IS_ARRAY) {
1659 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array parameter");
1663 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1665 ZOOM_options options = ZOOM_options_create();
1667 ZOOM_options_set_callback(options, ill_array_lookup,
1668 Z_ARRVAL_PP(&pval_package));
1669 ZOOM_package_destroy(p->zoom_package);
1670 p->zoom_package = ZOOM_connection_package(p->zoom_conn, options);
1671 ZOOM_package_send(p->zoom_package, pval_type->value.str.val);
1672 ZOOM_options_set_callback(options, 0, 0);
1673 ZOOM_options_destroy (options);
1679 /* {{{ proto void yaz_scan(resource id, type, query [, flags])
1680 Sends Scan Request */
1681 PHP_FUNCTION(yaz_scan)
1683 pval *pval_id, *pval_type, *pval_query, *pval_flags = 0;
1684 HashTable *flags_ht = 0;
1687 if (ZEND_NUM_ARGS() == 3) {
1688 if (zend_parse_parameters(3, "zzz", &pval_id, &pval_type, &pval_query)
1692 } else if (ZEND_NUM_ARGS() == 4) {
1693 if (zend_parse_parameters(4, "zzzz", &pval_id, &pval_type,
1694 &pval_query, &pval_flags) == FAILURE) {
1697 if (Z_TYPE_PP(&pval_flags) != IS_ARRAY) {
1698 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad flags parameter");
1701 flags_ht = Z_ARRVAL_PP(&pval_flags);
1706 convert_to_string_ex(&pval_type);
1707 convert_to_string_ex(&pval_query);
1709 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1710 ZOOM_scanset_destroy(p->zoom_scan);
1713 option_set(p, "number", array_lookup_string(flags_ht, "number"));
1714 option_set(p, "position", array_lookup_string(flags_ht, "position"));
1715 option_set(p, "stepSize", array_lookup_string(flags_ht, "stepsize"));
1716 p->zoom_scan = ZOOM_connection_scan(p->zoom_conn,
1717 Z_STRVAL_PP(&pval_query));
1723 /* {{{ proto array yaz_es_result(resource id)
1724 Inspects Extended Services Result */
1725 PHP_FUNCTION(yaz_es_result)
1730 if (ZEND_NUM_ARGS() != 1 ||
1731 zend_parse_parameters(1, "z", &pval_id) == FAILURE) {
1735 array_init(return_value);
1737 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1738 if (p && p->zoom_package) {
1739 const char *str = ZOOM_package_option_get(p->zoom_package,
1743 add_assoc_string(return_value, "targetReference", (char *) str, 1);
1745 str = ZOOM_package_option_get(p->zoom_package,
1748 add_assoc_string(return_value, "xmlUpdateDoc", (char *) str, 1);
1755 /* {{{ proto array yaz_scan_result(resource id [, array options])
1756 Inspects Scan Result */
1757 PHP_FUNCTION(yaz_scan_result)
1759 pval *pval_id, *pval_opt = 0;
1762 if (ZEND_NUM_ARGS() == 2) {
1763 if (zend_parse_parameters(2, "zz", &pval_id, &pval_opt) == FAILURE) {
1766 } else if (ZEND_NUM_ARGS() == 1) {
1767 if (zend_parse_parameters(1, "z", &pval_id) == FAILURE) {
1774 array_init(return_value);
1776 if (pval_opt && array_init(pval_opt) == FAILURE) {
1780 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1781 if (p && p->zoom_scan) {
1783 /* ZOOM_scanset_term changed from YAZ 3 to YAZ 4 */
1784 #if YAZ_VERSIONL >= 0x040000
1789 int size = ZOOM_scanset_size(p->zoom_scan);
1791 for (pos = 0; pos < size; pos++) {
1792 const char *term = ZOOM_scanset_term(p->zoom_scan, pos, &occ, &len);
1795 ALLOC_ZVAL(my_zval);
1796 array_init(my_zval);
1797 INIT_PZVAL(my_zval);
1799 add_next_index_string(my_zval, "term", 1);
1802 add_next_index_stringl(my_zval, (char*) term, len, 1);
1804 add_next_index_string(my_zval, "?", 1);
1806 add_next_index_long(my_zval, occ);
1808 term = ZOOM_scanset_display_term(p->zoom_scan, pos, &occ, &len);
1811 add_next_index_stringl(my_zval, (char*) term, len, 1);
1813 add_next_index_string(my_zval, "?", 1);
1816 zend_hash_next_index_insert(return_value->value.ht, (void *) &my_zval, sizeof(zval *), NULL);
1822 add_assoc_long(pval_opt, "number", size);
1824 v = ZOOM_scanset_option_get(p->zoom_scan, "stepSize");
1826 add_assoc_long(pval_opt, "stepsize", atoi(v));
1828 v = ZOOM_scanset_option_get(p->zoom_scan, "position");
1830 add_assoc_long(pval_opt, "position", atoi(v));
1832 v = ZOOM_scanset_option_get(p->zoom_scan, "scanStatus");
1834 add_assoc_long(pval_opt, "status", atoi(v));
1842 /* {{{ proto void yaz_ccl_conf(resource id, array package)
1843 Configure CCL package */
1844 PHP_FUNCTION(yaz_ccl_conf)
1846 pval *pval_id, *pval_package;
1849 if (ZEND_NUM_ARGS() != 2 ||
1850 zend_parse_parameters(2, "zz", &pval_id, &pval_package) == FAILURE) {
1854 if (Z_TYPE_PP(&pval_package) != IS_ARRAY) {
1855 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array parameter");
1859 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1861 HashTable *ht = Z_ARRVAL_PP(&pval_package);
1866 ccl_qual_rm(&p->bibset);
1867 p->bibset = ccl_qual_mk();
1869 for(zend_hash_internal_pointer_reset_ex(ht, &pos);
1870 zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
1871 zend_hash_move_forward_ex(ht, &pos)
1874 #if PHP_API_VERSION > 20010101
1875 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
1877 int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
1879 if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
1882 ccl_qual_fitem(p->bibset, (*ent)->value.str.val, key);
1889 /* {{{ proto bool yaz_ccl_parse(resource id, string query, array res)
1890 Parse a CCL query */
1891 PHP_FUNCTION(yaz_ccl_parse)
1893 pval *pval_id, *pval_query, *pval_res = 0;
1896 if (ZEND_NUM_ARGS() != 3 ||
1897 zend_parse_parameters(3, "zzz", &pval_id, &pval_query, &pval_res)
1902 pval_destructor(pval_res);
1903 array_init(pval_res);
1904 convert_to_string_ex(&pval_query);
1906 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1908 const char *query_str = pval_query->value.str.val;
1909 struct ccl_rpn_node *rpn;
1912 CCL_parser ccl_parser = ccl_parser_create(p->bibset);
1914 rpn = ccl_parser_find_str(ccl_parser, query_str);
1916 error_code = ccl_parser_get_error(ccl_parser, &error_pos);
1917 add_assoc_long(pval_res, "errorcode", error_code);
1921 add_assoc_string(pval_res, "errorstring",
1922 (char *) ccl_err_msg(error_code), 1);
1923 add_assoc_long(pval_res, "errorpos", error_pos);
1928 WRBUF wrbuf_pqf = wrbuf_alloc();
1929 ccl_stop_words_t csw = ccl_stop_words_create();
1930 int r = ccl_stop_words_tree(csw, p->bibset, &rpn);
1934 /* stop words were removed. Return stopwords info */
1935 zval *zval_stopwords;
1938 MAKE_STD_ZVAL(zval_stopwords);
1939 array_init(zval_stopwords);
1940 for (idx = 0; ; idx++)
1942 zval *zval_stopword;
1946 if (!ccl_stop_words_info(csw, idx, &qname, &term))
1949 MAKE_STD_ZVAL(zval_stopword);
1950 array_init(zval_stopword);
1952 add_assoc_string(zval_stopword, "field", (char *) qname, 1);
1953 add_assoc_string(zval_stopword, "term", (char *) term, 1);
1954 add_next_index_zval(zval_stopwords, zval_stopword);
1956 add_assoc_zval(pval_res, "stopwords", zval_stopwords);
1958 ccl_pquery(wrbuf_pqf, rpn);
1959 add_assoc_stringl(pval_res, "rpn",
1960 wrbuf_buf(wrbuf_pqf), wrbuf_len(wrbuf_pqf), 1);
1961 wrbuf_destroy(wrbuf_pqf);
1962 ccl_stop_words_destroy(csw);
1965 ccl_rpn_delete(rpn);
1973 /* {{{ proto bool yaz_database (resource id, string databases)
1974 Specify the databases within a session */
1975 PHP_FUNCTION(yaz_database)
1977 pval *pval_id, *pval_database;
1980 if (ZEND_NUM_ARGS() != 2 ||
1981 zend_parse_parameters(2, "zz", &pval_id, &pval_database) == FAILURE) {
1985 convert_to_string_ex(&pval_database);
1986 get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
1987 option_set(p, "databaseName", pval_database->value.str.val);
1993 /* {{{ php_yaz_init_globals
1995 static void php_yaz_init_globals(zend_yaz_globals *yaz_globals)
1997 yaz_globals->assoc_seq = 0;
1998 yaz_globals->max_links = 100;
1999 yaz_globals->keepalive = 120;
2000 yaz_globals->log_file = NULL;
2001 yaz_globals->log_mask = NULL;
2005 static void yaz_close_session(Yaz_Association *as TSRMLS_DC)
2007 if (*as && (*as)->order == YAZSG(assoc_seq)) {
2008 if ((*as)->persistent) {
2011 yaz_association_destroy(*as);
2017 static void yaz_close_link (zend_rsrc_list_entry *rsrc TSRMLS_DC)
2019 Yaz_Association *as = (Yaz_Association *) rsrc->ptr;
2020 yaz_close_session(as TSRMLS_CC);
2023 /* {{{ PHP_INI_BEGIN
2026 #if PHP_MAJOR_VERSION >= 5
2027 STD_PHP_INI_ENTRY("yaz.max_links", "100", PHP_INI_ALL, OnUpdateLong, max_links, zend_yaz_globals, yaz_globals)
2029 STD_PHP_INI_ENTRY("yaz.max_links", "100", PHP_INI_ALL, OnUpdateInt, max_links, zend_yaz_globals, yaz_globals)
2031 #if PHP_MAJOR_VERSION >= 5
2032 STD_PHP_INI_ENTRY("yaz.keepalive", "120", PHP_INI_ALL, OnUpdateLong, keepalive, zend_yaz_globals, yaz_globals)
2034 STD_PHP_INI_ENTRY("yaz.keepalive", "120", PHP_INI_ALL, OnUpdateInt, keepalive, zend_yaz_globals, yaz_globals)
2036 STD_PHP_INI_ENTRY("yaz.log_file", NULL, PHP_INI_ALL, OnUpdateString, log_file, zend_yaz_globals, yaz_globals)
2037 STD_PHP_INI_ENTRY("yaz.log_mask", NULL, PHP_INI_ALL, OnUpdateString, log_mask, zend_yaz_globals, yaz_globals)
2041 PHP_MINIT_FUNCTION(yaz)
2047 yaz_mutex = tsrm_mutex_alloc();
2050 ZEND_INIT_MODULE_GLOBALS(yaz, php_yaz_init_globals, NULL);
2052 REGISTER_INI_ENTRIES();
2054 REGISTER_LONG_CONSTANT("ZOOM_EVENT_NONE", ZOOM_EVENT_NONE,
2055 CONST_CS|CONST_PERSISTENT);
2056 REGISTER_LONG_CONSTANT("ZOOM_EVENT_CONNECT", ZOOM_EVENT_CONNECT,
2057 CONST_CS|CONST_PERSISTENT);
2058 REGISTER_LONG_CONSTANT("ZOOM_EVENT_SEND_DATA", ZOOM_EVENT_SEND_DATA,
2059 CONST_CS|CONST_PERSISTENT);
2060 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_DATA", ZOOM_EVENT_RECV_DATA,
2061 CONST_CS|CONST_PERSISTENT);
2062 REGISTER_LONG_CONSTANT("ZOOM_EVENT_TIMEOUT", ZOOM_EVENT_TIMEOUT,
2063 CONST_CS|CONST_PERSISTENT);
2064 REGISTER_LONG_CONSTANT("ZOOM_EVENT_UNKNOWN", ZOOM_EVENT_UNKNOWN,
2065 CONST_CS|CONST_PERSISTENT);
2066 REGISTER_LONG_CONSTANT("ZOOM_EVENT_SEND_APDU", ZOOM_EVENT_SEND_APDU,
2067 CONST_CS|CONST_PERSISTENT);
2068 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_APDU", ZOOM_EVENT_RECV_APDU,
2069 CONST_CS|CONST_PERSISTENT);
2070 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_RECORD", ZOOM_EVENT_RECV_RECORD,
2071 CONST_CS|CONST_PERSISTENT);
2072 REGISTER_LONG_CONSTANT("ZOOM_EVENT_RECV_SEARCH", ZOOM_EVENT_RECV_SEARCH,
2073 CONST_CS|CONST_PERSISTENT);
2075 fname = YAZSG(log_file);
2076 mask = YAZSG(log_mask);
2077 if (fname && *fname)
2079 yaz_log_init_file(fname);
2082 yaz_log_init_level(yaz_log_mask_str(mask));
2085 yaz_log_init_level(0);
2087 le_link = zend_register_list_destructors_ex (yaz_close_link, 0, "YAZ link", module_number);
2089 order_associations = 1;
2090 shared_associations = xmalloc(sizeof(*shared_associations) * MAX_ASSOC);
2091 for (i = 0; i < MAX_ASSOC; i++) {
2092 shared_associations[i] = 0;
2097 PHP_MSHUTDOWN_FUNCTION(yaz)
2101 if (shared_associations) {
2102 for (i = 0; i < MAX_ASSOC; i++) {
2103 yaz_association_destroy (shared_associations[i]);
2105 xfree(shared_associations);
2106 shared_associations = 0;
2109 tsrm_mutex_free (yaz_mutex);
2112 yaz_log_init_file(0);
2114 UNREGISTER_INI_ENTRIES();
2119 PHP_MINFO_FUNCTION(yaz)
2121 char version_str[20];
2123 strcpy(version_str, "unknown");
2124 yaz_version(version_str, 0);
2125 php_info_print_table_start();
2126 php_info_print_table_row(2, "YAZ Support", "enabled");
2127 php_info_print_table_row(2, "PHP/YAZ Version", PHP_YAZ_VERSION);
2128 php_info_print_table_row(2, "YAZ Version", version_str);
2129 php_info_print_table_row(2, "Compiled with YAZ version", YAZ_VERSION);
2130 php_info_print_table_end();
2133 PHP_RSHUTDOWN_FUNCTION(yaz)
2139 tsrm_mutex_lock(yaz_mutex);
2141 for (i = 0; i < YAZSG(max_links); i++) {
2142 Yaz_Association *as = shared_associations + i;
2145 if (now - (*as)->time_stamp > YAZSG(keepalive))
2147 yaz_association_destroy(*as);
2153 tsrm_mutex_unlock(yaz_mutex);
2158 PHP_RINIT_FUNCTION(yaz)
2162 sprintf(pidstr, "%ld", (long) getpid());
2164 tsrm_mutex_lock(yaz_mutex);
2166 YAZSG(assoc_seq) = order_associations++;
2168 tsrm_mutex_unlock(yaz_mutex);
2170 yaz_log_init_prefix(pidstr);
2174 zend_module_entry yaz_module_entry = {
2175 #if ZEND_MODULE_API_NO >= 20010901
2176 STANDARD_MODULE_HEADER,
2185 #if ZEND_MODULE_API_NO >= 20010901
2188 STANDARD_MODULE_PROPERTIES
2199 * vim600: sw=4 ts=4 fdm=marker
2200 * vim<600: sw=4 ts=4