Annotation of embedaddon/php/ext/interbase/ibase_events.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:    | Copyright (c) 1997-2013 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: 
1.1.1.2   misho      19: /* $Id$ */
1.1       misho      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>