eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q'
  if 0;

#!perl
#line 6

#--------------------------------------------------
# Following lines are configured by the Makefile:
$NEDTOOL = 'nedtool';
$XSLTPROC = 'xsltproc';
$GNED = 'gned';
$GHOSTSCRIPT = 'gs';
$CONVERT = 'convert';
$GIFTRANS = 'giftrans';
$DOT = '';
$PERL = 'perl';
#--------------------------------------------------

# OS check
use Config;

#if ($Config{'archname'} =~ /cygwin/i || $ENV{TERM} =~ /cygwin/i)
if ($Config{'archname'} =~ /cygwin/i)
{
    # forget cygwin: its /cygdrive/c/.. style paths are not understood by any normal program...
    error("the Cygwin environment and Cygwin's perl are not supported, please\n".
          "run this program from the Windows command prompt, or install MinGW instead of\n".
          "Cygwin!");
}

$isWindows = ($ENV{OS} =~ /windows/i) ? 1 : 0;

if ($isWindows && $ENV{OS} ne "Windows_NT")
{
    error("this program can only be used on Windows NT/2000/XP, but your OS environment variable says '$ENV{OS}'\n");
}

use Cwd;

$progdir = directoryof($0);

# assume the stylesheet and the postprocessor are in the same directory as we
$NEDDOC_XSL = "$progdir/neddoc.xsl";
$NEDDOC_PL = "$progdir/neddocproc.pl";

# process command-line options
$outdir = "html";
$doxytagfile = "";
$doxyhtmldir = "../api-doc/html";
$screenshots = 1;
$unassignedpars = 1;
$sourcecode = 1;
$all_files = 0;
$verbose = 1;
$debug = 0;

if ($DOT ne "")
{
    $have_dot = 1;
}

if (@ARGV==())
{
    $do_help = 1;
}

# process arg vector
while (@ARGV)
{
    $arg = $ARGV[0];
    if ($arg eq '-o')
    {
       shift @ARGV;
       $outdir = tobackslash($ARGV[0]);
    }
    elsif ($arg eq '-a' || $arg eq '--all')
    {
       $all_files = 1;
    }
    elsif ($arg eq '-d' || $arg eq '--doxyhtmldir')
    {
       shift @ARGV;
       $doxyhtmldir = tobackslash($ARGV[0]);
    }
    elsif ($arg eq '-t' || $arg eq '--doxytagfile')
    {
       shift @ARGV;
       $doxytagfile = tobackslash($ARGV[0]);
    }
    elsif ($arg eq '-n' || $arg eq '--no-figures')
    {
       $screenshots = 0;
    }
    elsif ($arg eq '-p' || $arg eq '--no-unassigned-pars')
    {
       $unassignedpars = 0;
    }
    elsif ($arg eq '-x' || $arg eq '--no-diagrams')
    {
       $have_dot = 0;
    }
    elsif ($arg eq '-z' || $arg eq '--no-source')
    {
       $sourcecode = 0;
    }
    elsif ($arg eq '-g' || $arg eq '--debug')
    {
       $debug = 1;
    }
    elsif ($arg eq '-s' || $arg eq '--silent')
    {
       $verbose = 0;
    }
    elsif ($arg eq '-h' || $arg eq '--help')
    {
       $do_help = 1;
    }
    elsif ($arg =~ /^-/)
    {
       print STDERR "opp_neddoc: $arg: invalid option, try -h for help\n";
       exit(2);
    }
    else
    {
       last;
    }
    shift @ARGV;
}

if ($do_help)
{
    print "opp_neddoc - NED and MSG documentation tool, part of OMNeT++/OMNEST\n";
    print "(c) 2003-2005 Andras Varga\n\n";
    print "Generates HTML model documentation from .ned and .msg files.\n\n";
    if ($GHOSTSCRIPT eq "" && $CONVERT eq "")
    {
        print "Note: cannot generate figures because Ghostscript is not installed.\n\n";
    }
    if ($DOT eq "")
    {
        print "Note: cannot generate usage diagrams because Graphviz is not installed.\n\n";
    }
    print "Usage: opp_neddoc options files-or-directories ...\n";
    print " -a, --all    process all *.ned and *.msg files recursively\n";
    print "              ('opp_neddoc -a' is equivalent to 'opp_neddoc .')\n";
    print " -o <dir>     output directory, defaults to ./html\n";
    print " -t <filename>, --doxytagfile <filename>\n";
    print "              turn on generating hyperlinks to Doxygen documentation;\n";
    print "              <filename> specifies name of XML tag file generated by Doxygen\n";
    print " -d <dir>, --doxyhtmldir <dir>\n";
    print "              directory of Doxygen-generated HTML files, relative to the \n";
    print "              opp_neddoc output directory (-o option). -t option must also be\n";
    print "              present to turn on linking to Doxygen. Default: ../api-doc/html\n";
    print " -n, --no-figures\n";
    print "              do not generate diagrams\n";
    print " -p, --no-unassigned-pars\n";
    print "              do not document unassigned parameters\n";
    print " -x, --no-diagrams\n";
    print "              do not generate usage and inheritance diagrams\n";
    print " -z, --no-source\n";
    print "              do not generate source code listing\n";
    print " -s, --silent suppress informational messages\n";
    print " -g, --debug  print invocations of external programs and other info\n";
    print " -h, --help   displays this help text\n";
    print "\n";
    print "Files specified as arguments are parsed and documented. For directories as\n";
    print "arguments, all .ned and .msg files under them (in that directory subtree) are\n";
    print "documented. Wildcards are accepted and they are NOT recursive, e.g.\n";
    print "foo/*.ned does NOT process files in foo/bar/ or any other subdirectory.\n";
    print "\n";
    print "Bugs:  (1) handles only files with .ned and .msg extensions, other files ";
    print "are \nsilently ignored; (2) does not filter out duplicate files (they will show up ";
    print "\nmultiple times in the documentation); (3) on Windows, file names are handled ";
    print "\ncase sensitively.\n";
    print "\n";
    exit(0);
}

# print platform
print (($isWindows ? "windows" : "unix"), " environment detected\n") if $debug;

$nul = ($isWindows ? "nul" : "/dev/null");

# we need backslashes in file names
$NEDTOOL = tobackslash($NEDTOOL);
$XSLTPROC = tobackslash($XSLTPROC);
$GNED = tobackslash($GNED);
$GHOSTSCRIPT = tobackslash($GHOSTSCRIPT);
$CONVERT = tobackslash($CONVERT);
$GIFTRANS = tobackslash($GIFTRANS);
$DOT = tobackslash($DOT);
$PERL = tobackslash($PERL);
$NEDDOC_XSL = tobackslash($NEDDOC_XSL);
$NEDDOC_PL = tobackslash($NEDDOC_PL);


# purge output directory
if (! -d $outdir)
{
    print "creating directory $outdir\n" if $debug;
    mkdir($outdir) || error("cannot create output directory '$outdir'");
}
else
{
    delete_recursive($outdir)==0 || error("cannot clean output directory '$outdir' from old files");
}

print "collecting files...\n" if $verbose;
if ($all_files)
{
    collect_files(".", "$outdir/filelist.txt")==0 || error("error creating the file list");
}
else
{
    if (@ARGV==())
    {
        print STDERR "opp_neddoc: no input files specified, type -h for help\n";
        exit(2);
    }

    while (@ARGV)
    {
        $arg = tobackslash(shift @ARGV);
        if ($arg =~ /^@(.*)/)
        {
            $f = $1;
            error("list files not yet supported");
        }
        elsif (-d $arg)
        {
            collect_files($arg, "$outdir/filelist.txt")==0 || error("error creating the file list");
        }
        elsif (-f $arg)
        {
            open FL,">>$outdir/filelist.txt";
            print FL $arg, "\n";
            close FL;
        }
        elsif ($arg =~ /[*?]/)
        {
            # looks like a glob pattern
            @files = glob($arg);
            if (@files==()) {
                print STDERR "opp_nedtool: warning: $arg doesn't match any files\n";
            } else {
                open FL,">>$outdir/filelist.txt";
                print FL join("\n",@files);
                print FL "\n";
                close FL;
            }
        }
        else
        {
            print STDERR "opp_nedtool: warning: $arg not found, ignoring\n";
            #error("$arg not found");
        }
    }
}

# make file names in filelist.txt relative to current directory; also weed out
# file names not ending in .ned or .msg (i.e. backup files ending in .ned~0)
$currentdir = tobackslash(cwd());
rename("$outdir/filelist.txt", "$outdir/filelist.tmp");
open FLIN, "$outdir/filelist.tmp";
open FLOUT, ">$outdir/filelist.txt";
while (<FLIN>)
{
    s/[\r\n]*$//;  # for Cygwin, chomp is not enough
    next if (!/.ned$/ && !/.msg$/);
    s|^\Q$currentdir\E[\\/]*||;
    print FLOUT $_, "\n";
}
close FLOUT;
close FLIN;
unlink("$outdir/filelist.tmp") if (!debug);

#
# now start the real job
#
print "transforming to xml...\n" if $verbose;
if ($NEDTOOL eq "") {error("nedtool not configured");}
runprog($NEDTOOL, "-x", "-e", "-t", "-y", "-m", "-o", "$outdir/inputfiles.xml", "\@$outdir/filelist.txt")==0 || error("error invoking nedtool");

if ($screenshots)
{
    if ($GHOSTSCRIPT ne "" || $CONVERT ne "")
    {
        print "exporting screenshots in Postscript using GNED...\n" if $verbose;
        if ($GNED eq "") {error("gned not configured");}
        runprog($GNED, "--", "-c", $outdir, "-e", "jpg", "\@$outdir/filelist.txt", ">$nul")==0 || error("error invoking GNED");
        print "converting Postscript to JPG...\n" if $verbose;
        foreach $i (glob("$outdir/*.eps"))
        {
           print "#" if (!$debug && $verbose);
           $jpg = $i;
           $jpg =~ s/eps$/jpg/;
           if ($CONVERT ne "") {
              # we prefer ImageMagick because many Ghostscript versions are broken (ignore -dEPSCrop)
              runprog($CONVERT, $i, $jpg, ">>$outdir/ghostscript.err")==0 || error("error invoking ImageMagick convert");
           } else {
              runprog($GHOSTSCRIPT, "-dEPSCrop", "-sNOPAUSE", "-sBATCH", "-sDEVICE=jpeg", "-sOutputFile=$jpg", $i, ">>$outdir/ghostscript.err")==0 || error("error invoking Ghostscript");
           }
        }
        print "\n" if (!$debug && $verbose);

        if (-s "$outdir/ghostscript.err")
        {
           print "see Ghostscript warnings in $outdir/ghostscript.err\n" if $verbose;
        }
        else
        {
            unlink("$outdir/ghostscript.err");
        }

        # must convert $outdir to absolute path, otherwise xslt will take it
        # as relative to the sylesheet (@#$#@$!!)
        $imagesxml = absolutepath("$outdir/images.xml");
    }
    else
    {
        print "skipping diagram export (Ghostscript not available)\n" if $verbose;
        $imagesxml = "";
    }
}

# hack: must convert $doxytagfile to absolute path, otherwise xslt will take it
# as relative to the sylesheet
if ($doxytagfile ne "") {
    $doxytagfile = absolutepath($doxytagfile);
}

print "applying XSLT stylesheet...\n" if $verbose;
if ($XSLTPROC eq "") {error("xsltproc not configured");}
@xsltcommand = ($XSLTPROC,
               "--stringparam", "outputdir", "\"".toslash($outdir)."\"",
               "--stringparam", "imagesxml", "\"".toslash($imagesxml)."\"",
               "--stringparam", "document-unassigned-params", "\"".($unassignedpars?"yes":"no")."\"",
               "--stringparam", "have-dot", "\"".($have_dot?"yes":"no")."\"",
               "--stringparam", "include-source-code", "\"".($sourcecode?"yes":"no")."\"",
               "--stringparam", "doxytagfile", "\"".toslash($doxytagfile)."\"",
               "--stringparam", "doxyhtmldir", "\"".toslash($doxyhtmldir)."\"",
               "--output", "-",
               "$NEDDOC_XSL", "$outdir/inputfiles.xml", ">$nul");
