#!/usr/bin/perl

use Getopt::Std;

# xpostconf - extract parameter info from postconf prototype file

# Usage: xpostconf [options] protofile [parameter...]
#
# -b: Brief output: print only the first sentence of each definition
#
# -c: print the classes named on the command line (default: all).
#
# -h: print help message.
#
# -p: print the parameters named on the command line (default: all).
#
# -s specfile: process the entries listed in the named file: ordinary
# text is copied as is, 
#	%CLASS class-name mode
#	%PARAM param-name mode
# are replaced by the respective information. Mode is b (brief)
# f (full) or i (ignore).
#
# If no -s is specified, extracts the named parameter text (all
# parameters by default).

$opt_b = undef;
$opt_c = undef;
$opt_p = undef;
$opt_s = undef;
$opt_v = undef;
getopts("bcps:v");

die "Usage: $0 [-bcpv] [-s specfile] protofile [parameter...]\n" 
	unless $protofile = shift(@ARGV);

# Save one definition.

sub save_text {
    if ($category eq "PARAM") {
	$param_text{$name} = $text;
	if ($opt_v) {
	    printf "saving entry %s %.20s..\n", $name, $text;
	} 
    } elsif ($category eq "CLASS") {
	$class_text{$name} = $text;
	if ($opt_v) {
	    printf "saving class %s %.20s..\n", $name, $text;
	} 
    } else {
	die "Unknown category: $category. Need PARAM or CLASS.\n";
    }
}

# Read the whole file even if we want to print only one parameter.

open(POSTCONF, $protofile) || die " cannot open $protofile: $!\n";

while(<POSTCONF>) {

    next if /^#/;
    next unless ($name || /\S/);

    if (/^%(PARAM|CLASS)/) {

	# Save the accumulated text.

	if ($name && $text) {
	    save_text();
	}

	# Reset the parameter name and accumulated text.

	$name = $text = "";
	$category = $1;

	# Accumulate the parameter name and default value.

	do {
	    $text .= $_;
	} while(($_ = <POSTCONF>) && /\S/);
	($junk, $name, $junk) = split(/\s+/, $text, 3);

    } 

    # Accumulate the text in the class or parameter definition.

    $text .= $_;

}

# Save the last definition.

if ($name && $text) {
    save_text();
}

# If working from a spec file, emit output in the specified order.

if ($opt_s) {
    open(SPEC, "$opt_s") || die "cannot open $opt_s: $!\m";
    while(<SPEC>) {
	if (/^%/) {
	    ($category, $name, $mode) = split(/\s+/, substr($_, 1));
	    if ($category eq "CLASS") {
		die "Unknown class name: $name.\n" 
		    unless $text = $class_text{$name};
	    } elsif ($category eq "PARAM") {
		die "Unknown parameter name: $name.\n"
		    unless $text = $param_text{$name};
	    } else {
		die "Unknown category: $category. Need CLASS or PARAM\n";
	    }
	    if ($mode eq "i") {
		next;
	    } elsif ($mode eq "b") {
		$text =~ s/\.\s.*/.\n\n/s;
	    } elsif ($mode ne "p") {
		die "Unknown mode: $mode. Need b or p or i,\n";
	    }
	    print $text, "\n";
	} else {
	    print;
	}
    }
    exit;
}

# Print all the parameters.

if ($opt_c) {
    $what = \%class_text;
} else {
    $what = \%param_text;
}

if ($#ARGV < 0) {
    for $name (sort keys %{$what}) {
	$text = ${$what}{$name};
	$text =~ s/\.\s.*/.\n\n/s if ($opt_b);
	print $text, "\n";
    }
} 

# Print parameters in the specified order.

else {
    for $name (@ARGV) {
	$text = ${$what}{$name};
	$text =~ s/\.\s.*/.\n\n/s if ($opt_b);
	print $text;
    }
}
