php-src/ext/yaz/php_yaz.c
Adam Dickmeiss dca01635d5 For YAZ, RSHUTDOWN closes persistent connections that have been idle
more than yaz.keepalive seconds. Default value for config yaz.keepalive
is 120 seconds. The shutdown prevents many sockets in CLOSE_WAIT state.
2003-10-24 19:32:09 +00:00

1654 lines
41 KiB
C

/*
+----------------------------------------------------------------------+
| PHP Version 4 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Adam Dickmeiss <adam@indexdata.dk> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#if HAVE_YAZ
#include "ext/standard/info.h"
#include "php_yaz.h"
#include <yaz/yaz-version.h>
#ifndef YAZ_VERSIONL
#error YAZ version 2.0 or later must be used.
#elif YAZ_VERSIONL < 0x020000
#error YAZ version 2.0 or later must be used.
#endif
#ifdef PHP_WIN32
#include <process.h>
#endif
#include <yaz/proto.h>
#include <yaz/marcdisp.h>
#include <yaz/yaz-util.h>
#include <yaz/yaz-ccl.h>
#include <yaz/zoom.h>
#define MAX_ASSOC 200
typedef struct Yaz_AssociationInfo *Yaz_Association;
struct Yaz_AssociationInfo {
CCL_parser ccl_parser;
ZOOM_connection zoom_conn;
ZOOM_resultset zoom_set;
ZOOM_scanset zoom_scan;
ZOOM_package zoom_package;
char *sort_criteria;
int persistent;
int in_use;
int order;
int zval_resource;
long time_stamp;
};
static Yaz_Association yaz_association_mk()
{
Yaz_Association p = xmalloc (sizeof(*p));
p->zoom_conn = ZOOM_connection_create (0);
p->zoom_set = 0;
p->zoom_scan = 0;
p->zoom_package = 0;
ZOOM_connection_option_set(p->zoom_conn, "implementationName", "PHP");
ZOOM_connection_option_set(p->zoom_conn, "async", "1");
p->sort_criteria = 0;
p->in_use = 0;
p->order = 0;
p->persistent = 0;
p->ccl_parser = ccl_parser_create();
p->ccl_parser->bibset = 0;
p->time_stamp = 0;
return p;
}
static void yaz_association_destroy (Yaz_Association p)
{
if (!p) {
return;
}
ZOOM_resultset_destroy(p->zoom_set);
ZOOM_scanset_destroy(p->zoom_scan);
ZOOM_package_destroy(p->zoom_package);
ZOOM_connection_destroy(p->zoom_conn);
xfree(p->sort_criteria);
ccl_qual_rm(&p->ccl_parser->bibset);
ccl_parser_destroy(p->ccl_parser);
}
#ifdef ZTS
static MUTEX_T yaz_mutex;
#endif
ZEND_DECLARE_MODULE_GLOBALS(yaz);
static Yaz_Association *shared_associations;
static int order_associations;
static int le_link;
function_entry yaz_functions [] = {
PHP_FE(yaz_connect, NULL)
PHP_FE(yaz_close, NULL)
PHP_FE(yaz_search, NULL)
PHP_FE(yaz_wait, second_arg_force_ref)
PHP_FE(yaz_errno, NULL)
PHP_FE(yaz_error, NULL)
PHP_FE(yaz_addinfo, NULL)
PHP_FE(yaz_hits, NULL)
PHP_FE(yaz_record, NULL)
PHP_FE(yaz_syntax, NULL)
PHP_FE(yaz_element, NULL)
PHP_FE(yaz_range, NULL)
PHP_FE(yaz_itemorder, NULL)
PHP_FE(yaz_es_result, NULL)
PHP_FE(yaz_scan, NULL)
PHP_FE(yaz_scan_result, second_arg_force_ref)
PHP_FE(yaz_present, NULL)
PHP_FE(yaz_ccl_conf, NULL)
PHP_FE(yaz_ccl_parse, third_arg_force_ref)
PHP_FE(yaz_database, NULL)
PHP_FE(yaz_sort, NULL)
PHP_FE(yaz_schema, NULL)
PHP_FE(yaz_set_option, NULL)
PHP_FE(yaz_get_option, NULL)
{NULL, NULL, NULL}
};
static void get_assoc(INTERNAL_FUNCTION_PARAMETERS, pval **id, Yaz_Association *assocp)
{
Yaz_Association *as = 0;
*assocp = 0;
#ifdef ZTS
tsrm_mutex_lock (yaz_mutex);
#endif
ZEND_FETCH_RESOURCE(as, Yaz_Association *, id, -1, "YAZ link", le_link);
if (as && *as && (*as)->order == YAZSG(assoc_seq) && (*as)->in_use) {
*assocp = *as;
} else {
#ifdef ZTS
tsrm_mutex_unlock (yaz_mutex);
#endif
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid YAZ handle");
}
}
static void release_assoc(Yaz_Association assoc)
{
#ifdef ZTS
if (assoc) {
tsrm_mutex_unlock(yaz_mutex);
}
#endif
}
static const char *array_lookup_string(HashTable *ht, const char *idx)
{
pval **pvalue;
if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
SEPARATE_ZVAL(pvalue);
convert_to_string(*pvalue);
return (*pvalue)->value.str.val;
}
return 0;
}
static long *array_lookup_long(HashTable *ht, const char *idx)
{
pval **pvalue;
if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
SEPARATE_ZVAL(pvalue);
convert_to_long(*pvalue);
return &(*pvalue)->value.lval;
}
return 0;
}
static long *array_lookup_bool(HashTable *ht, const char *idx)
{
pval **pvalue;
if (ht && zend_hash_find(ht, (char *) idx, strlen(idx) + 1, (void **) &pvalue) == SUCCESS) {
SEPARATE_ZVAL(pvalue);
convert_to_boolean(*pvalue);
return &(*pvalue)->value.lval;
}
return 0;
}
static const char *option_get(Yaz_Association as, const char *name)
{
if (!as) {
return 0;
}
return ZOOM_connection_option_get(as->zoom_conn, name);
}
static int option_get_int(Yaz_Association as, const char *name, int def)
{
const char *v;
v = ZOOM_connection_option_get(as->zoom_conn, name);
if (!v) {
return def;
}
return atoi(v);
}
static void option_set(Yaz_Association as, const char *name, const char *value)
{
if (as && value) {
ZOOM_connection_option_set(as->zoom_conn, name, value);
}
}
static void option_set_int(Yaz_Association as, const char *name, int v)
{
if (as) {
char s[30];
sprintf (s, "%d", v);
ZOOM_connection_option_set(as->zoom_conn, name, s);
}
}
static int strcmp_null(const char *s1, const char *s2)
{
if (s1 == 0 && s2 == 0) {
return 0;
}
if (s1 == 0 || s2 == 0) {
return -1;
}
return strcmp(s1, s2);
}
/* {{{ proto resource yaz_connect(string zurl [, array options])
Create target with given zurl. Returns positive id if successful. */
PHP_FUNCTION(yaz_connect)
{
int i;
char *cp;
char *zurl_str;
const char *user_str = 0, *group_str = 0, *pass_str = 0;
const char *cookie_str = 0, *proxy_str = 0;
const char *charset_str = 0;
const char *client_IP = 0;
const char *otherInfo[3];
int persistent = 1;
int piggyback = 1;
pval **zurl, **user = 0;
Yaz_Association as;
otherInfo[0] = otherInfo[1] = otherInfo[2] = 0;
if (ZEND_NUM_ARGS() == 1) {
if (zend_get_parameters_ex (1, &zurl) == FAILURE) {
WRONG_PARAM_COUNT;
}
} else if (ZEND_NUM_ARGS() == 2) {
if (zend_get_parameters_ex (2, &zurl, &user) == FAILURE) {
WRONG_PARAM_COUNT;
}
if (Z_TYPE_PP(user) == IS_ARRAY) {
long *persistent_val;
long *piggyback_val;
HashTable *ht = Z_ARRVAL_PP(user);
user_str = array_lookup_string(ht, "user");
group_str = array_lookup_string(ht, "group");
pass_str = array_lookup_string(ht, "password");
cookie_str = array_lookup_string(ht, "cookie");
proxy_str = array_lookup_string(ht, "proxy");
charset_str = array_lookup_string(ht, "charset");
persistent_val = array_lookup_bool(ht, "persistent");
if (persistent_val) {
persistent = *persistent_val;
}
piggyback_val = array_lookup_bool(ht, "piggyback");
if (piggyback_val) {
piggyback = *piggyback_val;
}
otherInfo[0] = array_lookup_string(ht, "otherInfo0");
otherInfo[1] = array_lookup_string(ht, "otherInfo1");
otherInfo[2] = array_lookup_string(ht, "otherInfo2");
} else {
convert_to_string_ex(user);
user_str = (*user)->value.str.val;
}
} else {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(zurl);
zurl_str = (*zurl)->value.str.val;
for (cp = zurl_str; *cp && strchr("\t\n ", *cp); cp++);
if (!*cp) {
RETURN_LONG(0);
}
/* see if we have it already ... */
#ifdef ZTS
tsrm_mutex_lock(yaz_mutex);
#endif
for (i = 0; i < YAZSG(max_links); i++) {
as = shared_associations[i];
if (persistent && as && !as->in_use &&
!strcmp_null(option_get(as, "host"), zurl_str) &&
!strcmp_null(option_get(as, "proxy"), proxy_str) &&
!strcmp_null(option_get(as, "user"), user_str) &&
!strcmp_null(option_get(as, "group"), group_str) &&
!strcmp_null(option_get(as, "pass"), pass_str) &&
!strcmp_null(option_get(as, "cookie"), cookie_str) &&
!strcmp_null(option_get(as, "charset"), charset_str))
break;
}
if (i == YAZSG(max_links)) {
/* we didn't have it (or already in use) */
int i0 = -1;
int min_order = 2000000000;
/* find completely free slot or the oldest one */
for (i = 0; i < YAZSG(max_links) && shared_associations[i]; i++) {
as = shared_associations[i];
if (persistent && !as->in_use && as->order < min_order) {
min_order = as->order;
i0 = i;
}
}
if (i == YAZSG(max_links)) {
i = i0;
if (i == -1) {
#ifdef ZTS
tsrm_mutex_unlock (yaz_mutex);
#endif
RETURN_LONG(0); /* no free slot */
} else { /* "best" free slot */
yaz_association_destroy(shared_associations[i]);
}
}
shared_associations[i] = as = yaz_association_mk ();
option_set(as, "proxy", proxy_str);
option_set(as, "user", user_str);
option_set(as, "group", group_str);
option_set(as, "pass", pass_str);
option_set(as, "cookie", cookie_str);
option_set(as, "charset", charset_str);
}
option_set(as, "otherInfo0", otherInfo[0]);
option_set(as, "otherInfo1", otherInfo[1]);
option_set(as, "otherInfo2", otherInfo[2]);
option_set(as, "clientIP", client_IP);
option_set(as, "piggyback", piggyback ? "1" : "0");
ZOOM_connection_connect(as->zoom_conn, zurl_str, 0);
as->in_use = 1;
as->persistent = persistent;
as->order = YAZSG(assoc_seq);
as->time_stamp = time(0);
#ifdef ZTS
tsrm_mutex_unlock (yaz_mutex);
#endif
ZEND_REGISTER_RESOURCE(return_value, &shared_associations[i], le_link);
as->zval_resource = Z_LVAL_P(return_value);
}
/* }}} */
/* {{{ proto bool yaz_close(resource id)
Destory and close target */
PHP_FUNCTION(yaz_close)
{
Yaz_Association p;
pval **id;
if (ZEND_NUM_ARGS() != 1) {
WRONG_PARAM_COUNT;
}
if (zend_get_parameters_ex (1, &id) == FAILURE) {
RETURN_FALSE;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
if (!p) {
RETURN_FALSE;
}
release_assoc(p);
zend_list_delete((*id)->value.lval);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool yaz_search(resource id, string type, string query)
Specify query of type for search - returns true if successful */
PHP_FUNCTION(yaz_search)
{
char *query_str, *type_str;
pval **id, **type, **query;
Yaz_Association p;
if (ZEND_NUM_ARGS() == 3) {
if (zend_get_parameters_ex(3, &id, &type, &query) == FAILURE) {
WRONG_PARAM_COUNT;
}
} else {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
if (!p) {
RETURN_FALSE;
}
convert_to_string_ex(type);
type_str = (*type)->value.str.val;
convert_to_string_ex(query);
query_str = (*query)->value.str.val;
ZOOM_resultset_destroy(p->zoom_set);
p->zoom_set = 0;
if (!strcmp(type_str, "rpn")) {
ZOOM_query q = ZOOM_query_create();
ZOOM_query_prefix(q, query_str);
if (p->sort_criteria) {
ZOOM_query_sortby(q, p->sort_criteria);
}
xfree(p->sort_criteria);
p->sort_criteria = 0;
p->zoom_set = ZOOM_connection_search(p->zoom_conn, q);
ZOOM_query_destroy(q);
RETVAL_TRUE;
}
if (!strcmp(type_str, "cql")) {
ZOOM_query q = ZOOM_query_create();
ZOOM_query_cql(q, query_str);
if (p->sort_criteria) {
ZOOM_query_sortby(q, p->sort_criteria);
}
xfree (p->sort_criteria);
p->sort_criteria = 0;
p->zoom_set = ZOOM_connection_search(p->zoom_conn, q);
ZOOM_query_destroy(q);
RETVAL_TRUE;
} else {
RETVAL_FALSE;
}
release_assoc(p);
}
/* }}} */
/* {{{ proto bool yaz_present(resource id)
Retrieve records */
PHP_FUNCTION(yaz_present)
{
pval **id;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 1) {
WRONG_PARAM_COUNT;
}
if (zend_get_parameters_ex(1, &id) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
if (!p) {
RETURN_FALSE;
}
if (p->zoom_set) {
size_t start = option_get_int(p, "start", 0);
size_t count = option_get_int(p, "count", 0);
if (count > 0) {
ZOOM_resultset_records(p->zoom_set, 0 /* recs */, start, count);
}
}
release_assoc(p);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool yaz_wait([array options])
Process events. */
PHP_FUNCTION(yaz_wait)
{
pval **pval_options = 0;
int event_mode = 0;
int no = 0;
ZOOM_connection conn_ar[MAX_ASSOC];
Yaz_Association conn_as[MAX_ASSOC];
int i, timeout = 15;
if (ZEND_NUM_ARGS() == 1) {
long *val = 0;
long *event_bool = 0;
HashTable *options_ht = 0;
if (zend_get_parameters_ex(1, &pval_options) == FAILURE) {
WRONG_PARAM_COUNT;
}
if (Z_TYPE_PP(pval_options) != IS_ARRAY) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array parameter");
RETURN_FALSE;
}
options_ht = Z_ARRVAL_PP(pval_options);
val = array_lookup_long(options_ht, "timeout");
if (val) {
timeout = *val;
}
event_bool = array_lookup_bool(options_ht, "event");
if (event_bool && *event_bool)
event_mode = 1;
}
#ifdef ZTS
tsrm_mutex_lock(yaz_mutex);
#endif
for (i = 0; i<YAZSG(max_links); i++) {
Yaz_Association p = shared_associations[i];
if (p && p->order == YAZSG(assoc_seq)) {
char str[20];
sprintf(str, "%d", timeout);
ZOOM_connection_option_set(p->zoom_conn, "timeout", str);
conn_as[no] = p;
conn_ar[no++] = p->zoom_conn;
}
}
#ifdef ZTS
tsrm_mutex_unlock(yaz_mutex);
#endif
if (event_mode) {
long ev = ZOOM_event(no, conn_ar);
if (ev <= 0) {
RETURN_FALSE;
} else {
Yaz_Association p = conn_as[ev-1];
int event_code = ZOOM_connection_last_event(p->zoom_conn);
add_assoc_long(*pval_options, "connid", ev);
add_assoc_long(*pval_options, "eventcode", event_code);
zend_list_addref(p->zval_resource);
Z_LVAL_P(return_value) = p->zval_resource;
Z_TYPE_P(return_value) = IS_RESOURCE;
return;
}
}
if (no) {
while (ZOOM_event (no, conn_ar))
;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto int yaz_errno(resource id)
Return last error number (>0 for bib-1 diagnostic, <0 for other error, 0 for no error */
PHP_FUNCTION(yaz_errno)
{
pval **id;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &id) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
if (!p) {
RETURN_LONG(0);
}
RETVAL_LONG(ZOOM_connection_errcode(p->zoom_conn));
release_assoc(p);
}
/* }}} */
/* {{{ proto string yaz_error(resource id)
Return last error message */
PHP_FUNCTION(yaz_error)
{
pval **id;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &id) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
if (p) {
int code = ZOOM_connection_errcode(p->zoom_conn);
const char *msg = ZOOM_connection_errmsg(p->zoom_conn);
if (!code) {
msg = "";
}
return_value->value.str.len = strlen(msg);
return_value->value.str.val = estrndup(msg, return_value->value.str.len);
return_value->type = IS_STRING;
}
release_assoc(p);
}
/* }}} */
/* {{{ proto string yaz_addinfo(resource id)
Return additional info for last error (empty string if none) */
PHP_FUNCTION(yaz_addinfo)
{
pval **id;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &id) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
if (p) {
const char *addinfo = ZOOM_connection_addinfo(p->zoom_conn);
return_value->value.str.len = strlen(addinfo);
return_value->value.str.val = estrndup(addinfo, return_value->value.str.len);
return_value->type = IS_STRING;
}
release_assoc(p);
}
/* }}} */
/* {{{ proto int yaz_hits(resource id)
Return number of hits (result count) for last search */
PHP_FUNCTION(yaz_hits)
{
pval **id;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &id) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, id, &p);
if (p && p->zoom_set) {
RETVAL_LONG(ZOOM_resultset_size(p->zoom_set));
} else {
RETVAL_LONG(0);
}
release_assoc(p);
}
/* }}} */
static Z_GenericRecord *marc_to_grs1(const char *buf, ODR o)
{
int entry_p;
int record_length;
int indicator_length;
int identifier_length;
int base_address;
int length_data_entry;
int length_starting;
int length_implementation;
int max_elements = 256;
Z_GenericRecord *r = odr_malloc (o, sizeof(*r));
r->elements = odr_malloc (o, sizeof(*r->elements) * max_elements);
r->num_elements = 0;
record_length = atoi_n(buf, 5);
if (record_length < 25) {
return 0;
}
indicator_length = atoi_n(buf + 10, 1);
identifier_length = atoi_n(buf + 11, 1);
base_address = atoi_n(buf + 12, 5);
length_data_entry = atoi_n(buf + 20, 1);
length_starting = atoi_n(buf + 21, 1);
length_implementation = atoi_n(buf + 22, 1);
for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) {
entry_p += 3 + length_data_entry + length_starting;
if (entry_p >= record_length) {
return 0;
}
}
base_address = entry_p + 1;
for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) {
Z_TaggedElement *tag;
int data_length;
int data_offset;
int end_offset;
int i;
char tag_str[4];
int identifier_flag = 1;
memcpy(tag_str, buf+entry_p, 3);
entry_p += 3;
tag_str[3] = '\0';
if ((r->num_elements + 1) >= max_elements) {
Z_TaggedElement **tmp = r->elements;
/* double array space, throw away old buffer (nibble memory) */
r->elements = odr_malloc(o, sizeof(*r->elements) * (max_elements *= 2));
memcpy(r->elements, tmp, r->num_elements * sizeof(*tmp));
}
tag = r->elements[r->num_elements++] = odr_malloc(o, sizeof(*tag));
tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
*tag->tagType = 3;
tag->tagOccurrence = 0;
tag->metaData = 0;
tag->appliedVariant = 0;
tag->tagValue = odr_malloc (o, sizeof(*tag->tagValue));
tag->tagValue->which = Z_StringOrNumeric_string;
tag->tagValue->u.string = odr_strdup(o, tag_str);
tag->content = odr_malloc(o, sizeof(*tag->content));
tag->content->which = Z_ElementData_subtree;
tag->content->u.subtree = odr_malloc(o, sizeof(*tag->content->u.subtree));
tag->content->u.subtree->elements = odr_malloc(o, sizeof(*r->elements));
tag->content->u.subtree->num_elements = 1;
tag = tag->content->u.subtree->elements[0] = odr_malloc(o, sizeof(**tag->content->u.subtree->elements));
tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
*tag->tagType = 3;
tag->tagOccurrence = 0;
tag->metaData = 0;
tag->appliedVariant = 0;
tag->tagValue = odr_malloc(o, sizeof(*tag->tagValue));
tag->tagValue->which = Z_StringOrNumeric_string;
tag->content = odr_malloc(o, sizeof(*tag->content));
data_length = atoi_n(buf + entry_p, length_data_entry);
entry_p += length_data_entry;
data_offset = atoi_n(buf + entry_p, length_starting);
entry_p += length_starting;
i = data_offset + base_address;
end_offset = i + data_length - 1;
if (indicator_length > 0 && indicator_length < 5) {
if (buf[i + indicator_length] != ISO2709_IDFS) {
identifier_flag = 0;
}
} else if (!memcmp (tag_str, "00", 2)) {
identifier_flag = 0;
}
if (identifier_flag && indicator_length) {
/* indicator */
tag->tagValue->u.string = odr_malloc(o, indicator_length + 1);
memcpy(tag->tagValue->u.string, buf + i, indicator_length);
tag->tagValue->u.string[indicator_length] = '\0';
i += indicator_length;
tag->content->which = Z_ElementData_subtree;
tag->content->u.subtree = odr_malloc(o, sizeof(*tag->content->u.subtree));
tag->content->u.subtree->elements = odr_malloc(o, 256 * sizeof(*r->elements));
tag->content->u.subtree->num_elements = 0;
while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset) {
int i0;
/* prepare tag */
Z_TaggedElement *parent_tag = tag;
Z_TaggedElement *tag = odr_malloc (o, sizeof(*tag));
if (parent_tag->content->u.subtree->num_elements < 256) {
parent_tag->content->u.subtree->elements[
parent_tag->content->u.subtree->num_elements++] = tag;
}
tag->tagType = odr_malloc(o, sizeof(*tag->tagType));
*tag->tagType = 3;
tag->tagOccurrence = 0;
tag->metaData = 0;
tag->appliedVariant = 0;
tag->tagValue = odr_malloc (o, sizeof(*tag->tagValue));
tag->tagValue->which = Z_StringOrNumeric_string;
/* sub field */
tag->tagValue->u.string = odr_malloc(o, identifier_length);
memcpy(tag->tagValue->u.string, buf + i + 1, identifier_length - 1);
tag->tagValue->u.string[identifier_length - 1] = '\0';
i += identifier_length;
/* data ... */
tag->content = odr_malloc(o, sizeof(*tag->content));
tag->content->which = Z_ElementData_string;
i0 = i;
while ( buf[i] != ISO2709_RS &&
buf[i] != ISO2709_IDFS &&
buf[i] != ISO2709_FS && i < end_offset) {
i++;
}
tag->content->u.string = odr_malloc(o, i - i0 + 1);
memcpy(tag->content->u.string, buf + i0, i - i0);
tag->content->u.string[i - i0] = '\0';
}
} else {
int i0 = i;
tag->tagValue->u.string = "@";
tag->content->which = Z_ElementData_string;
while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset) {
i++;
}
tag->content->u.string = odr_malloc(o, i - i0 +1);
memcpy(tag->content->u.string, buf + i0, i - i0);
tag->content->u.string[i-i0] = '\0';
}
}
return r;
}
static void retval_grs1(zval *return_value, Z_GenericRecord *p)
{
Z_GenericRecord *grs[20];
int eno[20];
int level = 0;
array_init(return_value);
eno[level] = 0;
grs[level] = p;
while (level >= 0) {
zval *my_zval;
Z_TaggedElement *e = 0;
Z_GenericRecord *p = grs[level];
int i;
char tag[256];
int taglen = 0;
if (eno[level] >= p->num_elements) {
--level;
if (level >= 0) {
eno[level]++;
}
continue;
}
/* eno[level]++; */
*tag = '\0';
for (i = 0; i <= level; i++) {
int tag_type = 3;
e = grs[i]->elements[eno[i]];
if (e->tagType) {
tag_type = *e->tagType;
}
taglen = strlen(tag);
sprintf(tag + taglen, "(%d,", tag_type);
taglen = strlen(tag);
if (e->tagValue->which == Z_StringOrNumeric_string) {
int len = strlen(e->tagValue->u.string);
memcpy(tag + taglen, e->tagValue->u.string, len);
tag[taglen+len] = '\0';
} else if (e->tagValue->which == Z_StringOrNumeric_numeric) {
sprintf(tag + taglen, "%d", *e->tagValue->u.numeric);
}
taglen = strlen(tag);
strcpy(tag + taglen, ")");
}
ALLOC_ZVAL(my_zval);
array_init(my_zval);
INIT_PZVAL(my_zval);
add_next_index_string(my_zval, tag, 1);
switch (e->content->which) {
case Z_ElementData_string:
add_next_index_string(my_zval, e->content->u.string, 1);
break;
case Z_ElementData_numeric:
add_next_index_long(my_zval, *e->content->u.numeric);
break;
case Z_ElementData_trueOrFalse:
add_next_index_long(my_zval, *e->content->u.trueOrFalse);
break;
case Z_ElementData_subtree:
level++;
grs[level] = e->content->u.subtree;
eno[level] = -1;
}
zend_hash_next_index_insert(return_value->value.ht, (void *) &my_zval, sizeof(zval *), NULL);
eno[level]++;
}
}
/* {{{ proto string yaz_record(resource id, int pos, string type)
Return record information at given result set position */
PHP_FUNCTION(yaz_record)
{
pval **pval_id, **pval_pos, **pval_type;
Yaz_Association p;
int pos;
char *type;
if (ZEND_NUM_ARGS() != 3) {
WRONG_PARAM_COUNT;
}
if (zend_get_parameters_ex(3, &pval_id, &pval_pos, &pval_type) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
convert_to_long_ex(pval_pos);
pos = (*pval_pos)->value.lval;
convert_to_string_ex(pval_type);
type = (*pval_type)->value.str.val;
if (p && p->zoom_set) {
ZOOM_record r = ZOOM_resultset_record(p->zoom_set, pos-1);
if (!strcmp(type, "string")) {
type = "render";
}
if (r) {
if (!strcmp(type, "array")) {
Z_External *ext = (Z_External *) ZOOM_record_get(r, "ext", 0);
if (ext->which == Z_External_OPAC)
ext = ext->u.opac->bibliographicRecord;
if (ext) {
oident *ent = oid_getentbyoid(ext->direct_reference);
if (ext->which == Z_External_grs1 && ent->value == VAL_GRS1) {
retval_grs1(return_value, ext->u.grs1);
} else if (ext->which == Z_External_octet) {
char *buf = (char *) (ext->u.octet_aligned->buf);
ODR odr = odr_createmem(ODR_DECODE);
Z_GenericRecord *rec = 0;
switch (ent->value) {
case VAL_SOIF:
case VAL_HTML:
break;
case VAL_TEXT_XML:
case VAL_APPLICATION_XML:
/* text2grs1(&buf, &len, t->odr_in, 0, 0); */
break;
default:
rec = marc_to_grs1(buf, odr);
}
if (rec) {
retval_grs1(return_value, rec);
}
odr_destroy(odr);
}
}
} else {
int rlen;
const char *info = ZOOM_record_get(r, type, &rlen);
return_value->value.str.len = (rlen > 0) ? rlen : 0;
return_value->value.str.val = estrndup(info, return_value->value.str.len);
return_value->type = IS_STRING;
}
}
}
release_assoc (p);
}
/* }}} */
/* {{{ proto void yaz_syntax(resource id, string syntax)
Set record syntax for retrieval */
PHP_FUNCTION(yaz_syntax)
{
pval **pval_id, **pval_syntax;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_syntax) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
convert_to_string_ex(pval_syntax);
option_set(p, "preferredRecordSyntax", (*pval_syntax)->value.str.val);
release_assoc(p);
}
/* }}} */
/* {{{ proto void yaz_element(resource id, string elementsetname)
Set Element-Set-Name for retrieval */
PHP_FUNCTION(yaz_element)
{
pval **pval_id, **pval_element;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_element) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
convert_to_string_ex(pval_element);
option_set(p, "elementSetName", (*pval_element)->value.str.val);
release_assoc(p);
}
/* }}} */
/* {{{ proto void yaz_schema(resource id, string schema)
Set Schema for retrieval */
PHP_FUNCTION(yaz_schema)
{
pval **pval_id, **pval_element;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_element) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
convert_to_string_ex(pval_element);
option_set(p, "schema", (*pval_element)->value.str.val);
release_assoc(p);
}
/* }}} */
/* {{{ proto void yaz_set_option(resource id, mixed options)
Set Option(s) for connection */
PHP_FUNCTION(yaz_set_option)
{
pval **pval_ar, **pval_name, **pval_val, **pval_id;
Yaz_Association p;
if (ZEND_NUM_ARGS() == 2) {
if (zend_get_parameters_ex(2, &pval_id, &pval_ar) == FAILURE) {
WRONG_PARAM_COUNT;
}
if (Z_TYPE_PP(pval_ar) != IS_ARRAY) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
if (p) {
HashPosition pos;
HashTable *ht;
zval **ent;
ht = Z_ARRVAL_PP(pval_ar);
for(zend_hash_internal_pointer_reset_ex(ht, &pos);
zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
zend_hash_move_forward_ex(ht, &pos)
) {
char *key;
ulong idx;
#if PHP_API_VERSION > 20010101
int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
#else
int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
#endif
if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
continue;
}
option_set(p, key, (*ent)->value.str.val);
}
release_assoc (p);
}
} else if (ZEND_NUM_ARGS() == 3) {
if (zend_get_parameters_ex(3, &pval_id, &pval_name, &pval_val) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc (INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
convert_to_string_ex(pval_name);
convert_to_string_ex(pval_val);
option_set(p, (*pval_name)->value.str.val, (*pval_val)->value.str.val);
release_assoc(p);
} else {
WRONG_PARAM_COUNT;
}
}
/* }}} */
/* {{{ proto string yaz_get_option(resource id, string name)
Set Option(s) for connection */
PHP_FUNCTION(yaz_get_option)
{
pval **pval_id, **pval_name;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 2) {
WRONG_PARAM_COUNT;
}
if (zend_get_parameters_ex(2, &pval_id, &pval_name) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
if (p) {
const char *name_str, *v;
convert_to_string_ex (pval_name);
name_str = (*pval_name)->value.str.val;
v = option_get(p, name_str);
if (!v) {
v = "";
}
return_value->value.str.len = strlen(v);
return_value->value.str.val = estrndup(v, return_value->value.str.len);
return_value->type = IS_STRING;
} else {
RETVAL_FALSE;
}
release_assoc(p);
}
/* }}} */
/* {{{ proto void yaz_range(resource id, int start, int number)
Set result set start point and number of records to request */
PHP_FUNCTION(yaz_range)
{
pval **pval_id, **pval_start, **pval_number;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &pval_id, &pval_start, &pval_number) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
convert_to_long_ex(pval_start);
convert_to_long_ex(pval_number);
option_set_int(p, "start", (*pval_start)->value.lval - 1);
option_set_int(p, "count", (*pval_number)->value.lval);
release_assoc(p);
}
/* }}} */
/* {{{ proto void yaz_sort(resource id, string sortspec)
Set result set sorting criteria */
PHP_FUNCTION(yaz_sort)
{
pval **pval_id, **pval_criteria;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_criteria) == FAILURE) {
WRONG_PARAM_COUNT;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
if (p) {
convert_to_string_ex(pval_criteria);
xfree(p->sort_criteria);
p->sort_criteria = xstrdup((*pval_criteria)->value.str.val);
}
release_assoc(p);
}
/* }}} */
const char *ill_array_lookup (void *handle, const char *name)
{
return array_lookup_string((HashTable *) handle, name);
}
/* {{{ proto void yaz_itemorder(resource id, array package)
Sends Item Order request */
PHP_FUNCTION(yaz_itemorder)
{
pval **pval_id, **pval_package;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_package) == FAILURE) {
WRONG_PARAM_COUNT;
}
if (Z_TYPE_PP(pval_package) != IS_ARRAY) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array parameter");
RETURN_FALSE;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
if (p) {
ZOOM_options options = ZOOM_options_create();
ZOOM_options_set_callback(options, ill_array_lookup, Z_ARRVAL_PP(pval_package));
ZOOM_package_destroy(p->zoom_package);
p->zoom_package = ZOOM_connection_package(p->zoom_conn, options);
ZOOM_package_send(p->zoom_package, "itemorder");
ZOOM_options_destroy (options);
}
release_assoc(p);
}
/* }}} */
/* {{{ proto void yaz_scan(resource id, type, query [, flags])
Sends Scan Request */
PHP_FUNCTION(yaz_scan)
{
pval **pval_id, **pval_type, **pval_query, **pval_flags = 0;
HashTable *flags_ht = 0;
Yaz_Association p;
if (ZEND_NUM_ARGS() == 3) {
if (zend_get_parameters_ex(3, &pval_id, &pval_type, &pval_query) == FAILURE) {
WRONG_PARAM_COUNT;
}
} else if (ZEND_NUM_ARGS() == 4) {
if (zend_get_parameters_ex(4, &pval_id, &pval_type, &pval_query, &pval_flags) == FAILURE) {
WRONG_PARAM_COUNT;
}
if (Z_TYPE_PP(pval_flags) != IS_ARRAY) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad flags parameter");
RETURN_FALSE;
}
flags_ht = Z_ARRVAL_PP(pval_flags);
} else {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(pval_type);
convert_to_string_ex(pval_query);
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
ZOOM_scanset_destroy(p->zoom_scan);
p->zoom_scan = 0;
if (p) {
option_set(p, "number", array_lookup_string(flags_ht, "number"));
option_set(p, "position", array_lookup_string(flags_ht, "position"));
option_set(p, "stepSize", array_lookup_string(flags_ht, "stepsize"));
p->zoom_scan = ZOOM_connection_scan(p->zoom_conn, Z_STRVAL_PP(pval_query));
}
release_assoc(p);
}
/* }}} */
/* {{{ proto array yaz_es_result(resource id)
Inspects Extended Services Result */
PHP_FUNCTION(yaz_es_result)
{
pval **pval_id;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &pval_id) == FAILURE) {
WRONG_PARAM_COUNT;
}
array_init(return_value);
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
if (p && p->zoom_package) {
const char *str = ZOOM_package_option_get(p->zoom_package, "targetReference");
if (str) {
add_assoc_string(return_value, "targetReference", (char *) str, 1);
}
}
release_assoc(p);
}
/* }}} */
/* {{{ proto array yaz_scan_result(resource id [, array options])
Inspects Scan Result */
PHP_FUNCTION(yaz_scan_result)
{
pval **pval_id, **pval_opt = 0;
Yaz_Association p;
if (ZEND_NUM_ARGS() == 2) {
if (zend_get_parameters_ex(2, &pval_id, &pval_opt) == FAILURE) {
WRONG_PARAM_COUNT;
}
} else if (ZEND_NUM_ARGS() == 1) {
if (zend_get_parameters_ex(1, &pval_id) == FAILURE) {
WRONG_PARAM_COUNT;
}
} else {
WRONG_PARAM_COUNT;
}
array_init(return_value);
if (pval_opt && array_init(*pval_opt) == FAILURE) {
RETURN_FALSE;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
if (p && p->zoom_scan) {
int pos = 0;
int occ, len;
int size = ZOOM_scanset_size(p->zoom_scan);
for (pos = 0; pos < size; pos++) {
const char *term = ZOOM_scanset_term(p->zoom_scan, pos, &occ, &len);
zval *my_zval;
ALLOC_ZVAL(my_zval);
array_init(my_zval);
INIT_PZVAL(my_zval);
add_next_index_string(my_zval, "term", 1);
if (term) {
add_next_index_stringl(my_zval, (char*) term, len, 1);
} else {
add_next_index_string(my_zval, "?", 1);
}
add_next_index_long(my_zval, occ);
zend_hash_next_index_insert(return_value->value.ht, (void *) &my_zval, sizeof(zval *), NULL);
}
if (pval_opt) {
const char *v;
add_assoc_long(*pval_opt, "number", size);
v = ZOOM_scanset_option_get(p->zoom_scan, "stepSize");
if (v) {
add_assoc_long(*pval_opt, "stepsize", atoi(v));
}
v = ZOOM_scanset_option_get(p->zoom_scan, "position");
if (v) {
add_assoc_long(*pval_opt, "position", atoi(v));
}
v = ZOOM_scanset_option_get(p->zoom_scan, "scanStatus");
if (v) {
add_assoc_long(*pval_opt, "status", atoi(v));
}
}
}
release_assoc(p);
}
/* }}} */
/* {{{ proto void yaz_ccl_conf(resource id, array package)
Configure CCL package */
PHP_FUNCTION(yaz_ccl_conf)
{
pval **pval_id, **pval_package;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_package) == FAILURE) {
WRONG_PARAM_COUNT;
}
if (Z_TYPE_PP(pval_package) != IS_ARRAY) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected array parameter");
RETURN_FALSE;
}
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
if (p) {
HashTable *ht = Z_ARRVAL_PP(pval_package);
HashPosition pos;
zval **ent;
char *key;
ccl_qual_rm(&p->ccl_parser->bibset);
p->ccl_parser->bibset = ccl_qual_mk();
for(zend_hash_internal_pointer_reset_ex(ht, &pos);
zend_hash_get_current_data_ex(ht, (void**) &ent, &pos) == SUCCESS;
zend_hash_move_forward_ex(ht, &pos)
) {
ulong idx;
#if PHP_API_VERSION > 20010101
int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, 0, &pos);
#else
int type = zend_hash_get_current_key_ex(ht, &key, 0, &idx, &pos);
#endif
if (type != HASH_KEY_IS_STRING || Z_TYPE_PP(ent) != IS_STRING) {
continue;
}
ccl_qual_fitem(p->ccl_parser->bibset, (*ent)->value.str.val, key);
}
}
release_assoc (p);
}
/* }}} */
/* {{{ proto bool yaz_ccl_parse(resource id, string query, array res)
Parse a CCL query */
PHP_FUNCTION(yaz_ccl_parse)
{
pval **pval_id, **pval_query, **pval_res = 0;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &pval_id, &pval_query, &pval_res) == FAILURE) {
WRONG_PARAM_COUNT;
}
pval_destructor(*pval_res);
array_init(*pval_res);
convert_to_string_ex (pval_query);
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
if (p) {
const char *query_str = (*pval_query)->value.str.val;
struct ccl_rpn_node *rpn;
struct ccl_token *token_list = ccl_parser_tokenize(p->ccl_parser, query_str);
rpn = ccl_parser_find(p->ccl_parser, token_list);
ccl_token_del(token_list);
add_assoc_long(*pval_res, "errorcode", p->ccl_parser->error_code);
if (p->ccl_parser->error_code) {
add_assoc_string(*pval_res, "errorstring", (char *) ccl_err_msg(p->ccl_parser->error_code), 1);
add_assoc_long(*pval_res, "errorpos", p->ccl_parser->error_pos - query_str);
RETVAL_FALSE;
} else {
WRBUF wrbuf_pqf = wrbuf_alloc();
ccl_pquery(wrbuf_pqf, rpn);
add_assoc_stringl(*pval_res, "rpn", wrbuf_buf(wrbuf_pqf), wrbuf_len(wrbuf_pqf), 1);
wrbuf_free(wrbuf_pqf, 1);
RETVAL_TRUE;
}
ccl_rpn_delete(rpn);
} else {
RETVAL_FALSE;
}
release_assoc(p);
}
/* }}} */
/* {{{ proto bool yaz_database (resource id, string databases)
Specify the databases within a session */
PHP_FUNCTION(yaz_database)
{
pval **pval_id, **pval_database;
Yaz_Association p;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &pval_id, &pval_database) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(pval_database);
get_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, pval_id, &p);
option_set(p, "databaseName", (*pval_database)->value.str.val);
RETVAL_TRUE;
release_assoc(p);
}
/* }}} */
/* {{{ php_yaz_init_globals
*/
static void php_yaz_init_globals(zend_yaz_globals *yaz_globals)
{
yaz_globals->assoc_seq = 0;
}
/* }}} */
static void yaz_close_session(Yaz_Association *as TSRMLS_DC)
{
if (*as && (*as)->order == YAZSG(assoc_seq)) {
if ((*as)->persistent) {
(*as)->in_use = 0;
} else {
yaz_association_destroy(*as);
*as = 0;
}
}
}
static void yaz_close_link (zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
Yaz_Association *as = (Yaz_Association *) rsrc->ptr;
yaz_close_session(as TSRMLS_CC);
}
/* {{{ PHP_INI_BEGIN
*/
PHP_INI_BEGIN()
#if PHP_MAJOR_VERSION >= 5
STD_PHP_INI_ENTRY("yaz.max_links", "100", PHP_INI_ALL, OnUpdateLong, max_links, zend_yaz_globals, yaz_globals)
#else
STD_PHP_INI_ENTRY("yaz.max_links", "100", PHP_INI_ALL, OnUpdateInt, max_links, zend_yaz_globals, yaz_globals)
#endif
#if PHP_MAJOR_VERSION >= 5
STD_PHP_INI_ENTRY("yaz.keepalive", "120", PHP_INI_ALL, OnUpdateLong, keepalive, zend_yaz_globals, yaz_globals)
#else
STD_PHP_INI_ENTRY("yaz.keepalive", "120", PHP_INI_ALL, OnUpdateInt, keepalive, zend_yaz_globals, yaz_globals)
#endif
STD_PHP_INI_ENTRY("yaz.log_file", NULL, PHP_INI_ALL, OnUpdateString, log_file, zend_yaz_globals, yaz_globals)
PHP_INI_END()
/* }}} */
PHP_MINIT_FUNCTION(yaz)
{
int i;
const char *fname;
nmem_init();
#ifdef ZTS
yaz_mutex = tsrm_mutex_alloc();
#endif
ZEND_INIT_MODULE_GLOBALS(yaz, php_yaz_init_globals, NULL);
REGISTER_INI_ENTRIES();
fname = YAZSG(log_file);
if (fname && *fname)
{
yaz_log_init_file(fname);
yaz_log_init_level(LOG_ALL);
}
else
yaz_log_init_level(0);
le_link = zend_register_list_destructors_ex (yaz_close_link, 0, "YAZ link", module_number);
order_associations = 1;
shared_associations = xmalloc(sizeof(*shared_associations) * MAX_ASSOC);
for (i = 0; i < MAX_ASSOC; i++) {
shared_associations[i] = 0;
}
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(yaz)
{
int i;
if (shared_associations) {
for (i = 0; i < MAX_ASSOC; i++) {
yaz_association_destroy (shared_associations[i]);
}
xfree(shared_associations);
shared_associations = 0;
nmem_exit();
}
#ifdef ZTS
tsrm_mutex_free (yaz_mutex);
#endif
yaz_log_init_file(0);
return SUCCESS;
}
PHP_MINFO_FUNCTION(yaz)
{
char version_str[20];
#if WIN32
HINSTANCE h = LoadLibrary("yaz");
unsigned long (__cdecl *p)(char *version_str, char *sys_str) = 0;
strcpy(version_str, "unknown");
if (h && (p = (unsigned long(__cdecl*)(char*,char*))
GetProcAddress(h, "yaz_version")))
p(version_str, 0);
if (h)
FreeLibrary(h);
#else
yaz_version(version_str, 0);
#endif
php_info_print_table_start();
php_info_print_table_row(2, "YAZ Support", "enabled");
php_info_print_table_row(2, "YAZ Version", version_str);
php_info_print_table_row(2, "Compiled with YAZ version", YAZ_VERSION);
php_info_print_table_end();
}
PHP_RSHUTDOWN_FUNCTION(yaz)
{
long now = time(0);
int i;
yaz_log(LOG_LOG, "rshutdown keepalive=%ld", YAZSG(keepalive));
#ifdef ZTS
tsrm_mutex_lock(yaz_mutex);
#endif
for (i = 0; i < YAZSG(max_links); i++) {
Yaz_Association *as = shared_associations + i;
if (*as)
{
if (now - (*as)->time_stamp > YAZSG(keepalive))
{
const char *host = option_get(*as, "host");
if (host)
yaz_log(LOG_LOG, "shutdown of %s", host);
yaz_association_destroy(*as);
*as = 0;
}
}
}
#ifdef ZTS
tsrm_mutex_unlock(yaz_mutex);
#endif
return SUCCESS;
}
PHP_RINIT_FUNCTION(yaz)
{
char pidstr[20];
sprintf(pidstr, "%ld", (long) getpid());
#ifdef ZTS
tsrm_mutex_lock(yaz_mutex);
#endif
YAZSG(assoc_seq) = order_associations++;
#ifdef ZTS
tsrm_mutex_unlock(yaz_mutex);
#endif
yaz_log_init_prefix(pidstr);
return SUCCESS;
}
zend_module_entry yaz_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"yaz",
yaz_functions,
PHP_MINIT(yaz),
PHP_MSHUTDOWN(yaz),
PHP_RINIT(yaz),
PHP_RSHUTDOWN(yaz),
PHP_MINFO(yaz),
#if ZEND_MODULE_API_NO >= 20010901
NO_VERSION_YET,
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_YAZ
ZEND_GET_MODULE(yaz)
# ifdef PHP_WIN32
# include "zend_arg_defs.c"
# endif
#endif
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/