Update XChat to r1514
This commit is contained in:
		
							parent
							
								
									d563f64ab8
								
							
						
					
					
						commit
						ed0e530b79
					
				
					 4 changed files with 156 additions and 70 deletions
				
			
		|  | @ -32,6 +32,10 @@ highlights. The full CVS log is available at www.xchat.org/cvslog/ | ||||||
|   * Fixed a bug in the reinit handling code. The bug prevented the plugin from |   * Fixed a bug in the reinit handling code. The bug prevented the plugin from | ||||||
|     cleaning up properly. Which includes unloading scripts and removing |     cleaning up properly. Which includes unloading scripts and removing | ||||||
| 	 their GUI entries. | 	 their GUI entries. | ||||||
|  |   * Remove the restriction on having only 1 package per script. Any inner | ||||||
|  |     packages declared will also be unloaded when the script is unload. If | ||||||
|  |     multiple script declare an inner package with the same name then unloading | ||||||
|  |     or reloading one of those scripts will cause problems. | ||||||
| 
 | 
 | ||||||
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ||||||
|  2.8.8 - 30/May/2010 |  2.8.8 - 30/May/2010 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,3 @@ | ||||||
| BEGIN { |  | ||||||
| 	$INC{'Xchat.pm'} = 'DUMMY'; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| $SIG{__WARN__} = sub { | $SIG{__WARN__} = sub { | ||||||
| 	my $message = shift @_; | 	my $message = shift @_; | ||||||
| 	my ($package) = caller; | 	my ($package) = caller; | ||||||
|  | @ -141,7 +137,7 @@ sub hook_server { | ||||||
| 	 | 	 | ||||||
| 	my $pkg_info = Xchat::Embed::pkg_info( $package ); | 	my $pkg_info = Xchat::Embed::pkg_info( $package ); | ||||||
| 	my $hook = Xchat::Internal::hook_server( | 	my $hook = Xchat::Internal::hook_server( | ||||||
| 		$message, $priority, $callback, $data | 		$message, $priority, $callback, $data, $package | ||||||
| 	); | 	); | ||||||
| 	push @{$pkg_info->{hooks}}, $hook if defined $hook; | 	push @{$pkg_info->{hooks}}, $hook if defined $hook; | ||||||
| 	return $hook; | 	return $hook; | ||||||
|  | @ -165,7 +161,7 @@ sub hook_command { | ||||||
| 	 | 	 | ||||||
| 	my $pkg_info = Xchat::Embed::pkg_info( $package ); | 	my $pkg_info = Xchat::Embed::pkg_info( $package ); | ||||||
| 	my $hook = Xchat::Internal::hook_command( | 	my $hook = Xchat::Internal::hook_command( | ||||||
| 		$command, $priority, $callback, $help_text, $data | 		$command, $priority, $callback, $help_text, $data, $package | ||||||
| 	); | 	); | ||||||
| 	push @{$pkg_info->{hooks}}, $hook if defined $hook; | 	push @{$pkg_info->{hooks}}, $hook if defined $hook; | ||||||
| 	return $hook; | 	return $hook; | ||||||
|  | @ -242,7 +238,7 @@ sub hook_print { | ||||||
| 
 | 
 | ||||||
| 	my $pkg_info = Xchat::Embed::pkg_info( $package ); | 	my $pkg_info = Xchat::Embed::pkg_info( $package ); | ||||||
| 	my $hook = Xchat::Internal::hook_print( | 	my $hook = Xchat::Internal::hook_print( | ||||||
| 		$event, $priority, $callback, $data | 		$event, $priority, $callback, $data, $package | ||||||
| 	); | 	); | ||||||
| 	push @{$pkg_info->{hooks}}, $hook if defined $hook; | 	push @{$pkg_info->{hooks}}, $hook if defined $hook; | ||||||
| 	return $hook; | 	return $hook; | ||||||
|  | @ -276,7 +272,7 @@ sub hook_fd { | ||||||
| 	my $fileno = fileno $fd; | 	my $fileno = fileno $fd; | ||||||
| 	return undef unless defined $fileno; # no underlying fd for this handle | 	return undef unless defined $fileno; # no underlying fd for this handle | ||||||
| 	 | 	 | ||||||
| 	my ($package) = Xchat::Embed::find_pkg(); | 	my $package = Xchat::Embed::find_pkg(); | ||||||
| 	$callback = Xchat::Embed::fix_callback( $package, $callback ); | 	$callback = Xchat::Embed::fix_callback( $package, $callback ); | ||||||
| 	 | 	 | ||||||
| 	my ($flags, $data) = (Xchat::FD_READ, undef); | 	my ($flags, $data) = (Xchat::FD_READ, undef); | ||||||
|  | @ -297,7 +293,8 @@ sub hook_fd { | ||||||
| 	my $hook = Xchat::Internal::hook_fd( | 	my $hook = Xchat::Internal::hook_fd( | ||||||
| 		$fileno, $cb, $flags, { | 		$fileno, $cb, $flags, { | ||||||
| 			DATA => $data, FD => $fd, CB => $callback, FLAGS => $flags, | 			DATA => $data, FD => $fd, CB => $callback, FLAGS => $flags, | ||||||
| 		} | 		}, | ||||||
|  | 		$package | ||||||
| 	); | 	); | ||||||
| 	push @{$pkg_info->{hooks}}, $hook if defined $hook; | 	push @{$pkg_info->{hooks}}, $hook if defined $hook; | ||||||
| 	return $hook; | 	return $hook; | ||||||
|  |  | ||||||
|  | @ -2,8 +2,39 @@ package Xchat::Embed; | ||||||
| use strict; | use strict; | ||||||
| use warnings; | use warnings; | ||||||
| # list of loaded scripts keyed by their package names | # list of loaded scripts keyed by their package names | ||||||
|  | # The package names are generated from the filename of the script using | ||||||
|  | # the file2pkg() function. | ||||||
|  | # The values of this hash are hash references with the following keys: | ||||||
|  | #   filename | ||||||
|  | #     The full path to the script. | ||||||
|  | #   gui_entry | ||||||
|  | #     This is xchat_plugin pointer that is used to remove the script from | ||||||
|  | #     Plugins and Scripts window when a script is unloaded. This has also | ||||||
|  | #     been converted with the PTR2IV() macro. | ||||||
|  | #   hooks | ||||||
|  | #     This is an array of hooks that are associated with this script. | ||||||
|  | #     These are pointers that have been converted with the PTR2IV() macro. | ||||||
|  | #   inner_packages | ||||||
|  | #     Other packages that are defined in a script. This is not recommended | ||||||
|  | #     partly because these will also get removed when a script is unloaded. | ||||||
|  | #   loaded_at | ||||||
|  | #     A timestamp of when the script was loaded. The value is whatever | ||||||
|  | #     Time::HiRes::time() returns. This is used to retain load order when | ||||||
|  | #     using the RELOADALL command. | ||||||
|  | #   shutdown | ||||||
|  | #     This is either a code ref or undef. It will be executed just before a | ||||||
|  | #     script is unloaded. | ||||||
| our %scripts; | our %scripts; | ||||||
| 
 | 
 | ||||||
|  | # This is a mapping of "inner package" => "containing script package" | ||||||
|  | our %owner_package; | ||||||
|  | 
 | ||||||
|  | # used to keep track of which package a hook belongs to, if the normal way of | ||||||
|  | # checking which script is calling a hook function fails this will be used | ||||||
|  | # instead. When a hook is created this will be copied to the HookData structure | ||||||
|  | # and when a callback is invoked this it will be used to set this value. | ||||||
|  | our $current_package; | ||||||
|  | 
 | ||||||
| sub load { | sub load { | ||||||
| 	my $file = expand_homedir( shift @_ ); | 	my $file = expand_homedir( shift @_ ); | ||||||
| 	my $package = file2pkg( $file ); | 	my $package = file2pkg( $file ); | ||||||
|  | @ -28,32 +59,45 @@ sub load { | ||||||
| 		# we shouldn't care about things after __END__ | 		# we shouldn't care about things after __END__ | ||||||
| 		$source =~ s/^__END__.*//ms; | 		$source =~ s/^__END__.*//ms; | ||||||
| 		 | 		 | ||||||
| 		if( |  | ||||||
| 			my @replacements = $source =~ |  | ||||||
| 				m/^\s*package ((?:[^\W:]+(?:::)?)+)\s*?;/mg |  | ||||||
| 		) { |  | ||||||
| 			 |  | ||||||
| 			if ( @replacements > 1 ) { |  | ||||||
| 				Xchat::print( |  | ||||||
| 					"Too many package defintions, only 1 is allowed\n" |  | ||||||
| 				); |  | ||||||
| 				return 1; |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			my $original_package = shift @replacements; |  | ||||||
| 			 |  | ||||||
| 			# remove original package declaration |  | ||||||
| 			$source =~ s/^(package $original_package\s*;)/#$1/m; |  | ||||||
| 			 |  | ||||||
| 			# fixes things up for code calling subs with fully qualified names |  | ||||||
| 			$source =~ s/${original_package}:://g; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		# this must come before the eval or the filename will not be found in | 		# this must come before the eval or the filename will not be found in | ||||||
| 		# Xchat::register | 		# Xchat::register | ||||||
| 		$scripts{$package}{filename} = $file; | 		$scripts{$package}{filename} = $file; | ||||||
| 		$scripts{$package}{loaded_at} = Time::HiRes::time(); | 		$scripts{$package}{loaded_at} = Time::HiRes::time(); | ||||||
| 
 | 
 | ||||||
|  | 		# this must be done before the error check so the unload will remove | ||||||
|  | 		# any inner packages defined by the script. if a script fails to load | ||||||
|  | 		# then any inner packages need to be removed as well. | ||||||
|  | 		my @inner_packages = $source =~ | ||||||
|  | 			m/^\s*package \s+ | ||||||
|  | 				((?:[^\W:]+(?:::)?)+)\s*? # package name | ||||||
|  | 				# strict version number | ||||||
|  | 				(?:\d+(?:[.]\d+) # positive integer or decimal-fraction | ||||||
|  | 					|v\d+(?:[.]\d+){2,})? # dotted-decimal v-string | ||||||
|  | 				[{;] | ||||||
|  | 			/mgx; | ||||||
|  | 
 | ||||||
|  | 		# check if any inner package defined in the to be loaded script has | ||||||
|  | 		# already been defined by another script | ||||||
|  | 		my @conflicts; | ||||||
|  | 		for my $inner ( @inner_packages ) { | ||||||
|  | 			if( exists $owner_package{ $inner } ) { | ||||||
|  | 				push @conflicts, $inner; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		# report conflicts and bail out | ||||||
|  | 		if( @conflicts ) { | ||||||
|  | 			my $error_message = | ||||||
|  | 				"'$file' won't be loaded due to conflicting inner packages:\n"; | ||||||
|  | 			for my $conflict_package ( @conflicts ) { | ||||||
|  | 				$error_message .= "   $conflict_package already defined in " . | ||||||
|  | 					pkg_info($owner_package{ $conflict_package })->{filename}."\n"; | ||||||
|  | 			} | ||||||
|  | 			Xchat::print( $error_message ); | ||||||
|  | 
 | ||||||
|  | 			return 2; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		my $full_path = File::Spec->rel2abs( $file ); | 		my $full_path = File::Spec->rel2abs( $file ); | ||||||
| 		$source =~ s/^/#line 1 "$full_path"\n\x7Bpackage $package;/; | 		$source =~ s/^/#line 1 "$full_path"\n\x7Bpackage $package;/; | ||||||
| 
 | 
 | ||||||
|  | @ -64,6 +108,8 @@ sub load { | ||||||
| 			$source =~ s/\Z/\x7D/; | 			$source =~ s/\Z/\x7D/; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		$scripts{$package}{inner_packages} = [ @inner_packages ]; | ||||||
|  | 		@owner_package{ @inner_packages } = ($package) x @inner_packages; | ||||||
| 		_do_eval( $source ); | 		_do_eval( $source ); | ||||||
| 
 | 
 | ||||||
| 		unless( exists $scripts{$package}{gui_entry} ) { | 		unless( exists $scripts{$package}{gui_entry} ) { | ||||||
|  | @ -120,11 +166,14 @@ sub unload { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 		if( exists $pkg_info->{gui_entry} ) { | 		if( exists $pkg_info->{gui_entry} ) { | ||||||
| 			plugingui_remove( $pkg_info->{gui_entry} ); | 			plugingui_remove( $pkg_info->{gui_entry} ); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
|  | 		delete @owner_package{ @{$pkg_info->{inner_packages}} }; | ||||||
|  | 		for my $inner_package ( @{$pkg_info->{inner_packages}} ) { | ||||||
|  | 			Symbol::delete_package( $inner_package ); | ||||||
|  | 		} | ||||||
| 		Symbol::delete_package( $package ); | 		Symbol::delete_package( $package ); | ||||||
| 		delete $scripts{$package}; | 		delete $scripts{$package}; | ||||||
| 		return Xchat::EAT_ALL; | 		return Xchat::EAT_ALL; | ||||||
|  | @ -207,7 +256,7 @@ sub find_external_pkg { | ||||||
| 	my $level = 1; | 	my $level = 1; | ||||||
| 
 | 
 | ||||||
| 	while( my @frame = caller( $level ) ) { | 	while( my @frame = caller( $level ) ) { | ||||||
| 		return @frame if $frame[0] !~ /^Xchat/; | 		return @frame if $frame[0] !~ /(?:^IRC$|^Xchat)/; | ||||||
| 		$level++; | 		$level++; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -221,10 +270,20 @@ sub find_pkg { | ||||||
| 		$level++; | 		$level++; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	my $current_package = get_current_package(); | ||||||
|  | 	if( defined $current_package ) { | ||||||
|  | 		return $current_package; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	my @frame = find_external_pkg(); | 	my @frame = find_external_pkg(); | ||||||
| 	my $location; | 	my $location; | ||||||
| 
 | 
 | ||||||
| 	if( $frame[0] or $frame[1] ) { | 	if( $frame[0] or $frame[1] ) { | ||||||
|  | 		my $calling_package = $frame[0]; | ||||||
|  | 		if( defined( my $owner = $owner_package{ $calling_package } ) ) { | ||||||
|  | 			return $owner; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		$location = $frame[1] ? $frame[1] : "package $frame[0]"; | 		$location = $frame[1] ? $frame[1] : "package $frame[0]"; | ||||||
| 		$location .= " line $frame[2]"; | 		$location .= " line $frame[2]"; | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -239,10 +298,6 @@ sub fix_callback { | ||||||
| 	my ($package, $callback) = @_; | 	my ($package, $callback) = @_; | ||||||
| 	 | 	 | ||||||
| 	unless( ref $callback ) { | 	unless( ref $callback ) { | ||||||
| 		# change the package to the correct one in case it was hardcoded |  | ||||||
| 		$callback =~ s/^.*:://; |  | ||||||
| 		$callback = qq[${package}::$callback]; |  | ||||||
| 
 |  | ||||||
| 		no strict 'subs'; | 		no strict 'subs'; | ||||||
| 		$callback = \&{$callback}; | 		$callback = \&{$callback}; | ||||||
| 	} | 	} | ||||||
|  | @ -250,4 +305,15 @@ sub fix_callback { | ||||||
| 	return $callback; | 	return $callback; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub get_current_package { | ||||||
|  | 	return $current_package; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub set_current_package { | ||||||
|  | 	my $old_package = $current_package; | ||||||
|  | 	$current_package = shift; | ||||||
|  | 
 | ||||||
|  | 	return $old_package; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 1 | 1 | ||||||
|  |  | ||||||
|  | @ -317,6 +317,14 @@ array2av (char *array[]) | ||||||
| 	return av; | 	return av; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* sets $Xchat::Embed::current_package */ | ||||||
|  | static void | ||||||
|  | set_current_package (SV *package) | ||||||
|  | { | ||||||
|  | 	SV *current_package = get_sv ("Xchat::Embed::current_package", 1); | ||||||
|  | 	SvSetSV_nosteal (current_package, package); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int | static int | ||||||
| fd_cb (int fd, int flags, void *userdata) | fd_cb (int fd, int flags, void *userdata) | ||||||
| { | { | ||||||
|  | @ -332,7 +340,9 @@ fd_cb (int fd, int flags, void *userdata) | ||||||
| 	XPUSHs (data->userdata); | 	XPUSHs (data->userdata); | ||||||
| 	PUTBACK; | 	PUTBACK; | ||||||
| 
 | 
 | ||||||
|  | 	set_current_package (data->package); | ||||||
| 	count = call_sv (data->callback, G_EVAL); | 	count = call_sv (data->callback, G_EVAL); | ||||||
|  | 	set_current_package (&PL_sv_undef); | ||||||
| 	SPAGAIN; | 	SPAGAIN; | ||||||
| 
 | 
 | ||||||
| 	if (SvTRUE (ERRSV)) { | 	if (SvTRUE (ERRSV)) { | ||||||
|  | @ -390,7 +400,10 @@ timer_cb (void *userdata) | ||||||
| 	if (data->ctx) { | 	if (data->ctx) { | ||||||
| 		xchat_set_context (ph, data->ctx); | 		xchat_set_context (ph, data->ctx); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	set_current_package (data->package); | ||||||
| 	count = call_sv (data->callback, G_EVAL); | 	count = call_sv (data->callback, G_EVAL); | ||||||
|  | 	set_current_package (&PL_sv_undef); | ||||||
| 	SPAGAIN; | 	SPAGAIN; | ||||||
| 
 | 
 | ||||||
| 	if (SvTRUE (ERRSV)) { | 	if (SvTRUE (ERRSV)) { | ||||||
|  | @ -447,7 +460,9 @@ server_cb (char *word[], char *word_eol[], void *userdata) | ||||||
| 	PUTBACK; | 	PUTBACK; | ||||||
| 
 | 
 | ||||||
| 	data->depth++; | 	data->depth++; | ||||||
|  | 	set_current_package (data->package); | ||||||
| 	count = call_sv (data->callback, G_EVAL); | 	count = call_sv (data->callback, G_EVAL); | ||||||
|  | 	set_current_package (&PL_sv_undef); | ||||||
| 	data->depth--; | 	data->depth--; | ||||||
| 	SPAGAIN; | 	SPAGAIN; | ||||||
| 	if (SvTRUE (ERRSV)) { | 	if (SvTRUE (ERRSV)) { | ||||||
|  | @ -494,7 +509,9 @@ command_cb (char *word[], char *word_eol[], void *userdata) | ||||||
| 	PUTBACK; | 	PUTBACK; | ||||||
| 
 | 
 | ||||||
| 	data->depth++; | 	data->depth++; | ||||||
|  | 	set_current_package (data->package); | ||||||
| 	count = call_sv (data->callback, G_EVAL); | 	count = call_sv (data->callback, G_EVAL); | ||||||
|  | 	set_current_package (&PL_sv_undef); | ||||||
| 	data->depth--; | 	data->depth--; | ||||||
| 	SPAGAIN; | 	SPAGAIN; | ||||||
| 	if (SvTRUE (ERRSV)) { | 	if (SvTRUE (ERRSV)) { | ||||||
|  | @ -568,7 +585,9 @@ print_cb (char *word[], void *userdata) | ||||||
| 	PUTBACK; | 	PUTBACK; | ||||||
| 
 | 
 | ||||||
| 	data->depth++; | 	data->depth++; | ||||||
|  | 	set_current_package (data->package); | ||||||
| 	count = call_sv (data->callback, G_EVAL); | 	count = call_sv (data->callback, G_EVAL); | ||||||
|  | 	set_current_package (&PL_sv_undef); | ||||||
| 	data->depth--; | 	data->depth--; | ||||||
| 	SPAGAIN; | 	SPAGAIN; | ||||||
| 	if (SvTRUE (ERRSV)) { | 	if (SvTRUE (ERRSV)) { | ||||||
|  | @ -843,31 +862,32 @@ XS (XS_Xchat_hook_server) | ||||||
| 	int pri; | 	int pri; | ||||||
| 	SV *callback; | 	SV *callback; | ||||||
| 	SV *userdata; | 	SV *userdata; | ||||||
|  | 	SV *package; | ||||||
| 	xchat_hook *hook; | 	xchat_hook *hook; | ||||||
| 	HookData *data; | 	HookData *data; | ||||||
| 
 | 
 | ||||||
| 	dXSARGS; | 	dXSARGS; | ||||||
| 
 | 
 | ||||||
| 	if (items != 4) { | 	if (items != 5) { | ||||||
| 		xchat_print (ph, | 		xchat_print (ph, | ||||||
| 						 "Usage: Xchat::Internal::hook_server(name, priority, callback, userdata)"); | 						 "Usage: Xchat::Internal::hook_server(name, priority, callback, userdata, package)"); | ||||||
| 	} else { | 	} else { | ||||||
| 		name = SvPV_nolen (ST (0)); | 		name = SvPV_nolen (ST (0)); | ||||||
| 		pri = (int) SvIV (ST (1)); | 		pri = (int) SvIV (ST (1)); | ||||||
| 		callback = ST (2); | 		callback = ST (2); | ||||||
| 		userdata = ST (3); | 		userdata = ST (3); | ||||||
|  | 		package = ST (4); | ||||||
| 		data = NULL; | 		data = NULL; | ||||||
| 		data = malloc (sizeof (HookData)); | 		data = malloc (sizeof (HookData)); | ||||||
| 		if (data == NULL) { | 		if (data == NULL) { | ||||||
| 			XSRETURN_UNDEF; | 			XSRETURN_UNDEF; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		data->callback = sv_mortalcopy (callback); | 		data->callback = newSVsv (callback); | ||||||
| 		SvREFCNT_inc (data->callback); | 		data->userdata = newSVsv (userdata); | ||||||
| 		data->userdata = sv_mortalcopy (userdata); |  | ||||||
| 		SvREFCNT_inc (data->userdata); |  | ||||||
| 		data->depth = 0; | 		data->depth = 0; | ||||||
| 		data->package = NULL; | 		data->package = newSVsv (package); | ||||||
|  | 
 | ||||||
| 		hook = xchat_hook_server (ph, name, pri, server_cb, data); | 		hook = xchat_hook_server (ph, name, pri, server_cb, data); | ||||||
| 
 | 
 | ||||||
| 		XSRETURN_IV (PTR2IV (hook)); | 		XSRETURN_IV (PTR2IV (hook)); | ||||||
|  | @ -883,26 +903,28 @@ XS (XS_Xchat_hook_command) | ||||||
| 	SV *callback; | 	SV *callback; | ||||||
| 	char *help_text = NULL; | 	char *help_text = NULL; | ||||||
| 	SV *userdata; | 	SV *userdata; | ||||||
|  | 	SV *package; | ||||||
| 	xchat_hook *hook; | 	xchat_hook *hook; | ||||||
| 	HookData *data; | 	HookData *data; | ||||||
| 
 | 
 | ||||||
| 	dXSARGS; | 	dXSARGS; | ||||||
| 
 | 
 | ||||||
| 	if (items != 5) { | 	if (items != 6) { | ||||||
| 		xchat_print (ph, | 		xchat_print (ph, | ||||||
| 						 "Usage: Xchat::Internal::hook_command(name, priority, callback, help_text, userdata)"); | 						 "Usage: Xchat::Internal::hook_command(name, priority, callback, help_text, userdata, package)"); | ||||||
| 	} else { | 	} else { | ||||||
| 		name = SvPV_nolen (ST (0)); | 		name = SvPV_nolen (ST (0)); | ||||||
| 		pri = (int) SvIV (ST (1)); | 		pri = (int) SvIV (ST (1)); | ||||||
| 		callback = ST (2); | 		callback = ST (2); | ||||||
| 
 | 
 | ||||||
| 		/* leave the help text has NULL if the help text is undefined to avoid
 | 		/* leave the help text as NULL if the help text is undefined to avoid
 | ||||||
| 		 * overriding the default help message for builtin commands */ | 		 * overriding the default help message for builtin commands */ | ||||||
| 		if (SvOK(ST (3))) { | 		if (SvOK(ST (3))) { | ||||||
| 			help_text = SvPV_nolen (ST (3)); | 			help_text = SvPV_nolen (ST (3)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		userdata = ST (4); | 		userdata = ST (4); | ||||||
|  | 		package = ST (5); | ||||||
| 		data = NULL; | 		data = NULL; | ||||||
| 
 | 
 | ||||||
| 		data = malloc (sizeof (HookData)); | 		data = malloc (sizeof (HookData)); | ||||||
|  | @ -910,12 +932,10 @@ XS (XS_Xchat_hook_command) | ||||||
| 			XSRETURN_UNDEF; | 			XSRETURN_UNDEF; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		data->callback = sv_mortalcopy (callback); | 		data->callback = newSVsv (callback); | ||||||
| 		SvREFCNT_inc (data->callback); | 		data->userdata = newSVsv (userdata); | ||||||
| 		data->userdata = sv_mortalcopy (userdata); |  | ||||||
| 		SvREFCNT_inc (data->userdata); |  | ||||||
| 		data->depth = 0; | 		data->depth = 0; | ||||||
| 		data->package = NULL; | 		data->package = newSVsv (package); | ||||||
| 		hook = xchat_hook_command (ph, name, pri, command_cb, help_text, data); | 		hook = xchat_hook_command (ph, name, pri, command_cb, help_text, data); | ||||||
| 
 | 
 | ||||||
| 		XSRETURN_IV (PTR2IV (hook)); | 		XSRETURN_IV (PTR2IV (hook)); | ||||||
|  | @ -932,30 +952,30 @@ XS (XS_Xchat_hook_print) | ||||||
| 	int pri; | 	int pri; | ||||||
| 	SV *callback; | 	SV *callback; | ||||||
| 	SV *userdata; | 	SV *userdata; | ||||||
|  | 	SV *package; | ||||||
| 	xchat_hook *hook; | 	xchat_hook *hook; | ||||||
| 	HookData *data; | 	HookData *data; | ||||||
| 	dXSARGS; | 	dXSARGS; | ||||||
| 	if (items != 4) { | 	if (items != 5) { | ||||||
| 		xchat_print (ph, | 		xchat_print (ph, | ||||||
| 						 "Usage: Xchat::Internal::hook_print(name, priority, callback, userdata)"); | 						 "Usage: Xchat::Internal::hook_print(name, priority, callback, userdata, package)"); | ||||||
| 	} else { | 	} else { | ||||||
| 		name = SvPV_nolen (ST (0)); | 		name = SvPV_nolen (ST (0)); | ||||||
| 		pri = (int) SvIV (ST (1)); | 		pri = (int) SvIV (ST (1)); | ||||||
| 		callback = ST (2); | 		callback = ST (2); | ||||||
| 		data = NULL; | 		data = NULL; | ||||||
| 		userdata = ST (3); | 		userdata = ST (3); | ||||||
|  | 		package = ST (4); | ||||||
| 
 | 
 | ||||||
| 		data = malloc (sizeof (HookData)); | 		data = malloc (sizeof (HookData)); | ||||||
| 		if (data == NULL) { | 		if (data == NULL) { | ||||||
| 			XSRETURN_UNDEF; | 			XSRETURN_UNDEF; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		data->callback = sv_mortalcopy (callback); | 		data->callback = newSVsv (callback); | ||||||
| 		SvREFCNT_inc (data->callback); | 		data->userdata = newSVsv (userdata); | ||||||
| 		data->userdata = sv_mortalcopy (userdata); |  | ||||||
| 		SvREFCNT_inc (data->userdata); |  | ||||||
| 		data->depth = 0; | 		data->depth = 0; | ||||||
| 		data->package = NULL; | 		data->package = newSVsv (package); | ||||||
| 		hook = xchat_hook_print (ph, name, pri, print_cb, data); | 		hook = xchat_hook_print (ph, name, pri, print_cb, data); | ||||||
| 
 | 
 | ||||||
| 		XSRETURN_IV (PTR2IV (hook)); | 		XSRETURN_IV (PTR2IV (hook)); | ||||||
|  | @ -990,13 +1010,10 @@ XS (XS_Xchat_hook_timer) | ||||||
| 			XSRETURN_UNDEF; | 			XSRETURN_UNDEF; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		data->callback = sv_mortalcopy (callback); | 		data->callback = newSVsv (callback); | ||||||
| 		SvREFCNT_inc (data->callback); | 		data->userdata = newSVsv (userdata); | ||||||
| 		data->userdata = sv_mortalcopy (userdata); |  | ||||||
| 		SvREFCNT_inc (data->userdata); |  | ||||||
| 		data->ctx = xchat_get_context (ph); | 		data->ctx = xchat_get_context (ph); | ||||||
| 		data->package = sv_mortalcopy (package); | 		data->package = newSVsv (package); | ||||||
| 		SvREFCNT_inc (data->package); |  | ||||||
| 		hook = xchat_hook_timer (ph, timeout, timer_cb, data); | 		hook = xchat_hook_timer (ph, timeout, timer_cb, data); | ||||||
| 		data->hook = hook; | 		data->hook = hook; | ||||||
| 
 | 
 | ||||||
|  | @ -1012,6 +1029,7 @@ XS (XS_Xchat_hook_fd) | ||||||
| 	SV *callback; | 	SV *callback; | ||||||
| 	int flags; | 	int flags; | ||||||
| 	SV *userdata; | 	SV *userdata; | ||||||
|  | 	SV *package; | ||||||
| 	xchat_hook *hook; | 	xchat_hook *hook; | ||||||
| 	HookData *data; | 	HookData *data; | ||||||
| 
 | 
 | ||||||
|  | @ -1025,6 +1043,7 @@ XS (XS_Xchat_hook_fd) | ||||||
| 		callback = ST (1); | 		callback = ST (1); | ||||||
| 		flags = (int) SvIV (ST (2)); | 		flags = (int) SvIV (ST (2)); | ||||||
| 		userdata = ST (3); | 		userdata = ST (3); | ||||||
|  | 		package = ST (4); | ||||||
| 		data = NULL; | 		data = NULL; | ||||||
| 
 | 
 | ||||||
| #ifdef WIN32 | #ifdef WIN32 | ||||||
|  | @ -1045,11 +1064,10 @@ XS (XS_Xchat_hook_fd) | ||||||
| 			XSRETURN_UNDEF; | 			XSRETURN_UNDEF; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		data->callback = sv_mortalcopy (callback); | 		data->callback = newSVsv (callback); | ||||||
| 		SvREFCNT_inc (data->callback); | 		data->userdata = newSVsv (userdata); | ||||||
| 		data->userdata = sv_mortalcopy (userdata); | 		data->depth = 0; | ||||||
| 		SvREFCNT_inc (data->userdata); | 		data->package = newSVsv (package); | ||||||
| 		data->package = NULL; |  | ||||||
| 		hook = xchat_hook_fd (ph, fd, flags, fd_cb, data); | 		hook = xchat_hook_fd (ph, fd, flags, fd_cb, data); | ||||||
| 		data->hook = hook; | 		data->hook = hook; | ||||||
| 
 | 
 | ||||||
|  | @ -1084,6 +1102,7 @@ XS (XS_Xchat_unhook) | ||||||
| 			if (userdata->package != NULL) { | 			if (userdata->package != NULL) { | ||||||
| 				SvREFCNT_dec (userdata->package); | 				SvREFCNT_dec (userdata->package); | ||||||
| 			} | 			} | ||||||
|  | 
 | ||||||
| 			free (userdata); | 			free (userdata); | ||||||
| 		} | 		} | ||||||
| 		XSRETURN (retCount); | 		XSRETURN (retCount); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue