Menu

[766a1d]: / showconfig  Maximize  Restore  History

Download this file

372 lines (280 with data), 8.1 kB

#!/usr/bin/perl -T
######################################################################
#
# showconfig --	Present LXR configuration as html
#
#	Andre J Littoz <ajlittoz@users.sf.net>
#
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
######################################################################

=head1 script showconfig

This script shows how LXR understood the configuration parameters
from F<lxr.conf> file. They are displayed in tabular form:

First column: parameter name

Second column: parameter type (I<string>, I<array>, I<hash>, ...)

Third column: value from tree-specific parameter group

Fourth column: value from global parameter group

With such a layout, it is easy to see if a global value is overridden
by a specific one.

=cut

use strict;
use lib do { $0 =~ m{(.*)/} ? "$1/lib" : 'lib' };  # if LXR modules are in ./lib

use LXR::Common;
use LXR::Template;


=head2 C<dumphash ($h, $left)>

Function C<dumphash> returns the contents of the input hash
as a ready-to-print string.

The value of a key may be a simple I<string> (displayed surrounded
with quotes), an I<array> (dumped "as is" without checking for further
references) or a I<hash> (recursively dumped surrounded with curly braces).

=over

=item 1

C<$h>

a reference to the I<hash> to dump

=item 2

C<$left>

the I<number> of spaces at left to indent this hash

=back

=cut

sub dumphash {
	my $h = shift;
	my $left = shift;
	my $d = ' 'x$left . '{ ';

	foreach my $k (sort keys %$h) {
		$d .= "'$k' => ";
	# Compute left spaces in case we need to recurse
		$d =~ m/([^\n]*)$/s;
		my $indent = length($1);
		my $v = $h->{$k};
		if (ref($v) eq 'ARRAY') {
			$d .= '[ ' . join("\n".' 'x$indent.', ', @$v);
			if (1 < scalar(@$v)) {
				$d .= "\n".' 'x$indent;
			} else {
				$d .= ' ';
			}
			$d .= ']';
		} elsif (ref($v) eq 'HASH') {
			$d .= "\n";
			$d .= dumphash ($v, $indent);
		} else {
			$d .= "'$v'";
		}
	# Prepare for next key with initial left spaces and comma
		$d .= "\n" . ' 'x$left . ', ';
	}
	# Replace last comma with closing curly braces
	$d =~ s/, $/}\n/;
	return $d;
}


=head2 C<parmvalue ($parm, $pg)>

Function C<parmvalue> dumps a parameter value if it exists in this
parameter group.

After testing for parameter existence, processing is dispatched
according to type value.

Parameter C<dbpass> is not dumped for security reason.

=over

=item 1

C<$parm>

a parameter name as a I<string>

=item 2

C<$pg>

a reference to a parameter group

=back

=cut

sub parmvalue {
	my $parm = shift;
	my $pg = shift;
	my $fallback = shift;

	return '' if !exists($pg->{$parm}) && !defined($fallback);
	my $val = $pg->{$parm} // $fallback->{$parm};
	if (ref($val) eq 'HASH') {
		return '<pre>' . dumphash($val, 0) . '</pre>';
	} elsif (ref($val) eq 'ARRAY') {
		return '<pre>' . join('<br>', @$val) . '</pre>';
	} else {
		if ('dbpass' eq $parm) {
			return '<h4>Hey, that\'s supposed to be a secret!</h4>';
		} else {
			return "<pre>$val</pre>";
		}
	}

}


=head2 C<parmexpand ($templ, $who, $pgs, $pgnr)>

Function C<parmexpand> is a "$function" substitution function.
It returns its block (contained in C<$tmpl>) expanded for each
accessible configuration parameter.

=over

=item 1

C<$templ>

a I<string> containing the template (i.e. argument)

=item 2

C<$who>

a I<string> containing the script name (i.e. showconfig)
requesting this substitution

=item 3

C<$pgs>

a reference to the parameter group array

=item 4

C<$pgnr>

parameter group index

=back

Parameter names are obtained from global C<$config> hash reference
since all parameters end up there.
"I<internal>" parameters C<'confpath'> and C<'parmgroupnr'> are removed
from the set.

A parameter may be defined in an included file like C<'filetype'>
from C<'filetypeconf'>. In this case, both specific and global columns
are empty.

A parameter is considered if it belongs in the global section or in the
requested tree section.

To dump values anyway, force C<$config> usage instead of a parameter
group through query argument C<_confall> with non zero value.

=cut

sub parmexpand {
	my ($templ, $who, $pgs, $pgnr) = @_;
	my $ret;
	my @keylist = ();
	my $parmgroup = @$pgs[$pgnr];
	my $globgroup = @$pgs[0];
	my $full = $HTTP->{'param'}{'_confall'} // 0;

	if ($full != 0) {
		my %seen;
		for (@$pgs) {
			while (defined(my $key = each %{$_})) {
				$seen{$key}++;
			}
		}
		if (1 < $full) {
			for (keys %$config) {
				$seen{$_}++
			}
		}
		@keylist = keys(%seen);
	} else {
		@keylist = keys %{{%$parmgroup, %$globgroup}};
	}

	for my $parm (sort @keylist) {
		next if (	$parm eq 'confpath'
				||	$parm eq 'parmgroupnr'
				);
		 my $extra =	!exists($$parmgroup{$parm})
					&&	!exists($$globgroup{$parm});
		$ret .= expandtemplate
					( $templ
					,	( 'force' => sub{ $extra ? 'conf_force' : '' }
						, 'parm' => sub{ $parm }
						, 'type' => sub{ 
										my $t = ref($config->{$parm});
										if ('' ne $t) {
											return lc($t);
										}
										return 'string';
									}
						, 'val'  => sub{ parmvalue	( $parm
													, $parmgroup
													, ( 1 < $full
													  ? $config
													  : undef
													  )
													)
									}
						, 'global'=> sub{
									parmvalue($parm, $globgroup)
										}
						)
					);
	}
	return $ret;
}


=head2 C<parmgrouplink ($pgnr, $pgs)>

Function C<parmgrouplink> is a "$variable" substitution function.
It returns an C<E<lt> A E<gt>> element invoking
script I<showconfig> to dump the designated parameter group.

=over

=item 1

C<$pgnr>

parameter group index

=item 2

C<$pgs>

a reference to the parameter group array

=back

Link is created only if C<$pgnr> has an acceptable value.
Otherwise, function returns string C<'none'>.

=cut

sub parmgrouplink {
	my ($pgnr, $pgs) = @_;

	if (0>=$pgnr || $pgnr > $#$pgs) {
		return 'none';
	} else {
		return "#$pgnr <a href='"
				. $config->treeurl($$pgs[$pgnr], $$pgs[0])
				. 'showconfig'
				. ( exists($$pgs[$pgnr]->{'treename'})
				  ? '/'.$$pgs[$pgnr]->{'treename'}
				  : ''
				  )
				. "?_parmgroup=$pgnr'> "
				. ($$pgs[$pgnr]->{'virtroot'} // $$pgs[0]->{'virtroot'})
				. (exists($$pgs[$pgnr]->{'treename'})
				  ? '/&hellip;/' . $$pgs[$pgnr]->{'treename'}
				  : ''
				  )
				. '</a>' ;
	}
}


=head2 Script entry point

Output is controlled by a template

Eventually, a specific parameter group may be dumped by passing
its index in URL argument C<_parmgroup>.
This index may receive a default value through configuration parameter
C<'parmgroupnr'>.

=cut

my $errorsig = "<!-- ! -->";
my $templ;

httpinit();
std_http_headers();

my $who = 'showconfig';
my @pgs = $config->readconfig();
my $which = $HTTP->{'param'}{'_parmgroup'}
			// $config->{'parmgroupnr'}
			// 1;
makeheader($who);
$templ = gettemplate	( 'htmlconfig'
						, $errorsig
						);
if ($templ =~ m/^$errorsig/) {
	die "Can't display configuration without 'htmlconfig' template\n";
}
print expandtemplate
	( $templ
	,	( 'conffile'	=> sub { '<em>' . $config->{'confpath'} . '</em>' }
		, 'virtroot'	=> sub { $pgs[$which]->{'virtroot'} }
		, 'parmgroupnr'	=> sub { $which
								. (1 < $HTTP->{'param'}{'_confall'}
								  ? ' (apocalyptical)'
								  : ''
								  )
								}
		, 'varbtnaction'=> sub { varbtnaction(@_, $who) }
		, 'previous'	=> sub { parmgrouplink($which-1, \@pgs) }
		, 'next'		=> sub { parmgrouplink($which+1, \@pgs) }
		, 'conf_parm'	=> sub { parmexpand (@_, $who, \@pgs, $which) }
		)
	);
makefooter($who);

httpclean;
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.