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:
Frodo Looijaard committed 1999-04-13 02:06:36 +00:00
1 parent 1715bec9a6
commit 56c373e592
3 files changed
+254 -189

No files matched your search

-41
View File
@@ -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
-148
View File
@@ -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;
}
+254
View File
@@ -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";
}