* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* $Id: zoom.h,v 1.41 2007-01-03 08:42:14 adam Exp $ */
+/* $Id: zoom.h,v 1.42 2007-01-09 13:56:48 adam Exp $ */
/**
* \file zoom.h
ZOOM_API(void)
ZOOM_options_set_int(ZOOM_options opt, const char *name, int value);
-/* ----------------------------------------------------------- */
-/* events */
-/* poll for events on a number of connections. Returns positive
- integer if event occurred ; zero if none occurred and no more
- events are pending. The positive integer specifies the
- connection for which the event occurred. */
+/** \brief select/poll socket mask: read */
+#define ZOOM_SELECT_READ 1
+/** \brief select/poll socket mask: write */
+#define ZOOM_SELECT_WRITE 2
+/** \brief select/poll socket mask: except */
+#define ZOOM_SELECT_EXCEPT 4
+
+/** \brief wait for events on connection(s) (BLOCKING)
+ \param no number of connections (size of cs)
+ \param cs connection array
+ \retval 0 no event was fired
+ \retval >0 event was fired for connection at (retval-1)
+
+ blocking poll for events on a number of connections. Returns positive
+ integer if event occurred ; zero if none occurred and no more
+ events are pending. The positive integer specifies the
+ connection for which the event occurred.
+*/
ZOOM_API(int)
ZOOM_event (int no, ZOOM_connection *cs);
+
+/** \brief determines if connection is idle (no active or pending work)
+ \param c connection
+ \retval 1 is idle
+ \retval 0 is non-idle (active)
+*/
+ZOOM_API(int)
+ZOOM_connection_is_idle(ZOOM_connection c);
+
+
+/** \brief processes one event for one of connections given
+ \param no number of connections (size of cs)
+ \param cs connection array
+ \retval 0 no event was processed
+ \retval >0 event was processed for connection at (retval-1)
+
+ This function attemps to deal with outstandings events in
+ a non-blocking fashion. If no events was processed (return value of 0),
+ then the system should attempt to deal with sockets in blocking mode
+ using socket select/poll which means calling the following functions:
+ ZOOM_connection_get_socket, ZOOM_connection_get_mask,
+ ZOOM_connection_get_timeout.
+*/
+ZOOM_API(int)
+ ZOOM_process_event(int no, ZOOM_connection *cs);
+
+
+/** \brief get socket fd for ZOOM connection
+ \param c connection
+ \retval -1 no socket assigned for connection
+ \retval >=0 socket for connection
+
+ Use this function when preparing for socket/poll and
+ in conjunction with ZOOM_connection_get_mask.
+*/
+ZOOM_API(int)
+ ZOOM_connection_get_socket(ZOOM_connection c);
+
+
+/** \brief get socket mask for connection
+ \param c connection
+ \returns mask for connection (possibly 0)
+
+ Use this function when preparing for socket select/poll and
+ in conjunction with ZOOM_connection_get_socket.
+*/
ZOOM_API(int)
-ZOOM_connection_is_idle(ZOOM_connection cs);
+ ZOOM_connection_get_mask(ZOOM_connection c);
+
+
+/** \brief set socket mask for connection (DO NOT call outside zoom) */
+ZOOM_API(int)
+ ZOOM_connection_set_mask(ZOOM_connection c, int mask);
+
+
+/** \brief get timeout in seconds for ZOOM connection
+ \param c connection
+ \returns timeout value in seconds
+
+ Use this function when preparing for socket/poll and
+ in conjunction with ZOOM_connection_get_socket.
+*/
+ZOOM_API(int)
+ ZOOM_connection_get_timeout(ZOOM_connection c);
+
+
+/** \brief fire socket event timeout
+ \param c connection
+ \retval 0 event was fired OK
+ \retval -1 event was not fired
+
+ Call this function when a timeout occurs - for example in the
+ case of select(2) returning 0.
+*/
+ZOOM_API(int)
+ ZOOM_connection_fire_event_timeout(ZOOM_connection c);
+
+
+/** \brief fire socket event activity (read,write,except)
+ \param c connection
+ \param mask or'ed mask of ZOOM_SELECT_.. values
+ \retval 0 event was fired OK
+ \retval -1 event was not fired
+*/
+ZOOM_API(int)
+ ZOOM_connection_fire_event_socket(ZOOM_connection c, int mask);
+
+
ZOOM_END_CDECL
/*
* Copyright (C) 1995-2007, Index Data ApS
* See the file LICENSE for details.
*
- * $Id: zoom-c.c,v 1.104 2007-01-03 08:42:15 adam Exp $
+ * $Id: zoom-c.c,v 1.105 2007-01-09 13:56:48 adam Exp $
*/
/**
* \file zoom-c.c
#include <yaz/cql.h>
#include <yaz/ccl.h>
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#if HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#if HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#endif
-#if HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#ifdef WIN32
-#if FD_SETSIZE < 512
-#define FD_SETSIZE 512
-#endif
-#include <winsock.h>
-#endif
-
static int log_api = 0;
static int log_details = 0;
c->proto = PROTO_Z3950;
c->cs = 0;
- c->mask = 0;
+ ZOOM_connection_set_mask(c, 0);
c->reconnect_ok = 0;
c->state = STATE_IDLE;
c->addinfo = 0;
if (c->cs)
cs_close(c->cs);
c->cs = 0;
- c->mask = 0;
+ ZOOM_connection_set_mask(c, 0);
c->state = STATE_IDLE;
}
/* no init request for SRW .. */
assert(c->tasks->which == ZOOM_TASK_CONNECT);
ZOOM_connection_remove_task(c);
- c->mask = 0;
+ ZOOM_connection_set_mask(c, 0);
ZOOM_connection_exec_task(c);
}
c->state = STATE_ESTABLISHED;
}
else if (ret > 0)
{
- c->state = STATE_CONNECTING;
- c->mask = ZOOM_SELECT_EXCEPT;
+ int mask = ZOOM_SELECT_EXCEPT;
if (c->cs->io_pending & CS_WANT_WRITE)
- c->mask += ZOOM_SELECT_WRITE;
+ mask += ZOOM_SELECT_WRITE;
if (c->cs->io_pending & CS_WANT_READ)
- c->mask += ZOOM_SELECT_READ;
+ mask += ZOOM_SELECT_READ;
+ ZOOM_connection_set_mask(c, mask);
+ c->state = STATE_CONNECTING;
return zoom_pending;
}
}
return zoom_complete;
}
-int z3950_connection_socket(ZOOM_connection c)
-{
- if (c->cs)
- return cs_fileno(c->cs);
- return -1;
-}
-
-int z3950_connection_mask(ZOOM_connection c)
-{
- if (c->cs)
- return c->mask;
- return 0;
-}
-
static void otherInfo_attach(ZOOM_connection c, Z_APDU *a, ODR out)
{
int i;
odr_prepend(c->odr_out, "ZOOM-C",
ireq->implementationName));
- version = odr_strdup(c->odr_out, "$Revision: 1.104 $");
+ version = odr_strdup(c->odr_out, "$Revision: 1.105 $");
if (strlen(version) > 10) /* check for unexpanded CVS strings */
version[strlen(version)-2] = '\0';
ireq->implementationVersion =
{
Z_InitResponse *initrs;
- c->mask = 0;
+ ZOOM_connection_set_mask(c, 0);
yaz_log(log_details, "%p recv_apdu apdu->which=%d", c, apdu->which);
switch(apdu->which)
{
"Content-Type");
const char *connection_head = z_HTTP_header_lookup(hres->headers,
"Connection");
- c->mask = 0;
+ ZOOM_connection_set_mask(c, 0);
yaz_log(log_details, "%p handle_http", c);
if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
}
else if (r == 1)
{
- c->mask = ZOOM_SELECT_EXCEPT;
+ int mask = ZOOM_SELECT_EXCEPT;
if (c->cs->io_pending & CS_WANT_WRITE)
- c->mask += ZOOM_SELECT_WRITE;
+ mask += ZOOM_SELECT_WRITE;
if (c->cs->io_pending & CS_WANT_READ)
- c->mask += ZOOM_SELECT_READ;
+ mask += ZOOM_SELECT_READ;
+ ZOOM_connection_set_mask(c, mask);
yaz_log(log_details, "%p do_write_ex write incomplete mask=%d",
c, c->mask);
}
else
{
- c->mask = ZOOM_SELECT_READ|ZOOM_SELECT_EXCEPT;
+ ZOOM_connection_set_mask(c, ZOOM_SELECT_READ|ZOOM_SELECT_EXCEPT);
yaz_log(log_details, "%p do_write_ex write complete mask=%d",
c, c->mask);
}
"cs_rcvconnect returned %d", c, ret);
if (ret == 1)
{
- c->mask = ZOOM_SELECT_EXCEPT;
+ int mask = ZOOM_SELECT_EXCEPT;
if (c->cs->io_pending & CS_WANT_WRITE)
- c->mask += ZOOM_SELECT_WRITE;
+ mask += ZOOM_SELECT_WRITE;
if (c->cs->io_pending & CS_WANT_READ)
- c->mask += ZOOM_SELECT_READ;
+ mask += ZOOM_SELECT_READ;
+ ZOOM_connection_set_mask(c, mask);
}
else if (ret == 0)
{
/* no init request for SRW .. */
assert(c->tasks->which == ZOOM_TASK_CONNECT);
ZOOM_connection_remove_task(c);
- c->mask = 0;
+ ZOOM_connection_set_mask(c, 0);
ZOOM_connection_exec_task(c);
}
c->state = STATE_ESTABLISHED;
return cs->last_event;
}
-ZOOM_API(int)
- ZOOM_event(int no, ZOOM_connection *cs)
-{
- int timeout = 30; /* default timeout in seconds */
- int timeout_set = 0; /* whether it was overriden at all */
-#if HAVE_SYS_POLL_H
- struct pollfd pollfds[1024];
- ZOOM_connection poll_cs[1024];
-#else
- struct timeval tv;
- fd_set input, output, except;
-#endif
- int i, r, nfds;
- int max_fd = 0;
-
- yaz_log(log_details, "ZOOM_event(no=%d,cs=%p)", no, cs);
-
- for (i = 0; i<no; i++)
- {
- ZOOM_connection c = cs[i];
- ZOOM_Event event;
-
-#if 0
- if (c)
- ZOOM_connection_show_tasks(c);
-#endif
-
- if (c && (event = ZOOM_connection_get_event(c)))
- {
- ZOOM_Event_destroy(event);
- return i+1;
- }
- }
- for (i = 0; i<no; i++)
- {
- ZOOM_connection c = cs[i];
- if (c)
- {
- ZOOM_Event event;
- ZOOM_connection_exec_task(c);
- if ((event = ZOOM_connection_get_event(c)))
- {
- ZOOM_Event_destroy(event);
- return i+1;
- }
- }
- }
-#if HAVE_SYS_POLL_H
-
-#else
- FD_ZERO(&input);
- FD_ZERO(&output);
- FD_ZERO(&except);
-#endif
- nfds = 0;
- for (i = 0; i<no; i++)
- {
- ZOOM_connection c = cs[i];
- int fd, mask;
- int this_timeout;
-
- if (!c)
- continue;
- fd = z3950_connection_socket(c);
- mask = z3950_connection_mask(c);
-
- if (fd == -1)
- continue;
- if (max_fd < fd)
- max_fd = fd;
-
- /* -1 is used for indefinite timeout (no timeout), so -2 here. */
- this_timeout = ZOOM_options_get_int(c->options, "timeout", -2);
- if (this_timeout != -2)
- {
- /* ensure the minimum timeout is used */
- if (!timeout_set)
- timeout = this_timeout;
- else if (this_timeout != -1 && this_timeout < timeout)
- timeout = this_timeout;
- timeout_set = 1;
- }
-#if HAVE_SYS_POLL_H
- if (mask)
- {
- short poll_events = 0;
-
- if (mask & ZOOM_SELECT_READ)
- poll_events += POLLIN;
- if (mask & ZOOM_SELECT_WRITE)
- poll_events += POLLOUT;
- if (mask & ZOOM_SELECT_EXCEPT)
- poll_events += POLLERR;
- pollfds[nfds].fd = fd;
- pollfds[nfds].events = poll_events;
- pollfds[nfds].revents = 0;
- poll_cs[nfds] = c;
- nfds++;
- }
-#else
- if (mask & ZOOM_SELECT_READ)
- {
- FD_SET(fd, &input);
- nfds++;
- }
- if (mask & ZOOM_SELECT_WRITE)
- {
- FD_SET(fd, &output);
- nfds++;
- }
- if (mask & ZOOM_SELECT_EXCEPT)
- {
- FD_SET(fd, &except);
- nfds++;
- }
-#endif
- }
- if (!nfds)
- return 0;
-
-#if HAVE_SYS_POLL_H
- while ((r = poll(pollfds, nfds,
- (timeout == -1 ? -1 : timeout * 1000))) < 0
- && errno == EINTR)
- {
- ;
- }
- if (r < 0)
- yaz_log(YLOG_WARN|YLOG_ERRNO, "ZOOM_event: poll");
- for (i = 0; i<nfds; i++)
- {
- ZOOM_connection c = poll_cs[i];
- if (r && c->mask)
- {
- int mask = 0;
- if (pollfds[i].revents & POLLIN)
- mask += ZOOM_SELECT_READ;
- if (pollfds[i].revents & POLLOUT)
- mask += ZOOM_SELECT_WRITE;
- if (pollfds[i].revents & POLLERR)
- mask += ZOOM_SELECT_EXCEPT;
- if (mask)
- ZOOM_connection_do_io(c, mask);
- }
- else if (r == 0 && c->mask)
- {
- ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT);
- /* timeout and this connection was waiting */
- set_ZOOM_error(c, ZOOM_ERROR_TIMEOUT, 0);
- do_close(c);
- ZOOM_connection_put_event(c, event);
- }
- }
-#else
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
-
- while ((r = select(max_fd+1, &input, &output, &except,
- (timeout == -1 ? 0 : &tv))) < 0 && errno == EINTR)
- {
- ;
- }
- if (r < 0)
- yaz_log(YLOG_WARN|YLOG_ERRNO, "ZOOM_event: select");
-
- r = select(max_fd+1, &input, &output, &except, (timeout == -1 ? 0 : &tv));
- for (i = 0; i<no; i++)
- {
- ZOOM_connection c = cs[i];
- int fd, mask;
-
- if (!c)
- continue;
- fd = z3950_connection_socket(c);
- mask = 0;
- if (r && c->mask)
- {
- /* no timeout and real socket */
- if (FD_ISSET(fd, &input))
- mask += ZOOM_SELECT_READ;
- if (FD_ISSET(fd, &output))
- mask += ZOOM_SELECT_WRITE;
- if (FD_ISSET(fd, &except))
- mask += ZOOM_SELECT_EXCEPT;
- if (mask)
- ZOOM_connection_do_io(c, mask);
- }
- if (r == 0 && c->mask)
- {
- ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT);
- /* timeout and this connection was waiting */
- set_ZOOM_error(c, ZOOM_ERROR_TIMEOUT, 0);
- do_close(c);
- ZOOM_connection_put_event(c, event);
- }
- }
-#endif
- for (i = 0; i<no; i++)
- {
- ZOOM_connection c = cs[i];
- ZOOM_Event event;
- if (c && (event = ZOOM_connection_get_event(c)))
- {
- ZOOM_Event_destroy(event);
- return i+1;
- }
- }
- return 0;
-}
-
/*
* Returns an xmalloc()d string containing RPN that corresponds to the
return xstrdup(pqfbuf);
}
+ZOOM_API(int) ZOOM_connection_fire_event_timeout(ZOOM_connection c)
+{
+ if (c->mask)
+ {
+ ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT);
+ /* timeout and this connection was waiting */
+ set_ZOOM_error(c, ZOOM_ERROR_TIMEOUT, 0);
+ do_close(c);
+ ZOOM_connection_put_event(c, event);
+ }
+ return 0;
+}
+
+ZOOM_API(int)
+ ZOOM_process_event(int no, ZOOM_connection *cs)
+{
+ int i;
+
+ yaz_log(log_details, "ZOOM_event_poll(no=%d,cs=%p)", no, cs);
+
+ for (i = 0; i<no; i++)
+ {
+ ZOOM_connection c = cs[i];
+ ZOOM_Event event;
+
+#if 0
+ if (c)
+ ZOOM_connection_show_tasks(c);
+#endif
+
+ if (c && (event = ZOOM_connection_get_event(c)))
+ {
+ ZOOM_Event_destroy(event);
+ return i+1;
+ }
+ }
+ for (i = 0; i<no; i++)
+ {
+ ZOOM_connection c = cs[i];
+ if (c)
+ {
+ ZOOM_Event event;
+ ZOOM_connection_exec_task(c);
+ if ((event = ZOOM_connection_get_event(c)))
+ {
+ ZOOM_Event_destroy(event);
+ return i+1;
+ }
+ }
+ }
+ return 0;
+}
+
+ZOOM_API(int) ZOOM_connection_fire_event_socket(ZOOM_connection c, int mask)
+{
+ if (c->mask && mask)
+ ZOOM_connection_do_io(c, mask);
+ return 0;
+}
+
+ZOOM_API(int) ZOOM_connection_get_socket(ZOOM_connection c)
+{
+ if (c->cs)
+ return cs_fileno(c->cs);
+ return -1;
+}
+
+ZOOM_API(int) ZOOM_connection_set_mask(ZOOM_connection c, int mask)
+{
+ c->mask = mask;
+ if (!c->cs)
+ return -1;
+ return 0;
+}
+
+ZOOM_API(int) ZOOM_connection_get_mask(ZOOM_connection c)
+{
+ if (c->cs)
+ return c->mask;
+ return 0;
+}
+
+ZOOM_API(int) ZOOM_connection_get_timeout(ZOOM_connection c)
+{
+ return ZOOM_options_get_int(c->options, "timeout", 30);
+}
+
/*
* Local variables:
* c-basic-offset: 4
--- /dev/null
+/*
+ * Copyright (C) 1995-2007, Index Data ApS
+ * See the file LICENSE for details.
+ *
+ * $Id: zoom-socket.c,v 1.1 2007-01-09 13:56:48 adam Exp $
+ */
+/**
+ * \file zoom-socket.c
+ * \brief Implements ZOOM C socket interface.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <yaz/zoom.h>
+
+#include <yaz/log.h>
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef WIN32
+#if FD_SETSIZE < 512
+#define FD_SETSIZE 512
+#endif
+#include <winsock.h>
+#endif
+
+
+ZOOM_API(int)
+ ZOOM_event_sys_select(int no, ZOOM_connection *cs)
+{
+ struct timeval tv;
+ fd_set input, output, except;
+ int i, r;
+ int max_fd = 0;
+ int timeout = 30;
+ int nfds = 0;
+
+ FD_ZERO(&input);
+ FD_ZERO(&output);
+ FD_ZERO(&except);
+
+ for (i = 0; i<no; i++)
+ {
+ ZOOM_connection c = cs[i];
+ int fd, mask;
+
+ if (!c)
+ continue;
+ fd = ZOOM_connection_get_socket(c);
+ mask = ZOOM_connection_get_mask(c);
+ timeout = ZOOM_connection_get_timeout(c);
+
+ if (fd == -1)
+ continue;
+ if (max_fd < fd)
+ max_fd = fd;
+
+ if (mask & ZOOM_SELECT_READ)
+ FD_SET(fd, &input);
+ if (mask & ZOOM_SELECT_WRITE)
+ FD_SET(fd, &output);
+ if (mask & ZOOM_SELECT_EXCEPT)
+ FD_SET(fd, &except);
+ if (mask)
+ nfds++;
+ }
+ if (nfds == 0)
+ return 0;
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ while ((r = select(max_fd+1, &input, &output, &except,
+ (timeout == -1 ? 0 : &tv))) < 0 && errno == EINTR)
+ {
+ ;
+ }
+ if (r < 0)
+ {
+ yaz_log(YLOG_WARN|YLOG_ERRNO, "ZOOM_event_sys_select");
+ return r;
+ }
+
+ for (i = 0; i<no; i++)
+ {
+ ZOOM_connection c = cs[i];
+ int fd, mask;
+
+ if (!c)
+ continue;
+ fd = ZOOM_connection_get_socket(c);
+ mask = 0;
+ if (r)
+ {
+ /* no timeout and real socket */
+ if (FD_ISSET(fd, &input))
+ mask += ZOOM_SELECT_READ;
+ if (FD_ISSET(fd, &output))
+ mask += ZOOM_SELECT_WRITE;
+ if (FD_ISSET(fd, &except))
+ mask += ZOOM_SELECT_EXCEPT;
+ if (mask)
+ ZOOM_connection_fire_event_socket(c, mask);
+ }
+ else
+ ZOOM_connection_fire_event_timeout(c);
+ }
+ return r;
+}
+
+#if HAVE_SYS_POLL_H
+ZOOM_API(int)
+ ZOOM_event_sys_poll(int no, ZOOM_connection *cs)
+{
+ struct pollfd pollfds[1024];
+ ZOOM_connection poll_cs[1024];
+ int i, r;
+ int nfds = 0;
+ int timeout = 30;
+
+ for (i = 0; i<no; i++)
+ {
+ ZOOM_connection c = cs[i];
+ int fd, mask;
+
+ if (!c)
+ continue;
+ fd = ZOOM_connection_get_socket(c);
+ mask = ZOOM_connection_get_mask(c);
+ timeout = ZOOM_connection_get_timeout(c);
+
+ if (fd == -1)
+ continue;
+ if (mask)
+ {
+ short poll_events = 0;
+
+ if (mask & ZOOM_SELECT_READ)
+ poll_events += POLLIN;
+ if (mask & ZOOM_SELECT_WRITE)
+ poll_events += POLLOUT;
+ if (mask & ZOOM_SELECT_EXCEPT)
+ poll_events += POLLERR;
+ pollfds[nfds].fd = fd;
+ pollfds[nfds].events = poll_events;
+ pollfds[nfds].revents = 0;
+ poll_cs[nfds] = c;
+ nfds++;
+ }
+ }
+ if (nfds == 0)
+ return 0;
+ while ((r = poll(pollfds, nfds,
+ (timeout == -1 ? -1 : timeout * 1000))) < 0
+ && errno == EINTR)
+ {
+ ;
+ }
+ if (r < 0)
+ {
+ yaz_log(YLOG_WARN|YLOG_ERRNO, "ZOOM_event_sys_poll");
+ return r;
+ }
+ for (i = 0; i<nfds; i++)
+ {
+ ZOOM_connection c = poll_cs[i];
+ if (r)
+ {
+ int mask = 0;
+ if (pollfds[i].revents & POLLIN)
+ mask += ZOOM_SELECT_READ;
+ if (pollfds[i].revents & POLLOUT)
+ mask += ZOOM_SELECT_WRITE;
+ if (pollfds[i].revents & POLLERR)
+ mask += ZOOM_SELECT_EXCEPT;
+ ZOOM_connection_fire_event_socket(c, mask);
+ }
+ else
+ ZOOM_connection_fire_event_timeout(c);
+ }
+ return r;
+}
+#endif
+
+ZOOM_API(int)
+ ZOOM_event(int no, ZOOM_connection *cs)
+{
+ int r;
+
+ r = ZOOM_process_event(no, cs);
+ if (r)
+ return r;
+#if HAVE_SYS_POLL_H
+ ZOOM_event_sys_poll(no, cs);
+#else
+ ZOOM_event_sys_select(no, cs);
+#endif
+ return ZOOM_process_event(no, cs);
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+