#
#	callbacks.c - maintain a list of functions to call when needed
#	callbacks.pl
#
#	Daniel Smith, dansmith@autodesk.com, Late 1990 - 1992
#
#	The purpose of this is to be able to call functions that "clean-up"
#	or reset states when we need them.  The logic is pretty much:
#
#		if (there are functions to call)
#			traverse the list of functions, calling
#			each one in turn, and then go on with what we
#			were going to do...
#
#	I'm trying to write this in such a way where I can drop into
#	a lot of different programs, hence the static-ness going on here.
#	The only calls coming from the outside are going to be do_callbacks (),
#	keep_callback (), and add_callback ().
#
#	History:
#
#	Sun Feb 16 14:15:19 PST 1992
#	dropped this into SoftList lib, added $cmds lines.
#
#	Sometime in Late 1991
#	ported from C to Perl
#
#	Tue Nov  6 10:22:08 PST 1990 daniel
#	created
#

# these lines for SoftList...
$cmds{"add_callback"} = '&add_callback';
$cmds{"keep_callback"} = '&keep_callback';
$cmds{"do_callbacks"} = '&do_callbacks';

$num_keepers = $callback_idx = $keep_idx = $num_callbacks = 0;


#
#	add_callback - register a new callback in our list
#
sub add_callback {
    $callback_function[$num_callbacks++ + $callback_idx] = "@_";
}

#
#	keep_callback - keep this callback around after calling do_callbacks
#
sub keep_callback {
    $callback_function[$num_keepers++ + $keep_idx] = "@_";
}
 

sub do_callbacks {
    local($who_called) = @_;
 
    #
    #	call each one in turn..."who_called" should be defined so
    #	that the callback knows who its parent is
    #
	
    for ($i = 0; $i < $num_callbacks; $i++) {
	eval "$callback_function[$i + $callback_idx] ($who_called)";
    }
    $num_callbacks = $num_keepers;
    $num_keepers = 0;

    #
    #	Some callbacks might want to be called again, so
    #	we flip the indexes
    #
    $tmp = $callback_idx;
    $callback_idx = keep_idx;
    $keep_idx = $tmp;
}
1;

__END__

#	the following is a test program for callbacks...
#
#
#
#	print "test\n";
#
#	&add_callback ('&fooby');
#	&add_callback ('&fuzzy');
#	&add_callback ('&wuzzy');
#	&do_callbacks ("0");
#	&do_callbacks ("1");
#	&do_callbacks ("0");
#	&do_callbacks ("1");
#
#
#
#sub fooby {
#
#	local ($parent) = @_;
#
#	print " this is fooby... parent was $parent\n";
#}
#
#sub fuzzy {
#
#	$parent = @_;
#
#	print " this is fuzzy... parent was $parent\n";
#	&keep_callback('&fuzzy');
#}
#
#sub wuzzy {
#
#	$parent = @_;
#
#	print " this is wuzzy... parent was $parent\n";
#}


#	ok, as a bonus, here's the original C version :-)

/*
**	callbacks.c - maintain a list of functions to call when needed
**
**	daniel@island.com, Daniel Smith
**
**	The purpose of this is to be able to call functions that "clean-up"
**	or reset states when we need them.  The logic is pretty much:
**
**		if (there are functions to call)
**			traverse the list of functions, calling
**			each one in turn, and then go on with what we
**			were going to do...
**
**	I'm trying to write this in such a way where I can drop into
**	a lot of different programs, hence the static-ness going on here.
**	The only calls coming from the outside are going to be do_callbacks (),
**	keep_callback (), and add_callback ().
**
**	History:
**
**	Tue Nov  6 10:22:08 PST 1990 daniel
**	created
*/

#define MAX_CALLBACKS 16384
static int num_callbacks = 0, num_keepers = 0, callback_idx = 0, keep_idx = 1;

/*
**	one indice is for callbacks, and the other stores "keepers"
**	(callbacks that are going to be reused), by flipping indices
**	we avoid copying pointers (from keeper to callback...)
*/
static void (*callback_function[MAX_CALLBACKS][2]) ();

/* the worker bees */
void add_callback ();
void keep_callback ();
void do_callback ();

 
/*
**	add_callback - register a new callback in our list
*/
void add_callback (user_function)
void (*user_function) ();
{
	if (num_callbacks < MAX_CALLBACKS - 1)
		callback_function[num_callbacks++][callback_idx] =
								user_function;
}

/*
**	keep_callback - keep this callback around after calling do_callbacks
*/
void keep_callback (user_function)
void (*user_function) ();
{
	if (num_keepers < MAX_CALLBACKS - 1)
		callback_function[num_keepers++][keep_idx] = user_function;
}
 

/*
**	do_callbacks - traverse our list of callback functions
**
**	each callback should/can be set up like this:
**
**	void some_callback (parent)
**	int parent
**	{
**		switch (parent) {
**			case LINE_PARENT:
**				bla bla bla...
**			case ARC_PARENT:
**				bla bla bla...
**			default:
**		}
**	}
*/
void do_callbacks (who_called)
int who_called;
{
	int i, tmp;
 
	/*
	**	call each one in turn..."who_called" should be defined so
	**	that the callback knows who its parent is
	*/

	for (i = 0; i < num_callbacks; i++) {
		callback_function[i][callback_idx] (who_called);
	}
	num_callbacks = num_keepers;
	num_keepers = 0;

	/*
	**	Some callbacks might want to be called again, so
	**	we flip the indexes
	*/
	tmp = callback_idx, callback_idx = keep_idx, keep_idx = tmp;
}
1;
