summary.pl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. #!/usr/bin/perl
  2. # Generate the Summary of Library Facilities (summary.texi).
  3. # Copyright (C) 2017-2019 Free Software Foundation, Inc.
  4. # This file is part of the GNU C Library.
  5. # Contributed by Rical Jasan <ricaljasan@pacific.net>, 2017.
  6. # The GNU C Library is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU Lesser General Public License
  8. # as published by the Free Software Foundation; either version 2.1 of
  9. # the License, or (at your option) any later version.
  10. # The GNU C Library is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. # Lesser General Public License for more details.
  14. # You should have received a copy of the GNU Lesser General Public
  15. # License along with the GNU C Library; if not, see
  16. # <http://www.gnu.org/licenses/>.
  17. # Anything declared in a header or defined in a standard should have
  18. # its origins annotated using the @standards macro (see macro.texi).
  19. # This script checks all such elements in the manual (generally,
  20. # @def|item*-commands), ensuring annotations are present and correct.
  21. # If any errors are detected, they are all reported at the end and
  22. # failure is indicated.
  23. use strict;
  24. use warnings;
  25. use locale;
  26. use File::Basename;
  27. $| = 1;
  28. my $script = basename $0;
  29. &help if $ARGV[0] eq "--help"; # Will exit(0).
  30. my @texis = @ARGV;
  31. # Various regexes.
  32. my $nde = qr/^\@node /;
  33. my $def = qr/^\@def/;
  34. my $itm = qr/^\@item /;
  35. my $itms = qr/^\@itemx? /; # Don't match @itemize.
  36. my $ann = qr/^\@(def\w+|item)x? /; # Annotatable.
  37. my $std = qr/^\@standards\{/;
  38. my $stx = qr/^\@standardsx\{/;
  39. my $stds = qr/^\@standardsx?\{/;
  40. my $strict_std = qr/^\@standards\{([^,]+, )[^,\}]+\}$/;
  41. my $strict_stx = qr/^\@standardsx\{([^,]+, ){2}[^,\}]+\}$/;
  42. my $lcon = qr/([vf]?table|itemize|enumerate)/;
  43. my $list = qr/^\@${lcon}/;
  44. my $endl = qr/^\@end ${lcon}/;
  45. my $ign = qr/^\@ignore/;
  46. my $eig = qr/^\@end ignore/;
  47. # Global scope.
  48. my $node;
  49. our $texi;
  50. my $input;
  51. my %entries;
  52. my %errors;
  53. for $texi (@texis) {
  54. open $input, '<', $texi or die "open $texi: $!";
  55. while (my $line = <$input>) {
  56. if ($line =~ $nde) {
  57. $node = &get_node($line);
  58. } elsif ($line =~ $def) {
  59. &process_annotation($line);
  60. } elsif ($line =~ $list) {
  61. &process_list($1); # @items occur in list or table context.
  62. } elsif ($line =~ $stds) {
  63. &record_error("Misplaced annotation", ["[$.] ".$line]);
  64. } elsif ($line =~ $ign) {
  65. while (<$input> !~ $eig) {}
  66. }
  67. }
  68. close $input or die "close $texi: $!";
  69. }
  70. # Disabled until annotations are complete.
  71. &print_errors() if %errors && 0; # Will exit(1).
  72. print("\@c DO NOT EDIT THIS FILE!\n".
  73. "\@c This file is generated by $script from the Texinfo sources.\n".
  74. "\@c The \@items are \@include'd from a \@table in header.texi.\n\n");
  75. &print_entry($_) for sort keys %entries;
  76. # Processes an annotatable element, including any subsequent elements
  77. # in an @*x chain, ensuring @standards are present, with valid syntax,
  78. # either recording any errors detected or creating Summary entries.
  79. # This function is the heart of the script.
  80. #
  81. # Prototypes and standards are gathered into separate lists and used
  82. # to evaluate the completeness and correctness of annotations before
  83. # generating the Summary entries. "Prototype" is used to refer to an
  84. # element's entire definition while avoiding conflation with
  85. # @def*-commands. "Element" is strictly used here to refer to the
  86. # name extracted from the prototype, as used in @standardsx, for
  87. # sorting the Summary.
  88. sub process_annotation
  89. {
  90. my $line = shift;
  91. my (@prototypes, @standards, $i, @tmp);
  92. # Gather prototypes and standards.
  93. push @prototypes, $line;
  94. while ($line = <$input>) {
  95. last if $line !~ $ann;
  96. push @prototypes, $line;
  97. }
  98. if ($line !~ $stds) { # The fundamental error.
  99. return &record_error('Missing annotation', \@prototypes);
  100. }
  101. push @standards, $line;
  102. push @standards, $line while ($line = <$input>) =~ $stds;
  103. # If next line is an @item, seek back to catch it on the next
  104. # iteration. This avoids imposing a non-Texinfo syntax
  105. # requirement of blank lines between consecutive annotated @items.
  106. if ($line =~ $itm) {
  107. seek $input, -length($line), 1 or die "seek: $!";
  108. }
  109. # Strict check for syntax errors. Other matches are loose, which
  110. # aids error detection and reporting by ensuring things that look
  111. # like standards aren't simply passed over, but caught here.
  112. for ($i=0; $i<@standards; ++$i) {
  113. my $standard = $standards[$i];
  114. if ($standard !~ $strict_std && $standard !~ $strict_stx) {
  115. push @tmp, $standard;
  116. }
  117. }
  118. return &record_error('Invalid syntax', \@tmp) if @tmp;
  119. # @standardsx should not be in non-@*x chains.
  120. if (@prototypes == 1) {
  121. for ($i=0; $i<@standards; ++$i) {
  122. return &record_error('Misplaced @standardsx', \@prototypes)
  123. if $standards[$i] =~ $stx;
  124. }
  125. }
  126. # @standards may only occur once in @*x chains, at the beginning.
  127. if (@prototypes > 1) {
  128. for ($i=1; $i<@standards; ++$i) {
  129. return &record_error('Misplaced @standards', \@prototypes)
  130. if $standards[$i] =~ $std;
  131. }
  132. }
  133. # The @standards are aligned.
  134. &add_entries(\@prototypes, \@standards);
  135. }
  136. # Goes through the prototypes, cleaning them up and extracting the
  137. # elements, pairing them with the appropriate annotations to create
  138. # Summary entries.
  139. sub add_entries
  140. {
  141. my ($prototypes, $standards) = @_;
  142. my $isx = @{$prototypes} > 1 ? 1 : 0;
  143. my $allx = $standards->[0] =~ $stx ? 1 : 0;
  144. my ($defstd, $defhdr, %standardsx, $i, $j);
  145. # Grab the default annotation and index any @standardsx. Take
  146. # care in case there is no default.
  147. if ($isx) {
  148. if (!$allx) {
  149. ($defstd, $defhdr)
  150. = $standards->[0] =~ /${std}([^,]+), (.*)\}$/;
  151. }
  152. for ($i = $allx ? 0 : 1; $i<@{$standards}; ++$i) {
  153. my ($e, $s, $h)
  154. = $standards->[$i] =~ /${stx}([^,]+), ([^,]+), (.*)\}$/;
  155. push @{$standardsx{$e}{hs}}, [$h, $s];
  156. }
  157. }
  158. for ($i=0; $i<@{$prototypes}; ++$i) {
  159. my $e = &get_element($prototypes->[$i]);
  160. my $p = &get_prototype($prototypes->[$i]);
  161. my ($s, $h);
  162. if ($isx && exists $standardsx{$e}) {
  163. for ($j=0; $j<@{$standardsx{$e}{hs}}; ++$j) {
  164. $h = $standardsx{$e}{hs}[$j]->[0];
  165. $s = $standardsx{$e}{hs}[$j]->[1];
  166. &record_entry($e, $p, $h, $s, $node);
  167. ++$standardsx{$e}{seen};
  168. }
  169. } elsif ($isx && $allx) {
  170. &record_error('Missing annotation', [$prototypes->[$i]]);
  171. } elsif ($isx) {
  172. &record_entry($e, $p, $defhdr, $defstd, $node);
  173. } else {
  174. for ($j=0; $j<@{$standards}; ++$j) {
  175. ($s, $h) = $standards->[$j] =~ /${std}([^,]+), ([^,\}]+)\}$/;
  176. &record_entry($e, $p, $h, $s, $node);
  177. }
  178. }
  179. }
  180. # Check if there were any unmatched @standardsx.
  181. for my $e (keys %standardsx) {
  182. if (!exists $standardsx{$e}{seen}) {
  183. &record_error('Spurious @standardsx', [$e."\n"])
  184. }
  185. }
  186. }
  187. # Stores a Summary entry in %entries. May be called multiple times
  188. # per element if multiple header and standard annotations exist. Also
  189. # keys on prototypes, as some elements have multiple prototypes. See
  190. # isnan in arith.texi for one example.
  191. sub record_entry
  192. {
  193. my ($ele, $proto, $hdr, $std, $node) = @_;
  194. push @{$entries{$ele}{$proto}}, [$hdr, $std, $node];
  195. }
  196. # Processes list or table contexts, with nesting.
  197. sub process_list
  198. {
  199. my $type = shift;
  200. my $in_vtbl = $type eq "vtable" ? 1 : 0;
  201. while (my $line = <$input>) {
  202. if ($line =~ $itms) {
  203. next if ! $in_vtbl; # Not an annotatable context.
  204. &process_annotation($line);
  205. } elsif ($line =~ $def) {
  206. &process_annotation($line);
  207. } elsif ($line =~ $stds) {
  208. &record_error('Misplaced annotation', ["[$.] ".$line]);
  209. } elsif ($line =~ $endl) {
  210. return; # All done.
  211. } elsif ($line =~ $list) {
  212. &process_list($1); # Nested list.
  213. }
  214. }
  215. }
  216. # Returns the current node from an @node line. Used for referencing
  217. # from the Summary.
  218. sub get_node
  219. {
  220. my $line = shift;
  221. chomp $line;
  222. $line =~ s/$nde//;
  223. my ($n) = split ',', $line;
  224. return $n
  225. }
  226. # Returns the cleaned up prototype from @def|item* lines.
  227. sub get_prototype
  228. {
  229. my $dfn = shift;
  230. chomp $dfn;
  231. $dfn =~ s/\s+/ /g; # Collapse whitespace.
  232. $dfn =~ s/ \{([^\}]*)\} / $1 /g; # Remove grouping braces.
  233. $dfn =~ s/^\@\S+ //; # Remove @-command.
  234. $dfn =~ s/^Macro //i; # Scrape off cruft...
  235. $dfn =~ s/^Data Type //i;
  236. $dfn =~ s/^Variable //i;
  237. $dfn =~ s/^Deprecated Function //i;
  238. $dfn =~ s/^SVID Macro //i;
  239. $dfn =~ s/^Obsolete function //i;
  240. $dfn =~ s/^Constant //i;
  241. $dfn =~ s/^Type //i;
  242. $dfn =~ s/^Function //i;
  243. $dfn =~ s/^\{(.*)\}$/$1/; # Debrace yourself.
  244. $dfn =~ s/^\{([^\}]*)\} /$1 /; # These ones too.
  245. return $dfn;
  246. }
  247. # Returns an annotated element's name.
  248. #
  249. # Takes a line defining an annotatable element (e.g., @def|item*),
  250. # splitting it on whitespace. The element is generally detected as
  251. # the member immediately preceding the first parenthesized expression
  252. # (e.g., a function), or the last token in the list. Some additional
  253. # cleanup is applied to the element before returning it.
  254. sub get_element
  255. {
  256. my $i = 0;
  257. my @toks = split /\s+/, shift;
  258. # tzname array uses '['; don't match function pointers.
  259. ++$i while $toks[$i] && $toks[$i] !~ /^[\(\[](?!\*)/;
  260. $toks[$i-1] =~ s/^\*//; # Strip pointer type syntax.
  261. $toks[$i-1] =~ s/^\{?([^\}]+)\}?$/$1/; # Strip braces.
  262. $toks[$i-1] =~ s/^\(\*([^\)]+)\)$/$1/; # Function pointers.
  263. return $toks[$i-1];
  264. }
  265. # Records syntax errors detected in the manual related to @standards.
  266. # The @def|item*s are grouped by file, then errors, to make it easier
  267. # to track down exactly where and what the problems are.
  268. sub record_error
  269. {
  270. my ($err, $list) = @_;
  271. push @{$errors{$texi}{$err}}, $_ for (@{$list});
  272. return 0;
  273. }
  274. # Reports all detected errors and exits with failure. Indentation is
  275. # used for readability, and "ERROR" is used for visibility.
  276. sub print_errors
  277. {
  278. for $texi (sort keys %errors) {
  279. print STDERR "ERRORS in $texi:\n";
  280. for my $err (sort keys %{$errors{$texi}}) {
  281. print STDERR " $err:\n";
  282. print STDERR " $_" for (@{$errors{$texi}{$err}});
  283. }
  284. }
  285. print(STDERR "\nFor a description of expected syntax, see ".
  286. "\`$script --help'\n\n");
  287. exit 1;
  288. }
  289. # Prints an entry in the Summary.
  290. #
  291. # All the blank lines in summary.texi may seem strange at first, but
  292. # they have significant impact on how Texinfo renders the output.
  293. # Essentially, each line is its own paragraph. There is a @comment
  294. # with the element name, arguably unnecessary, but useful for seeing
  295. # the sorting order and extracted element names, and maintains the
  296. # format established by summary.awk. Each @item in the @table is the
  297. # prototype, which may be anything from just a variable name to a
  298. # function declaration. The body of each @item contains lines
  299. # annotating the headers and standards each element is declared
  300. # in/comes from, with a reference to the @node documenting the element
  301. # wrt. each header and standard combination.
  302. sub print_entry
  303. {
  304. my $element = shift;
  305. for my $prototype (sort keys %{$entries{$element}}) {
  306. print "\@comment $element\n\@item $prototype\n\n";
  307. for (@{$entries{$element}{$prototype}}) {
  308. my ($header, $standard, $node)
  309. = ($_->[0], $_->[1], $_->[2]);
  310. if ($header =~ /^\(none\)$/i) {
  311. $header = "\@emph{no header}";
  312. } elsif ($header =~ /\(optional\)$/) {
  313. $header =~ s/^(\S+) \((.*)\)$/\@file{$1} \@emph{$2}/;
  314. } elsif ($header ne '???') {
  315. $header = "\@file{$header}";
  316. }
  317. print "$header ($standard): \@ref{$node}.\n\n";
  318. }
  319. }
  320. }
  321. # Document the syntax of @standards.
  322. sub help
  323. {
  324. print "$script ";
  325. print <<'EOH';
  326. generates the Summary of Library Facilities (summary.texi)
  327. from @standards and @standardsx macros in the Texinfo sources (see
  328. macros.texi). While generating the Summary, it also checks that
  329. @standards are used, correctly.
  330. In general, any @def*-command or @item in a @vtable is considered
  331. annotatable. "Misplaced annotation" refers to @standards macros
  332. detected outside an annotatable context. "Missing annotation" refers
  333. to annotatable elements without @standards. @standards are expected
  334. to immediately follow the elements being annotated. In @*x lists,
  335. @standards sets the default annotation and may only occur as the first
  336. annotation ("Misplaced @standards"). @standardsx may not be used
  337. outside @*x lists ("Misplaced @standardsx"). "Spurious @standardsx"
  338. refers to otherwise valid @standardsx macros that were not matched to
  339. an element in an @*x list. "Invalid syntax" means just that.
  340. The syntax of @standards annotations is designed to accomodate
  341. multiple header and standards annotations, as necessary.
  342. Examples:
  343. @deftp FOO
  344. @standards{STD, HDR}
  345. @defvar BAR
  346. @standards{STD, HDR1}
  347. @standards{STD, HDR2}
  348. @deftypefun foo
  349. @deftypefunx fool
  350. @standards{STD, HDR}
  351. @item bar
  352. @itemx baz
  353. @standardsx{bar, STD1, HDR1}
  354. @standardsx{baz, STD1, HDR1}
  355. @standardsx{baz, STD2, HDR2}
  356. Note that @standardsx deviates from the usual Texinfo syntax in that
  357. it is optional and may be used without @standards.
  358. EOH
  359. ; exit 0;
  360. }