#!/usr/bin/perl -w
#----------------------------------------------------------------------
# File:
#   scrdoc
#
# Module:
#   Documentation generation for SCR-Agents
#
# Summary:
#   Generates documentation for SCR files base on comments.
#
# Authors:
#   Gregor Fischer <fischer@suse.de>
#
# $Id$
#
#----------------------------------------------------------------------
use strict;
use Getopt::Std;
use File::Find;
use IO::File;
use XML::Writer;

use vars ('$VERSION','$Options');
my $VERSION = "0.2.0";
my $Options = {};

main();
exit(0);

#----------------------------------------------------------------------
# main
#----------------------------------------------------------------------

sub main {
    #my $Options = {};
    getopts("f:o:d:hp:vVD:", $Options) || usage() || exit(1);

    if ($Options->{h}) {
	usage();
	exit(0);
    }

    if ($Options->{V}) {
	print STDERR "$0 $VERSION\n";
	exit(0);
    }

    if ($Options->{d}) {
	push @ARGV, findFiles();
    }

    my $FileInfo = {};
    foreach my $FileName (@ARGV) {
	my $SingleFileInfo = parseFile($FileName);
	$FileInfo->{$FileName} = $SingleFileInfo;
    }

    if (defined $Options->{f} && $Options->{f} =~ /^xml$/) {
	generateSCRXMLDoc($FileInfo);
    } else {
	#generateIndex($FileInfo, $Options);
	#generateDoc($FileInfo);
	generateSCRDoc($FileInfo);
    }
}

#----------------------------------------------------------------------
sub usage {
    print STDERR <<EOT;
Usage: $0 [OPTION] [FILE [FILE [...]]]

  -o DIR                 all generated files go in the specified
			 directory (instead of the current)
  -d DIR                 look for input files in DIR
  -f FORMAT		 output format html or xml
  -p PATTERN             when searching directories (with -d) use the
			 specified pattern (RegExp) instead of the
			 default (.*\\.scr)
  -h                     show this help page
  -v                     be verbose
  -V                     show version
  -D PATH                path to the YaST2 documentation. This should
			 be a relative path from the place the generated
			 files go to. Or you can specify an absolute path.
			 (Default: "file:/usr/share/doc/packages")

EOT
}
#----------------------------------------------------------------------
sub findFiles {
    my $Dir = $Options->{d};
    my $Pattern = $Options->{p} || ".*\\.scr";

    my @List = ();

    find( sub {
	$File::Find::prune = 1 if (-d && /^CVS$/);
	$File::Find::prune = 1 if (-d && /^testsuite$/);
	if (-f && -r && -s && /^$Pattern$/o) {
	    print STDERR "Found: $File::Find::name\n" if ($Options->{v});
	    push(@List, $File::Find::name);
	}
    } , $Dir );
    return @List;
}
#----------------------------------------------------------------------
sub parseFile {
    my $FileName = shift;

    # Analyse Filename
    my $Info = {};
    $Info->{FileName} = $FileName;
    $FileName =~ /^(.*)\/(.*)\.(.*)$/i;
    $Info->{FileNamePath} = $1;
    $Info->{FileNameBase} = $2;
    $Info->{FileNameExt}  = $3;

    # Read whole File
    my $File = "";
    open(FILE, "<$FileName") || die "Cannot open $FileName.";
    while (my $Line = <FILE>) {
	$File .= $Line;
    }
    close(FILE);

    # Analyse File
    my $Blocks = extractBlocksFromFile($File);

    # Extract Info from Blocks
    my $FileInfo = extractInfoFromBlock($Blocks,$Info);

    return $Info->{Comments} = $Info;

    return $Info;
}
#----------------------------------------------------------------------
sub extractBlocksFromFile {
    my $File = shift;

    # Get every comment and possibly next line if special
    my @Blocks = ($File =~ m{/\*.*?\*/(?:[^\n]*\n(?:\s*\n)*^(?:[^\n]*define|\.)[^\n]*$)?}gsm);
    
    # If file starts with "." on first position, it's an old style scr file
    if ($File =~ /^(\..*?)[ \t]*\n/) {
	unshift @Blocks, "/**\n * $1\n */\n$1\n";
    }

    if (scalar(@Blocks) == 0) {
	foreach my $line (split(/\n/, $File)) {
	    if ($line =~ /\s*(^\.\S+)/) {
		push @Blocks, $1;
		last;
	    }
	}
    }

    return \@Blocks;
}
#----------------------------------------------------------------------

