[v2,4/5] manual: Enforce header and standard requirements.

Message ID 20161206105525.21117-5-ricaljasan@pacific.net
State New
Headers show

Commit Message

Rical Jasan Dec. 6, 2016, 10:55 a.m.
Introduces a new script, check-stds.pl, which examines the
	immediately preceding lines of entries requiring annotation
	for valid header and standard annotations.

	Only two classes of entries can currently be known to require
	annotation: @def*-commands and @item entries within @vtables.
	Note that summary.awk also indexes @vindex entries, but this
	script does not enforce any requirements upon them, as they
	are better addressed by reworking the documentation in more
	significant ways (than conversion of @vindexed @items in
	@tables to @items in @vtables, for example).

	Standards are essentially free-form, and headers must look
	like *.h, and multiple headers may not be comma-separated.

	The syntax comment in summary.awk is updated, and the new
	script is added to the Makefile.  It exits with error
	(printing any) in case of trouble, so this should help prevent
	new errors from creeping in.

	* manual/check-stds.pl: New file.  Check anything that we can
	know deserves header/standard annotation, and report errors.
	* manual/Makefile: Use check-stds.pl.
	* manual/summary.awk: Update comment about syntax.
---
 manual/Makefile      |   1 +
 manual/check-stds.pl | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++
 manual/summary.awk   |   3 +-
 3 files changed, 214 insertions(+), 1 deletion(-)
 create mode 100755 manual/check-stds.pl

Patch hide | download patch | download mbox

diff --git a/manual/Makefile b/manual/Makefile
index f2f694f..d6d8c27 100644
--- a/manual/Makefile
+++ b/manual/Makefile
@@ -85,6 +85,7 @@  $(objpfx)summary.texi: $(objpfx)stamp-summary ;
 $(objpfx)stamp-summary: summary.awk $(filter-out $(objpfx)summary.texi, \
 					$(texis-path))
 	$(SHELL) ./check-safety.sh $(filter-out $(objpfx)%, $(texis-path))
+	$(PERL) check-stds.pl $^
 	$(AWK) -f $^ | sort -t'' -df -k 1,1 | tr '\014' '\012' \
 		> $(objpfx)summary-tmp
 	$(move-if-change) $(objpfx)summary-tmp $(objpfx)summary.texi
