mirror of
https://github.com/lm-sensors/lm-sensors.git
synced 2026-11-02 13:30:30 +00:00
Rewrote the doc-features program in Perl.
This program scan the C-sources of the library and all kernel modules and
outputs everything it can find about all features.
To do: sort features and add command-line parameters, implement slightly
better layout.
The perl program completely replaces the C program and already has
much more functionality.
This program will be very helpful to write the kernel module documentation,
and especially to keep it up-to-date: as the C sources are examined,
updates need only be done at one place, in the source code.
git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@384 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
1 parent
1715bec9a6
commit
56c373e592
3 files changed
+254
-189
No files matched your search
@@ -1,41 +0,0 @@
|
||||
# Module.mk - Makefile for a Linux module for reading sensor data.
|
||||
# Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Note that MODULE_DIR (the directory in which this file resides) is a
|
||||
# 'simply expanded variable'. That means that its value is substituted
|
||||
# verbatim in the rules, until it is redefined.
|
||||
MODULE_DIR := prog/doc
|
||||
|
||||
# Regrettably, even 'simply expanded variables' will not put their currently
|
||||
# defined value verbatim into the command-list of rules...
|
||||
PROGDOCTARGETS := $(MODULE_DIR)/doc-features
|
||||
PROGDOCSOURCES := $(MODULE_DIR)/doc-features.c
|
||||
|
||||
# Include all dependency files. We use '.rd' to indicate this will create
|
||||
# executables.
|
||||
INCLUDEFILES += $(PROGDOCSOURCES:.c=.rd)
|
||||
|
||||
$(PROGDOCTARGETS): $(PROGDOCSOURCES:.c=.ro) lib/$(LIBSHBASENAME)
|
||||
$(CC) -o $@ $(PROGDOCSOURCES:.c=.ro) -Llib -lsensors
|
||||
|
||||
all-prog-doc: $(PROGDOCTARGETS)
|
||||
all :: all-prog-doc
|
||||
|
||||
clean-prog-doc:
|
||||
$(RM) $(PROGDOCSOURCES:.c=.rd) $(PROGDOCSOURCES:.c=.ro) \
|
||||
$(PROGDOCTARGETS)
|
||||
clean :: clean-prog-doc
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
doc-features.c - A program to dump sensor feature documentation
|
||||
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/* This program uses undocumented sensors library access. It it undocumented
|
||||
for a reason: normal programs really should not work on this level! */
|
||||
|
||||
#include "lib/data.h"
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
|
||||
const char *lookup_feature_name(int featurenr,
|
||||
const sensors_chip_features *chipdata)
|
||||
{
|
||||
int i;
|
||||
if (featurenr == SENSORS_NO_MAPPING)
|
||||
return "";
|
||||
for (i = 0; chipdata->feature[i].name ; i++)
|
||||
if (chipdata->feature[i].number == featurenr)
|
||||
return chipdata->feature[i].name;
|
||||
return "***ERROR***";
|
||||
}
|
||||
|
||||
const char *mode_string(int mode)
|
||||
{
|
||||
if (mode == SENSORS_MODE_RW)
|
||||
return "RW";
|
||||
else if (mode == SENSORS_MODE_R)
|
||||
return "R ";
|
||||
else if (mode == SENSORS_MODE_W)
|
||||
return " W";
|
||||
else
|
||||
return "--";
|
||||
}
|
||||
|
||||
void dump_feature(const sensors_chip_feature *featuredata,
|
||||
const sensors_chip_features *chipdata)
|
||||
{
|
||||
printf(" %17s: %17s %17s %2s\n",featuredata->name,
|
||||
lookup_feature_name(featuredata->logical_mapping,chipdata),
|
||||
lookup_feature_name(featuredata->compute_mapping,chipdata),
|
||||
mode_string(featuredata->mode));
|
||||
}
|
||||
|
||||
int qsort_compare (const void *f1, const void *f2)
|
||||
{
|
||||
return strcmp((* ((sensors_chip_feature * const *)f1))->name,
|
||||
(* ((sensors_chip_feature * const *)f2))->name);
|
||||
}
|
||||
|
||||
void dump_chip (const sensors_chip_features *chipdata)
|
||||
{
|
||||
int i;
|
||||
sensors_chip_feature **features;
|
||||
for (i = 0; chipdata->feature[i].name; i++);
|
||||
|
||||
features = malloc(sizeof(*features) * i+1);
|
||||
for (i = 0; chipdata->feature[i].name; i++)
|
||||
features[i] = chipdata->feature + i;
|
||||
features[i] = chipdata->feature + i;
|
||||
qsort(features,i,sizeof(*features),qsort_compare);
|
||||
|
||||
printf("Chip `%s'\n",chipdata->prefix);
|
||||
printf(" %17s %17s %17s %2s\n","NAME","LABEL CLASS","COMPUTE CLASS",
|
||||
"RW");
|
||||
for (i = 0; features[i]->name; i++)
|
||||
dump_feature(features[i],chipdata);
|
||||
|
||||
free(features);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void print_short_help(void)
|
||||
{
|
||||
fprintf(stderr,"Usage: doc-features [-h] [-v] [chipname]..\n");
|
||||
fprintf(stderr,"Try `doc-features -h' for more information\n");
|
||||
}
|
||||
|
||||
void print_long_help(void)
|
||||
{
|
||||
fprintf(stderr,"Usage: doc-features [-h] [-v] [chipname]..\n");
|
||||
fprintf(stderr," -h, --help Display this help text\n");
|
||||
fprintf(stderr," -v, --version Display version information\n");
|
||||
fprintf(stderr,"If no chipnames are specified, information for all chips is dumped.\n");
|
||||
}
|
||||
|
||||
void print_version(void)
|
||||
{
|
||||
printf("doc-features version 1.0\n");
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int c,i;
|
||||
|
||||
struct option long_opts[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'v'}
|
||||
};
|
||||
|
||||
while(1) {
|
||||
c = getopt_long(argc,argv,"hv",long_opts,NULL);
|
||||
if (c == EOF)
|
||||
break;
|
||||
switch(c) {
|
||||
case ':':
|
||||
case '?':
|
||||
print_short_help();
|
||||
exit(1);
|
||||
case 'h':
|
||||
print_long_help();
|
||||
exit(0);
|
||||
case 'v':
|
||||
print_version();
|
||||
exit(0);
|
||||
default:
|
||||
fprintf(stderr,"Internal error while parsing options!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc)
|
||||
for (i = 0; sensors_chip_features_list[i].prefix ; i++)
|
||||
dump_chip(sensors_chip_features_list+i);
|
||||
else
|
||||
for (; optind != argc ; optind ++)
|
||||
for (i = 0; sensors_chip_features_list[i].prefix; i++)
|
||||
if (!strcmp(sensors_chip_features_list[i].prefix,argv[optind]))
|
||||
dump_chip(sensors_chip_features_list+i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Executable
+254
@@ -0,0 +1,254 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
|
||||
# Features is a hash of references (indexed by SENSORS_*_PREFIX names) to
|
||||
# a hash with these elements:
|
||||
# prefix: The prefix name
|
||||
# arrayname: The name of the c-array containing its data
|
||||
# features: A reference to an array 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
|
||||
|
||||
use vars qw(%features %sysctls %feature_name);
|
||||
|
||||
# Scan chips.h to get all prefix values
|
||||
# Store the results in features{...}->prefix
|
||||
# $_[0]: Name of chips.h file
|
||||
sub scan_chips_h
|
||||
{
|
||||
my ($chips_h) = @_;
|
||||
my ($def,$val);
|
||||
open INPUTFILE,$chips_h or die "Can't open $chips_h!";
|
||||
while (<INPUTFILE>) {
|
||||
$features{$def}->{prefix} = $val
|
||||
if ($def,$val) = /^\s*#\s*define\s+(SENSORS_\w+_PREFIX)\s+"(\S+)"/;
|
||||
|
||||
}
|
||||
close INPUTFILE;
|
||||
}
|
||||
|
||||
# Scan chips.c to get the features names
|
||||
# Store the results in features{...}->arrayname
|
||||
# $_[0]: Name of the chips.c file
|
||||
sub scan_chips_c_1
|
||||
{
|
||||
my ($chips_c) = @_;
|
||||
my ($def,$val);
|
||||
open INPUTFILE,$chips_c or die "Can't open $chips_c!";
|
||||
while (<INPUTFILE> !~ /^\s*sensors_chip_features/ ) {};
|
||||
while (<INPUTFILE>) {
|
||||
last if /^\s*{\s*0/;
|
||||
$features{$def}->{arrayname} = $val
|
||||
if ($def,$val) = /^\s*{\s*(SENSORS_\w+_PREFIX)\s*,\s*(\w+)\s*}\s*,\s*$/;
|
||||
}
|
||||
close INPUTFILE;
|
||||
}
|
||||
|
||||
# $_[0]: line to tokenize
|
||||
# Returns the 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.
|
||||
sub tokenize
|
||||
{
|
||||
my ($line) = @_;
|
||||
my (@res,$next);
|
||||
@res = ();
|
||||
$line =~ s/^\s*//;
|
||||
while (length $line) {
|
||||
if ($line =~ s/^\s*$//) {
|
||||
last;
|
||||
} elsif ($line =~ s/^{\s*//) {
|
||||
push @res, '{';
|
||||
} elsif ($line =~ s/^}\s*//) {
|
||||
push @res, '}';
|
||||
} elsif ($line =~ s/^;\s*//) {
|
||||
push @res, ';';
|
||||
} elsif ($line =~ s/^,\s*//) {
|
||||
push @res, ',';
|
||||
} else {
|
||||
($next) = $line =~ /^(\S+?)(?=[{},;\s])\s*/;
|
||||
$line =~ s/^(\S+?)(?=[{},;\s])\s*//;
|
||||
push @res, $next;
|
||||
}
|
||||
}
|
||||
return @res;
|
||||
}
|
||||
|
||||
# $_[0]: File to read from
|
||||
# $_[1]: Feature to write to
|
||||
sub scan_chip_c_entry
|
||||
{
|
||||
my ($file,$feature) = @_;
|
||||
my ($line,@tokens,$next,$new);
|
||||
for (;;) {
|
||||
$line = <$file>;
|
||||
@tokens = (@tokens,tokenize($line));
|
||||
last if $line =~ /;/;
|
||||
}
|
||||
die "Parse error: initial '{' expected for $feature->arrayname"
|
||||
if shift @tokens ne '{';
|
||||
$feature->{features} = [];
|
||||
while (shift @tokens eq '{') {
|
||||
$new = {};
|
||||
$new->{number} = shift @tokens;
|
||||
last if $new->{number} eq "0";
|
||||
die "Parse error: ',' expected for $feature->arrayname"
|
||||
if shift @tokens ne ',';
|
||||
$next = shift @tokens;
|
||||
($new->{name}) = $next =~ /^"(.*)"$/;
|
||||
die "Parse error: ',' expected for $feature->arrayname"
|
||||
if shift @tokens ne ',';
|
||||
$new->{logical_mapping} = shift @tokens;
|
||||
die "Parse error: ',' expected for $feature->arrayname"
|
||||
if shift @tokens ne ',';
|
||||
$new->{compute_mapping} = shift @tokens;
|
||||
die "Parse error: ',' expected for $feature->arrayname"
|
||||
if shift @tokens ne ',';
|
||||
$next = shift @tokens;
|
||||
$new->{mode_read} = ($next eq "SENSORS_MODE_R" or
|
||||
$next eq "SENSORS_MODE_RW")?1:0;
|
||||
$new->{mode_write} = ($next eq "SENSORS_MODE_W" or
|
||||
$next eq "SENSORS_MODE_RW")?1:0;
|
||||
die "Parse error: ',' expected for $feature->arrayname"
|
||||
if shift @tokens ne ',';
|
||||
$new->{sysctl} = shift @tokens;
|
||||
die "Parse error: ',' expected for $feature->arrayname"
|
||||
if shift @tokens ne ',';
|
||||
$next = shift @tokens;
|
||||
($new->{offset}) = $next =~ /^VALUE\s*\((\d+)\s*\)/
|
||||
or die "Parse error: 'VALUE(..)' expected for $feature->arrayname";
|
||||
die "Parse error: ',' expected for $feature->arrayname"
|
||||
if shift @tokens ne ',';
|
||||
$new->{magnitude} = shift @tokens;
|
||||
$next = shift @tokens;
|
||||
$next = shift @tokens if $next eq ',';
|
||||
push @{$feature->{features}},$new;
|
||||
$feature_name{$new->{number}} = $new->{name};
|
||||
die "Parse error: '}' expected for $feature->arrayname" if $next ne '}';
|
||||
shift @tokens;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
# Scan chips.c to get the features names
|
||||
# Store the results in features{...}->feature
|
||||
# $_[0]: Name of the chips.c file
|
||||
sub scan_chips_c_2
|
||||
{
|
||||
my ($chips_c) = @_;
|
||||
my ($line,$name,$el,$feature);
|
||||
open INPUTFILE,$chips_c or die "Can't open $chips_c!";
|
||||
while ($line = <INPUTFILE>) {
|
||||
next if $line !~ /sensors_chip_feature /;
|
||||
($name) = $line =~ /sensors_chip_feature\s*(\w+)\s*\[/;
|
||||
foreach $el (keys %features) {
|
||||
$feature = $features{$el};
|
||||
last if $feature->{arrayname} eq $name
|
||||
}
|
||||
die "Can't find feature belonging to $name!" if (! defined $feature);
|
||||
scan_chip_c_entry \*INPUTFILE,$feature;
|
||||
}
|
||||
}
|
||||
|
||||
# $_[0]: Name of the kernels module
|
||||
sub scan_kernel_module
|
||||
{
|
||||
my ($module_name) = @_;
|
||||
my ($line,@tokens,$val,$name);
|
||||
open INPUTFILE,$module_name or die "Can't open $module_name!";
|
||||
while ($line = <INPUTFILE>) {
|
||||
next if $line !~ /^\s*static\s*ctl_table/;
|
||||
@tokens = ();
|
||||
for (;;) {
|
||||
$line = <INPUTFILE>;
|
||||
@tokens = (@tokens,tokenize($line));
|
||||
last if $line =~ /;/;
|
||||
}
|
||||
while (@tokens) {
|
||||
for (;;) {
|
||||
$val = shift @tokens;
|
||||
last if $val ne '{';
|
||||
}
|
||||
last if $val eq "0";
|
||||
die "Parse error: ',' expected within $module_name"
|
||||
if shift @tokens ne ',';
|
||||
$name = shift @tokens;
|
||||
($sysctls{$val}) = $name =~ /^"(\S+)"$/;
|
||||
for (;;) {
|
||||
last if shift @tokens eq '{';
|
||||
}
|
||||
}
|
||||
}
|
||||
close INPUTFILE;
|
||||
}
|
||||
|
||||
# $_[0]: Base directory
|
||||
sub scan_all
|
||||
{
|
||||
my ($prefix) = @_;
|
||||
my ($filename);
|
||||
scan_chips_h $prefix . "/lib/chips.h";
|
||||
scan_chips_c_1 $prefix . "/lib/chips.c";
|
||||
scan_chips_c_2 $prefix . "/lib/chips.c";
|
||||
foreach $filename (glob ($prefix ."/kernel/chips/*.c")) {
|
||||
scan_kernel_module $filename
|
||||
}
|
||||
}
|
||||
|
||||
# $_[0]: index in master hash
|
||||
sub output_data
|
||||
{
|
||||
my ($index) = @_;
|
||||
my ($feature,$data,$read_write);
|
||||
$feature = $features{$index};
|
||||
printf "Chip `%s'\n",$feature->{prefix};
|
||||
print " LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE\n";
|
||||
foreach $data (@{$feature->{features}}) {
|
||||
$read_write = $data->{mode_read} + 2 * $data->{mode_write};
|
||||
if ($read_write == 0) {
|
||||
$read_write = "--";
|
||||
} elsif ($read_write == 1) {
|
||||
$read_write = "R ";
|
||||
} elsif ($read_write == 2) {
|
||||
$read_write = " W";
|
||||
} else {
|
||||
$read_write = "RW";
|
||||
}
|
||||
printf "%15s %15s %15s %2s %2s\n",
|
||||
$data->{name}, $feature_name{$data->{logical_mapping}},
|
||||
$feature_name{$data->{compute_mapping}},
|
||||
$read_write,$data->{magnitude};
|
||||
}
|
||||
print "\n";
|
||||
print " LABEL FEATURE SYMBOL ".
|
||||
"SYSCTL FILE:OFFSET\n";
|
||||
foreach $data (@{$feature->{features}}) {
|
||||
printf "%15s %40s %15s:%1d\n",$data->{name}, $data->{number},
|
||||
$sysctls{$data->{sysctl}}, $data->{offset}, $data->{magnitude};
|
||||
}
|
||||
}
|
||||
|
||||
sub initialize
|
||||
{
|
||||
$feature_name{SENSORS_NO_MAPPING} = "NONE";
|
||||
}
|
||||
|
||||
|
||||
initialize;
|
||||
scan_all "../..";
|
||||
my $el;
|
||||
foreach $el (keys %features) {
|
||||
output_data $el;
|
||||
print "\n\n";
|
||||
}
|
||||
Reference in new issue
Block a user