#----------------------------------------------------------------------
sub extractInfoFromBlock {
    my $Blocks = shift;
    my $Info = shift;

    $Info->{Intro}    = [];
    $Info->{Module}   = [];
    $Info->{Mount}    = [];
    $Info->{Function} = [];
    $Info->{General}  = [];

    for (my $BlockNumber = 0; $BlockNumber <= $#$Blocks; ++$BlockNumber) {
	my $Block = $Blocks->[$BlockNumber];
	
	my $Comment = "";
	my $Rest = "";
	
	# sometimes, only the mount-point is defined
	# and no other documentation is included
	if ($Block =~ /^\.\S+$/) {
	    $Comment = "";
	    $Rest = $Block;
	} else {
	    # Split up Comment and Rest
	    $Block =~ /(\/\*.*?\*\/)[^\n]*\n(?:\s*\n)*^(.*)\Z/ms;

	    $Comment = $1;
	    $Rest = $2;
	}
	
	# Analyse Rest
	my $Type  = "";
	my $Value = "";
	if ($Rest =~ /^(\.\S+)/) {
	    $Type  = "mountpoint";
	    $Value = $1;
	} elsif ($Rest =~ /define\s*`*(\S+)/) { #`
	    $Type  = "function";
	    $Value = $1;
	} else {
	    $Type = "unknown";
	}
	
	my $BlockInfo = analyseComment($Comment);

	# Mountpoint is the special case
	if ($Type eq "mountpoint") {
	    #print STDERR "MOUNTPOINT: $BlockNumber ($Value)\n";
	    $BlockInfo->{MountPoint} = $Value;
	    push @{$Info->{Mount}}, $BlockInfo;
	}

	# Categorize Comment
	if ($Block =~ /^\/\*[^\*]/) {
	    #print STDERR "SKIP: $BlockNumber\n";
	    next;
	} elsif ($Block =~ /\/\*\*\*/) {
	    #print STDERR "INTRO: $BlockNumber\n";
	    push @{$Info->{Intro}}, $BlockInfo;
	} elsif ($Type eq "function") {
	    #print STDERR "FUNTION: $BlockNumber ($Value)\n";
	    $BlockInfo->{FunctionName} = $Value;
	    push @{$Info->{Function}}, $BlockInfo;
	} elsif (@{$Info->{Module}} == 0) {
	    #print STDERR "MODULE: $BlockNumber\n";
	    push @{$Info->{Module}}, $BlockInfo;
	} else {
	    #print STDERR "GENERAL: $BlockNumber ($Type,$Value)\n";
	    push @{$Info->{General}}, $BlockInfo;
	}
    }
    
    return $Info;
}
#----------------------------------------------------------------------
sub ConvertAliases ($) {
    my $Name = shift;

    # General description
    if ($Name =~ /Description/i || $Name =~ /Descr/i) {
        $Name = "General";
    # Author is alias for Authors
    } elsif ($Name =~ /Author/i) {
        $Name = "Authors";
    } elsif ($Name =~ /Examples/i) {
        $Name = "Example";
    }

    return $Name;
}
#----------------------------------------------------------------------
sub MakeExampleNicer ($$) {
    my $example = shift;
    my $blankchar = shift;

    my @lines = split(/\n/, $example);
    
    # find the minimal count of spaces on the left side of example
    my $minspaces = 99999;
    foreach my $line (@lines) {
	# ignore blank lines
	next if ($line =~ /^$blankchar*$/);
	# find out count of spaces
	$line =~ /^($blankchar*).*$/;
	if (length($1) < $minspaces) {
	    $minspaces = length($1);
	}
    }
    if ($minspaces > 0) {
	$example = "";
	foreach my $line (@lines) {
	    for (1..$minspaces) {
		$line =~ s/^$blankchar//;
	    }
	    $line =~ s/^[ \t]*$//;
	    $example .= ($example ne "" ? "\n":"").$line;
	}
    }
    
    $example =~ s/^\n+//g;
    $example =~ s/\n+$//g;
    return $example;
}
#----------------------------------------------------------------------
sub analyseComment {
    my $Comment = shift;

    my $Info = {};

    # Collect @xxx lines
    while ($Comment =~ s/^\s*\**\s*\@(\S+)(?:[\t ](.*?)\s*)?(\n|\z)//m) {
	$Info->{$1} = [] unless (defined $Info->{$1});
	push @{ $Info->{$1} }, $2;
    }

    # Go through the comments line by line
    # Find the 'Name' and 'Text'
    # If both are found, add it to the map
    my $Name = "";
    my $Text = "";
    foreach my $line (split(/\n/, $Comment)) {
	# 'Name: Text' or 'Name:' (with text on the following line)
	if ($line =~ /^\s*\**\s*([a-zA-Z]+):(.*)/) {
	    $Name = $1;
	    $Text = $2;
	    # do not reformat only examples
	    if ($Name ne "Example") {
		$Text =~ s/^\s*(.*)\s*$/$1/;
	    }
	# final '*/', delete the 'Name'
	} elsif ($line =~ /^\s*\*+\//) {
	    $Name = "";
	# special tag ID
	} elsif ($line =~ /^\s*\**\s*(\$Id\:.*?\$)\s*/mi) {
	    $Name = "ID";
	    $Text = $1;
	# a blank line means if a 'Text' comes on the next line
	# the 'Name' is 'General' ('Description')
	# the only exception is an 'Example' (it allows blank lines)
	} elsif ($line =~ /^\s*\**\s*$/ && $Name ne "Example") {
	    $Name = "General";
	    $Text = "";
	# just a text, 'Name' should be already defined
	} elsif ($line =~ /^\s*\**(.*)/) {
	    $Text = $1;
	    # do not reformat only examples
	    if ($Name ne "Example") {
		$Text =~ s/^\s*(.*)\s*$/$1/;
	    }
	} else {
	    warn
		"Unknown input: $line\n".
		"Current Name was: ".$Name."\n".
		"Current Text was: ".$Text;
	}
	
	# Convert 'Name' aliases bofore the record is written
	$Name = ConvertAliases($Name);
	
	if ($Name && $Text) {
	    $Info->{$Name} .= "\n".$Text;
	}
    }
    
    # Transform example (remove some spaces)
    if (defined $Info->{"Example"}) {
	$Info->{"Example"} = MakeExampleNicer($Info->{"Example"}, " ");
	$Info->{"Example"} = MakeExampleNicer($Info->{"Example"}, "\t");
    }
    
    # remove opening newlines
    foreach $Name (keys %{$Info}) {
	$Info->{$Name} =~ s/^\n//m;
    }
    
    return $Info;
}
#----------------------------------------------------------------------
#----------------------------------------------------------------------
sub generateIndex {
    my $FileInfos = shift;

    foreach my $FileName (sort keys %$FileInfos) {
	my $FileInfo = $FileInfos->{$FileName};
	print "----------------------------------------------------\n";
	print $FileInfo->{FileNameBase}. "\n";
	my $MountInfo = $FileInfo->{Mount};
	foreach my $MountBlock (@$MountInfo) {
	    print $MountBlock->{MountPoint} . "\n";
	    #print $FileInfo->{FileNameBase} . "\n";
	    foreach my $Key (sort keys %$MountBlock) {
		print "$Key: $MountBlock->{$Key}\n";
	    }
	    print "\n";
	}
	print "====================================================\n";
 

    }

}
#----------------------------------------------------------------------
sub generateSCRDoc {
    my $FileInfos = shift;
    my $OutputDir = $Options->{o} || ".";

    open (SCRINDEX, ">$OutputDir/index.scr.html");
    open (SCROVERVIEW, ">$OutputDir/overview.scr.html");

    printHTMLHeader(OUT   => \*SCRINDEX,
	    Title => "YaST2 Documentation - SCR Index",
	    OverviewLink => 1
	    );
    print SCRINDEX "<h1>SCR Index</h1>\n";
    print SCRINDEX "<table>\n";
    print SCRINDEX "<tr><th>Mount Point</th><th>Summary</th></tr>";

    printHTMLHeader(OUT   => \*SCROVERVIEW,
	    Title => "YaST2 Documentation - SCR Overview",
	    IndexLink => 1,
	    );
    print SCROVERVIEW "<h1>SCR Overview</h1>\n";

    foreach my $FileName (sort {
	    $FileInfos->{$a}->{Mount}->[0]->{MountPoint}
	    cmp
	    $FileInfos->{$b}->{Mount}->[0]->{MountPoint};
	} keys %$FileInfos) {
	my $FileInfo = $FileInfos->{$FileName};
	open (SCRDETAIL, ">$OutputDir/" .
	    $FileInfo->{FileNameBase} . ".html");
	printHTMLHeader(
		OUT   => \*SCRDETAIL,
		Title => "YaST2 Documentation - SCR - "
		    . $FileInfo->{FileNameBase} . $FileInfo->{FileNameExt},
		IndexLink => 1,
		OverviewLink => 1,
		);

	my $MountInfo = $FileInfo->{Mount};
	foreach my $MountBlock
	    (sort {$a->{MountPoint} cmp $b->{MountPoint}} @$MountInfo) {

	    # Index
	    printHTMLMountPoint(OUT => \*SCRINDEX,
		Style => "short",
		BaseDir => $OutputDir,
		FileNameBase => $FileInfo->{FileNameBase},
		Info => $MountBlock,
		);

	    # Overview
	    printHTMLMountPoint(OUT => \*SCROVERVIEW,
		Style => "normal",
		BaseDir => $OutputDir,
		FileNameBase => $FileInfo->{FileNameBase},
		Info => $MountBlock,
		);

	    # Detailed View
	    printHTMLMountPoint(OUT => \*SCRDETAIL,
		Style => "long",
		BaseDir => $OutputDir,
		FileNameBase => $FileInfo->{FileNameBase},
		Info => $MountBlock,
		);
	}
	printHTMLFooter(
	    OUT => \*SCRDETAIL,
	    GeneratedFrom => $FileName,
	    );
	close(SCRDETAIL);
    }

    print SCRINDEX "</table>\n";
    printHTMLFooter(OUT => \*SCRINDEX);
    close(SCRINDEX);

    printHTMLFooter(OUT => \*SCROVERVIEW);
    close(SCROVERVIEW);

}
#----------------------------------------------------------------------
#----------------------------------------------------------------------
#----------------------------------------------------------------------
#----------------------------------------------------------------------
#----------------------------------------------------------------------
sub printHTMLHeader {
    my %Param = @_;

    my $OUT = $Param{OUT} || \*STDOUT;
    $Param{Title} ||= "YaST2 Documentation";

    print $OUT "<html><head><title>";
    print $OUT $Param{Title};
    print $OUT "</title></head>\n<body>\n";
    if ($Param{IndexLink} || $Param{OverviewLink}) {
	print $OUT "<a href=\"index.scr.html\">Index</a> " if $Param{IndexLink};
	print $OUT "<a href=\"overview.scr.html\">Overview</a> " if $Param{OverviewLink};
	print $OUT "<hr>\n";
    }
}
#----------------------------------------------------------------------
sub printHTMLFooter {
    my %Param = @_;

    my $OUT = $Param{OUT} || \*STDOUT;

    my $Login = getlogin || getpwuid($<) || "unknown";

    print $OUT "<hr><font size=\"-1\">\n";
    print $OUT "Generated at " . scalar localtime() . " <br>\n";
    print $OUT "by $Login <br>\n";
    print $OUT "from " . $Param{GeneratedFrom} . " <br>\n"
	if $Param{GeneratedFrom};
    print $OUT "with $0 ($VERSION)<br>\n";
    print $OUT "</font></body></html>\n";
}
#----------------------------------------------------------------------
sub printHTMLMountPoint {
    my %Param = @_;

    my $OUT = $Param{OUT} || \*STDOUT;
    $Param{Style} ||= "normal";
    my $MountPoint = $Param{Info}->{MountPoint};
    my $Link = $Param{BaseDir} . "/" . $Param{FileNameBase} . ".html";

    if ($Param{Style} eq "short") {
	# Short
	print $OUT "<tr>";
	print $OUT "<td><a href=\"$Link\">$MountPoint</a></td>";
	print $OUT "<td>";
	print $OUT ($Param{Info}->{Summary} || "&nbsp;");
	print $OUT "</td>";
	print $OUT "</tr>\n";
    } elsif ($Param{Style} eq "normal") {
	# Normal
	print $OUT "<table border=\"0\" cellspacing=\"0\" width=\"100%\" bgcolor=\"#f96500\" cellpadding=1>";
	print $OUT "<tr><td>";
	print $OUT "<table width=\"100%\" bgcolor=\"#ffc080\" cellspacing=\"0\" cellpadding=\"3\" border=\"0\">";
	print $OUT "<tr><td>";
	print $OUT "<font size=\"+1\"><tt><b>";
	print $OUT "<a href=\"$Link\" name=\"$MountPoint\">$MountPoint</a>";
	print $OUT "</b></tt></font>";
	print $OUT "</td></tr></table>";
	print $OUT "</td></tr></table>";

	if ($Param{Info}->{General}) {
	    print $OUT "<p>" . $Param{Info}->{General} . "</p>";
	}

	if ($Param{Info}->{Example}) {
	    print $OUT "<b>Example:</b>";
	    print $OUT "<pre>\n" . $Param{Info}->{Example} . "\n</pre>\n";
	}
    } elsif ($Param{Style} eq "long") {
	# Long
	print $OUT "<table border=\"0\" cellspacing=\"0\" width=\"100%\" bgcolor=\"#f96500\" cellpadding=1>";
	print $OUT "<tr><td>";
	print $OUT "<table width=\"100%\" bgcolor=\"#ffc080\" cellspacing=\"0\" cellpadding=\"3\" border=\"0\">";
	print $OUT "<tr><td>";
	print $OUT "<font size=\"+1\"><tt><b>";
	print $OUT "<a href=\"overview.scr.html#$MountPoint\" name=\"$MountPoint\">$MountPoint</a>";
	print $OUT "</b></tt></font>";
	print $OUT "</td></tr></table>";
	print $OUT "</td></tr></table>";

	my %Skip = ();
	$Skip{MountPoint} = 1;
	if ($Param{Info}->{Summary}) {
	    print $OUT "<p><b>" . $Param{Info}->{Summary} . "</b></p>";
	    $Skip{Summary} = 1;
	}

	if ($Param{Info}->{General}) {
	    print $OUT "<p>" . $Param{Info}->{General} . "</p>";
	    $Skip{General} = 1;
	}

	if ($Param{Info}->{Access}) {
	    print $OUT "<p><b>Access:</b> ";
	    print $OUT $Param{Info}->{Access};
	    print $OUT "</p>";
	    $Skip{Access} = 1;
	}

	if ($Param{Info}->{Example}) {
	    print $OUT "<b>Example:</b>";
	    print $OUT "<pre>\n" . $Param{Info}->{Example} . "\n</pre>\n";
	    $Skip{Example} = 1;
	}

	if ($Param{Info}->{See}) {
	    print $OUT "<b>See:</b><ul>";
	    my @See = split(/\n\s*/, $Param{Info}->{See});
	    foreach my $See (@See) {
		print $OUT "<li>" . expandSeeToLink($See) . "</li>";
	    }
	    print $OUT "</ul>\n";
	    $Skip{See} = 1;
	}

	if ($Param{Info}->{Authors}) {
	    print $OUT "<b>Authors:</b><p>";
	    my $Authors = $Param{Info}->{Authors};
	    $Authors =~ s/\((\S+\@(\S+\.)+\S+)\)/<a href="(mailto:$1">$1<\/a>)/g;
	    $Authors =~ s/<(\S+\@(\S+\.)+\S+)>/&lt;<a href="mailto:$1">$1<\/a>&gt;/g;
	    $Authors =~ s/\n/<br>\n/g;
	    print $OUT $Authors;
	    print $OUT "</p>";
	    $Skip{Authors} = 1;
	}

	if ($Param{Info}->{File}) {
	    print $OUT "<b>File:</b>" . $Param{Info}->{File} . "<br>\n";
	    $Skip{File} = 1;
	}

	if ($Param{Info}->{Module}) {
	    print $OUT "<b>Module:</b>" . $Param{Info}->{Module} . "<br>\n";
	    $Skip{Module} = 1;
	}

	if ($Param{Info}->{ID}) {
	    print $OUT "<p>" . $Param{Info}->{ID} . "</p>";
	    $Skip{ID} = 1;
	}

	print $OUT "<pre>\n";
	foreach my $Key (sort keys %{$Param{Info}}) {
	    next if $Skip{$Key};
	    print $OUT "$Key: " . $Param{Info}->{$Key} . "\n";
	}
	print $OUT "</pre>\n";
    } else {
	print $OUT "Unknown Style: $Param{Style}\n";
    }

    print $OUT "\n</body></html>\n";
}
#----------------------------------------------------------------------
sub expandSeeToLink {
    my $See = shift;

    if ($See =~ /<a/i) {
	# Link
	return $See;
    } elsif ($See =~ /^\s*MountPoint:?\s+(.*?)\s*$/i) {
	# Mountpoint
	return "<a href=\"overview.scr.html#$1\">$1</a>";
    } elsif ($See =~ /^\s*man:?\s+(.*?)\s*$/i) {
	# man page
	return "<a href=\"man:/$1\">man $1</a>";
    } elsif ($See =~ /^\s*info:?\s+(.*?)\s*$/i) {
	# info page
	return "<a href=\"info:/$1\">info $1</a>";
    } elsif ($See =~ /^\s*((http|ftp):\/\/.*?)\s*$/i) {
	# Ext reference
	return "<a href=\"$1\">$1</a>";
    } else {
	return expandNameToLink($See);
    }
}
#----------------------------------------------------------------------
sub expandNameToLink {
    my $Name = shift;
    $Name =~ s/^\s*//;
    $Name =~ s/\s*$//;

    #my $YaST2DocHome = "../..";
    my $YaST2DocHome = $Options->{D} || "file:/usr/share/doc/packages";
    my %ExplicitLinks = (
	libscr => "$YaST2DocHome/libscr/autodocs/index.html",
	anyagent => "$YaST2DocHome/yast2-agent-any/anyagent.html",
    );

    if (exists $ExplicitLinks{$Name}) {
	return "<a href=\"$ExplicitLinks{$Name}\">$Name</a>";
    } elsif ($Name =~ m|^[^/].*/|) {
	return "<a href=\"$YaST2DocHome/$Name\">$Name</a>";
    } else {
	my $FileName = $Name;
	$FileName =~ s/\s/_/g;
	$FileName .= ".html" unless ($FileName =~ /\.html?$/);
	return "<a href=\"$FileName\">$Name</a>";
    }

}
#----------------------------------------------------------------------
###
 # Function generates XML document from the internal parsed data
 # and prints it to the stdout
 #
 # @param $FileInfo hash
 ##
