516 lines
11 KiB
Plaintext
516 lines
11 KiB
Plaintext
|
#!/usr/bin/perl -w -- # -*- Perl -*-
|
||
|
#
|
||
|
# xslns-build - generate a parallel set of DocBook5 namespaced
|
||
|
# stylesheet directories from a directory of
|
||
|
# non-namespaced stylesheets.
|
||
|
#
|
||
|
|
||
|
my $Usage = "
|
||
|
USAGE:
|
||
|
$0 input-dir output-dir
|
||
|
|
||
|
where:
|
||
|
input-dir is the directory containing namespaced stylesheets
|
||
|
output-dir is the destination for the non-namespaced stylesheets
|
||
|
|
||
|
Note: an existing output-dir will be completely removed
|
||
|
before creating new output.
|
||
|
";
|
||
|
|
||
|
#######################################################
|
||
|
# Modules to use
|
||
|
#
|
||
|
use strict;
|
||
|
use IO::File;
|
||
|
use File::Basename;
|
||
|
use File::Path;
|
||
|
use File::Find;
|
||
|
use File::Copy;
|
||
|
|
||
|
#######################################################
|
||
|
# Global variables
|
||
|
#
|
||
|
my $srcdir;
|
||
|
my $destdir;
|
||
|
|
||
|
my @dirlist;
|
||
|
my @passthru;
|
||
|
my @xslfiles;
|
||
|
|
||
|
# Regular expressions
|
||
|
|
||
|
# namespace name regexp
|
||
|
my $ns = "[A-Za-z]+";
|
||
|
# other names
|
||
|
my $n = "[A-Za-z][A-Za-z0-9]+";
|
||
|
# xml names
|
||
|
my $w = "[A-Za-z][-A-Za-z0-9._#]+";
|
||
|
# docbook element names (lowercase and numbers)
|
||
|
my $dbname = "[a-z][a-z0-9]+";
|
||
|
|
||
|
# Don't delete namespace to any xsl files in these directories
|
||
|
my @PassthruDirs = (
|
||
|
'extensions',
|
||
|
'profiling',
|
||
|
'images',
|
||
|
'tools',
|
||
|
'build',
|
||
|
'website',
|
||
|
'wordml',
|
||
|
);
|
||
|
|
||
|
# Don't remove namespace to these particular files
|
||
|
my @PassthruFiles = (
|
||
|
'html-rtf.xsl',
|
||
|
'html2xhtml.xsl',
|
||
|
'xsl2profile.xsl',
|
||
|
'olink.xsl',
|
||
|
'addns.xsl',
|
||
|
'stripns.xsl',
|
||
|
);
|
||
|
|
||
|
umask 002;
|
||
|
|
||
|
#######################################################
|
||
|
# main
|
||
|
#
|
||
|
|
||
|
# Get the source and output directories
|
||
|
|
||
|
$srcdir = $ARGV[0];
|
||
|
$destdir = $ARGV[1];
|
||
|
|
||
|
unless ( $srcdir ) {
|
||
|
print "ERROR: must specify input directory of non-namespaced "
|
||
|
. " stylesheets. Exiting.\n";
|
||
|
die "$Usage\n";
|
||
|
}
|
||
|
|
||
|
unless ( -d $srcdir ) {
|
||
|
print "ERROR: specified input directory does not exist. Exiting.\n";
|
||
|
die "$Usage\n";
|
||
|
}
|
||
|
|
||
|
unless ( $destdir ) {
|
||
|
print "ERROR: must specify output directory. Exiting.\n";
|
||
|
die "$Usage\n";
|
||
|
|
||
|
}
|
||
|
|
||
|
# Remove any previous output completely
|
||
|
|
||
|
if ( -d $destdir) {
|
||
|
print "Removing old output directory $destdir.\n";
|
||
|
|
||
|
unless ( rmtree($destdir) ) {
|
||
|
die "ERROR: cannot remove previous output directory. Exiting.\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Create new output directory.
|
||
|
print "Creating the output directory $destdir.\n";
|
||
|
|
||
|
unless ( mkpath($destdir) ) {
|
||
|
die "ERROR: cannot create output directory $destdir.\n";
|
||
|
}
|
||
|
|
||
|
copyDirectories($srcdir);
|
||
|
|
||
|
copyPassthru();
|
||
|
|
||
|
copyXsl();
|
||
|
|
||
|
addFiles();
|
||
|
|
||
|
|
||
|
#######################################################
|
||
|
# copyDirectories - create the output directories
|
||
|
#
|
||
|
sub copyDirectories {
|
||
|
|
||
|
my ($src) = @_;
|
||
|
|
||
|
# populate @dirlist
|
||
|
find(\&dirlist, $src );
|
||
|
|
||
|
foreach my $d (@dirlist) {
|
||
|
$d =~ s/$srcdir/$destdir/;
|
||
|
print "$d\n";
|
||
|
mkdir $d;
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
#######################################################
|
||
|
# dirlist - list directories (used by find)
|
||
|
#
|
||
|
sub dirlist {
|
||
|
|
||
|
if ( -d $_ ) {
|
||
|
push(@dirlist, $File::Find::name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#######################################################
|
||
|
# copyPassthru - copy non-XSL files to output
|
||
|
#
|
||
|
sub copyPassthru {
|
||
|
|
||
|
# populate @passthru
|
||
|
find(\&passthruFiles, $srcdir );
|
||
|
|
||
|
foreach my $f (@passthru) {
|
||
|
my $dest = $f;
|
||
|
$dest =~ s/$srcdir/$destdir/;
|
||
|
print STDOUT "$f\n";
|
||
|
copy ($f, $dest);
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
#######################################################
|
||
|
# passthruFiles - list non-xsl files to copy
|
||
|
#
|
||
|
sub passthruFiles {
|
||
|
|
||
|
if ( -f $_ ) {
|
||
|
unless ( /\.xsl$/ or /\.ent$/ ) {
|
||
|
push(@passthru, $File::Find::name);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#######################################################
|
||
|
# copyXsl - copy XSL files to output, possibly filtering
|
||
|
#
|
||
|
sub copyXsl {
|
||
|
|
||
|
# populate @xslfiles
|
||
|
find(\&xslFiles, $srcdir );
|
||
|
|
||
|
foreach my $f (@xslfiles) {
|
||
|
my $dest = $f;
|
||
|
$dest =~ s/$srcdir/$destdir/;
|
||
|
print STDOUT "$f\n";
|
||
|
|
||
|
my $basename = basename $f;
|
||
|
my $dirname = dirname $f;
|
||
|
$dest =~ m|^$destdir/(.*?)/|;
|
||
|
my $dir = $1;
|
||
|
if ( grep /^$basename$/,@PassthruFiles ) {
|
||
|
copy($f, $dest);
|
||
|
}
|
||
|
elsif ( grep /^$dir$/, @PassthruDirs ) {
|
||
|
copy($f, $dest);
|
||
|
}
|
||
|
else {
|
||
|
nsfilter($f, $dest);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
#######################################################
|
||
|
# xslFiles - list xsl files to process
|
||
|
#
|
||
|
sub xslFiles {
|
||
|
|
||
|
if ( -f $_ ) {
|
||
|
if ( /\.xsl$/ or /\.ent$/ ) {
|
||
|
push(@xslfiles, $File::Find::name);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#######################################################
|
||
|
# nsfilter - delete namespace prefix to element names
|
||
|
#
|
||
|
sub nsfilter {
|
||
|
|
||
|
my ($infile, $outfile) = @_;
|
||
|
|
||
|
# Open and read the whole file into $_ variable for parsing
|
||
|
my $Filehandle = IO::File->new($infile)
|
||
|
or die "Can't open file $infile $!\n";
|
||
|
read ($Filehandle, $_, -s $infile);
|
||
|
$Filehandle->close;
|
||
|
|
||
|
my $Output = IO::File->new("> $outfile")
|
||
|
or die "Cannot write to output file $outfile.\n";
|
||
|
|
||
|
# Set to autoflush
|
||
|
select($Output); $| = 1;
|
||
|
|
||
|
# delete the docbook5 namespace declaration in root element
|
||
|
|
||
|
s|xmlns:d="http://docbook.org/ns/docbook"\n?||s;
|
||
|
|
||
|
# remove namespace d from exclude-result-prefixes
|
||
|
# This version if only "d"
|
||
|
s|\s*exclude-result-prefixes\s*=\s*"d"\s*| |s;
|
||
|
# This version if d added to others at end
|
||
|
s|(exclude-result-prefixes\s*=\s*".*?)\s+d"|$1"|s;
|
||
|
# This version if d added at beginning
|
||
|
s|(exclude-result-prefixes\s*=\s*")d\s+(.*?")|$1$2|s;
|
||
|
# This version if d added in middle
|
||
|
s|(exclude-result-prefixes\s*=\s*".*?)\s+d\s+(.*?")|$1 $2|s;
|
||
|
|
||
|
# Convert addNS to stripNS
|
||
|
s|href="../common/addns.xsl"|href="../common/stripns.xsl"|sg;
|
||
|
|
||
|
s|addns\.xsl|stripns.xsl|sg;
|
||
|
s|with\.namespace|no.namespace|sg;
|
||
|
s|addNS|stripNS|sg;
|
||
|
s|(namesp\.\s+)add|$1cut|sg;
|
||
|
s|added namespace before|stripped namespace before|sg;
|
||
|
s|(Unable to )add( the namespace from )DB4( document)|$1strip$2DB5$3|sg;
|
||
|
|
||
|
# change namespace test from != to =
|
||
|
s|(namespace-uri\(/\*\)\s*)!=(\s*['"]http://docbook.org/ns/docbook['"])|$1=$2|sg;
|
||
|
|
||
|
# Set the db.prefix for template/titlepage.xsl
|
||
|
s|(<xsl:variable name="db.prefix">)d:(</xsl:variable>)|$1$2|sg;
|
||
|
|
||
|
# remove d: prefix to literal tocentry in maketoc.xsl
|
||
|
if ($infile =~ /maketoc/) {
|
||
|
s|d:(tocentry)|$1|sg;
|
||
|
}
|
||
|
|
||
|
# Process certain XSL attributes to remove d: namespace if needed
|
||
|
# and output everything using this while loop.
|
||
|
|
||
|
while ( /^(.*?)((match|select|test|count|from|use|elements)(\s*=\s*("|'))(.*?)(\5)|(select)(\s*=\s*("|'))(.*?)(\5))/sg ) {
|
||
|
|
||
|
my $notname = $1;
|
||
|
my $attname = $3;
|
||
|
my $prefix = $4;
|
||
|
my $attvalue = $6;
|
||
|
my $post = $7;
|
||
|
my $rest = $';
|
||
|
|
||
|
&filter($notname, $Output);
|
||
|
|
||
|
print $Output $attname . $prefix;
|
||
|
|
||
|
# parse the attribute value
|
||
|
while ( $attvalue =~ /^(.*?)($ns:)($n)(.*$)/sg ) {
|
||
|
|
||
|
# process the leading content which is not pass through
|
||
|
&fixnamespace($1, $Output);
|
||
|
|
||
|
if ( $2 eq 'd:' ) {
|
||
|
print $Output $3;
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
print $Output $2;
|
||
|
print $Output $3;
|
||
|
}
|
||
|
|
||
|
$attvalue = $4; # and recurse
|
||
|
}
|
||
|
|
||
|
&fixnamespace($attvalue, $Output);
|
||
|
|
||
|
print $Output $post;
|
||
|
|
||
|
$_ = $rest;
|
||
|
|
||
|
}
|
||
|
|
||
|
# print the leftovers
|
||
|
&filter($_, $Output);
|
||
|
|
||
|
close $Output;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
# fix any special case params like certain manpage params
|
||
|
# that put element names inside param string
|
||
|
|
||
|
sub filter {
|
||
|
my ($string, $Output) = @_;
|
||
|
|
||
|
# Fix up index ENTITY declarations
|
||
|
$string = &indexentitydecl($string);
|
||
|
|
||
|
while ( $string =~ m|^(.*?)(<xsl:param([^>]+[^/])>)(.*?)(</xsl:param>)|sg ) {
|
||
|
my $before = $1;
|
||
|
my $starttag = $2;
|
||
|
my $startstuff = $3;
|
||
|
my $value = $4;
|
||
|
my $endtag = $5;
|
||
|
my $rest = $';
|
||
|
|
||
|
$startstuff =~ /name="(.*?)"/;
|
||
|
my $pname = $1;
|
||
|
|
||
|
print $Output $before;
|
||
|
print $Output $starttag;
|
||
|
|
||
|
# add namespace to elements inside these params
|
||
|
if ( $pname =~ /(^refentry.manual.fallback.profile$|^refentry.source.fallback.profile$|^refentry.version.profile$|^refentry.date.profile$)/ ) {
|
||
|
|
||
|
# while ( $value =~ /^(.*?)(\$$w|$w\(|$ns:$n|$w:|db:$n|\@$n:$n|'.*?'|&$w;|\@$w|not \(|stringlength \(|normalize-space \()(.*$)/sg ) {
|
||
|
|
||
|
while ( $value =~ /^(.*?)($ns:)($n)(.*$)/sg ) {
|
||
|
|
||
|
# process the leading content which is not pass through
|
||
|
&fixnamespace($1, $Output);
|
||
|
|
||
|
if ( $2 eq 'd:' ) {
|
||
|
print $Output $3;
|
||
|
}
|
||
|
else {
|
||
|
print $Output $2;
|
||
|
print $Output $3;
|
||
|
}
|
||
|
$value = $4; # and recurse
|
||
|
}
|
||
|
|
||
|
&fixnamespace($value, $Output);
|
||
|
}
|
||
|
else {
|
||
|
print $Output $value;
|
||
|
}
|
||
|
|
||
|
print $Output $endtag;
|
||
|
|
||
|
$string = $rest;
|
||
|
|
||
|
}
|
||
|
|
||
|
print $Output $string;
|
||
|
|
||
|
}
|
||
|
|
||
|
sub indexentitydecl {
|
||
|
my ($string) = @_;
|
||
|
|
||
|
my $newstring = '';
|
||
|
|
||
|
while ( $string =~ m@^(.*?)(<!ENTITY\s+([\w.]+)\s+('|"))(.*?)(\4\s*>)@sg ) {
|
||
|
my $before = $1;
|
||
|
my $entitystart = $2;
|
||
|
my $entityname = $3;
|
||
|
my $value = $5;
|
||
|
my $entityend = $6;
|
||
|
my $rest = $';
|
||
|
|
||
|
$newstring .= $before;
|
||
|
$newstring .= $entitystart;
|
||
|
|
||
|
while ( $value =~ /^(.*?)($ns:)($n)(.*$)/sg ) {
|
||
|
|
||
|
# process the leading content which is not pass through
|
||
|
$newstring .= &namespacefilter($1);
|
||
|
|
||
|
if ( $2 eq 'd:' ) {
|
||
|
$newstring .= $3;
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
$newstring .= $2;
|
||
|
$newstring .= $3;
|
||
|
}
|
||
|
|
||
|
$value = $4; # and recurse
|
||
|
|
||
|
}
|
||
|
|
||
|
$newstring .= &namespacefilter($value);
|
||
|
|
||
|
$newstring .= $entityend;
|
||
|
|
||
|
$string = $rest;
|
||
|
|
||
|
}
|
||
|
|
||
|
$newstring .= $string;
|
||
|
|
||
|
return $newstring;
|
||
|
}
|
||
|
|
||
|
|
||
|
# prints a filtered string to the designated output
|
||
|
sub fixnamespace {
|
||
|
my ($string, $Output) = @_;
|
||
|
|
||
|
my $newstring = &namespacefilter($string);
|
||
|
print $Output $newstring;
|
||
|
}
|
||
|
|
||
|
# Returns a new string with namespace prefixes added
|
||
|
sub namespacefilter {
|
||
|
|
||
|
my ($string) = @_;
|
||
|
|
||
|
my $newstring = '';
|
||
|
|
||
|
while ( $string =~ /^(.*?)d:($dbname)(.*$)/s ) {
|
||
|
|
||
|
my $pre = $1;
|
||
|
my $name = $2;
|
||
|
my $rest = $3;
|
||
|
|
||
|
$newstring .= $pre;
|
||
|
|
||
|
# pass through XSL key words and mixed case names and olink elements
|
||
|
if ( $name =~ /(^mod$|^div$|^and$|^or$|^ttl$|^xreftext$|^dir$|^id$|^sitemap$|^obj$|^document$|^exsl$|^.*[A-Z].*$)/ ) {
|
||
|
|
||
|
# pass this name through
|
||
|
$newstring .= $name;
|
||
|
}
|
||
|
# pass through man template temporary elements
|
||
|
elsif ( $name =~ /(^cell$|^notesource$|^bold$|^italic$|^div$|^p$|^substitution$)/ ) {
|
||
|
|
||
|
# pass this name through
|
||
|
$newstring .= $name;
|
||
|
}
|
||
|
# pass through references to man temporary elements
|
||
|
elsif ( $name =~ /(^date$|^title$|^manual$|^source$)/ and $pre =~ /refentry\.metadata/ ) {
|
||
|
|
||
|
# pass this name through
|
||
|
$newstring .= $name;
|
||
|
}
|
||
|
# Pass through if preceded or followed by uppercase letters
|
||
|
elsif ($pre =~ /[-._A-Z]$/ || $rest =~ /^[-._A-Z]/) {
|
||
|
$newstring .= "d:" . $name;
|
||
|
}
|
||
|
else {
|
||
|
# remove the namespace prefix
|
||
|
$newstring .= $name;
|
||
|
}
|
||
|
|
||
|
$string = $rest;
|
||
|
}
|
||
|
|
||
|
# print any leftovers
|
||
|
$newstring .= $string;
|
||
|
|
||
|
return $newstring;
|
||
|
}
|
||
|
|
||
|
|
||
|
#######################################################
|
||
|
# addFiles - add some new files to db5xsl
|
||
|
#
|
||
|
sub addFiles {
|
||
|
my $miscdir = dirname $0;
|
||
|
$miscdir .= '/xslnsfiles';
|
||
|
print STDOUT "miscdir is $miscdir" . "\n";
|
||
|
# copy("$miscdir/manpages.table.xsl", "$destdir/manpages/table.xsl");
|
||
|
# copy("$miscdir/titlepage.xsl", "$destdir/template/titlepage.xsl");
|
||
|
# Copy the ns VERSION file, not the copy from non-ns
|
||
|
copy("$destdir/VERSION", "$destdir/VERSION.xsl");
|
||
|
|
||
|
# delete these obsolete files.
|
||
|
|
||
|
# Replace stripns.xsl with addns.xsl in profiling module
|
||
|
&nsfilter("$srcdir/profiling/profile.xsl", "$destdir/profiling/profile.xsl");
|
||
|
}
|