diff --git a/manual/check-stds.pl b/manual/check-stds.pl
new file mode 100755
index 0000000..b4b7146
--- /dev/null
+++ b/manual/check-stds.pl
@@ -0,0 +1,211 @@ 
+#!/usr/bin/perl
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Rical Jasan <ricaljasan@pacific.net>, 2016.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library 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
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+# Complement summary.awk by finding entries within the manual that
+# require header and standards @comments, ensuring they have them,
+# and verifying their syntax.  Also see summary.awk.
+
+use strict;
+use warnings;
+
+# Keep track of context.
+my @lines;
+my ($cur, $std, $hdr, $ctx) = (0, 1, 2, 3);
+
+# Error messages.
+my $missing_header = "Missing header.";
+my $missing_standard = "Missing standard.";
+
+# Accept files to check as args.
+my @texis = @ARGV;
+
+for (my $i=0; $i<@texis; $i++) {
+    # Probes is a special chapter...
+    if ($texis[$i] =~ /probes\.texi$/) {
+	splice(@texis, $i, 1);
+	last;
+    }
+}
+
+# @c-style comments aren't used.
+my $comment = qr/^\@comment /;
+# Strict check for header @comments, based on current practice.
+my $header = qr/${comment}(([\w\/]+\.h ?)+(\(optional\))?|\(none\))$/i;
+# Standards are free-form but do not contain @-commands.
+my $standard = qr/${comment}[^\@]+/;
+# All @def*-commands need annotation.
+my $def = qr/^\@def/;
+# Not all @items do; we'll know by context.
+my $item = qr/^\@itemx? /;
+# @items in @vtables must be annotated.
+my $vtable = qr/^\@vtable /;
+my $vtable_end = qr/^\@end vtable$/;
+# @tables must be recognized for recursion.
+my $table = qr/^\@table /;
+my $table_end = qr/\@end table$/;
+# Contexts we know need checking.
+my $table_or_list = qr/^\@v?table /;
+
+# For subsequent analysis.
+my %errors;
+
+# Global scope.
+my $input;
+
+for (@texis) {
+    open $input, '<', $_;
+    while ($lines[$cur] = <$input>)
+    {
+	if ($lines[$cur] =~ $def)
+	{
+	    &check_annotations();
+	}
+	elsif ($lines[$cur] =~ $table_or_list)
+	{
+	    &check_items();
+	}
+
+	&shuffle();
+    }
+    close $input;
+}
+
+if (%errors)
+{
+    &print_errors();
+    exit 1;
+}
+
+exit 0;
+
+sub shuffle
+{
+    $lines[$ctx] = $lines[$hdr] if $lines[$hdr];
+    $lines[$hdr] = $lines[$std] if $lines[$std];
+    $lines[$std] = $lines[$cur];
+}
+
+sub store_error
+{
+    push @{$errors{$_}}, {
+	errors => shift,
+	line => $lines[$cur],
+	standard => $lines[$std] ? $lines[$std] : undef,
+	header => $lines[$hdr] ? $lines[$hdr] : undef,
+	context => $lines[$ctx] ? $lines[$ctx] : undef,
+    };
+}
+
+sub check_annotations
+{
+    my @errors;
+
+    if (!$lines[$std] || $lines[$std] !~ $standard) {
+	push @errors, $missing_standard
+    }
+
+    if (!$lines[$hdr]) {
+	push @errors, $missing_header;
+    }
+    elsif ($lines[$hdr] !~ $header) {
+	if ($lines[$std] =~ $header) {
+	    push @errors, $missing_standard;
+	} else {
+	    push @errors, $missing_header;
+	}
+    }
+
+    &store_error(\@errors) if @errors;
+}
+
+sub check_items
+{
+    if ($lines[$cur] =~ $vtable)
+    {
+	&check_vtable();
+    }
+    elsif ($lines[$cur] =~ $table)
+    {
+	&check_table();
+    }
+}
+
+sub check_vtable
+{
+    &shuffle();
+    until (($lines[$cur] = <$input>) =~ $vtable_end)
+    {
+	# detect nested tables or lists.
+	if ($lines[$cur] =~ $table_or_list)
+	{
+	    &check_items();
+	}
+	# vtable item
+	elsif ($lines[$cur] =~ $item)
+	{
+	    &check_annotations();
+	}
+	elsif ($lines[$cur] =~ $def)
+	{
+	    &check_annotations();
+	}
+	&shuffle();
+    }
+}
+
+sub check_table
+{
+    &shuffle();
+    until (($lines[$cur] = <$input>) =~ $table_end) {
+	# detect nested tables/lists.
+	if ($lines[$cur] =~ $table_or_list)
+	{
+	    &check_items();
+	}
+	&shuffle();
+    }
+}
+
+sub print_errors
+{
+    for my $texi (sort keys %errors)
+    {
+	my $printed_texi = 0;
+
+	for (@{$errors{$texi}})
+	{
+	    if (!$printed_texi)
+	    {
+		print STDERR "****\nErrors detected in $texi:\n\n";
+		$printed_texi = 1;
+	    }
+	    print STDERR "----------------\n";
+	    for my $error (@{$_->{errors}})
+	    {
+		print STDERR "$error\n";
+	    }
+	    print STDERR "\n";
+	    print STDERR "C:$_->{context}" if $_->{context};
+	    print STDERR "H:$_->{header}" if $_->{header};
+	    print STDERR "S:$_->{standard}" if $_->{standard};
+	    print STDERR "L:$_->{line}";
+	    print STDERR "  ^^^^\n\n";
+	}
+    }
+}
diff --git a/manual/summary.awk b/manual/summary.awk
index 7f721e9..e6e0c49 100644
--- a/manual/summary.awk
+++ b/manual/summary.awk
@@ -17,9 +17,10 @@ 
 # <http://www.gnu.org/licenses/>.
 
 # This script recognizes sequences that look like:
-#	@comment HEADER.h
+#	@comment HEADER.h[ HEADER.h[...]]
 #	@comment STANDARD
 #	@def... ITEM | @item ITEM | @vindex ITEM
+# where STANDARD is essentially free-form.
 
 BEGIN { header = 0;
 nameword["@defun"]=1