#! /usr/bin/perl -w # Extract all examples from the manual source. # This file is part of GNU Bison # Copyright (C) 1992, 2000-2001, 2005-2006, 2009-2013 Free Software # Foundation, Inc. # # 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 3 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, see . # Usage: extexi [OPTION...] input-file.texi ... -- [FILES to extract] # Look for @example environments preceded with lines such as: # # @comment file calc.y # or # @comment file calc.y: 3 # # and output their content in that file (calc.y). When numbers are # provided, use them to decide the output order (block numbered 1 is # output before block 2, even if the latter appears before). The same # number may be used several time, in which case the order of # appearance is used. use strict; # Whether we generate synclines. my $synclines = 0; # normalize($block) # ----------------- # Remove Texinfo mark up. sub normalize($) { local ($_) = @_; s/^\@(c |comment|dots|end (ignore|group)|ignore|group).*//mg; s/\@value\{VERSION\}/$ENV{VERSION}/g; s/^\@(error|result)\{\}//mg; s/\@([{}@])/$1/g; s/\@comment.*//; $_; } # Print messages only once. my %msg; sub message($) { my ($msg) = @_; if (! $msg{$msg}) { print STDERR "extexi: $msg\n"; $msg{$msg} = 1; } } # basename => full file name for files we should extract. my %file_wanted; sub process ($) { my ($in) = @_; use IO::File; my $f = new IO::File($in) or die "$in: cannot open: $?"; # FILE-NAME => { BLOCK-NUM => CODE } my %file; # The latest "@comment file: FILE [BLOCK-NUM]" arguments. my $file; my $block; # The @example block currently read. my $input; local $_; while (<$f>) { if (/^\@comment file: ([^:\n]+)(?::\s*(\d+))?$/) { my $f = $1; $block = $2 || 1; if ($file_wanted{$f}) { $file = $file_wanted{$f}; message(" GEN $file"); } else { message("SKIP $f"); } } elsif ($file && /^\@(small)?example$/ .. /^\@end (small)?example$/) { if (/^\@(small)?example$/) { # Bison supports synclines, but not Flex. $input .= sprintf ("#line %s \"$in\"\n", $. + 1) if $synclines && $file =~ /\.[chy]*$/; next; } elsif (/^\@end (small)?example$/) { die "no contents: $file" if $input eq ""; $file{$file}{$block} .= normalize($input); $file = $input = undef; ++$block; } else { $input .= $_; } } } # Output the files. for my $file (keys %file) { # No spurious end of line: use printf. my $o = new IO::File(">$file") or die "$file: cannot create: $?"; print $o $file{$file}{$_} for sort keys %{$file{$file}}; } } my @input; my $seen_dash = 0; for my $arg (@ARGV) { if ($seen_dash) { use File::Basename; $file_wanted{basename($arg)} = $arg; } elsif ($arg eq '--') { $seen_dash = 1; } elsif ($arg eq '--synclines') { $synclines = 1; } else { push @input, $arg; } } process $_ foreach @input; ### Setup "GNU" style for perl-mode and cperl-mode. ## Local Variables: ## perl-indent-level: 2 ## perl-continued-statement-offset: 2 ## perl-continued-brace-offset: 0 ## perl-brace-offset: 0 ## perl-brace-imaginary-offset: 0 ## perl-label-offset: -2 ## cperl-indent-level: 2 ## cperl-brace-offset: 0 ## cperl-continued-brace-offset: 0 ## cperl-label-offset: -2 ## cperl-extra-newline-before-brace: t ## cperl-merge-trailing-else: nil ## cperl-continued-statement-offset: 2 ## End: