cvs: embed /php-irssi ext-irssi.c /php-irssi/examples timeout.php

[email protected] ("Wez Furlong") Sat, 01 Feb 2003 13:51:34 -0000
Newsgroups php.embed.cvs
Message-ID <cvswez1044107494@cvsserver>
--wez1044107494
Content-Type: text/plain

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.
  
  
--wez1044107494
Content-Type: text/plain
Content-Disposition: attachment; filename="wez-20030201085134.txt"

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 <[email protected]>                                    |
   +----------------------------------------------------------------------+
-  $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);

?>

--wez1044107494--