2
0
mirror of https://github.com/lm-sensors/lm-sensors synced 2025-10-21 15:05:58 +00:00
Files
lm-sensors/prog/doc/doc-features.pl
Jean Delvare 9ab12ef229 Better message on tokenization error.
git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@1867 7894878c-1315-0410-8ee3-d5d059ff63e0
2003-07-07 11:36:17 +00:00

358 lines
9.5 KiB
Perl
Executable File

#!/usr/bin/perl -w
#
# doc-features.pl - Generate module/library documentation
# Copyright (c) 1999 Frodo Looijaard <frodol@dds.nl>
# Copyright (c) 2002 Jean Delvare <khali@linux-fr.org>
#
# 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.
#
use strict;
# %prefix contains the SENSORS_*_PREFIX defines as found in lib/chips.h.
# It is generated by scan_chips_h(). It shouldn't have duplicated values.
# %arrayname contains the sensors_chip_features array as found in
# lib/chips.c. It is generated by scan_chips_c_1(). It may have duplicated
# values.
# %prefix and %arrayname are expected to have the same set of keys, and
# this is verified in scan_all().
#
# %sysctl contains the sysctl filenames as found in kernel/chips/*.c. It
# is generated by scan_kernel_chip, which is called on each file. It has
# (of course) duplicated values.
#
# %features contains the features for all chips as found in lib/chips.c.
# They are stored as arrays of references to hashes, each containing the
# following fields:
# number: The preprocessor symbol for the number of this feature
# name: The name of this feature
# logical_mapping: The preprocessor symbol for the logical mapping
# feature
# compute_mapping: The preprocessor symbol for the compute mapping
# feature
# mode_read: 1 if the feature is readable, 0 if not
# mode_write: 1 if the feature is writable, 0 if not
# sysctl: Preprocessor name of the sysctl file
# offset: Offset (in longs) within the sysctl file
# magnitude: Magnitude of this feature
#
# %mapping contains the feature names. It is generated while parsing
# lib/chips.c and is later used to display the mappings.
use vars qw(%prefix %arrayname %sysctl %features %mapping);
# Scan chips.h to get all prefixes values.
# Store the results in %prefix.
# $_[0]: Path to chips.h
sub scan_chips_h
{
my $chips_h = shift;
open INPUTFILE, $chips_h
or die "Can't open $chips_h";
while (<INPUTFILE>)
{
if (m/^\s*#\s*define\s+(SENSORS_\w+_PREFIX)\s+"(\S+)"/)
{
die "Duplicate #define $1 in $chips_h"
if defined $prefix{$1};
$prefix{$1} = $2;
}
}
close INPUTFILE;
}
# Scan chips.c to get the feature array names.
# Store the results in %arrayname.
# $_[0]: Path to chips.c
sub scan_chips_c_1
{
my $chips_c = shift;
open INPUTFILE, $chips_c
or die "Can't open $chips_c";
while (<INPUTFILE> !~ m/^\s*sensors_chip_features\s/) {}
while (<INPUTFILE>)
{
last if m/^\s*\{\s*0/;
if (m/^\s*\{\s*(SENSORS_\w+_PREFIX)\s*,\s*(\w+)\s*\}\s*,/)
{
die "Duplicate entry $1 in sensors_chip_features"
if defined $arrayname{$1};
$arrayname{$1} = $2;
}
}
close INPUTFILE;
}
# Returns a list of tokens.
# Tokens are either '{', '}', ',', ';' or anything between them. Spaces on
# each side of a token are removed; spaces inside a token are not.
# Used by scan_kernel_chip() and scan_chips_c_2().
# $_[0]: Line to tokenize
sub tokenize
{
my $line = shift;
my @res = ();
$line =~ s/^\s*//;
while (length $line)
{
last if $line =~ s/^\s*$//;
$line =~ s/^([{};,])\s*//
or $line =~ s/^([^{},;]+?)\s*([{},;\n])/$2/;
die "Parse error"
unless defined $1;
push @res, $1;
}
return @res;
}
# Scan one chip file to get sysctl filenames.
# Store the results in %prefix.
# $_[0]: Kernel chip filename
sub scan_kernel_chip
{
my $chip = shift;
my $line;
open INPUTFILE, $chip
or die "Can't open $chip";
while ($line = <INPUTFILE>)
{
next unless $line =~ m/^\s*static\s+ctl_table/;
last if $line =~ m/;/; # Skip dynamic ctl_table
my @tokens = tokenize($line);
while ($line = <INPUTFILE>)
{
push @tokens, tokenize($line);
last if $line =~ m/;/;
}
while (shift @tokens ne '{') { die "Tokenization failed in $chip" unless @tokens }
for (;;)
{
while (shift @tokens ne '{') { die "Tokenization failed in $chip" unless @tokens }
my $val = shift @tokens;
last if $val eq '0';
die "Parse error: ',' expected after '$val' within $chip"
if shift @tokens ne ',';
my $name = shift @tokens;
die "Parse error: invalid name '$name' within $chip"
unless ($sysctl{$val}) = $name =~ m/^"(.+)"$/;
}
}
close INPUTFILE;
}
# Scan chips.c to get the feature arrays.
# Store the results in %feature.
# $_[0]: Path to chips.c
sub scan_chips_c_2
{
my $chips_c = shift;
my $line;
open INPUTFILE, $chips_c or
die "Can't open $chips_c";
while (<INPUTFILE>)
{
next unless m/sensors_chip_feature\s+(\w+)\s*\[/;
my $name = $1;
my @tokens = ();
while ($line = <INPUTFILE>)
{
push @tokens, tokenize($line);
last if $line =~ m/;/;
}
$features{$name} = [];
die "Parse error: '{' expected for $name"
if shift @tokens ne '{';
for(;;)
{
my $new = {};
while (shift @tokens ne '{') { die unless @tokens }
$new->{number} = shift @tokens;
last if $new->{number} eq '0';
die "Parse error: ',' expected for $name"
if shift @tokens ne ',';
($new->{name}) = (shift @tokens) =~ m/^"(.*)"$/
or die "Parse error: Bad name for $name";
die "Parse error: ',' expected for $name"
if shift @tokens ne ',';
$new->{logical_mapping} = shift @tokens;
die "Parse error: ',' expected for $name"
if shift @tokens ne ',';
$new->{compute_mapping} = shift @tokens;
die "Parse error: ',' expected for $name"
if shift @tokens ne ',';
my $next = shift @tokens;
$new->{mode_read} = ($next =~ m/_RW?$/);
$new->{mode_write} = ($next =~ m/_R?W$/);
die "Parse error: ',' expected for $name"
if shift @tokens ne ',';
$new->{sysctl} = shift @tokens;
die "Parse error: ',' expected for $name"
if shift @tokens ne ',';
($new->{offset}) = (shift @tokens) =~ m/^VALUE\s*\(\s*(\d+)\s*\)/
or die "Parse error: Bad offset for $name";
die "Parse error: ',' expected for $name"
if shift @tokens ne ',';
$new->{magnitude} = shift @tokens;
push @{$features{$name}}, $new;
$mapping{$new->{number}} = $new->{name};
while (shift @tokens ne '}') { die unless @tokens }
die "Parse error: ',' expected after $name"
if shift @tokens ne ',';
}
}
close INPUTFILE;
}
# $_[0]: Base directory
sub scan_all
{
my $basedir = shift;
$basedir =~ s/\/*$//;
# Generate %prefix
scan_chips_h("$basedir/lib/chips.h");
# Generate %arrayname
scan_chips_c_1("$basedir/lib/chips.c");
# Check that %prefix and %arrayname have the same set of keys
foreach my $item (keys %prefix)
{
die "Missing array name for $item"
unless defined $arrayname{$item};
}
foreach my $item (keys %arrayname)
{
die "Missing #define for $item"
unless defined $prefix{$item};
}
#Generate ??
scan_chips_c_2("$basedir/lib/chips.c");
# Generate %sysctl
foreach my $filename (glob "$basedir/kernel/chips/*.c")
{
scan_kernel_chip($filename);
}
}
# $_[0]: Prefix
sub output_data
{
my $index = shift;
printf "Chip '\%s'\n", $prefix{$index};
print "\n";
printf "\%-21s \%-21s \%-21s \%5s \%5s\n", 'LABEL', 'LABEL CLASS',
'COMPUTE CLASS', 'MODE', 'MAGN';
foreach my $data (@{$features{$arrayname{$index}}})
{
print STDERR "Missing logical mapping for $data->{logical_mapping} (index = $index, name = $data->{name})\n"
unless defined $mapping{$data->{logical_mapping}};
print STDERR "Missing compute mapping for $data->{compute_mapping} (index = $index, name = $data->{name})\n"
unless defined $mapping{$data->{compute_mapping}};
printf "\%-21s \%-21s \%-21s \%4s \%2d\n", $data->{name},
$mapping{$data->{logical_mapping}} || '?',
$mapping{$data->{compute_mapping}} || '?',
($data->{mode_read}?'R':'-').($data->{mode_write}?'W':'-'),
$data->{magnitude};
}
print "\n";
printf "\%-21s \%-38s \%16s:\%1s\n", 'LABEL', 'FEATURE SYMBOL',
'SYSCTL FILE', 'N';
foreach my $data (@{$features{$arrayname{$index}}})
{
print STDERR "Missing sysctl for $data->{sysctl} (index = $index, name = $data->{name})\n"
unless defined $sysctl{$data->{sysctl}};
printf "\%-21s \%-38s \%16s:\%1d\n",$data->{name}, $data->{number},
$sysctl{$data->{sysctl}} || '?', $data->{offset};
}
print "\n", "\n";
}
if (@ARGV < 1 or $ARGV[0] =~ m/^-/)
{
print "Usage: $0 PATH [PREFIXES ...]\n",
" PATH is the path to the base directory of the lm_sensors tree.\n",
" PREFIXES are the chips that have to be output. If none are\n",
" specified, all chips are printed.\n";
exit 0;
}
%prefix = %arrayname = %sysctl = %features = ();
%mapping = (SENSORS_NO_MAPPING => '-');
scan_all(shift @ARGV);
print "Chip Features\n", "-------------\n", "\n";
if (@ARGV)
{
my %rprefix = reverse %prefix;
foreach my $prefix (@ARGV)
{
if (exists $rprefix{$prefix})
{
output_data($rprefix{$prefix})
}
else
{
my $lines = 0;
print "No chip named `$prefix' was found.\n",
"Suggestions:\n";
foreach my $k (sort keys %rprefix)
{
if (grep /$prefix/, $k)
{
print " $k\n";
$lines++;
}
}
print " (none)\n"
unless $lines;
print "\n";
}
}
}
else
{
foreach my $item (sort keys %prefix)
{
output_data($item);
}
}