#!/usr/bin/perl

sub cstr2pod {
    local($_) = shift;
    s/\\"/"/go;
    s/"([^\"]*)"/"C<$1>"/go;
    $_;
}

$section = 1;

@section_order = (
		  'NAME',
		  'SYNOPSIS',
		  'DESCRIPTION',
		  'OPTIONS',
		  'RETURN VALUE',
		  'ERRORS',
		  'EXAMPLES',
		  'ENVIRONMENT',
		  'FILES',
		  'SEE ALSO',
		  'NOTES',
		  'CAVEATS',
		  'WARNINGS',
		  'DIAGNOSTICS',
		  'BUGS',
		  'RESTRICTIONS',
		  'AUTHOR',
		  'AUTHORS',
		  'HISTORY'
		  );

sub type2word {
    my($type) = shift;
    return 'INT' if $type eq 'integer';
    return 'UINT' if $type eq 'ulong';
    return 'STR' if $type eq 'string' || $type eq 'stringlist';
    return '' if $type eq 'flag' || $type eq 'counter';
    die "Invalid cli option type '$type'";
}

sub add_option {
    my($short, $long, $type, $desc) = @_;

    my $s = '[B<';
    my $o = '=item B<';
    if($short) {
	$s .= "-$short";
	$o .= "-$short";
	if($type) {
	    $s .= " $type";
	    $o .= " $type";
	}
    }
    if($short && $long) {
	$s .= ">]\n[B<";
	$o .= ">, B<";
    }
    if($long) {
	$s .= "--$long";
	$o .= "--$long";
	if($type) {
	    $s .= "=$type";
	    $o .= "=$type";
	}
    }
    $s .= ">]\n";
    $o .= ">\n\n$desc\n\n";

    $synopsis .= $s;
    $options = "=over 8\n\n" unless $options;
    $options .= $o;
}

sub parse_option {
    local($_) = shift;
    s/^\s*\{\s*//o;
    s/\s*\},?\s*/ /o;

    my $short = $1 if s/^'([^\'])',\s*//o;
    die "Invalid cli option" unless $short || s/^0,\s*//o;

    my $long = $1 if s/^"([^\"]+)",\s*//o;
    die "Invalid cli_option" unless $long || s/^0,\s*//o;

    my $type = $1 if s/^cli_option::(\S+),\s*//o;
    die "Invalid cli_option" unless $type;
    $type = &type2word($type);

    my $val = $1 if s/^([^,]+),\s*//o;
    my $var = $1 if s/^&([^,]+),\s*//o;

    my $desc = cstr2pod($1) if s/^"([^,]+)",\s*//o;
    die "Invalid cli_option" unless $desc;
    $desc =~ s/\.?$/./o if $desc;

    my $default = $1 if s/^"([^\"]+)"\s+//o;
    die "Invalid cli_option" unless $default || s/^0\s+//o;
    $desc .= " Defaults to $default." if $default;

    s/\s*\/\/\s*/ /go;
    s/^\s*//o;

    add_option($short, $long, $type, $_ || $desc);
}

sub parse_options {
    $synopsis = "B<$program>\n";

    my $line;
    while(<>) {
	s/^\s+//o;
	s/\s+$//o;
	if($line && /^\{/o) {
	    &parse_option($line);
	    $line = "";
	}
	next if /^\{\s*0\s*\},?/o;
	next if /^\{\s*0\s*,\s*\},?/o;
	last if /^\s*\};/o;
	$line =~ s/$/ $_/;
    }
    &parse_option($line) if $line;

    $synopsis .= "I<$usage>" if $usage;
    $options .= "=back" if $options;
    $sections{'SYNOPSIS'} = $synopsis;
    $sections{'OPTIONS'} = $options;
}

sub parse_notes {
    my $section;
    my $title;
    while(<>) {
	chomp;
	last unless /^$/o || s/^\/\/\s*//o;
	if(/^[\sA-Z]+$/o) {
	    $sections{$title} = $section if $title && $section;
	    undef $section;
	    $title = $_;
	} else {
	    $section .= "$_\n";
	}
    }
    $sections{$title} = $section if $title && $section;
}

sub parse_header_line {
    local($_, $comment) = @_;
    if(s/^\s*const\s+char\s*\*\s*cli_(\S+)\s*=\s*//o) {
	my $name = $1;
	s/;\s*$//o;
	s/^\"//;
	s/\"$//o;
	s/\\n$//o;
	s/\\n""/\n/go;
	$program = $_ if $name eq 'program';
	$prefix = $_ if $name eq 'help_prefix';
	$usage = $_ if $name eq 'args_usage';
	$suffix = $_ if $name eq 'help_suffix';
    }
}

sub parse_header {
    my $comment = '';
    my $line = '';
    while(<>) {
	s/^\s+//o;
	s/\s+$//o;
	if(s/^.*Copyright\s*\(C\)\s*[\d,]+\s*//o) {
	    $author = $_;
	} else {
	    last if ($program && $prefix && /^$/o);
	    next if /^#/o;
	    $comment .= "$1\n" if s|\s*//\s*(.*)$||o;
	    $line =~ s/$/\n$_/;
	    if(/;$/o) {
		&parse_header_line($line, $comment);
		undef $line;
		undef $comment;
	    }
	}
    }
}

sub parse_description {
    while(<>) {
	s/^\s+//o;
	s/\s+$//o;
	last if / cli_options\[\]\s*=\s*\{/o;
	next unless s/^\/\/\s*//o;
	$description .= "$_\n";
    }
}

&parse_header;
&parse_description;
&parse_options;
&parse_notes;

$description .= "\n\n$suffix\n" if $suffix;

$sections{'NAME'} = "$program - $prefix";
$sections{'DESCRIPTION'} = $description;
$sections{'AUTHORS'} = $author if $author;

foreach $section (@section_order) {
    print "=head1 $section\n\n$sections{$section}\n\n"
	if $sections{$section};
}

1;
