Annotation of embedaddon/php/ext/interbase/ibase_events.c, revision 1.1.1.4
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.4 ! misho 5: | Copyright (c) 1997-2014 The PHP Group |
1.1 misho 6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Authors: Ard Biesheuvel <a.k.biesheuvel@its.tudelft.nl> |
16: +----------------------------------------------------------------------+
17: */
18:
19: #ifdef HAVE_CONFIG_H
20: #include "config.h"
21: #endif
22:
23: #include "php.h"
24:
25: #if HAVE_IBASE
26:
27: #include "php_interbase.h"
28: #include "php_ibase_includes.h"
29:
30: static int le_event;
31:
32: static void _php_ibase_event_free(char *event_buf, char *result_buf) /* {{{ */
33: {
34: isc_free(event_buf);
35: isc_free(result_buf);
36: }
37: /* }}} */
38:
39: void _php_ibase_free_event(ibase_event *event TSRMLS_DC) /* {{{ */
40: {
41: unsigned short i;
42:
43: event->state = DEAD;
44:
45: if (event->link != NULL) {
46: ibase_event **node;
47:
48: if (event->link->handle != NULL &&
49: isc_cancel_events(IB_STATUS, &event->link->handle, &event->event_id)) {
50: _php_ibase_error(TSRMLS_C);
51: }
52:
53: /* delete this event from the link struct */
54: for (node = &event->link->event_head; *node != event; node = &(*node)->event_next);
55: *node = event->event_next;
56: }
57:
58: if (event->callback) {
59: zval_dtor(event->callback);
60: FREE_ZVAL(event->callback);
61: event->callback = NULL;
62:
63: _php_ibase_event_free(event->event_buffer,event->result_buffer);
64:
65: for (i = 0; i < event->event_count; ++i) {
66: efree(event->events[i]);
67: }
68: efree(event->events);
69: }
70: }
71: /* }}} */
72:
73: static void _php_ibase_free_event_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
74: {
75: ibase_event *e = (ibase_event *) rsrc->ptr;
76:
77: _php_ibase_free_event(e TSRMLS_CC);
78:
79: efree(e);
80: }
81: /* }}} */
82:
83: void php_ibase_events_minit(INIT_FUNC_ARGS) /* {{{ */
84: {
85: le_event = zend_register_list_destructors_ex(_php_ibase_free_event_rsrc, NULL,
86: "interbase event", module_number);
87: }
88: /* }}} */
89:
90: static void _php_ibase_event_block(ibase_db_link *ib_link, unsigned short count, /* {{{ */
91: char **events, unsigned short *l, char **event_buf, char **result_buf)
92: {
93: ISC_STATUS dummy_result[20];
94: unsigned long dummy_count[15];
95:
96: /**
97: * Unfortunately, there's no clean and portable way in C to pass arguments to
98: * a variadic function if you don't know the number of arguments at compile time.
99: * (And even if there were a way, the Interbase API doesn't provide a version of
100: * this function that takes a va_list as an argument)
101: *
102: * In this case, the number of arguments is limited to 18 by the underlying API,
103: * so we can work around it.
104: */
105:
106: *l = (unsigned short) isc_event_block(event_buf, result_buf, count, events[0],
107: events[1], events[2], events[3], events[4], events[5], events[6], events[7],
108: events[8], events[9], events[10], events[11], events[12], events[13], events[14]);
109:
110: /**
111: * Currently, this is the only way to correctly initialize an event buffer.
112: * This is clearly something that should be fixed, cause the semantics of
113: * isc_wait_for_event() indicate that it blocks until an event occurs.
114: * If the Firebird people ever fix this, these lines should be removed,
115: * otherwise, events will have to fire twice before ibase_wait_event() returns.
116: */
117:
118: isc_wait_for_event(dummy_result, &ib_link->handle, *l, *event_buf, *result_buf);
119: isc_event_counts(dummy_count, *l, *event_buf, *result_buf);
120: }
121: /* }}} */
122:
123: /* {{{ proto string ibase_wait_event([resource link_identifier,] string event [, string event [, ...]])
124: Waits for any one of the passed Interbase events to be posted by the database, and returns its name */
125: PHP_FUNCTION(ibase_wait_event)
126: {
127: zval ***args;
128: ibase_db_link *ib_link;
129: int num_args;
130: char *event_buffer, *result_buffer, *events[15];
131: unsigned short i = 0, event_count = 0, buffer_size;
132: unsigned long occurred_event[15];
133:
134: RESET_ERRMSG;
135:
136: /* no more than 15 events */
137: if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 16) {
138: WRONG_PARAM_COUNT;
139: }
140:
141: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
142: return;
143: }
144:
145: if (Z_TYPE_PP(args[0]) == IS_RESOURCE) {
146: if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, args[0], -1, "InterBase link", le_link, le_plink)) {
147: efree(args);
148: RETURN_FALSE;
149: }
150: i = 1;
151: } else {
152: if (ZEND_NUM_ARGS() > 15) {
153: efree(args);
154: WRONG_PARAM_COUNT;
155: }
156: if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", le_link, le_plink)) {
157: efree(args);
158: RETURN_FALSE;
159: }
160: }
161:
162: for (; i < ZEND_NUM_ARGS(); ++i) {
163: convert_to_string_ex(args[i]);
164: events[event_count++] = Z_STRVAL_PP(args[i]);
165: }
166:
167: /* fills the required data structure with information about the events */
168: _php_ibase_event_block(ib_link, event_count, events, &buffer_size, &event_buffer, &result_buffer);
169:
170: /* now block until an event occurs */
171: if (isc_wait_for_event(IB_STATUS, &ib_link->handle, buffer_size, event_buffer, result_buffer)) {
172: _php_ibase_error(TSRMLS_C);
173: _php_ibase_event_free(event_buffer,result_buffer);
174: efree(args);
175: RETURN_FALSE;
176: }
177:
178: /* find out which event occurred */
179: isc_event_counts(occurred_event, buffer_size, event_buffer, result_buffer);
180: for (i = 0; i < event_count; ++i) {
181: if (occurred_event[i]) {
182: char *result = estrdup(events[i]);
183: _php_ibase_event_free(event_buffer,result_buffer);
184: efree(args);
185: RETURN_STRING(result,0);
186: }
187: }
188:
189: /* If we reach this line, isc_wait_for_event() did return, but we don't know
190: which event fired. */
191: _php_ibase_event_free(event_buffer,result_buffer);
192: efree(args);
193: RETURN_FALSE;
194: }
195: /* }}} */
196:
197: static isc_callback _php_ibase_callback(ibase_event *event, /* {{{ */
198: unsigned short buffer_size, char *result_buf)
199: {
200: /* this function is called asynchronously by the Interbase client library. */
201: TSRMLS_FETCH_FROM_CTX(event->thread_ctx);
202:
203: /**
204: * The callback function is called when the event is first registered and when the event
205: * is cancelled. I consider this is a bug. By clearing event->callback first and setting
206: * it to -1 later, we make sure nothing happens if no event was actually posted.
207: */
208: switch (event->state) {
209: unsigned short i;
210: unsigned long occurred_event[15];
211: zval event_name, link_id, return_value, *args[2];
212:
213: default: /* == DEAD */
214: break;
215: case ACTIVE:
216: args[0] = &event_name;
217: args[1] = &link_id;
218:
219: /* copy the updated results into the result buffer */
220: memcpy(event->result_buffer, result_buf, buffer_size);
221:
222: INIT_ZVAL(event_name);
223: INIT_ZVAL(link_id);
224: ZVAL_RESOURCE(&link_id, event->link_res_id);
225:
226: /* find out which event occurred */
227: isc_event_counts(occurred_event, buffer_size, event->event_buffer, event->result_buffer);
228: for (i = 0; i < event->event_count; ++i) {
229: if (occurred_event[i]) {
230: ZVAL_STRING(&event_name,event->events[i],0);
231: break;
232: }
233: }
234:
235: /* call the callback provided by the user */
236: if (SUCCESS != call_user_function(EG(function_table), NULL,
237: event->callback, &return_value, 2, args TSRMLS_CC)) {
238: _php_ibase_module_error("Error calling callback %s" TSRMLS_CC, Z_STRVAL_P(event->callback));
239: break;
240: }
241:
242: if (Z_TYPE(return_value) == IS_BOOL && !Z_BVAL(return_value)) {
243: event->state = DEAD;
244: break;
245: }
246: case NEW:
247: /* re-register the event */
248: if (isc_que_events(IB_STATUS, &event->link->handle, &event->event_id, buffer_size,
249: event->event_buffer,(isc_callback)_php_ibase_callback, (void *)event)) {
250:
251: _php_ibase_error(TSRMLS_C);
252: }
253: event->state = ACTIVE;
254: }
255: return 0;
256: }
257: /* }}} */
258:
259: /* {{{ proto resource ibase_set_event_handler([resource link_identifier,] callback handler, string event [, string event [, ...]])
260: Register the callback for handling each of the named events */
261: PHP_FUNCTION(ibase_set_event_handler)
262: {
263: /**
264: * The callback passed to this function should take an event name (string) and a
265: * link resource id (int) as arguments. The value returned from the function is
266: * used to determine if the event handler should remain set.
267: */
268: char *cb_name;
269: zval ***args, **cb_arg;
270: ibase_db_link *ib_link;
271: ibase_event *event;
272: unsigned short i = 1, buffer_size;
273: int link_res_id, num_args;
274:
275: RESET_ERRMSG;
276:
277: /* Minimum and maximum number of arguments allowed */
278: if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 17) {
279: WRONG_PARAM_COUNT;
280: }
281:
282: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
283: return;
284: }
285:
286: /* get a working link */
287: if (Z_TYPE_PP(args[0]) != IS_STRING) {
288: /* resource, callback, event_1 [, ... event_15]
289: * No more than 15 events
290: */
291: if (ZEND_NUM_ARGS() < 3 || ZEND_NUM_ARGS() > 17) {
292: efree(args);
293: WRONG_PARAM_COUNT;
294: }
295:
296: cb_arg = args[1];
297: i = 2;
298:
299: if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, args[0], -1, "InterBase link", le_link, le_plink)) {
300: efree(args);
301: RETURN_FALSE;
302: }
303:
304: convert_to_long_ex(args[0]);
305: link_res_id = Z_LVAL_PP(args[0]);
306:
307: } else {
308: /* callback, event_1 [, ... event_15]
309: * No more than 15 events
310: */
311: if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 16) {
312: efree(args);
313: WRONG_PARAM_COUNT;
314: }
315:
316: cb_arg = args[0];
317:
318: if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", le_link, le_plink)) {
319: efree(args);
320: RETURN_FALSE;
321: }
322: link_res_id = IBG(default_link);
323: }
324:
325: /* get the callback */
326: if (!zend_is_callable(*cb_arg, 0, &cb_name TSRMLS_CC)) {
327: _php_ibase_module_error("Callback argument %s is not a callable function" TSRMLS_CC, cb_name);
328: efree(cb_name);
329: efree(args);
330: RETURN_FALSE;
331: }
332: efree(cb_name);
333:
334: /* allocate the event resource */
335: event = (ibase_event *) safe_emalloc(sizeof(ibase_event), 1, 0);
336: TSRMLS_SET_CTX(event->thread_ctx);
337: event->link_res_id = link_res_id;
338: event->link = ib_link;
339: event->event_count = 0;
340: event->state = NEW;
341: event->events = (char **) safe_emalloc(sizeof(char *),ZEND_NUM_ARGS()-i,0);
342:
343: ALLOC_ZVAL(event->callback);
344: *event->callback = **cb_arg;
345: INIT_PZVAL(event->callback);
346: zval_copy_ctor(event->callback);
347:
348: for (; i < ZEND_NUM_ARGS(); ++i) {
349: convert_to_string_ex(args[i]);
350: event->events[event->event_count++] = estrdup(Z_STRVAL_PP(args[i]));
351: }
352:
353: /* fills the required data structure with information about the events */
354: _php_ibase_event_block(ib_link, event->event_count, event->events,
355: &buffer_size, &event->event_buffer, &event->result_buffer);
356:
357: /* now register the events with the Interbase API */
358: if (isc_que_events(IB_STATUS, &ib_link->handle, &event->event_id, buffer_size,
359: event->event_buffer,(isc_callback)_php_ibase_callback, (void *)event)) {
360:
361: _php_ibase_error(TSRMLS_C);
362: efree(event);
363: efree(args);
364: RETURN_FALSE;
365: }
366:
367: event->event_next = ib_link->event_head;
368: ib_link->event_head = event;
369:
370: ZEND_REGISTER_RESOURCE(return_value, event, le_event);
371: zend_list_addref(Z_LVAL_P(return_value));
372: efree(args);
373: }
374: /* }}} */
375:
376: /* {{{ proto bool ibase_free_event_handler(resource event)
377: Frees the event handler set by ibase_set_event_handler() */
378: PHP_FUNCTION(ibase_free_event_handler)
379: {
380: zval *event_arg;
381:
382: RESET_ERRMSG;
383:
384: if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &event_arg)) {
385: ibase_event *event;
386:
387: ZEND_FETCH_RESOURCE(event, ibase_event *, &event_arg, -1, "Interbase event", le_event);
388:
389: event->state = DEAD;
390:
391: zend_list_delete(Z_LVAL_P(event_arg));
392: RETURN_TRUE;
393: } else {
394: RETURN_FALSE;
395: }
396: }
397: /* }}} */
398:
399: #endif /* HAVE_IBASE */
400:
401: /*
402: * Local variables:
403: * tab-width: 4
404: * c-basic-offset: 4
405: * End:
406: * vim600: sw=4 ts=4 fdm=marker
407: * vim<600: sw=4 ts=4
408: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>