#!/usr/bin/perl -w

#    xmltoman - simple xml to man converter
#    Copyright (C) 2000-2002 Oliver Kurth <oku@masqmail.cx>
#                       2003 Lennart Poettering <mzkzygbzna@0pointer.de>
#
#    This program 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; if not, see <http://www.gnu.org/licenses/>.

use XML::Parser;

my $buffer = "";
my $break_req = 0;

my @stack;
my $stack_n = 0;

my $para = 0; 

sub out {
    my $t = shift;

    if ($t ne "") {
        print $t;
        $break_req=1;
    }
}

sub out_buf {
    local $_;

    my $space = shift;

    $_ = $buffer;
    $buffer = "";

    s/\n/\ /gm;
    s/\s+/\ /gm;
    s/^\s*//gm if (!$break_req);
    s/^\s$//gm if (!$space);
    
    out($_);
}

sub stack_push {
    my $a = shift;

    if ($stack_n == 0 or $a ne $stack[$stack_n-1]) {
        out("\\fB") if $a =~ /^bold$/;
        out("\\fI") if $a =~ /^italic$/;
    }

    $stack[$stack_n++] = $a;
}

sub stack_pop {
    local $_;
    
    if ($stack_n > 0) {
        $stack_n--;

        if ($stack_n > 0) {
            $a = $stack[$stack_n-1];
            out("\\fB") if $a =~ /^bold$/;
            out("\\fI") if $a =~ /^italic$/;
        } else {
            out("\\f1");
        }
    }
}

sub handle_start {
    local $_;
    my $expat = shift;
    my $element = shift;
    my %attr = @_;
    
    $_ = $element;

    if (/^manpage$/) {
        out_buf(0);
        print "\n" if ($break_req);
        print ".TH " . $attr{name} . " " . $attr{section} . " User Manuals\n";
        print ".SH NAME\n";
        print $attr{name} . " \\- " . $attr{desc} . "\n";
        $break_req = 0;
    } elsif (/^synopsis$/) {
        out_buf(0);
        print "\n" if ($break_req);
        print ".SH SYNOPSIS\n";
        $section = $element;
        $break_req = 0;
        stack_push("bold");
    } elsif (/^description$/) {
        out_buf(0);
        print "\n" if ($break_req);
        print ".SH DESCRIPTION\n";
        $section = $element;
        $break_req = 0;
    } elsif (/^options$/) {
        out_buf(0);
        print "\n" if ($break_req);
        print ".SH OPTIONS\n";
        $section = $element;
        $break_req = 0;
    } elsif (/^seealso$/) {
        out_buf(0);
        print "\n" if ($break_req);
        print ".SH SEE ALSO\n";
        $section = $element;
        $break_req = 0;
    } elsif (/^section$/) {
        out_buf(0);
        print "\n" if ($break_req);
        print ".SH ".uc($attr{name})."\n";
        $section = $attr{name};
        $break_req = 0;
    } elsif (/^option$/) {
        out_buf(0);
        print "\n" if ($break_req);
        print ".TP\n";
        $break_req = 0;
    } elsif (/^p$/ or /^cmd$/) {
        out_buf(0);
        print "\n" if ($para);
        $break_req = 0;
    } elsif (/^optdesc$/) {
        out_buf(0);
        $break_req = 0;
    } elsif (/^arg$/ or /^file$/) {
        out_buf(1);
        stack_push("italic");
    } elsif (/^opt$/) {
        out_buf(1);
        stack_push("bold");
    } elsif (/^manref$/) {
        out_buf(1);
        stack_push("bold");
        out($attr{name} ."(" . $attr{section} . ")");
        stack_pop();
    } elsif (/^url$/) {
        out_buf(1);
        stack_push("bold");
        out($attr{href});
        stack_pop();
    };

    $para = 0;
}

sub handle_end {
    local $_;
    my $expat = shift;
    my $element = shift;
    
    $_ = $element;

    $para = 0;

    if (/^description$/ or /^options$/ or /^section$/ or /^seealso$/) {
        out_buf(0);
    } elsif (/^p$/ or /^cmd$/) {
        out_buf(0);
        print "\n" if ($break_req);
        $para = 1;
        $break_req = 0;
    } elsif (/^synopsis$/) {
        out_buf(0);
        stack_pop();
    } elsif (/^opt$/ or /^arg$/ or /^file$/) {
        out_buf(1);
        stack_pop();
    } elsif (/^manpage$/) {
        out_buf(0);
        print "\n" if $break_req;
        $break_req = 0;
    } elsif (/^optdesc$/ or /^cmd$/ or /^option$/) {
        # Simply ignore
    } else {
        out_buf(1);
    }
};

sub handle_char {
    local $_;
    my $expat = shift;
    my $string = shift;
    
    $buffer .= $string;
}

MAIN:{
    my $file = shift;

    if (!$file) {
        print STDERR "You need to specify a file to parse\n";
        exit(1);
    }
    
    my $parser = new XML::Parser(Handlers => {
        Start => \&handle_start, 
        End => \&handle_end,
        Char => \&handle_char});

    $parser->parsefile($file, ProtocolEncoding => 'ISO-8859-1');
}
