#!/usr/bin/env perl
#
#  This file is part of Docbook::Convert.
#
#  This software is copyright (c) 2026 by Andrew Speer <andrew.speer@isolutions.com.au>.
#
#  This is free software; you can redistribute it and/or modify it under
#  the same terms as the Perl 5 programming language system itself.
#
#  Full license text is available at:
#
#  <http://dev.perl.org/licenses/>
#
use strict qw(vars);
use vars   qw($VERSION);
no warnings qw(utf8);


#  External modules
#
use IO::File;
use Getopt::Long;
Getopt::Long::Configure('no_ignore_case');
use Pod::Usage;
use FindBin qw($RealBin $Script);
use File::Find;
use Cwd qw(cwd abs_path);
use Docbook::Convert;
use Docbook::Convert::Util;
use Docbook::Convert::Constant;


#  Used for debugging only
#
use Data::Dumper;
$Data::Dumper::Indent=1;
$Data::Dumper::Terse=1;


#  Version Info, must be all one line for MakeMaker, CPAN.
#
$VERSION='1.011';


#  Run main routine
#
exit ${&main(&getopt(\@ARGV)) || die 'unknown error'};


#===================================================================================================


sub getopt {


    #  Parse options and dispatch to actual work routine below
    #
    my $argv_ar=shift();


    #  Get options
    #
    my %opt;


    #  Converts some constant settings into settable options
    #
    my @getopt_constant=map {$GETOPT_CONSTANT_HR->{$_} ? $_ . $GETOPT_CONSTANT_HR->{$_} : $_}
        keys %{$GETOPT_CONSTANT_HR};


    #  Get command line options
    #
    GetOptions(
        \%opt,
        @{$GETOPT_AR},
        @getopt_constant,
        'pandoc',
    ) || pod2usage(2);
    pod2usage(-verbose => 99, -sections => 'SYNOPSIS|Options', -exitval => 1) if $opt{'help'};
    pod2usage(-verbose => 2)                                                  if $opt{'man'};
    $opt{'version'} && do {
        print "$Script version: $VERSION\n";
        exit 0
    };


    #  Turn on debug and verbosity if needed
    #
    ($VERBOSE, $DEBUG)=@opt{qw(verbose debug)};


    #  Debug
    #
    $opt{'dumpopt'} && do {
        CORE::print STDERR Dumper([sort @{$GETOPT_AR}, @getopt_constant]);
        exit 0;
    };


    # Recursing ?
    #
    if (exists $opt{'recurse'} || $opt{'recursedir'}) {
        my $dn=$opt{'recursedir'} || cwd();
        $dn=Cwd::abs_path($dn);
        my @fn;
        my $wanted_cr=sub {
            return unless -f (my $fn=$File::Find::name);
            return if $fn=~/\/\._/;    #  Mac temp file
            push @fn, $fn if ($fn=~/\Q$XMLSUFFIX\E$/);
        };
        find($wanted_cr, $dn);
        @fn ||
            #return err("no files with '%s' suffix found when recursing directory '$dn'", $XMLSUFFIX);
            return msg("no files with '%s' suffix found when recursing directory '$dn'", $XMLSUFFIX);
        $opt{'infile'}=\@fn;
    }


    #  Get infile
    #
    unless (@{$opt{'infile'}}) {
        $opt{'infile'}=@{$argv_ar} ? $argv_ar : [\*STDIN];
    }


    #  Set handler
    #
    $opt{'handler'} ||= (
        ($opt{'markdown'} && 'markdown') ||
            $HANDLER_DEFAULT
    );


    #  Done
    #
    return \%opt;

}


sub main {

    #  Passed a list of options and convert file/input stream
    #
    my $opt_hr=shift();
    foreach my $fn (@{$opt_hr->{'infile'}}) {
        my $output;
        if ($opt_hr->{'pandoc'}) {
            die "--pandoc requires a filename\n" if ref($fn);
            require Docbook::Convert::Pandoc;
            $output=Docbook::Convert::Pandoc->new()->convert_file($fn);
        }
        elsif (ref($fn) eq 'GLOB') {
            $output=Docbook::Convert->process($fn, $opt_hr);
        }
        else {
            msg("processing file: $fn");
            $output=Docbook::Convert->process_file($fn, $opt_hr);
        }
        if (my $out_fn=$opt_hr->{'outfile'}) {
            if ($out_fn=~/^\.(.*)$/) {

                #  Output file option is something like '.foo'. Means add '.foo' to input file name
                #  and make that the output file name
                #
                my $ext=$1;
                ($out_fn=$fn)=~s/\Q$XMLSUFFIX\E$//;
                $out_fn.=".${ext}";
            }
            my $out_fh=IO::File->new($out_fn, O_WRONLY | O_CREAT | O_TRUNC) ||
                return err("unable to write to output file $out_fn, $!");
            print $out_fh $output;
        }
        else {
            print $output;
        }
    }
    return \undef;

}

__END__

=begin markdown

# NAME #

docbook-convert - convert DocBook articles and reference pages to Markdown

# SYNOPSIS #

`docbook-convert --markdown file.xml`

# Description #

docbook-convert converts DocBook documents to Markdown. Use --pandoc for guides
with local includes, section IDs and MkDocs admonitions. Direct conversion to
POD and merging XML into Perl source are no longer supported.

This utility will work on Docbook 4+ Articles and Refentry templates. See Limitations in this document for information on
 capabilities of this program.

# Options #

* **--pandoc**

    Convert a filename to Markdown using Pandoc and the supplied Lua/XSL filters.
    Local includes are expanded and section IDs preserved. This mode requires
    pandoc, xmllint and xsltproc.

