Annotation of embedaddon/php/ext/interbase/ibase_events.c, revision 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>