########################################################################
#
# function is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.  If not, write to
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
#
########################################################################
#
#  Project      :  File Preprocessor - function module
#  Filename     :  $RCSfile: function.pm,v $
#  Author       :  $Author: darren $
#  Maintainer   :  Darren Miller: darren@cabaret.demon.co.uk
#  File version :  $Revision: 1.2 $
#  Last changed :  $Date: 2001/07/16 12:35:25 $
#  Description  :  This module adds the function keyword which allows you
#                  to have macros which call Perl functions
#                  being replaces
#  Licence      :  GNU copyleft
#
########################################################################
# THIS IS A FILEPP MODULE, YOU NEED FILEPP TO USE IT!!!
# usage: filepp -m function.pm <files>
########################################################################

package Function;

use strict "vars";
use strict "subs";

# version number of module
my $VERSION = '1.0.0';

# hash table of users functions
my %Functions = ();


########################################################################
# AddFunction(macro, function) 
# adds a function to list, inputs:
# macro:    macro which will call function
# function: function to call when macro found
########################################################################
sub AddFunction {
    my ($macro, $function) = @_;
    $Functions{$macro} = $function;
     Filepp::Debug("Added function macro $macro which calls $function");
}

########################################################################
# Function($string)
# keyword frontend to AddFunction
########################################################################
sub Function {
    my $input = shift;
    my ($macro, $function) = split(/\s+/, $input, 2);
    AddFunction($macro, $function);
}
Filepp::AddKeyword("function", "Function::Function");


##############################################################################
# RemoveFunction(macro)
# macro is deleted from list, all occurrences of macro found in
# document are ignored.
##############################################################################
sub RemoveFunction
{
    my $macro = shift;
    delete $Functions{$macro};
    Filepp::Debug("Removed function macro $macro");
}

########################################################################
# Rmunction($string)
# keyword frontend to RemoveFunction
########################################################################
sub Rmfunction {
    my $input = shift;
    my ($macro) = split(/\s+/, $input, 1);
    RemoveFunction($macro);
}
Filepp::AddKeyword("rmfunction", "Function::Rmfunction");


########################################################################
# $string = RunFunctions($string)
# main processing function - takes in input line and searches for any
# functions in the list and then runs them
########################################################################
sub RunFunctions
{
    my $input = shift;
    my $output = "";   # initialise output to empty string
    
    OUTER : while($input =~ /\S/) {
	my ($macro, $string);
	# run function macros which are "words" only
	my @Words = split(/(\w+)/, $input, 2);
	$output =  $output.$Words[0];
	if($#Words == 2) { $macro = $Words[1]; $input = $Words[2]; }
	else             { $input = ""; last OUTER; }
	
	# check if macro is at start of string and is a proper function call
	# (must be followed by a "(" )
	if(exists($Functions{$macro}) && Filepp::DefineArgsUsed($input)) {
	    # get function and the arguments for the function
	    my $function = $Functions{$macro};
	    my @Args = Filepp::ParseArgs($input);
	    # last element of args is remainder of input
	    $input = pop(@Args);
	    
	    # check for any nested functions in Args and call them now
	    my $i;
	    for($i=0; $i<=$#Args; $i++) {
		$Args[$i] = RunFunctions($Args[$i]);
	    }
	    
	    # run the function and add result to output
	    my $returned = $function->(@Args);
	    Filepp::Debug("Function $macro returned $returned");
	    $output = $output.$returned;
	}
	# macro not matched, add to output and move swiftly on
	else { $output = $output.$macro; }
    }
    return $output.$input;
}
Filepp::AddProcessor("Function::RunFunctions");


return 1;

########################################################################
# End of file
########################################################################
