PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/interbase - ibase_events.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 109 163 66.9 %
Date: 2014-04-18 Functions: 8 9 88.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 5                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2013 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$ */
      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           5 : static void _php_ibase_event_free(char *event_buf, char *result_buf) /* {{{ */
      35             : {
      36           5 :         isc_free(event_buf);
      37           5 :         isc_free(result_buf);
      38           5 : }
      39             : /* }}} */
      40             : 
      41           9 : void _php_ibase_free_event(ibase_event *event TSRMLS_DC) /* {{{ */
      42             : {
      43             :         unsigned short i;
      44             : 
      45           9 :         event->state = DEAD;
      46             : 
      47           9 :         if (event->link != NULL) {
      48             :                 ibase_event **node;
      49             : 
      50           5 :                 if (event->link->handle != NULL &&
      51           0 :                                 isc_cancel_events(IB_STATUS, &event->link->handle, &event->event_id)) {
      52           0 :                         _php_ibase_error(TSRMLS_C);
      53             :                 }
      54             : 
      55             :                 /* delete this event from the link struct */
      56           5 :                 for (node = &event->link->event_head; *node != event; node = &(*node)->event_next);
      57           5 :                 *node = event->event_next;
      58             :         }
      59             : 
      60           9 :         if (event->callback) {
      61           5 :                 zval_dtor(event->callback);
      62           5 :                 FREE_ZVAL(event->callback);
      63           5 :                 event->callback = NULL;
      64             : 
      65           5 :                 _php_ibase_event_free(event->event_buffer,event->result_buffer);
      66             : 
      67          10 :                 for (i = 0; i < event->event_count; ++i) {
      68           5 :                         efree(event->events[i]);
      69             :                 }
      70           5 :                 efree(event->events);
      71             :         }
      72           9 : }
      73             : /* }}} */
      74             : 
      75           5 : static void _php_ibase_free_event_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
      76             : {
      77           5 :         ibase_event *e = (ibase_event *) rsrc->ptr;
      78             : 
      79           5 :         _php_ibase_free_event(e TSRMLS_CC);
      80             : 
      81           5 :         efree(e);
      82           5 : }
      83             : /* }}} */
      84             : 
      85       19341 : void php_ibase_events_minit(INIT_FUNC_ARGS) /* {{{ */
      86             : {
      87       19341 :         le_event = zend_register_list_destructors_ex(_php_ibase_free_event_rsrc, NULL, 
      88             :             "interbase event", module_number);
      89       19341 : }
      90             : /* }}} */
      91             : 
      92           5 : 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          70 :         *l = (unsigned short) isc_event_block(event_buf, result_buf, count, events[0],
     109          35 :                 events[1], events[2], events[3], events[4], events[5], events[6], events[7],
     110          35 :                 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           5 :         isc_wait_for_event(dummy_result, &ib_link->handle, *l, *event_buf, *result_buf);
     121           5 :         isc_event_counts(dummy_count, *l, *event_buf, *result_buf);
     122           5 : }
     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           0 : 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           0 :         unsigned short i = 0, event_count = 0, buffer_size;
     134             :         unsigned long occurred_event[15];
     135             : 
     136           0 :         RESET_ERRMSG;
     137             : 
     138             :         /* no more than 15 events */
     139           0 :         if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 16) {
     140           0 :                 WRONG_PARAM_COUNT;
     141             :         }
     142             : 
     143           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
     144           0 :                 return;
     145             :         }
     146             : 
     147           0 :         if (Z_TYPE_PP(args[0]) == IS_RESOURCE) {
     148           0 :                 if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, args[0], -1, "InterBase link", le_link, le_plink)) {
     149           0 :                         efree(args);
     150           0 :                         RETURN_FALSE;
     151             :                 }
     152           0 :                 i = 1;
     153             :         } else {
     154           0 :                 if (ZEND_NUM_ARGS() > 15) {
     155           0 :                         efree(args);
     156           0 :                         WRONG_PARAM_COUNT;
     157             :                 }
     158           0 :                 if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", le_link, le_plink)) {
     159           0 :                         efree(args);
     160           0 :                         RETURN_FALSE;
     161             :                 }
     162             :         }
     163             : 
     164           0 :         for (; i < ZEND_NUM_ARGS(); ++i) {
     165           0 :                 convert_to_string_ex(args[i]);
     166           0 :                 events[event_count++] = Z_STRVAL_PP(args[i]);
     167             :         }
     168             : 
     169             :         /* fills the required data structure with information about the events */
     170           0 :         _php_ibase_event_block(ib_link, event_count, events, &buffer_size, &event_buffer, &result_buffer);
     171             : 
     172             :         /* now block until an event occurs */
     173           0 :         if (isc_wait_for_event(IB_STATUS, &ib_link->handle, buffer_size, event_buffer, result_buffer)) {
     174           0 :                 _php_ibase_error(TSRMLS_C);
     175           0 :                 _php_ibase_event_free(event_buffer,result_buffer);
     176           0 :                 efree(args);
     177           0 :                 RETURN_FALSE;
     178             :         }
     179             : 
     180             :         /* find out which event occurred */
     181           0 :         isc_event_counts(occurred_event, buffer_size, event_buffer, result_buffer);
     182           0 :         for (i = 0; i < event_count; ++i) {
     183           0 :                 if (occurred_event[i]) {
     184           0 :                         char *result = estrdup(events[i]);
     185           0 :                         _php_ibase_event_free(event_buffer,result_buffer);
     186           0 :                         efree(args);
     187           0 :                         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           0 :         _php_ibase_event_free(event_buffer,result_buffer);
     194           0 :         efree(args);
     195           0 :         RETURN_FALSE;
     196             : }
     197             : /* }}} */
     198             : 
     199           7 : 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           7 :         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           1 :                         break;
     217             :                 case ACTIVE:
     218           5 :                         args[0] = &event_name;
     219           5 :                         args[1] = &link_id;
     220             : 
     221             :                         /* copy the updated results into the result buffer */
     222           5 :                         memcpy(event->result_buffer, result_buf, buffer_size);
     223             : 
     224           5 :                         INIT_ZVAL(event_name);
     225           5 :                         INIT_ZVAL(link_id);
     226           5 :                         ZVAL_RESOURCE(&link_id, event->link_res_id);
     227             : 
     228             :                         /* find out which event occurred */
     229           5 :                         isc_event_counts(occurred_event, buffer_size, event->event_buffer, event->result_buffer);
     230           5 :                         for (i = 0; i < event->event_count; ++i) {
     231           5 :                                 if (occurred_event[i]) {
     232           5 :                                         ZVAL_STRING(&event_name,event->events[i],0);
     233           5 :                                         break;
     234             :                                 }
     235             :                         }
     236             : 
     237             :                         /* call the callback provided by the user */
     238           5 :                         if (SUCCESS != call_user_function(EG(function_table), NULL,
     239             :                                         event->callback, &return_value, 2, args TSRMLS_CC)) {
     240           0 :                                 _php_ibase_module_error("Error calling callback %s" TSRMLS_CC, Z_STRVAL_P(event->callback));
     241           0 :                                 break;
     242             :                         }
     243             : 
     244           5 :                         if (Z_TYPE(return_value) == IS_BOOL && !Z_BVAL(return_value)) {
     245           1 :                                 event->state = DEAD;
     246           1 :                                 break;
     247             :                         }
     248             :                 case NEW:
     249             :                         /* re-register the event */
     250          10 :                         if (isc_que_events(IB_STATUS, &event->link->handle, &event->event_id, buffer_size,
     251           5 :                                 event->event_buffer,(isc_callback)_php_ibase_callback, (void *)event)) {
     252             : 
     253           0 :                                 _php_ibase_error(TSRMLS_C);
     254             :                         }
     255           5 :                         event->state = ACTIVE;
     256             :         }
     257           7 :         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          12 : 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          12 :         unsigned short i = 1, buffer_size;
     275             :         int link_res_id, num_args;
     276             : 
     277          12 :         RESET_ERRMSG;
     278             :         
     279             :         /* Minimum and maximum number of arguments allowed */
     280          12 :         if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 17) {
     281           1 :                 WRONG_PARAM_COUNT;
     282             :         }
     283             : 
     284          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
     285           0 :                 return;
     286             :         }
     287             : 
     288             :         /* get a working link */
     289          11 :         if (Z_TYPE_PP(args[0]) != IS_STRING) {
     290             :                 /* resource, callback, event_1 [, ... event_15]
     291             :                  * No more than 15 events
     292             :                  */
     293           6 :                 if (ZEND_NUM_ARGS() < 3 || ZEND_NUM_ARGS() > 17) {
     294           0 :                         efree(args);
     295           0 :                         WRONG_PARAM_COUNT;
     296             :                 }
     297             : 
     298           6 :                 cb_arg = args[1];
     299           6 :                 i = 2;
     300             : 
     301           6 :                 if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, args[0], -1, "InterBase link", le_link, le_plink)) {
     302           2 :                         efree(args);
     303           2 :                         RETURN_FALSE;
     304             :                 }
     305             : 
     306          24 :                 convert_to_long_ex(args[0]);
     307           4 :                 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           5 :                 if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 16) {
     314           0 :                         efree(args);
     315           0 :                         WRONG_PARAM_COUNT;
     316             :                 }
     317             : 
     318           5 :                 cb_arg = args[0];
     319             : 
     320           5 :                 if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", le_link, le_plink)) {
     321           0 :                         efree(args);
     322           0 :                         RETURN_FALSE;
     323             :                 }
     324           5 :                 link_res_id = IBG(default_link);
     325             :         }
     326             : 
     327             :         /* get the callback */
     328           9 :         if (!zend_is_callable(*cb_arg, 0, &cb_name TSRMLS_CC)) {
     329           4 :                 _php_ibase_module_error("Callback argument %s is not a callable function" TSRMLS_CC, cb_name);
     330           4 :                 efree(cb_name);
     331           4 :                 efree(args);
     332           4 :                 RETURN_FALSE;
     333             :         }
     334           5 :         efree(cb_name);
     335             : 
     336             :         /* allocate the event resource */
     337           5 :         event = (ibase_event *) safe_emalloc(sizeof(ibase_event), 1, 0);
     338             :         TSRMLS_SET_CTX(event->thread_ctx);
     339           5 :         event->link_res_id = link_res_id;
     340           5 :         event->link = ib_link;
     341           5 :         event->event_count = 0;
     342           5 :         event->state = NEW;
     343           5 :         event->events = (char **) safe_emalloc(sizeof(char *),ZEND_NUM_ARGS()-i,0);
     344             : 
     345           5 :         ALLOC_ZVAL(event->callback);
     346           5 :         *event->callback = **cb_arg;
     347           5 :         INIT_PZVAL(event->callback);
     348           5 :         zval_copy_ctor(event->callback);
     349             : 
     350          10 :         for (; i < ZEND_NUM_ARGS(); ++i) {
     351          11 :                 convert_to_string_ex(args[i]);
     352           5 :                 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           5 :         _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          10 :         if (isc_que_events(IB_STATUS, &ib_link->handle, &event->event_id, buffer_size,
     361           5 :                 event->event_buffer,(isc_callback)_php_ibase_callback, (void *)event)) {
     362             : 
     363           0 :                 _php_ibase_error(TSRMLS_C);
     364           0 :                 efree(event);
     365           0 :                 efree(args);
     366           0 :                 RETURN_FALSE;
     367             :         }
     368             : 
     369           5 :         event->event_next = ib_link->event_head;
     370           5 :         ib_link->event_head = event;
     371             : 
     372           5 :         ZEND_REGISTER_RESOURCE(return_value, event, le_event);
     373           5 :         zend_list_addref(Z_LVAL_P(return_value));
     374           5 :         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           1 : PHP_FUNCTION(ibase_free_event_handler)
     381             : {
     382             :         zval *event_arg;
     383             : 
     384           1 :         RESET_ERRMSG;
     385             : 
     386           1 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &event_arg)) {
     387             :                 ibase_event *event;
     388             : 
     389           1 :                 ZEND_FETCH_RESOURCE(event, ibase_event *, &event_arg, -1, "Interbase event", le_event);
     390             : 
     391           1 :                 event->state = DEAD;
     392             : 
     393           1 :                 zend_list_delete(Z_LVAL_P(event_arg));
     394           1 :                 RETURN_TRUE;
     395             :         } else {
     396           0 :                 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             :  */

Generated by: LCOV version 1.10

Generated at Fri, 18 Apr 2014 07:01:28 +0000 (6 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.