cvs: php4 / MAINTAINERS /ext/yaz/ Makefile.in config.m4 php_yaz.c php_yaz.h setup.stub

[email protected] (dickmeiss)
Newsgroups php.version4
Message-ID <cvsdickmeiss959291674@cvsserver>
dickmeiss		Thu May 25 14:54:34 2000 EDT

  Added files:
    /php4/ext/yaz	Makefile.in config.m4 php_yaz.c php_yaz.h setup.stub 

  Modified files:
    /php4	MAINTAINERS 
  Log:
  Added extension YAZ (Z39.50 client role).
  
  
Index: php4/MAINTAINERS
diff -u php4/MAINTAINERS:1.17 php4/MAINTAINERS:1.18
--- php4/MAINTAINERS:1.17	Thu May 25 04:01:31 2000
+++ php4/MAINTAINERS	Thu May 25 14:54:34 2000
@@ -115,6 +115,10 @@
 PRIMARY MAINTAINER:  Thies C. Arntzen <[email protected]>
 STATUS:              Maintained
 --------------------------------------------------------------------------------
+EXTENSION:           yaz
+PRIMARY MAINTAINER:  Adam Dickmeiss <[email protected]>
+STATUS:              Maintained
+--------------------------------------------------------------------------------
 EXTENSION:           zlib
 PRIMARY MAINTAINER:  Stefan Roehrich <[email protected]>
 STATUS:              Maintained

Index: php4/ext/yaz/Makefile.in
+++ php4/ext/yaz/Makefile.in
LTLIBRARY_NAME    = libyaz.la
LTLIBRARY_SOURCES = php_yaz.c

include $(top_srcdir)/build/dynlib.mk


Index: php4/ext/yaz/config.m4
+++ php4/ext/yaz/config.m4
dnl $Id: config.m4,v 1.1 2000/05/25 21:54:34 dickmeiss Exp $

AC_ARG_WITH(yaz,
[  --with-yaz[=DIR]        Include YAZ support (ANSI/NISO Z39.50). DIR is
                          the YAZ bin install directory],
[
	yazconfig=NONE
	if test "$withval" != "no"; then
		if test "$withval" = "yes"; then
			AC_PATH_PROG(yazconfig, yaz-config, NONE)
		else
			if test -r ${withval}/yaz-config; then
				yazconfig=${withval}/yaz-config
			else
				yazconfig=${withval}/bin/yaz-config
			fi
		fi
	fi
	AC_MSG_CHECKING(for YAZ support)
	if test -f $yazconfig; then
  		AC_DEFINE(HAVE_YAZ,1,[Whether you have YAZ])
		. $yazconfig
		for i in $YAZLIB; do
			case $i in
			-l*)
				ii=`echo $i|cut -c 3-`
				AC_ADD_LIBRARY($ii)
				;;
			-L*)
				ii=`echo $i|cut -c 3-`
				AC_ADD_LIBPATH($ii)
				;;
			esac
		done
		for i in $YAZINC; do
			case $i in
			-I*)
				ii=`echo $i|cut -c 3-`
				AC_ADD_INCLUDE($ii)
				;;
			esac
		done
    		AC_MSG_RESULT(yes)
    		PHP_EXTENSION(yaz)
	else
		AC_MSG_RESULT(no)
	fi
],[
	AC_MSG_CHECKING(for YAZ support)
	AC_MSG_RESULT(no)
])

Index: php4/ext/yaz/php_yaz.c
+++ php4/ext/yaz/php_yaz.c
/*
   +----------------------------------------------------------------------+
   | PHP version 4.0                                                      |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group                   |
   +----------------------------------------------------------------------+
   | This source file is subject to version 2.02 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
   | available at through the world-wide-web at                           |
   | http://www.php.net/license/2_02.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          |
   | [email protected] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Authors: Adam Dickmeiss <[email protected]>                          |
   +----------------------------------------------------------------------+
 */

/* $Id: php_yaz.c,v 1.1 2000/05/25 21:54:34 dickmeiss Exp $ */

#include "php.h"

#if HAVE_YAZ
#include "php_yaz.h"

#include <yaz/proto.h>
#include <yaz/tcpip.h>
#include <yaz/pquery.h>
#include <yaz/diagbib1.h>
#include <yaz/otherinfo.h>
#include <yaz/marcdisp.h>
#include <yaz/yaz-util.h>

#define MAX_ASSOC 100

#define PHP_YAZ_DEBUG 1

typedef struct Yaz_ResultSetInfo *Yaz_ResultSet;
typedef struct Yaz_AssociationInfo *Yaz_Association;
typedef struct Yaz_RecordCacheInfo *Yaz_RecordCache;

struct Yaz_RecordCacheInfo {
	Z_NamePlusRecordList recordList;
	Yaz_RecordCache next;
};

struct Yaz_ResultSetInfo {
	Z_Query *query;
	Z_ReferenceId *referenceId;
	ODR odr;
	int resultCount;
	Yaz_ResultSet next;
	Z_NamePlusRecordList *recordList;
};

#define PHP_YAZ_SELECT_READ 1
#define PHP_YAZ_SELECT_WRITE 2
#define PHP_YAZ_STATE_CONNECTING	1
#define PHP_YAZ_STATE_ESTABLISHED	2
#define PHP_YAZ_STATE_CLOSED		3

#define PHP_YAZ_ERROR_CONNECTION_LOST (-1)
#define PHP_YAZ_ERROR_DECODE (-2)
#define PHP_YAZ_ERROR_ENCODE (-3)
#define PHP_YAZ_ERROR_CONNECT (-4)
#define PHP_YAZ_ERROR_INIT (-5)
#define PHP_YAZ_ERROR_TIMEOUT (-6)

