#!/usr/bin/perl
#
# HPP - A simple HTML Pre-processor
# (C) Copyright 1998, 2000 by Nicholas A. Rusnov
# Portions (C) Copyright 1998 by Etherbox Software
#
# Licensed under the Gnu General Public License
# You may copy this file freely, modify, distribute modifed
# copies, spindle, fold, bend and mutilate at will, however,
# I am not responsible for any failure to operate or damages
# resulting from said failure, or any damages at all for that
# matter.
#
use Getopt::Long;
use SelfLoader;
use IO::File;
$debug = 0;
%asserts = {};
$version = '1.2';
%defines = {'HPPVERSION' => $version};
@includes = ();
@files = ();
sub init
{
my %options;
GetOptions(\%options,"help","h","D=s%","A=s@","I=s@","pod","debug");
if ($options{'help'} || $options{'h'})
{
help_msg();
exit;
}
if ($options{'pod'})
{
system("pod2text $0 | more");
exit;
}
if ($#ARGV != 1)
{
help_msg();
print "\nIncorrect number of arguments: need exactly 2 (input and output files).\n";
exit 1;
}
($infile,$outfile) = @ARGV;
if (!-f $infile)
{
print "Bad Input File $infile.\n";
exit 2;
}
if (-f $outfile)
{
system("mv $outfile $outfile"."~");
}
if ($options{'D'})
{
my $defs=$options{'D'};
my $foo;
for $foo (keys(%$defs))
{
$defines{$foo}=$$defs{$foo};
}
}
if ($options{'I'})
{
my $incs=$options{'I'};
my $foo;
for $foo (@$incs)
{
if ($foo !~ /.*\/$/)
{
$foo .= "/";
}
push @includes,$foo;
}
}
if ($options{'A'})
{
my $ass=$options{'A'};
my $foo;
my @baz;
for $foo (@$ass)
{
@baz = split/-/,$foo,2;
$quux = [];
if ($asserts{$baz[0]})
{
$quux = $asserts{$baz[0]};
}
push @$quux,$baz[1];
$asserts{$baz[0]} = $quux;
}
}
if ($options{'debug'})
{
$debug = 1;
}
}
init();
push @files,$infile;
open OUTF, ">>$outfile";
doone();
close OUTF;
if ($debug)
{
dump_table();
}
__DATA__
sub action
{
my $line = shift;
my $file = shift;
if ($line =~ /^\#endif/i)
{
$noact = 0;
return;
}
if ($line =~ /^\#else/i)
{
if ($noact)
{
$noact = 0;
}
else
{
$noact = 1;
}
return;
}
return if ($noact);
if ($line =~ /^\#include\s+\"(\S+)\"/i)
{
if (-f $1)
{
unshift @files,$1;
doone();
}
else
{
die "Can't find include file $1\n";
}
return;
}
if ($line =~ /^\#include\s+\<(\S+)\>/i)
{
my $foo;
my $file = $1;
for $foo (@includes)
{
if (-f $foo.$file)
{
unshift @files,$foo.$file;
doone();
}
}
return;
}
if ($line =~ /^\#define\s+(\S+)\s?\=\s?(\S+)/i)
{
$defines{$1} = $2;
return;
}
if ($line =~ /^\#assert\s+(\S+)\s?\((.+)\)/i)
{
$quux = [];
if ($asserts{$1})
{
$quux = $asserts{$1};
}
push @$quux,$2;
$asserts{$1} = $quux;
return;
}
if ($line =~ /^\#v(\S+)/i)
{
if ($defines{$1})
{
print OUTF $defines{$1}."\n";
}
return;
}
if ($line =~ /^\#ifdef\s+(\S+)\s?/i)
{
$noact = 1 unless $defines{$1};
return;
}
if ($line =~ /^\#ifndef\s+(\S+)\s?/i)
{
$noact = 1 if $defines{$1};
return;
}
if ($line =~ /^\#if\s+(.*)/i)
{
$line = $1;
if ($line =~ /^\#(\S+)\s+\((\S+)\)$/i)
{
if (!($asserts{$1}))
{
$noact = 1;
return;
}
my $baz = $asserts{$1};
my $bang = $2;
if (!(grep(/$bang/,@$baz)))
{
$noact = 1;
return;
}
}
return;
}
print OUTF "\n";
}
sub doone
{
my $file = $files[0];
my $line;
my $handle = new IO::File;
$handle->open($file) || die "can't open $file.";
while (<$handle>)
{
$line = $_;
if ($line =~ /^\#.*/)
{
chomp $line;
# do special stuff..
action($line,$file);
}
else
{
print OUTF "$line" if (!$noact);
}
}
$noact = 0;
shift(@files);
}
sub help_msg
{
print "HPP - A simple HTML Preprocessor (version $version)\n";
print <<__help__;
usage: $0 [-D /define/] [-A /assert/] [-I includedir] infile outfile
$0 -pod prints out the POD documentation.
define syntax: VARIABLE=value
assert syntax: name-assertion
__help__
}
sub dump_table
{
print "asserts..\n";
for $foo (keys(%asserts))
{
$quux = $asserts{$foo};
for $bar (@$quux)
{
print "$foo ( $bar ) \n";
}
}
print "defines..\n";
for $foo (keys(%defines))
{
print "$foo = ".$defines{$foo}."\n";
}
}
__END__
=head1 NAME
hpp - A simple HTML Pre-processor.
=head1 SYNOPSIS
=over 4
hpp [B<-D> I=I] [B<-A> I-I] [B<-I> I=I] I I
=back
=head1 OPTIONS
=over 4
=item B<-D>
Create a new definition. Takes the argument I=I.
=item B<-A>
Create a new assertion or add a value to an already-existing assertion. Takes the argument I-I
=item B<-I>
Add a directory to the include directory list.
=back
=head1 SUPPORTED DIRECTIVES
=over 4
=item B<#include>
Include a file, much like in B. If the filename is enclosed in <>s, it is taken from the include directories. Otherwise it should be enclosed in ""s, in which case its taken from the CWD.
=item B<#define>
Define a variable to a value. Unlike B, variables I have values. Syntax is I=I.
=item B<#assert>
Much like #assert in B, takes an argument in the form I(I).
=item B<#v>
Unlike B, hpp does not dereference variables created with #define everywhere in the input stream. It only dereferences them when it finds #vI.
=item B<#else> and B<#endif>
#endif I terminate an #if. #else may occur anywhere between an #if and an #endif.
=item B<#if>
hpp only recognizes the syntax, #if #I(I) for if.
=item B<#ifdef> and B<#ifndef>
hpp only recognizes wether or not a variable exists, and can't compare the value of the variable (yet).
=back
=head1 BUGS
=over 4
Incomplete #if/#ifdef/#ifndef support. No #elseif support. Dangerous #if nesting. Include paths have to be absolute and are broken in general.
=back
=head1 AUTHOR and COPYRIGHT
HPP - A simple HTML Pre-processor
(C) Copyright 1998, 2000 by Nicholas A. Rusnov
Portions (C) Copyright 1998 by Etherbox Software
Licensed under the Gnu General Public License
You may copy this file freely, modify, distribute modifed
copies, spindle, fold, bend and mutilate at will, however,
I am not responsible for any failure to operate or damages
resulting from said failure, or any damages at all for that
matter.
=cut