#!/usr/bin/perl -w --
#
# man2xpcomp - build a template completion script snippet from a man page
#
#  Copyright (C) 2001 Ingo K"ohne
#
#  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, write to the Free Software Foundation, Inc.,
#  59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.


use Getopt::Std;

$opt_k = "yes";
$opt_h = 0;

getopts('m:S:kh');

if ($opt_h == 1)
{
    print "man2xpcomp [-h] [-m <option syntax>] [-S <header>] -k  [<section>] <command>
Translate option descriptions in a manual page into a skeleton for an
xpcomp completion script.  
  -h\t\tthis help
  -m short\texpect short options only
  -m long\texpect short and long options
  -m longonly\texpect long options only but also with single dash
  -m singledash\texpect short and long options without double dashes
  -k\t\texpect variants of the same option be seperated by comma
  -S <header>\theader of the chapter in which to look for option descriptions
  <section>\tsection ('1' to '9') in which to look for the manual page 
  <command>\tcommand name (or rather manual page name)
";
    exit 0;
}

if (not defined ($ARGV[0]))
{
    print "Missing command name (try -h)\n";
    exit 1;
}
if (defined ($ARGV[1]))
{
    open MAN, "man -S '$ARGV[0]' '$ARGV[1]'|";
    $command = $ARGV[1];
}
else
{
    open MAN, "man '$ARGV[0]'|";
    $command = $ARGV[0];
}

$i = 0;
$n = -1;

$match_arg_word = "(?:[-a-z]+|[-A-Z]+)";
$match_optional = "\\[[^\\]]*\\]";
$match_arg = "(?:(?:$match_arg_word)?(?:$match_optional)?)";
$match_long_name = "([a-zA-Z][-a-z0-9A-Z_]+)";
$match_short = "-([a-zA-Z])(\\s?\\[?($match_arg)\\]?)?"; 

if ( not defined ($opt_m) )
{
    $opt_m = "long";
}
    
SWITCH: {
    if ( $opt_m =~ /^short$/ ) {
	$match_opt = "(?:$match_short)";
	last SWITCH;
    }
    if ( $opt_m =~ /^long$/ ) {
	$match_long = "--$match_long_name(\\[?\\s*=?\\s*($match_arg)\\]?)?";
	$match_opt = "(?:$match_long|$match_short)";
	last SWITCH;
    }
    if ( $opt_m =~ /^longonly$/ ) {
	$match_long = "--?$match_long_name(\\[?\\s*=?\\s*($match_arg)\\]?)?";
	$match_opt = "(?:$match_long|$match_short)";
	last SWITCH;
    }
    if ( $opt_m =~ /^singledash$/ ) {
	$match_long = "-$match_long_name(\\[?\\s*=?\\s*($match_arg)\\]?)?";
	$match_opt = "(?:$match_long|$match_short)";
	last SWITCH;
    }
    exit 1;
}

 HEADER: while ( <MAN> ) 
{
	s/.\ch//g; 
	if ( not /^\s*[A-Z ]+\s*$/ ) { next HEADER; }
	if (defined ($opt_S))
	{ 
	    if (not /$opt_S/ ) {next HEADER; }
	    last HEADER;
	}
	if ( /(NAME|SYNOPSIS|DESCRIPTION|EXAMPLES)/ ) { next HEADER; }
	last HEADER;
}


 LINE: while (<MAN>)
{
    s/.\ch//g;
    
    if ( /^(SEE ALSO|DIAGNOSTICS|BUGS|FILES|AUTHOR)$/ ) { last LINE; }

    $n = 0;

    $match_komma = "";    
    while (/^ {7}$match_komma$match_opt\b/) {

	if ( defined ($1) ){
	    $is_long=1;
	    $name=$1;
	    $arg=$3;
	} elsif ( defined($4) ) {
	    $is_long=0;
	    $name=$4;
	    $arg=$6;
	} else { next LINE; }


	#if ( defined ($arg) and $arg ne "" )
	if ( defined ($name) and $name ne "" )
	{
	    $compl[$i]->{$name} = $arg;
	}
	$n++;
	if ( defined ( $opt_k ) and $opt_k eq "yes" )
	{
	    $match_komma = "(?:(?:[^\\[,]|$match_optional)*(?:,|or)){$n} ? ?";
	}
	else
	{
	    $match_komma = "(?:(?:[^\\[, ]|$match_optional)* ){$n} ? ?";
	}
    }
    if ($n !=0) {
	$i++;
    }
	
}

print "\n. ../include/common\n";
print "\ncmd=$command\n\n";

foreach (@compl)
{
    $options = "";
    $arg = "";
    foreach my $option ( keys %{$_} )
    {
	$options = "$options $option";

	if ( defined $$_{$option} )
	{
	    if ( $arg eq "" )
	    {
		$arg = $$_{$option};
	    }
	    elsif ( defined ($$_{$option}) and $$_{$option} ne "" and $arg ne $$_{$option} )
	    {
		$arg .= "#$$_{$option}";
	    }
	}
    }
    
    if ( $arg ne "" )
    {
	print "optcomplete -C '#$arg'  \$cmd$options\n";
    }
    else
    {
	print "optcomplete  \$cmd$options\n";
    }
}
print "optcomplete -f  \$cmd NONOPT\n";

print "\noptcomplete -m $opt_m  \$cmd\n";
print "\ncomplete -F xpcompfunc  \$cmd\n";
print "\nunset cmd \${!xpc_*}\n";