struct Yaz_AssociationInfo {
	char *host_port;
	int num_databaseNames;
	char **databaseNames;
	COMSTACK cs;
	char *cookie;
	char *proxy;
	char *auth_open;
	char *user;
	char *group;
	char *pass;
	int error;
	char *addinfo;
	Yaz_ResultSet resultSets;
	int order;
	int state;
	int mask_select;
	int reconnect_flag;
	ODR odr_in;
	ODR odr_out;
	char *buf_out;
	int len_out;
	char *buf_in;
	int len_in;
	int (*action)(Yaz_Association t);
	int resultSetStartPoint;
	int numberOfRecordsRequested;
	char *elementSetNames;
	char *preferredRecordSyntax;
};

static Yaz_Association yaz_association_mk ()
{
	Yaz_Association p = xmalloc (sizeof(*p));
	p->host_port = 0;
	p->num_databaseNames = 0;
	p->databaseNames = 0;
	p->cs = 0;
	p->cookie = 0;
	p->proxy = 0;
	p->auth_open = 0;
	p->user = 0;
	p->group = 0;
	p->pass = 0;
	p->error = 0;
	p->addinfo = 0;
	p->resultSets = 0;
	p->order = 0;
	p->state = PHP_YAZ_STATE_CLOSED;
	p->mask_select = 0;
	p->reconnect_flag = 0;
	p->odr_in = odr_createmem (ODR_DECODE);
	p->odr_out = odr_createmem (ODR_ENCODE);
	p->buf_out = 0;
	p->len_out = 0;
	p->buf_in = 0;
	p->len_in = 0;
	p->action = 0;
	p->resultSetStartPoint = 1;
	p->numberOfRecordsRequested = 10;
	p->elementSetNames = 0;
	p->preferredRecordSyntax = 0;
	return p;
}

static void yaz_association_destroy (Yaz_Association p)
{
	int i;
	if (!p)
		return ;
	xfree (p->host_port);
	for (i = 0; i<p->num_databaseNames; i++)
		xfree (p->databaseNames[i]);
	xfree (p->databaseNames);
	if (p->cs)
		cs_close (p->cs);
	xfree (p->cookie);
	xfree (p->proxy);
	xfree (p->auth_open);
	xfree (p->user);
	xfree (p->group);
	xfree (p->pass);
	xfree (p->addinfo);
	odr_destroy (p->odr_in);
	odr_destroy (p->odr_out);
	/* buf_out */
	/* buf_in */
	/* action */
	xfree (p->elementSetNames);
	xfree (p->preferredRecordSyntax);
}

static Yaz_ResultSet yaz_resultset_mk()
{
	ODR odr = odr_createmem (ODR_ENCODE);
	Yaz_ResultSet p = odr_malloc (odr, sizeof(*p));
	
	p->query = 0;
	p->referenceId = 0;
	p->odr = odr;
	p->resultCount = 0;
	p->next = 0;
	p->recordList = 0;
	return p;
}

static void yaz_resultset_destroy (Yaz_ResultSet p)
{
	if (!p)
		return;
	if (p->odr)
		odr_destroy (p->odr);
}

static Yaz_Association *shared_associations;
static int order_associations;

/*
  when id = 0, it means all targes...
  id = yaz_connect(zurl, user,group, pass);
  yaz_set_db(id, db)
  yaz_error(id)
  yaz_errno(id)
  yaz_addinfo(id)
  
  yaz_wait()
  yaz_range(id, from, to, syntax, elementset)
  yaz_search(id, type, query)
  yaz_hits(id)
  yaz_record(id, pos)
  
  yaz_scan(id)
  yaz_scan_point(id, scanterm, before, after)
  yaz_scan_result(id, pos)
  
  yaz_close(id)
*/

function_entry yaz_functions [] = {
	PHP_FE(yaz_connect, NULL)
	PHP_FE(yaz_close, NULL)
	PHP_FE(yaz_search, NULL)
	PHP_FE(yaz_wait, NULL)
	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)
	{NULL, NULL, NULL}
};

static Yaz_Association get_assoc (pval **id)
{
	int i;
	convert_to_long_ex(id);
	i = (*id)->value.lval;
	
	if (i < 1 || i > MAX_ASSOC)
		return 0;
	return shared_associations[i-1];
}


static void do_close (Yaz_Association p)
{
	p->mask_select = 0;
	p->state = PHP_YAZ_STATE_CLOSED;
	if (p->cs)
	{
		cs_close (p->cs);
		p->cs = 0;
	}
}

static void do_connect (Yaz_Association p)
{
	void *addr;
	
	p->reconnect_flag = 0;
	p->cs = cs_create (tcpip_type, 0, PROTO_Z3950);
	addr = tcpip_strtoaddr (p->host_port);
	if (!addr)
	{
		do_close(p);
		p->error = PHP_YAZ_ERROR_CONNECT;
		return;
	}
	cs_connect (p->cs, addr);
	p->state = PHP_YAZ_STATE_CONNECTING;
	p->mask_select = PHP_YAZ_SELECT_READ | PHP_YAZ_SELECT_WRITE;
}

static void response_diag (Yaz_Association t, Z_DiagRec *p)
{
	Z_DefaultDiagFormat *r;
	char *addinfo = 0;

	xfree (t->addinfo);
	t->addinfo = 0;
	if (p->which != Z_DiagRec_defaultFormat)
	{
		t->error = PHP_YAZ_ERROR_DECODE;
		return;
	}
	r = p->u.defaultFormat;
#ifdef ASN_COMPILED
	switch (r->which)
	{
	case Z_DefaultDiagFormat_v2Addinfo:
		addinfo = r->u.v2Addinfo;
		break;
	case Z_DefaultDiagFormat_v3Addinfo:
		addinfo = r->u.v3Addinfo;
		break;
	}
#else
	addinfo = r->addinfo;
#endif
	if (addinfo)
		t->addinfo = xstrdup (addinfo);
	t->error = *r->condition;
}

static int send_present (Yaz_Association t);

void handle_records (Yaz_Association t, Z_Records *sr)
{
	if (sr && sr->which == Z_Records_NSD)
	{
#ifdef ASN_COMPILED
		Z_DiagRec dr, *dr_p = &dr;
		dr.which = Z_DiagRec_defaultFormat;
		dr.u.defaultFormat = sr->u.nonSurrogateDiagnostic;
		
		response_diag (t, dr_p);
#else
		response_diag (t, sr->u.nonSurrogateDiagnostic);
#endif
	}
	else if (sr && sr->which == Z_Records_multipleNSD)
	{
		if (sr->u.multipleNonSurDiagnostics->num_diagRecs >= 1)
			response_diag(t,	sr->u.multipleNonSurDiagnostics->diagRecs[0]);
		else
			t->error = PHP_YAZ_ERROR_DECODE;
	}
	else 
	{
		if (t->numberOfRecordsRequested > 0 && !t->resultSets->recordList)
		{
			int i;
			
			t->resultSets->recordList =
				odr_malloc (t->resultSets->odr,
							sizeof(*t->resultSets->recordList));
			t->resultSets->recordList->records =
				odr_malloc (t->resultSets->odr, t->numberOfRecordsRequested
							 * sizeof(*t->resultSets->recordList->records));
			for (i = 0; i < t->numberOfRecordsRequested; i++)
				t->resultSets->recordList->records[i] = 0;
			if (t->numberOfRecordsRequested + t->resultSetStartPoint-1 > 
				t->resultSets->resultCount)
				t->numberOfRecordsRequested = t->resultSets->resultCount -
					t->resultSetStartPoint + 1;
			t->resultSets->recordList->num_records =
				t->numberOfRecordsRequested;
		}
		if (sr && sr->which == Z_Records_DBOSD)
		{
			int j, i;
			Z_NamePlusRecordList *p =
				sr->u.databaseOrSurDiagnostics;
			for (j = 0; j < t->resultSets->recordList->num_records; j++)
				if (!t->resultSets->recordList->records[j])
					break;
			for (i = 0; i<p->num_records; i++)
				t->resultSets->recordList->records[i+j] = p->records[i];
			/* transfer our response to search_nmem .. we need it later */
			nmem_transfer (t->resultSets->odr->mem, odr_extract_mem (t->odr_in));
		}
	}
}

static void search_response (Yaz_Association t, Z_SearchResponse *sr)
{
	t->resultSets->resultCount = *sr->resultCount;
	handle_records (t, sr->records);
}

static void present_response (Yaz_Association t, Z_PresentResponse *pr)
{
	handle_records (t, pr->records);
}

static void handle_apdu (Yaz_Association t, Z_APDU *apdu)
{
	Z_InitResponse *initrs;

	t->mask_select = 0;

	switch(apdu->which)
	{
	case Z_APDU_initResponse:
		initrs = apdu->u.initResponse;
		if (!*initrs->result)
		{
			t->error = PHP_YAZ_ERROR_INIT;
		}
		else
		{
			char *cookie =
				yaz_oi_get_string_oidval (&apdu->u.initResponse->otherInfo,
										  VAL_COOKIE, 1, 0);
			if (cookie)
			{
				xfree(t->cookie);
				t->cookie = xstrdup(cookie);
			}
			(*t->action) (t);
		}
		break;
	case Z_APDU_searchResponse:
		search_response (t, apdu->u.searchResponse);
		send_present (t);
		break;
	case Z_APDU_presentResponse:
		present_response (t, apdu->u.presentResponse);
		send_present (t);
		break;
#if 0
	case Z_APDU_scanResponse:
		zlog (req, t->name, " scan response");
		scanResponse (req, t, apdu->u.scanResponse);
		break;
#endif
#if USE_ES
	case Z_APDU_extendedServicesResponse:
		zlog (req, t->name, " ES response");
		esResponse (req, t, apdu->u.extendedServicesResponse);
		break;
#endif
	case Z_APDU_close:
		do_close(t);
		if (t->reconnect_flag)
			do_connect (t);
		else
			t->error = PHP_YAZ_ERROR_CONNECTION_LOST;
		break;
	default:
		do_close (t);
		t->error = PHP_YAZ_ERROR_DECODE;
		break;
	}
}

static int do_read (Yaz_Association t)
{
	int r;
	Z_APDU *apdu;

	r = cs_get (t->cs, &t->buf_in, &t->len_in);
	if (r == 1)
		return 0;
	if (r <= 0)
	{
		do_close (t);
		if (t->reconnect_flag)
		{
			do_connect (t);
		}
		else
		{
			do_close (t);
			t->error = PHP_YAZ_ERROR_CONNECTION_LOST;
		}
	}
	else
	{
		odr_reset (t->odr_in);
		odr_setbuf (t->odr_in, t->buf_in, r, 0);
		if (!z_APDU (t->odr_in, &apdu, 0, 0))
		{
			do_close (t);
			t->error = PHP_YAZ_ERROR_DECODE;
		}
		else
		{
			/* apdu_log(req, t->odr_print, apdu); */
			handle_apdu (t, apdu);
		}
	}
	return 1;
}

static int do_write (Yaz_Association t)
{
	int r;
	
	if ((r=cs_put (t->cs, t->buf_out, t->len_out)) < 0)
	{
		if (t->reconnect_flag)
		{
			do_close (t);
			do_connect (t);
		}
		else
		{
			if (t->state == PHP_YAZ_STATE_CONNECTING)
				t->error = PHP_YAZ_ERROR_CONNECT;
			else
				t->error = PHP_YAZ_ERROR_CONNECTION_LOST;
			do_close (t);
			return 1;
		}
	}
	else if (r == 1)
	{
		t->state = PHP_YAZ_STATE_ESTABLISHED;
		t->mask_select = PHP_YAZ_SELECT_READ|PHP_YAZ_SELECT_WRITE;
	}
	else
	{
		t->state = PHP_YAZ_STATE_ESTABLISHED;
		t->mask_select = PHP_YAZ_SELECT_READ;
	}
	return 0;
}


static int send_APDU (Yaz_Association t, Z_APDU *a)
{
	if (t->cookie)
	{
		Z_OtherInformation **oi;
		yaz_oi_APDU(a, &oi);
		yaz_oi_set_string_oidval(oi, t->odr_out, VAL_COOKIE, 1, t->cookie);
	}
/* from ZAP */
#if 0
	if (req->request->connection)
	{
		Z_OtherInformation **oi;
		zlog (req, t->name, " encoding client_ip");
		yaz_oi_APDU(a, &oi);
		yaz_oi_set_string_oidval(oi, t->odr_out, VAL_CLIENT_IP, 1,
								 req->request->connection->remote_ip);
	}
#endif
	if (!z_APDU(t->odr_out, &a, 0, 0))
	{
		do_close (t);
		t->error = PHP_YAZ_ERROR_ENCODE;
		return -1;
	}
	/* apdu_log(req, t->odr_print, a); */
	t->buf_out = odr_getbuf(t->odr_out, &t->len_out, 0);
	odr_reset(t->odr_out);
	do_write (t);
	return 0;	
}

static char **set_DatabaseNames (Yaz_Association t, int *num)
{
	char **databaseNames;
	char *c, *cp = strchr (t->host_port, '/');
	int no = 2;

	if (cp)
	{
		c = cp;
		while ((c = strchr(c, '+')))
		{
			c++;
			no++;
		}
	}
	else
		cp = "/Default";
	databaseNames = odr_malloc (t->odr_out, no * sizeof(*databaseNames));
	no = 0;
	while (*cp)
	{
		c = ++cp;
		c = strchr (c, '+');
		if (!c)
			c = cp + strlen(cp);
		else if (c == cp)
			continue;
		/* cp ptr to first char of db name, c is char following db name */
		databaseNames[no] = odr_malloc (t->odr_out, 1+c-cp);
		memcpy (databaseNames[no], cp, c-cp);
		databaseNames[no][c-cp] = '\0';
		no++;
		cp = c;
	}
	databaseNames[no] = NULL;
	*num = no;
	return databaseNames;
}

static int send_search (Yaz_Association t)
{
	Yaz_ResultSet r = t->resultSets;
	Z_APDU *apdu = zget_APDU(t->odr_out, Z_APDU_searchRequest);
	Z_SearchRequest *sreq = apdu->u.searchRequest;
	
	/* resultSetPrepare (req, t, req->cur_pa); */
	if (t->resultSetStartPoint == 1)
	{
		sreq->largeSetLowerBound = odr_malloc (t->odr_out, sizeof(int));
		*sreq->largeSetLowerBound = 999999;
		sreq->smallSetUpperBound = &t->numberOfRecordsRequested;
		sreq->mediumSetPresentNumber = &t->numberOfRecordsRequested;
		if (t->elementSetNames && *t->elementSetNames)
		{
			Z_ElementSetNames *esn = odr_malloc (t->odr_out, sizeof(*esn));
			
			esn->which = Z_ElementSetNames_generic;
			esn->u.generic = t->elementSetNames;
			sreq->mediumSetElementSetNames = esn;
			sreq->smallSetElementSetNames = esn;
		}
	}
	else
	{
		sreq->smallSetUpperBound = odr_malloc (t->odr_out, sizeof(int));
		*sreq->smallSetUpperBound = 0;
		sreq->largeSetLowerBound = odr_malloc (t->odr_out, sizeof(int));
		*sreq->largeSetLowerBound = 1;
		sreq->mediumSetPresentNumber = odr_malloc (t->odr_out, sizeof(int));
		*sreq->mediumSetPresentNumber = 0;
	}
	sreq->query = r->query;
	if (t->preferredRecordSyntax && *t->preferredRecordSyntax)
	{
		struct oident ident;
		
		ident.proto = PROTO_Z3950;
		ident.oclass = CLASS_RECSYN;
		ident.value = oid_getvalbyname (t->preferredRecordSyntax);
		sreq->preferredRecordSyntax =
			odr_oiddup (t->odr_out, oid_getoidbyent (&ident));
	}
	sreq->databaseNames = set_DatabaseNames (t, &sreq->num_databaseNames);
	
	send_APDU (t, apdu);
	return 1;
}

static int send_present (Yaz_Association t)
{
	Z_APDU *apdu = zget_APDU(t->odr_out, Z_APDU_presentRequest);
	Z_PresentRequest *req = apdu->u.presentRequest;
	int i = 0;
	
	if (!t->resultSets->recordList)	  /* no records to retrieve at all .. */
	{
#if PHP_YAZ_DEBUG
		php_log_err("No records to retrieve...");
#endif
		return 0;
	}
	
	while (1)
	{
		if (i >= t->resultSets->recordList->num_records) 
		{						/* got all records ... */
			/* searchHits (zreq, t); */
			return 0;
		}
		if (!t->resultSets->recordList->records[i])
			break;
		i++;
	}
	/* got record(s) to retrieve */
	
	req->resultSetStartPoint = odr_malloc (t->odr_out, sizeof(int));
	*req->resultSetStartPoint = t->resultSetStartPoint + i;
	
	req->numberOfRecordsRequested = odr_malloc (t->odr_out, sizeof(int));
	*req->numberOfRecordsRequested = t->resultSets->recordList->num_records - i;
	
	if (t->preferredRecordSyntax && *t->preferredRecordSyntax)
	{
		struct oident ident;
		
		ident.proto = PROTO_Z3950;
		ident.oclass = CLASS_RECSYN;
		ident.value = oid_getvalbyname (t->preferredRecordSyntax);
		req->preferredRecordSyntax =
			odr_oiddup (t->odr_out, oid_getoidbyent (&ident));
	}
	
	if (t->elementSetNames && *t->elementSetNames)
	{
		Z_ElementSetNames *esn = odr_malloc (t->odr_out, sizeof(*esn));
		Z_RecordComposition *compo = odr_malloc (t->odr_out, sizeof(*compo));
		
		esn->which = Z_ElementSetNames_generic;
		esn->u.generic = t->elementSetNames;
		compo->which = Z_RecordComp_simple;
		compo->u.simple = esn;
		req->recordComposition = compo;
	}
	send_APDU (t, apdu);
	return 1;
}

static void send_init(Yaz_Association t)
{
	int i = 0;
	Z_APDU *apdu = zget_APDU(t->odr_out, Z_APDU_initRequest);
	Z_InitRequest *ireq = apdu->u.initRequest;
	Z_IdPass *pass = odr_malloc(t->odr_out, sizeof(*pass));
	Z_IdAuthentication *auth = odr_malloc(t->odr_out, sizeof(*auth));
	const char *auth_open = t->auth_open;
	const char *auth_groupId = t->group;
	const char *auth_userId = t->user;
	const char *auth_password = t->pass;
	
	ODR_MASK_SET(ireq->options, Z_Options_search);
	ODR_MASK_SET(ireq->options, Z_Options_present);
	ODR_MASK_SET(ireq->options, Z_Options_namedResultSets);
	ODR_MASK_SET(ireq->options, Z_Options_scan);
	
	ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_1);
	ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_2);
	ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_3);
	
	ireq->implementationName = "PHP/YAZ";
	
	*ireq->maximumRecordSize = 1024*1024;
	*ireq->preferredMessageSize = 1024*1024;
	
	if (auth_open && *auth_open)
	{
		auth->which = Z_IdAuthentication_open;
		auth->u.open = odr_malloc(t->odr_out, strlen(auth_open)+1);
		strcpy(auth->u.open, auth_open);
		ireq->idAuthentication = auth;
	}
	pass->groupId = 0;
	if (auth_groupId && *auth_groupId)
	{
		pass->groupId = odr_malloc(t->odr_out, strlen(auth_groupId)+1);
		strcpy(pass->groupId, auth_groupId);
		i++;
	}
	pass->userId = 0;
	if (auth_userId && *auth_userId)
	{
		pass->userId = odr_malloc(t->odr_out, strlen(auth_userId)+1);
		strcpy(pass->userId, auth_userId);
		i++;
	}
	pass->password = 0;
	if (auth_password && *auth_password)
	{
		pass->password = odr_malloc(t->odr_out, strlen(auth_password)+1);
		strcpy(pass->password, auth_password);
		i++;
	}
	if(i)
	{
		auth->which = Z_IdAuthentication_idPass;
		auth->u.idPass = pass;
		ireq->idAuthentication = auth;
	}
	if (t->proxy)
		yaz_oi_set_string_oidval(&ireq->otherInfo, t->odr_out,
								 VAL_PROXY, 1, t->host_port);
	send_APDU (t, apdu);
}

static int do_event (int *id)
{
	fd_set input, output;
	int i;
	int no = 0;
	int max_fd = 0;
	struct timeval tv;
	
	tv.tv_sec = 15;
	tv.tv_usec = 0;
	
	FD_ZERO (&input);
	FD_ZERO (&output);
	for (i = 0; i < MAX_ASSOC; i++)
	{
		Yaz_Association p = shared_associations[i];
		int fd;
		if (!p || p->order != order_associations || !p->cs)
			continue;
		fd = cs_fileno (p->cs);
		if (max_fd < fd)
			max_fd = fd;
		if (p->mask_select & PHP_YAZ_SELECT_READ)
		{
			FD_SET (fd, &input);
			no++;
		}
		if (p->mask_select & PHP_YAZ_SELECT_WRITE)
		{
			FD_SET (fd, &output);
			no++;
		}
	}
	if (!no)
		return 0;
	no = select (max_fd+1, &input, &output, 0, &tv);
	for (i = 0; i<MAX_ASSOC; i++)
	{
		int fd;
		Yaz_Association p = shared_associations[i];
		if (!p || p->order != order_associations || !p->cs)
			continue;
		*id = i+1;
		fd =cs_fileno(p->cs);
		if (no <= 0)
		{
			if (p->mask_select)	   /* only mark for those still pending */
			{
				if (p->state == PHP_YAZ_STATE_CONNECTING)
					p->error = PHP_YAZ_ERROR_CONNECT;
				else
					p->error = PHP_YAZ_ERROR_TIMEOUT;
				do_close (p);
			}
		}
		else if (p->state == PHP_YAZ_STATE_CONNECTING)
		{
			if (FD_ISSET (fd, &input))
			{
				do_close(p);
				p->error = PHP_YAZ_ERROR_CONNECT;
				return 2;
			}
			else if (FD_ISSET (fd, &output))
			{
				send_init(p);
			}
		}
		else if (p->state == PHP_YAZ_STATE_ESTABLISHED)
		{
			if (FD_ISSET (fd, &input))
				do_read (p);
			if (p->cs && FD_ISSET (fd, &output))
				do_write (p);
		}
		else
		{
			do_close (p);
			p->error = PHP_YAZ_ERROR_CONNECTION_LOST;
		}
	}
	return no;
}

/* {{{ proto int yaz_connect(string zurl)
   Create target with given zurl. Returns positive id if succesful. */
PHP_FUNCTION(yaz_connect)
{
	int i;
	char *cp;
	char *zurl_str;
	pval **zurl;
	if (ARG_COUNT(ht) < 1 || zend_get_parameters_ex (1, &zurl) == FAILURE)
	{
		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 ... */
	for (i = 0; i<MAX_ASSOC; i++)
		if (shared_associations[i] && shared_associations[i]->host_port &&
			shared_associations[i]->order != order_associations &&
			!strcmp (shared_associations[i]->host_port, zurl_str))
			break;
	if (i == MAX_ASSOC)
	{
		/* 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<MAX_ASSOC && shared_associations[i]; i++)
			if (shared_associations[i]->order < min_order
				&& shared_associations[i]->order != order_associations)
			{
				min_order = shared_associations[i]->order;
				i0 = i;
			}
		if (i == MAX_ASSOC)
		{
			i = i0;
			if (i == -1)
			{
				RETURN_LONG(0);          /* no free slot */
			}
			else                         /* "best" free slot */
				yaz_association_destroy(shared_associations[i]);
		}
		shared_associations[i] = yaz_association_mk ();
		shared_associations[i]->host_port = xstrdup (zurl_str);
	}
	shared_associations[i]->order = order_associations;
	shared_associations[i]->error = 0;
	shared_associations[i]->numberOfRecordsRequested = 10;
	shared_associations[i]->resultSetStartPoint = 1;
	RETURN_LONG(i+1);
}
/* }}} */

/* {{{ proto int yaz_close(int id)
   Destory and close target */
PHP_FUNCTION(yaz_close)
{
	pval **id;
	int i;
	if (ARG_COUNT(ht) != 1)
		WRONG_PARAM_COUNT;
	if (zend_get_parameters_ex (1, &id) == FAILURE)
		RETURN_FALSE;
	convert_to_long_ex (id);
	i = (*id)->value.lval -1;
	if (i < 0 || i >= MAX_ASSOC || !shared_associations[i])
		RETURN_FALSE;
	yaz_association_destroy (shared_associations[i]);
	shared_associations[i] = 0;
	RETURN_TRUE;
}
/* }}} */

/* {{{ proto int yaz_search(int 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;
	Yaz_ResultSet r;
	if (ARG_COUNT(ht) != 3)
		WRONG_PARAM_COUNT;
	if (zend_get_parameters_ex(3, &id, &type, &query) == FAILURE)
	{
		WRONG_PARAM_COUNT;
	}
	p = get_assoc (id);
	if (!p)
	{
#if PHP_YAZ_DEBUG
		php_log_err ("get_assoc failed");
#endif
		RETURN_FALSE;
	}
	convert_to_string_ex (type);
	type_str = (*type)->value.str.val;
	convert_to_string_ex (query);
	query_str = (*query)->value.str.val;
	yaz_resultset_destroy (p->resultSets);
	r = p->resultSets = yaz_resultset_mk();
	r->query = odr_malloc (r->odr, sizeof(*r->query));
	if (!strcmp (type_str, "rpn"))
	{
		r->query->which = Z_Query_type_1;
		r->query->u.type_1 = p_query_rpn (r->odr, PROTO_Z3950, query_str);
		if (!r->query->u.type_1)
		{
			yaz_resultset_destroy(r);
			p->resultSets = 0;
#if PHP_YAZ_DEBUG
			php_log_err ("bad rpn");
#endif
			RETURN_FALSE;
		}
	}
	else
	{
		yaz_resultset_destroy(r);
		p->resultSets = 0;
#if PHP_YAZ_DEBUG
		php_log_err ("bad query type");
#endif
		RETURN_FALSE;
	}
	RETURN_TRUE;
}
/* }}} */

/* {{{ proto int yaz_wait()
   Process all outstanding events. */
PHP_FUNCTION(yaz_wait)
{
	int i;
	int id;
	for (i = 0; i<MAX_ASSOC; i++)
	{
		Yaz_Association p = shared_associations[i];
		if (!p || p->order != order_associations || !p->resultSets)
			continue;
		p->action = send_search;
		if (!p->cs)
		{
			do_connect (p);
		}
		else
		{
			p->reconnect_flag = 1;
			send_search (p);
		}
	}
	while (do_event(&id))
		;
	RETURN_TRUE;
}
/* }}} */

/* {{{ proto int yaz_errno(int 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 (ARG_COUNT(ht) != 1 || zend_get_parameters_ex(1, &id) == FAILURE)
	{
		WRONG_PARAM_COUNT;
	}
	p = get_assoc (id);
	if (!p)
	{
		RETURN_LONG(0);
	}
	RETURN_LONG(p->error);
}
/* }}} */

/* {{{ proto string yaz_error(int id)
   Return last error message */
PHP_FUNCTION(yaz_error)
{
	pval **id;
	Yaz_Association p;
	if (ARG_COUNT(ht) != 1 || zend_get_parameters_ex(1, &id) == FAILURE)
	{
		WRONG_PARAM_COUNT;
	}
	p = get_assoc (id);
	if (p && p->error)
	{
		const char *msg = 0;
		if (p->error < 0)
		{
			switch (p->error)
			{
			case PHP_YAZ_ERROR_CONNECTION_LOST:
				msg = "connection lost";
				break;
			case PHP_YAZ_ERROR_DECODE:
				msg = "decoding failure";
				break;
			case PHP_YAZ_ERROR_ENCODE:
				msg = "encoding failure";
				break;
			case PHP_YAZ_ERROR_CONNECT:
				msg = "connect failed";
				break;
			case PHP_YAZ_ERROR_INIT:
				msg = "initialization failed";
				break;
			case PHP_YAZ_ERROR_TIMEOUT:
				msg = "timeout failure";
				break;
			default:
				msg = "unknown failure";
				break;
			}
		}
		else
		{
			msg = diagbib1_str (p->error);
			if (!msg)
				msg = "unknown diagnostic";
		}
		/* Not macro using because RETURN_STRING throws away const */
		return_value->value.str.len = strlen(msg);
		return_value->value.str.val =
			estrndup(msg, return_value->value.str.len);
		return_value->type = IS_STRING;
	}
}
/* }}} */

/* {{{ proto string yaz_addinfo(int id)
   Return additional info for last error (empty string if none) */
PHP_FUNCTION(yaz_addinfo)
{
	pval **id;
	Yaz_Association p;
	if (ARG_COUNT(ht) != 1 || zend_get_parameters_ex(1, &id) == FAILURE)
	{
		WRONG_PARAM_COUNT;
	}
	p = get_assoc (id);
	if (p && p->error > 0 && p->addinfo && *p->addinfo)
	{
		RETURN_STRING(p->addinfo, 1);
	}
}
/* }}} */

/* {{{ proto int yaz_hits(int id)
   Return number of hits (result count) for last search */
PHP_FUNCTION(yaz_hits)
{
	pval **id;
	Yaz_Association p;
	if (ARG_COUNT(ht) != 1 || zend_get_parameters_ex(1, &id) == FAILURE)
	{
		WRONG_PARAM_COUNT;
	}
	p = get_assoc (id);
	if (!p || !p->resultSets)
	{
		RETURN_LONG(0);
	}
	RETURN_LONG(p->resultSets->resultCount);
}
/* }}} */

Z_GenericRecord *marc_to_grs1(const char *buf, ODR o, Odr_oid *oid)
{
    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, 4);
	
    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];
		
        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 (memcmp (tag_str, "00", 2) && 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;

	if (array_init(return_value) == FAILURE)
	{
		RETURN_FALSE;
	}
	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;
		default:
		}
		zend_hash_next_index_insert (return_value->value.ht,
									 (void *) &my_zval, sizeof(zval *), NULL);
		eno[level]++;
	}
}


/* {{{ proto string yaz_record(int 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 (ARG_COUNT(ht) != 3)
		WRONG_PARAM_COUNT;
	if (zend_get_parameters_ex(3, &pval_id, &pval_pos, &pval_type) == FAILURE)
	{
		WRONG_PARAM_COUNT;
	}
	p = get_assoc (pval_id);

	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->resultSets && p->resultSets->recordList &&
		pos >= p->resultSetStartPoint &&
		pos < p->resultSetStartPoint + p->resultSets->recordList->num_records)
	{
		Z_NamePlusRecord *npr =
			p->resultSets->recordList->records[pos - p->resultSetStartPoint];
		if (npr->which == Z_NamePlusRecord_databaseRecord)
		{
			Z_External *r = (Z_External *) npr->u.databaseRecord;
			oident *ent = oid_getentbyoid(r->direct_reference);
			
			if (!strcmp (type, "syntax"))
			{
				if (ent && ent->desc)
					RETVAL_STRING(ent->desc, 1);
			}
			else if (!strcmp (type, "string"))
			{
				if (r->which == Z_External_sutrs && ent->value == VAL_SUTRS)
				{
					RETVAL_STRINGL(r->u.sutrs->buf, r->u.sutrs->len, 1);
				}
				else if (r->which == Z_External_octet)
				{
					char *buf = (char *) (r->u.octet_aligned->buf);
					int len = r->u.octet_aligned->len;
					
					switch (ent->value)
					{
					case VAL_SOIF:
					case VAL_HTML:
						break;
					case VAL_TEXT_XML:
					case VAL_APPLICATION_XML:
						break;
					default:
					}
					RETVAL_STRINGL(buf, len, 1);
				}
			}
			else if (!strcmp (type, "array"))
			{
				if (r->which == Z_External_grs1 && ent->value == VAL_GRS1)
				{
					retval_grs1 (return_value, r->u.grs1);
				}
				else if (r->which == Z_External_octet)
				{
					char *buf = (char *) (r->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, r->direct_reference);
					}
					if (rec)
						retval_grs1 (return_value, rec);
					odr_destroy (odr);
				}
			}
		}
	}
}
/* }}} */


/* {{{ proto int yaz_syntax(int id, string syntax)
   Set record syntax for retrieval */
PHP_FUNCTION(yaz_syntax)
{
	pval **pval_id, **pval_syntax;
	Yaz_Association p;
	if (ARG_COUNT(ht) != 2 || 
		zend_get_parameters_ex(2, &pval_id, &pval_syntax) == FAILURE)
	{
		WRONG_PARAM_COUNT;
	}
	p = get_assoc (pval_id);
	if (p)
	{
		convert_to_string_ex (pval_syntax);
		xfree (p->preferredRecordSyntax);
		p->preferredRecordSyntax = xstrdup ((*pval_syntax)->value.str.val);
	}
}
/* }}} */

/* {{{ proto int yaz_element(int id, string elementsetname)
   Set Element-Set-Name for retrieval */
PHP_FUNCTION(yaz_element)
{
	pval **pval_id, **pval_element;
	Yaz_Association p;
	if (ARG_COUNT(ht) != 2 || 
		zend_get_parameters_ex(2, &pval_id, &pval_element) == FAILURE)
	{
		WRONG_PARAM_COUNT;
	}
	p = get_assoc (pval_id);
	if (p)
	{
		convert_to_string_ex (pval_element);
		xfree (p->elementSetNames);
		p->elementSetNames = xstrdup ((*pval_element)->value.str.val);
	}
}
/* }}} */

/* {{{ proto int yaz_range(int 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 (ARG_COUNT(ht) != 3 || 
		zend_get_parameters_ex(3, &pval_id, &pval_start, &pval_number) ==
		FAILURE)
	{
		WRONG_PARAM_COUNT;
	}
	p = get_assoc (pval_id);
	if (p)
	{
		convert_to_long_ex (pval_start);
		p->resultSetStartPoint = (*pval_start)->value.lval;
		convert_to_long_ex (pval_number);
		p->numberOfRecordsRequested = (*pval_number)->value.lval;
	}
}
/* }}} */

PHP_MINIT_FUNCTION(yaz)
{
	int i;
#if PHP_YAZ_DEBUG
	php_log_err ("PHP_MINIT_FUNCTION yaz");
#endif
	nmem_init();
	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 PHP_YAZ_DEBUG
	php_log_err ("PHP_MSHUTDOWN_FUNCTION yaz");
#endif
	if (!shared_associations)
		return SUCCESS;
	for (i = 0; i<MAX_ASSOC; i++)
		yaz_association_destroy (shared_associations[i]);
	xfree (shared_associations);
	shared_associations = 0;
	nmem_exit();
	return SUCCESS;
}

PHP_MINFO_FUNCTION(yaz)
{
#if PHP_YAZ_DEBUG
	php_log_err ("PHP_MINFO_FUNCTION yaz");
#endif
}

PHP_RSHUTDOWN_FUNCTION(yaz)
{
#if PHP_YAZ_DEBUG
	php_log_err ("PHP_RSHUTDOWN yaz");
#endif
	return SUCCESS;
}

PHP_RINIT_FUNCTION(yaz)
{
	order_associations++;
#if PHP_YAZ_DEBUG
	php_log_err ("PHP_RINIT yaz");
#endif
	return SUCCESS;
}

zend_module_entry yaz_module_entry = {
	"YAZ",
	yaz_functions,
	PHP_MINIT(yaz),
	PHP_MSHUTDOWN(yaz),
	PHP_RINIT(yaz),
	PHP_RSHUTDOWN(yaz),
	PHP_MINFO(yaz),
	STANDARD_MODULE_PROPERTIES
};

#if COMPILE_DL
DLEXPORT zend_module_entry *get_module(void) { return &yaz_module_entry; }
#endif


#endif
/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 */

Index: php4/ext/yaz/php_yaz.h
+++ php4/ext/yaz/php_yaz.h
/* 
   +----------------------------------------------------------------------+
   | PHP version 4.0                                                      |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group                   |
   +----------------------------------------------------------------------+
   | This source file is subject to version 2.02 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
   | available at through the world-wide-web at                           |
   | http://www.php.net/license/2_02.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          |
   | [email protected] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Authors: Adam Dickmeiss <[email protected]>                          |
   +----------------------------------------------------------------------+
 */

/* $Id: php_yaz.h,v 1.1 2000/05/25 21:54:34 dickmeiss Exp $ */

#ifndef PHP_YAZ_H
#define PHP_YAZ_H

#if HAVE_YAZ

extern zend_module_entry yaz_module_entry;
#define yaz_module_ptr &yaz_module_entry

PHP_FUNCTION(yaz_connect);
PHP_FUNCTION(yaz_close);
PHP_FUNCTION(yaz_search);
PHP_FUNCTION(yaz_wait);
PHP_FUNCTION(yaz_errno);
PHP_FUNCTION(yaz_error);
PHP_FUNCTION(yaz_addinfo);
PHP_FUNCTION(yaz_hits);
PHP_FUNCTION(yaz_record);
PHP_FUNCTION(yaz_syntax);
PHP_FUNCTION(yaz_element);
PHP_FUNCTION(yaz_range);

#else

#define yaz_module_ptr NULL
#endif

#define phpext_yaz_ptr yaz_module_ptr
#endif

Index: php4/ext/yaz/setup.stub
+++ php4/ext/yaz/setup.stub
# $Source: /local/repository/php4/ext/yaz/setup.stub,v $
# $Id: setup.stub,v 1.1 2000/05/25 21:54:34 dickmeiss Exp $

define_option with-yaz 'YAZ support?' yesnodir \
    'no /usr/bin YAZ base install' \
'     Whether to build with YAZ (Z39.50 protocol package)\n
     support.\n
     More info about YAZ can be found at http://www.indexdata.dk/yaz/'
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.