cvs: embed /php-irssi ext-irssi.c /php-irssi/examples timeout.php
| From: | Wez Furlong | Date: | Sat, 01 Feb 2003 13:51:34 +0000 |
| Subject: | cvs: embed /php-irssi ext-irssi.c /php-irssi/examples timeout.php | ||
| Groups: | php.embed.cvs | ||
| Request: | Send a blank email to php-embed-cvs+get-11@lists.php.net to get a copy of this message | ||
wez Sat Feb 1 08:51:34 2003 EDT
Added files:
/embed/php-irssi/examples timeout.php
Modified files:
/embed/php-irssi ext-irssi.c
Log:
Implement timeout API.
See examples/timeout.php for a demonstration.
Index: embed/php-irssi/ext-irssi.c diff -u embed/php-irssi/ext-irssi.c:1.6 embed/php-irssi/ext-irssi.c:1.7 --- embed/php-irssi/ext-irssi.c:1.6 Fri Jan 31 23:46:56 2003 +++ embed/php-irssi/ext-irssi.c Sat Feb 1 08:51:34 2003 @@ -14,7 +14,7 @@ +----------------------------------------------------------------------+ | Author: Wez Furlong <wez@php.net> | +----------------------------------------------------------------------+ - $Id: ext-irssi.c,v 1.6 2003/02/01 04:46:56 wez Exp $ + $Id: ext-irssi.c,v 1.7 2003/02/01 13:51:34 wez Exp $ */ #include "php-irssi.h" #include "php-signals-list.h" /* generated by php during make */ @@ -28,8 +28,17 @@ struct sig_record { zval *handler; - int signal_id; zval *arg; + enum { SIG_REC_TYPE_SIGNAL, SIG_REC_TYPE_TIMEOUT } type; + union { + struct { + int signal_id; + } sig; + struct { + int tag; + int one_shot; + } timeout; + } v; }; HashTable *bound_signals; @@ -51,6 +60,73 @@ /* Signals */ +static char *signal_hash_key(char *signame, zval *callback TSRMLS_DC) +{ + char *key = NULL; + + if (Z_TYPE_P(callback) == IS_ARRAY) { + zval **obj = NULL, **func = NULL; + + zend_hash_index_find(Z_ARRVAL_P(callback), 0, (void**)&obj); + zend_hash_index_find(Z_ARRVAL_P(callback), 1, (void**)&func); + + if (obj == NULL || func == NULL) { + return NULL; + } + + convert_to_string_ex(func); + + if (Z_TYPE_PP(obj) == IS_OBJECT) { + spprintf(&key, 0, "%s@%d@%s", signame, (*obj)->value.obj.handle, Z_STRVAL_PP(func)); + return key; + } + + /* class name */ + convert_to_string_ex(obj); + spprintf(&key, 0, "%s@%s@%s", signame, Z_STRVAL_PP(obj), Z_STRVAL_PP(func)); + return key; + } + if (Z_TYPE_P(callback) == IS_STRING) { + spprintf(&key, 0, "%s@%s", signame, Z_STRVAL_P(callback)); + return key; + } + return NULL; +} + +static char *timeout_hash_key(int tag, zval *callback TSRMLS_DC) +{ + char *key = NULL; + + if (Z_TYPE_P(callback) == IS_ARRAY) { + zval **obj = NULL, **func = NULL; + + zend_hash_index_find(Z_ARRVAL_P(callback), 0, (void**)&obj); + zend_hash_index_find(Z_ARRVAL_P(callback), 1, (void**)&func); + + if (obj == NULL || func == NULL) { + return NULL; + } + + convert_to_string_ex(func); + + if (Z_TYPE_PP(obj) == IS_OBJECT) { + spprintf(&key, 0, "%d@%d@%s", tag, (*obj)->value.obj.handle, Z_STRVAL_PP(func)); + return key; + } + + /* class name */ + convert_to_string_ex(obj); + spprintf(&key, 0, "%d@%s@%s", tag, Z_STRVAL_PP(obj), Z_STRVAL_PP(func)); + return key; + } + if (Z_TYPE_P(callback) == IS_STRING) { + spprintf(&key, 0, "%d@%s", tag, Z_STRVAL_P(callback)); + return key; + } + return NULL; +} + + static inline struct php_irssi_signal_args *sigid_to_args(int sigid) { int i; @@ -174,39 +250,113 @@ } } -static char * signal_hash_key(char *signame, zval *callback TSRMLS_DC) +static int php_source_event(struct sig_record *rec) { - char *key = NULL; + zval **zargs[1] = { NULL }; + zval *arg = NULL, *retval = NULL; + int argc = 0, i; + + if (rec->arg) { + MAKE_STD_ZVAL(arg); + *arg = *(rec->arg); + zval_copy_ctor(arg); + + zargs[argc++] = &arg; + } + + call_user_function_ex(EG(function_table), + NULL, + rec->handler, + &retval, + argc, + zargs, + 0, NULL TSRMLS_CC); - if (Z_TYPE_P(callback) == IS_ARRAY) { - zval **obj = NULL, **func = NULL; + if (retval) + zval_ptr_dtor(&retval); - zend_hash_index_find(Z_ARRVAL_P(callback), 0, (void**)&obj); - zend_hash_index_find(Z_ARRVAL_P(callback), 1, (void**)&func); + if (arg) { + FREE_ZVAL(arg); + } - if (obj == NULL || func == NULL) { - return NULL; - } + if (rec->v.timeout.one_shot) { + char *sighash = timeout_hash_key(rec->v.timeout.tag, rec->handler TSRMLS_CC); + zend_hash_del(bound_signals, sighash, strlen(sighash)+1); + efree(sighash); + } + + return 1; +} - convert_to_string_ex(func); - - if (Z_TYPE_PP(obj) == IS_OBJECT) { - spprintf(&key, 0, "%s@%d@%s", signame, (*obj)->value.obj.handle, Z_STRVAL_PP(func)); - return key; - } - - /* class name */ - convert_to_string_ex(obj); - spprintf(&key, 0, "%s@%s@%s", signame, Z_STRVAL_PP(obj), Z_STRVAL_PP(func)); - return key; +PHP_FUNCTION(irssi_timeout_remove) +{ + char *signame; + long signame_len; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", + &signame, &signame_len)) { + return; } - if (Z_TYPE_P(callback) == IS_STRING) { - spprintf(&key, 0, "%s@%s", signame, Z_STRVAL_P(callback)); - return key; + + zend_hash_del(bound_signals, signame, signame_len+1); +} + +/* proto string irssi_timeout_add(long msecsinterval, mixed callback, [mixed arg, [bool oneshot]]) + Requests that callback be called every msecsinterval. */ +PHP_FUNCTION(irssi_timeout_add) +{ + zval *sigarg = NULL, *funcname, *tmp; + long msecsinterval; + int sigid; + struct sig_record *rec; + char *sighash = NULL; + zend_bool oneshot = 0; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|z!b", + &msecsinterval, + &funcname, + &sigarg, + &oneshot + )) { + return; + } + + rec = emalloc(sizeof(struct sig_record)); + + MAKE_STD_ZVAL(rec->handler); + *(rec->handler) = *funcname; + zval_copy_ctor(rec->handler); + + if (sigarg) { + MAKE_STD_ZVAL(rec->arg); + *(rec->arg) = *sigarg; + zval_copy_ctor(rec->arg); + } else { + rec->arg = NULL; + } + + rec->type = SIG_REC_TYPE_TIMEOUT; + rec->v.timeout.tag = g_timeout_add(msecsinterval, (GSourceFunc)php_source_event, rec); + rec->v.timeout.one_shot = oneshot; + + sighash = timeout_hash_key(rec->v.timeout.tag, rec->handler TSRMLS_CC); + + if (sighash) { + zend_hash_update(bound_signals, sighash, strlen(sighash)+1, &rec, sizeof(rec), NULL); + + /* no need to dup it */ + RETVAL_STRING(sighash, 0); + + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to hash timeout handler"); + zend_hash_next_index_insert(bound_signals, &rec, sizeof(rec), NULL); + + RETVAL_NULL(); } - return NULL; } + + /* proto void irssi_signal_add(string signalname, mixed callback, [long priority, mixed sigarg]) Binds a function to a signal. priority is one of the IRSSI_PRIORITY_XXX constants */ PHP_FUNCTION(irssi_signal_add) @@ -234,6 +384,7 @@ } rec = emalloc(sizeof(struct sig_record)); + rec->type = SIG_REC_TYPE_SIGNAL; sigid = signal_get_uniq_id(signame); @@ -241,7 +392,7 @@ *(rec->handler) = *funcname; zval_copy_ctor(rec->handler); - rec->signal_id = sigid; + rec->v.sig.signal_id = sigid; if (sigarg) { MAKE_STD_ZVAL(rec->arg); @@ -367,8 +518,6 @@ RETURN_FALSE; } - signal_remove_id((*rec)->signal_id, sig_func, rec); - zend_hash_del(bound_signals, sighash, strlen(sighash)+1); efree(sighash); @@ -379,6 +528,12 @@ static void sig_rec_dtor(void *pDest) { struct sig_record *rec = *(struct sig_record **)pDest; + + if (rec->type == SIG_REC_TYPE_SIGNAL) { + signal_remove_id(rec->v.sig.signal_id, sig_func, rec); + } else { + g_source_remove(rec->v.timeout.tag); + } if (rec->handler) { zval_ptr_dtor(&rec->handler); @@ -459,6 +614,8 @@ PHP_FE(irssi_signal_emit, NULL) PHP_FE(irssi_signal_remove, NULL) PHP_FE(irssi_signal_get_arg, NULL) + PHP_FE(irssi_timeout_add, NULL) + PHP_FE(irssi_timeout_remove, NULL) NULL, NULL, NULL }; Index: embed/php-irssi/examples/timeout.php +++ embed/php-irssi/examples/timeout.php <?php /* $Id: timeout.php,v 1.1 2003/02/01 13:51:34 wez Exp $ * * Timeouts. * * This sample demonstrates how to request that irssi call back into * your PHP script at regular intervals. * Timeouts are specified in millisecond intervals, and it is worth noting * that the timing of the intervals can never be 100% accurate. * It should be "good enough" for most purposes. * * Just like any callback made from irssi, you should not hang around for * too long; long delays can cause irssi to drop network connections to * your chatnets. */ /* This snippet shows how to trigger an event at 1 second intervals. * The event will continue to occur for all time. */ function ticktock() { static $tick = true; if ($tick) echo "TICK!\n"; else echo "TOCK!\n"; $tick = !$tick; } $tag = irssi_timeout_add(1000, "ticktock"); /* Surely, after a while that ticktock will become annoying, so this * next snippet shows how to create a one-shot timeout that will * turn off the tick tock and never be called again. */ function shut_that_thing_off($tag) { irssi_timeout_remove($tag); echo "No more ticking!"; } irssi_timeout_add(5000, "shut_that_thing_off", $tag, true); ?>
Index: embed/php-irssi/ext-irssi.c diff -u embed/php-irssi/ext-irssi.c:1.6 embed/php-irssi/ext-irssi.c:1.7 --- embed/php-irssi/ext-irssi.c:1.6 Fri Jan 31 23:46:56 2003 +++ embed/php-irssi/ext-irssi.c Sat Feb 1 08:51:34 2003 @@ -14,7 +14,7 @@ +----------------------------------------------------------------------+ | Author: Wez Furlong <wez@php.net> | +----------------------------------------------------------------------+ - $Id: ext-irssi.c,v 1.6 2003/02/01 04:46:56 wez Exp $ + $Id: ext-irssi.c,v 1.7 2003/02/01 13:51:34 wez Exp $ */ #include "php-irssi.h" #include "php-signals-list.h" /* generated by php during make */ @@ -28,8 +28,17 @@ struct sig_record { zval *handler; - int signal_id; zval *arg; + enum { SIG_REC_TYPE_SIGNAL, SIG_REC_TYPE_TIMEOUT } type; + union { + struct { + int signal_id; + } sig; + struct { + int tag; + int one_shot; + } timeout; + } v; }; HashTable *bound_signals; @@ -51,6 +60,73 @@ /* Signals */ +static char *signal_hash_key(char *signame, zval *callback TSRMLS_DC) +{ + char *key = NULL; + + if (Z_TYPE_P(callback) == IS_ARRAY) { + zval **obj = NULL, **func = NULL; + + zend_hash_index_find(Z_ARRVAL_P(callback), 0, (void**)&obj); + zend_hash_index_find(Z_ARRVAL_P(callback), 1, (void**)&func); + + if (obj == NULL || func == NULL) { + return NULL; + } + + convert_to_string_ex(func); + + if (Z_TYPE_PP(obj) == IS_OBJECT) { + spprintf(&key, 0, "%s@%d@%s", signame, (*obj)->value.obj.handle, Z_STRVAL_PP(func)); + return key; + } + + /* class name */ + convert_to_string_ex(obj); + spprintf(&key, 0, "%s@%s@%s", signame, Z_STRVAL_PP(obj), Z_STRVAL_PP(func)); + return key; + } + if (Z_TYPE_P(callback) == IS_STRING) { + spprintf(&key, 0, "%s@%s", signame, Z_STRVAL_P(callback)); + return key; + } + return NULL; +} + +static char *timeout_hash_key(int tag, zval *callback TSRMLS_DC) +{ + char *key = NULL; + + if (Z_TYPE_P(callback) == IS_ARRAY) { + zval **obj = NULL, **func = NULL; + + zend_hash_index_find(Z_ARRVAL_P(callback), 0, (void**)&obj); + zend_hash_index_find(Z_ARRVAL_P(callback), 1, (void**)&func); + + if (obj == NULL || func == NULL) { + return NULL; + } + + convert_to_string_ex(func); + + if (Z_TYPE_PP(obj) == IS_OBJECT) { + spprintf(&key, 0, "%d@%d@%s", tag, (*obj)->value.obj.handle, Z_STRVAL_PP(func)); + return key; + } + + /* class name */ + convert_to_string_ex(obj); + spprintf(&key, 0, "%d@%s@%s", tag, Z_STRVAL_PP(obj), Z_STRVAL_PP(func)); + return key; + } + if (Z_TYPE_P(callback) == IS_STRING) { + spprintf(&key, 0, "%d@%s", tag, Z_STRVAL_P(callback)); + return key; + } + return NULL; +} + + static inline struct php_irssi_signal_args *sigid_to_args(int sigid) { int i; @@ -174,39 +250,113 @@ } } -static char * signal_hash_key(char *signame, zval *callback TSRMLS_DC) +static int php_source_event(struct sig_record *rec) { - char *key = NULL; + zval **zargs[1] = { NULL }; + zval *arg = NULL, *retval = NULL; + int argc = 0, i; + + if (rec->arg) { + MAKE_STD_ZVAL(arg); + *arg = *(rec->arg); + zval_copy_ctor(arg); + + zargs[argc++] = &arg; + } + + call_user_function_ex(EG(function_table), + NULL, + rec->handler, + &retval, + argc, + zargs, + 0, NULL TSRMLS_CC); - if (Z_TYPE_P(callback) == IS_ARRAY) { - zval **obj = NULL, **func = NULL; + if (retval) + zval_ptr_dtor(&retval); - zend_hash_index_find(Z_ARRVAL_P(callback), 0, (void**)&obj); - zend_hash_index_find(Z_ARRVAL_P(callback), 1, (void**)&func); + if (arg) { + FREE_ZVAL(arg); + } - if (obj == NULL || func == NULL) { - return NULL; - } + if (rec->v.timeout.one_shot) { + char *sighash = timeout_hash_key(rec->v.timeout.tag, rec->handler TSRMLS_CC); + zend_hash_del(bound_signals, sighash, strlen(sighash)+1); + efree(sighash); + } + + return 1; +} - convert_to_string_ex(func); - - if (Z_TYPE_PP(obj) == IS_OBJECT) { - spprintf(&key, 0, "%s@%d@%s", signame, (*obj)->value.obj.handle, Z_STRVAL_PP(func)); - return key; - } - - /* class name */ - convert_to_string_ex(obj); - spprintf(&key, 0, "%s@%s@%s", signame, Z_STRVAL_PP(obj), Z_STRVAL_PP(func)); - return key; +PHP_FUNCTION(irssi_timeout_remove) +{ + char *signame; + long signame_len; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", + &signame, &signame_len)) { + return; } - if (Z_TYPE_P(callback) == IS_STRING) { - spprintf(&key, 0, "%s@%s", signame, Z_STRVAL_P(callback)); - return key; + + zend_hash_del(bound_signals, signame, signame_len+1); +} + +/* proto string irssi_timeout_add(long msecsinterval, mixed callback, [mixed arg, [bool oneshot]]) + Requests that callback be called every msecsinterval. */ +PHP_FUNCTION(irssi_timeout_add) +{ + zval *sigarg = NULL, *funcname, *tmp; + long msecsinterval; + int sigid; + struct sig_record *rec; + char *sighash = NULL; + zend_bool oneshot = 0; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|z!b", + &msecsinterval, + &funcname, + &sigarg, + &oneshot + )) { + return; + } + + rec = emalloc(sizeof(struct sig_record)); + + MAKE_STD_ZVAL(rec->handler); + *(rec->handler) = *funcname; + zval_copy_ctor(rec->handler); + + if (sigarg) { + MAKE_STD_ZVAL(rec->arg); + *(rec->arg) = *sigarg; + zval_copy_ctor(rec->arg); + } else { + rec->arg = NULL; + } + + rec->type = SIG_REC_TYPE_TIMEOUT; + rec->v.timeout.tag = g_timeout_add(msecsinterval, (GSourceFunc)php_source_event, rec); + rec->v.timeout.one_shot = oneshot; + + sighash = timeout_hash_key(rec->v.timeout.tag, rec->handler TSRMLS_CC); + + if (sighash) { + zend_hash_update(bound_signals, sighash, strlen(sighash)+1, &rec, sizeof(rec), NULL); + + /* no need to dup it */ + RETVAL_STRING(sighash, 0); + + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to hash timeout handler"); + zend_hash_next_index_insert(bound_signals, &rec, sizeof(rec), NULL); + + RETVAL_NULL(); } - return NULL; } + + /* proto void irssi_signal_add(string signalname, mixed callback, [long priority, mixed sigarg]) Binds a function to a signal. priority is one of the IRSSI_PRIORITY_XXX constants */ PHP_FUNCTION(irssi_signal_add) @@ -234,6 +384,7 @@ } rec = emalloc(sizeof(struct sig_record)); + rec->type = SIG_REC_TYPE_SIGNAL; sigid = signal_get_uniq_id(signame); @@ -241,7 +392,7 @@ *(rec->handler) = *funcname; zval_copy_ctor(rec->handler); - rec->signal_id = sigid; + rec->v.sig.signal_id = sigid; if (sigarg) { MAKE_STD_ZVAL(rec->arg); @@ -367,8 +518,6 @@ RETURN_FALSE; } - signal_remove_id((*rec)->signal_id, sig_func, rec); - zend_hash_del(bound_signals, sighash, strlen(sighash)+1); efree(sighash); @@ -379,6 +528,12 @@ static void sig_rec_dtor(void *pDest) { struct sig_record *rec = *(struct sig_record **)pDest; + + if (rec->type == SIG_REC_TYPE_SIGNAL) { + signal_remove_id(rec->v.sig.signal_id, sig_func, rec); + } else { + g_source_remove(rec->v.timeout.tag); + } if (rec->handler) { zval_ptr_dtor(&rec->handler); @@ -459,6 +614,8 @@ PHP_FE(irssi_signal_emit, NULL) PHP_FE(irssi_signal_remove, NULL) PHP_FE(irssi_signal_get_arg, NULL) + PHP_FE(irssi_timeout_add, NULL) + PHP_FE(irssi_timeout_remove, NULL) NULL, NULL, NULL }; Index: embed/php-irssi/examples/timeout.php +++ embed/php-irssi/examples/timeout.php <?php /* $Id: timeout.php,v 1.1 2003/02/01 13:51:34 wez Exp $ * * Timeouts. * * This sample demonstrates how to request that irssi call back into * your PHP script at regular intervals. * Timeouts are specified in millisecond intervals, and it is worth noting * that the timing of the intervals can never be 100% accurate. * It should be "good enough" for most purposes. * * Just like any callback made from irssi, you should not hang around for * too long; long delays can cause irssi to drop network connections to * your chatnets. */ /* This snippet shows how to trigger an event at 1 second intervals. * The event will continue to occur for all time. */ function ticktock() { static $tick = true; if ($tick) echo "TICK!\n"; else echo "TOCK!\n"; $tick = !$tick; } $tag = irssi_timeout_add(1000, "ticktock"); /* Surely, after a while that ticktock will become annoying, so this * next snippet shows how to create a one-shot timeout that will * turn off the tick tock and never be called again. */ function shut_that_thing_off($tag) { irssi_timeout_remove($tag); echo "No more ticking!"; } irssi_timeout_add(5000, "shut_that_thing_off", $tag, true); ?>