sub generateSCRXMLDoc {
    my $FileInfos = shift;

    my $output = new IO::File(">output.xml") || do {
	warn "Cannot open file output.xml: ".$!."\n";
	exit 1;
    };
    print "File 'output.xml' has been created\n";

    my $writer = new XML::Writer(OUTPUT => $output, NEWLINES => 0, UNSAFE => 1);
    $writer->startTag('scrdoc');
    $writer->startTag('mountpoints');

    foreach my $FileName (sort {
	    $FileInfos->{$a}->{Mount}->[0]->{MountPoint}
	    cmp
	    $FileInfos->{$b}->{Mount}->[0]->{MountPoint};
    } keys %$FileInfos) {
	my $FI = $FileInfos->{$FileName};
	    foreach my $MP (@{$FI->{'Mount'}}) {
		$writer->startTag('mountpoint_item');

		if (defined $FI->{'FileName'}) {
		$writer->startTag('file');
		$writer->characters($FI->{'FileName'});
		$writer->endTag('file');
		}
	    
		if (defined $MP->{'MountPoint'}) {
		$writer->startTag('mountpoint');
		$writer->characters($MP->{'MountPoint'});
		$writer->endTag('mountpoint');
		}

		if (defined $MP->{'Summary'}) {
		$writer->startTag('summary');
		$writer->characters($MP->{'Summary'});
		$writer->endTag('summary');
		}

		if (defined $MP->{'General'}) {
		$writer->startTag('general');
		$writer->characters($MP->{'General'});
		$writer->endTag('general');
		}

		if (defined $MP->{'Authors'}) {
		$writer->startTag('authors');
		foreach my $author (split (/\n/, $MP->{'Authors'})) {
		    $writer->startTag('ITEM');
		    $writer->characters($author);
		    $writer->endTag('ITEM');
		}
		$writer->endTag('authors');
		}

		if (defined $MP->{'Example'}) {
		$writer->startTag('example');
		$writer->characters($MP->{'Example'});
		$writer->endTag('example');
		}

		if (defined $MP->{'Access'}) {
		$writer->startTag('access');
		$writer->characters($MP->{'Access'});
		$writer->endTag('access');
		}

		if (defined $MP->{'See'}) {
		$writer->startTag('see');
		$writer->characters($MP->{'See'});
		$writer->endTag('see');
		}

		$writer->endTag('mountpoint_item');
	    }
    }

    $writer->endTag('mountpoints');
    $writer->endTag('scrdoc');
    $writer->end();
    $output->close() || do {
	warn "Cannot save output.xml file";
	exit 1;
    };
    print "File 'output.xml' has been saved\n\n";
}
