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

Generated by: LCOV version 1.10

Generated at Sat, 23 Aug 2014 22:39:33 +0000 (4 days ago)

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