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