* **--dump**

    Dump internal parse tree of Docbook file. Useful for debugging.

* **--handler -h**

    Which output handler to use. Use --handler=markdown (or md).

* **--help**

    Short help file

* **-f --in -infile**

    Name of input file. If not supplied in options input file with be first command line argument \- or if not supplied STDIN

* **--man**

    Show this manpage

* **--markdown --md**

    Output as Markdown. Shorthand for \--handler=markdown

* **--meta_display_title_h_style**

    If rendering a metadata title which heading style should be applied. One of h1..h4

* **--meta_display_bottom**

    Render any metadata at the bottom of the document

* **--meta_display_title**

    Optional title to be rendered as a prefix to any metadata displayed

* **--meta_display_top**

    Render any metadata at the top of the document

* **--no_html**

    Do not incorporate any HTML in the output \(e.g. images). This may limit what can be converted.

* **--no_image_fetch**

    If an image incorporated into a Docbook file has attributes which indicate scaling should be applied the image will be fetched
 by the converter and the appropriate width calculated. This option
 will prevent fetching of remote images, and thus will nullify any
 scaling attributes associated with images.

* **--silent**

    Do not warn on any unhandled tags or other issues

* **-o --out -outfile**

    Name of file any output should be sent to. If specified as suffix only \(e.g. \--outfile=.foo) then the \.xml extension will be
 stripped from the input file name and the nominated suffix applied.
 The result will be used as the output file name. Userful with \--recurse

* **--recursedir|d**

    Convert all \.xml files in a nominated directory

* **--recurse**

    Convert all files in the current working directory and any sub-directories

* **-V -version**

    Display the version number of the utility

# Examples #

    # Convert a single file to markdown

    docbook-convert --markdown -f mydoc.xml -o mydoc.md

    # Convert all files in a directory to markdown

    docbook-convert --markdown --recursedir ~/mydoc/ -o .md

    # Include meta-data in output

    docbook-convert --markdown --meta_display_top myarticle.xml -o myarticle.md

# Limitations #

This utility and associated Perl module will only convert a subset of Docbook entities and tags.

# LICENSE and COPYRIGHT

This file is part of Docbook::Convert.

This software is copyright (c) 2026 by Andrew Speer <andrew.speer@isolutions.com.au>.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

Full license text is available at:

<http://dev.perl.org/licenses/>


=end markdown


=head1 NAME

docbook-convert - convert DocBook articles and reference pages to Markdown


=head1 SYNOPSIS

C<docbook-convert --markdown file.xml>


=head1 Description

docbook-convert converts DocBook documents to Markdown. Use --pandoc for guides
with local includes, section IDs and MkDocs admonitions. Direct conversion to
POD and merging XML into Perl source are no longer supported.

This utility will work on Docbook 4+ Articles and Refentry templates. See Limitations in this document for information on
 capabilities of this program.


=head1 Options

=over

=item *

B<--pandoc>

Convert a filename to Markdown using Pandoc and the supplied Lua/XSL filters.
Local includes are expanded and section IDs preserved. This mode requires
pandoc, xmllint and xsltproc.



=item *

B<--dump>

Dump internal parse tree of Docbook file. Useful for debugging.



=item *

B<--handler -h>

Which output handler to use. Use --handler=markdown (or md).



=item *

B<--help>

Short help file



=item *

B<-f --in -infile>

Name of input file. If not supplied in options input file with be first command line argument - or if not supplied STDIN



=item *

B<--man>

Show this manpage



=item *

B<--markdown --md>

Output as Markdown. Shorthand for --handler=markdown



=item *

B<--meta_display_title_h_style>

If rendering a metadata title which heading style should be applied. One of h1..h4



=item *

B<--meta_display_bottom>

Render any metadata at the bottom of the document



=item *

B<--meta_display_title>

Optional title to be rendered as a prefix to any metadata displayed



=item *

B<--meta_display_top>

Render any metadata at the top of the document



=item *

B<--no_html>

Do not incorporate any HTML in the output (e.g. images). This may limit what can be converted.



=item *

B<--no_image_fetch>

If an image incorporated into a Docbook file has attributes which indicate scaling should be applied the image will be fetched
 by the converter and the appropriate width calculated. This option
 will prevent fetching of remote images, and thus will nullify any
 scaling attributes associated with images.



=item *

B<--silent>

Do not warn on any unhandled tags or other issues



=item *

B<-o --out -outfile>

Name of file any output should be sent to. If specified as suffix only (e.g. --outfile=.foo) then the .xml extension will be
 stripped from the input file name and the nominated suffix applied.
 The result will be used as the output file name. Userful with --recurse



=item *

B<--recursedir|d>

Convert all .xml files in a nominated directory



=item *

B<--recurse>

Convert all files in the current working directory and any sub-directories



=item *

B<-V -version>

Display the version number of the utility



=back


=head1 Examples

    # Convert a single file to markdown

    docbook-convert --markdown -f mydoc.xml -o mydoc.md

    # Convert all files in a directory to markdown

    docbook-convert --markdown --recursedir ~/mydoc/ -o .md

    # Include meta-data in output

    docbook-convert --markdown --meta_display_top myarticle.xml -o myarticle.md


=head1 Limitations

This utility and associated Perl module will only convert a subset of Docbook entities and tags.


=head1 LICENSE and COPYRIGHT

This file is part of Docbook::Convert.

This software is copyright (c) 2025 by Andrew Speer E<lt>andrew.speer@isolutions.com.auE<gt>.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

Full license text is available at:

E<lt>L<http://dev.perl.org/licenses/&gt;>

=cut