runprog(@xsltcommand)==0 || error("error invoking xsltproc");

if ($have_dot)
{
    print "generating diagrams via DOT...\n" if $verbose;
    foreach $i (glob("$outdir/*.dot"))
    {
       print "#" if (!$debug && $verbose);
       $gif = $i; $gif =~ s/dot$/gif/;
       $map = $i; $map =~ s/dot$/map/;
       runprog($DOT, "-Tgif",  "<$i", ">$gif", "2>>$outdir/dot.err")==0 || error("error invoking DOT");
       runprog($DOT, "-Tcmap", "<$i", ">$map", "2>>$outdir/dot.err")==0 || error("error invoking DOT");
       if ($GIFTRANS ne "")
       {
           rename($gif, "$outdir/__tmp.gif");
           runprog($GIFTRANS, "-t", "\"#ffffff\"", tobackslash("$outdir/__tmp.gif"), ">$gif")==0 || error("error invoking giftrans");
           unlink("$outdir/__tmp.gif");
       }
    }
    print "\n" if (!$debug && $verbose);
    if (-s "$outdir/dot.err")
    {
       print "see warnings from $DOT in $outdir/dot.err\n" if $verbose;
    }
    else
    {
        unlink("$outdir/dot.err");
    }
}

print "formatting comments...\n" if $verbose;
runprog($PERL, $NEDDOC_PL, $outdir)==0 || error("error invoking HTML formatter");

if (!$debug)
{
    unlink(glob("$outdir/*.eps"));
    unlink(glob("$outdir/*.dot"));
    unlink(glob("$outdir/*.map"));
    unlink("$outdir/inputfiles.xml");
    unlink("$outdir/images.xml");
    unlink("$outdir/filelist.txt");
}
else
{
    print "intermediate files left in $outdir/ (debug mode doesn't delete them)\n";
}

print "documentation created in $outdir/ -- start page is index.html\n" if $verbose;


sub runprog
{
    my @prog = @_;
    print "running: ".join(' ',@prog)."\n" if $debug;
    if ($isWindows) {
        system($ENV{COMSPEC}, "/c", @prog);
    } else {
        system(@prog);
    }
}

sub absolutepath
{
    my $filename = tobackslash(shift);
    if ($isWindows) {
        # COMSPEC is necessary to prevent getting other "dir" programs in the path
        $absfilename = `$ENV{COMSPEC} /c dir /s /b $filename`;
        if ($?) {error("'$filename' does not exist")}
        chomp($absfilename);
    } else {
        $absfilename = $filename;
        $absfilename = cwd()."/".$filename if (!($filename =~ /^\//));
        if (! -f $absfilename) {error("'$filename' does not exist");}
    }
    $absfilename;
}

sub error
{
    my $msg = shift;
    print STDERR "opp_neddoc: ", $msg, "\n";
    exit(2);
}

sub tobackslash
{
    my $f = shift;
    $f =~ s|/|\\|g if $isWindows;
    $f;
}

sub toslash
{
    my $f = shift;
    $f =~ s|\\|/|g;
    $f;
}

sub directoryof
{
    my $dir = shift;
    $dir =~ s|[^/\\:]*$||g;
    $dir = "." if ($dir eq "");
    $dir;
}

sub delete_recursive
{
    my $dir = tobackslash(shift);
    if ($isWindows) {
        runprog("del", "/s", "/q", "$dir\\*", ">$nul");
    } else {
        runprog("rm -rf $dir/*");
    }

}

sub collect_files
{
    my $dir = tobackslash(shift);
    my $listfile = tobackslash(shift);
    if ($isWindows) {
        # Issue: "dir" returns error (nonzero exit code) if no file was listed.
        # To prevent that from stopping opp_neddoc with error, we forcefully return 0
        # here. Downside is that any "real" error will go unnoticed, but if there
        # was a problem with $ENV{COMSPEC} we'd have choked on it already.
        # (TODO: we could check output was really "File Not Found")
        runprog("dir", "/s", "/b", "$dir\\*.ned", "$dir\\*.msg", ">>$listfile", "2>>nul");
        0;
    } else {
        runprog("find $dir -name '*.ned' -o -name '*.msg' >>$listfile");
    }
}

