autom4te.in

来自「LINUX下的源码工具,可自己分析,或者直接装在系统上作为应用」· IN 代码 · 共 1,233 行 · 第 1/3 页

IN
1,233
字号
Copyright 2002 Free Software Foundation, Inc.This is free software; see the source for copying conditions.  There is NOwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.EOF## ---------- #### Routines.  #### ---------- ### $OPTION# files_to_options (@FILE)# ------------------------# Transform Autom4te conventions (e.g., using foo.m4f to designate a frozen# file) into a suitable command line for M4 (e.g., using --reload-state).sub files_to_options (@){  my (@file) = @_;  my @res;  foreach my $file (@file)    {      if ($file =~ /\.m4f$/)	{	  push @res, "--reload-state=$file";	}      else	{	  push @res, $file;	}    }  return join ' ', @res;}# load_configuration ($FILE)# --------------------------# Load the configuration $FILE.sub load_configuration ($){  my ($file) = @_;  use Text::ParseWords;  my $cfg = new Autom4te::XFile ($file);  my $lang;  while ($_ = $cfg->getline)    {      chomp;      # Comments.      next	if /^\s*(\#.*)?$/;      my @words = shellwords ($_);      my $type = shift @words;      if ($type eq 'begin-language:')	{	  error "$file:$.: end-language missing for: $lang"	    if defined $lang;	  $lang = lc $words[0];	}      elsif ($type eq 'end-language:')	{	  error "$file:$.: end-language mismatch: $lang"	    if $lang ne lc $words[0];	  $lang = undef;	}      elsif ($type eq 'args:')	{	  error "$file:$.: no current language"	    unless defined $lang;	  push @{$language{$lang}}, @words;	}      else	{	  error "$file:$.: unknown directive: $type";	}    }}# parse_args ()# -------------# Process any command line arguments.sub parse_args (){  # We want to look for the early options, which should not be found  # in the configuration file.  Prepend to the user arguments.  # Perform this repeatedly so that we can use --language in language  # definitions.  Beware that there can be several --language  # invocations.  my @language;  do {    @language = ();    use Getopt::Long;    Getopt::Long::Configure ("pass_through", "permute");    GetOptions ("l|language=s" => \@language);    foreach (@language)      {	error "unknown language: $_"	  unless exists $language{lc $_};	unshift @ARGV, @{$language{lc $_}};      }  } while @language;  # --debug is useless: it is parsed below.  if (exists $ENV{'AUTOM4TE_DEBUG'})    {      print STDERR "$me: concrete arguments:\n";      foreach my $arg (@ARGV)	{	  print STDERR "| $arg\n";	}    }  # Process the arguments for real this time.  my @trace;  my @prepend_include;  getopt    (     # Operation modes:     "o|output=s"   => \$output,     "W|warnings=s" => \@warning,     "m|mode=s"     => \$mode,     "M|melt"       => \$melt,     # Library directories:     "B|prepend-include=s" => \@prepend_include,     "I|include=s"         => \@include,     # Tracing:     # Using a hash for traces is seducing.  Unfortunately, upon `-t FOO',     # instead of mapping `FOO' to undef, Getopt maps it to `1', preventing     # us from distinguishing `-t FOO' from `-t FOO=1'.  So let's do it     # by hand.     "t|trace=s"     => \@trace,     "p|preselect=s" => \@preselect,     # Freezing.     "F|freeze" => \$freeze,     # Caching.     "C|cache=s" => \$cache,     "no-cache"  => sub { $cache = undef; },    );  error "too few argumentsTry `$me --help' for more information."    unless @ARGV;  # Freezing:  # We cannot trace at the same time (well, we can, but it sounds insane).  # And it implies melting: there is risk not to update properly using  # old frozen files, and worse yet: we could load a frozen file and  # refreeze it!  A sort of caching :)  error "cannot freeze and trace"    if $freeze && @trace;  $melt = 1    if $freeze;  # Names of the cache directory, cache directory index, trace cache  # prefix, and output cache prefix.  If the cache is not to be  # preserved, default to a temporary directory (automatically removed  # on exit).  $cache = $tmp    unless $cache;  $icache = "$cache/requests";  $tcache = "$cache/traces.";  $ocache = "$cache/output.";  # Normalize the includes: the first occurrence is enough, several is  # a pain since it introduces a useless difference in the path which  # invalidates the cache.  And strip `.' which is implicit and always  # first.  @include = grep { !/^\.$/ } uniq (reverse(@prepend_include), @include);  # Convert @trace to %trace, and work around the M4 builtins tracing  # problem.  # The default format is `$f:$l:$n:$%'.  foreach (@trace)    {      /^([^:]+)(?::(.*))?$/ms;      $trace{$1} = defined $2 ? $2 : '$f:$l:$n:$%';      $trace{$m4_builtin_alternate_name{$1}} = $trace{$1}	if exists $m4_builtin_alternate_name{$1};    }  # Work around the M4 builtins tracing problem for @PRESELECT.  push (@preselect,	map { $m4_builtin_alternate_name{$_} }	grep { exists $m4_builtin_alternate_name{$_} } @preselect);  # If we find frozen files, then all the files before it are  # discarded: the frozen file is supposed to include them all.  #  # We don't want to depend upon m4's --include to find the top level  # files, so we use `find_file' here.  Try to get a canonical name,  # as it's part of the key for caching.  And some files are optional  # (also handled by `find_file').  my @argv;  foreach (@ARGV)    {      if (/\.m4f$/)	{	  # Frozen files are optional => pass a `?' to `find_file'.	  my $file = find_file ("$_?", @include);	  if (!$melt && $file)	    {	      @argv = ($file);	    }	  else	    {	      s/\.m4f$/.m4/;	      push @argv, find_file ($_, @include);	    }	}      else	{	  my $file = find_file ($_, @include);	  push @argv, $file	    if $file;	}    }  @ARGV = @argv;}# handle_m4 ($REQ, @MACRO)# ------------------------# Run m4 on the input files, and save the traces on the @MACRO.sub handle_m4 ($@){  my ($req, @macro) = @_;  # The warnings are the concatenation of 1. application's defaults,  # 2. $WARNINGS, $3 command line options, in that order.  # Set them in the order expected by the M4 macros: the converse.  my $m4_warnings =    lc join (',', reverse (split (',', ($ENV{'WARNINGS'} || '')),			   map { split /,/ } @warning));  # GNU m4 appends when using --error-output.  unlink ($tcache . $req->id . "t");  # Run m4.  #  # Neutralize its stdin, so that GNU M4 1.5 doesn't neutralize SIGINT.  #  # We don't output directly to the cache files, to avoid problems  # when we are interrupted (that leaves corrupted files).  xsystem ("$m4"	   . join (' --include=', '', @include)	   . " --define=m4_warnings=$m4_warnings"	   . ' --debug=aflq'	   . (!exists $ENV{'AUTOM4TE_NO_FATAL'} ? ' --fatal-warning' : '')	   . " --error-output=$tcache" . $req->id . "t"	   . join (' --trace=',   '', sort @macro)	   . " " . files_to_options (@ARGV)	   . ' </dev/null'	   . " >$ocache" . $req->id . "t");  # Everything went ok: preserve the outputs.  foreach my $file (map { $_ . $req->id } ($tcache, $ocache))    {      use File::Copy;      move ("${file}t", "$file")	or error "cannot not rename ${file}t as $file: $!";    }}# warn_forbidden ($WHERE, $WORD, %FORBIDDEN)# ------------------------------------------# $WORD is forbidden.  Warn with a dedicated error message if in# %FORBIDDEN, otherwise, a simple `error: possibly undefined macro'# will do.my $first_warn_forbidden = 1;sub warn_forbidden ($$%){  my ($where, $word, %forbidden) = @_;  my $message;  for my $re (sort keys %forbidden)    {      if ($word =~ $re)	{	  $message = $forbidden{$re};	  last;	}    }  $message ||= "possibly undefined macro: $word";  warn "$where: error: $message\n";  if ($first_warn_forbidden)    {      warn <<EOF;      If this token and others are legitimate, please use m4_pattern_allow.      See the Autoconf documentation.EOF      $first_warn_forbidden = 0;    }}# handle_output ($REQ, $OUTPUT)# -----------------------------# Run m4 on the input files, perform quadrigraphs substitution, check for# forbidden tokens, and save into $OUTPUT.sub handle_output ($$){  my ($req, $output) = @_;  verbose "creating $output";  # Load the forbidden/allowed patterns.  handle_traces ($req, "$tmp/patterns",		 ('m4_pattern_forbid' => 'forbid:$1:$2',		  'm4_pattern_allow'  => 'allow:$1'));  my @patterns = new Autom4te::XFile ("$tmp/patterns")->getlines;  chomp @patterns;  my %forbidden =    map { /^forbid:([^:]+):.+$/ => /^forbid:[^:]+:(.+)$/ } @patterns;  my $forbidden = join ('|', map { /^forbid:([^:]+)/ } @patterns) || "^\$";  my $allowed   = join ('|', map { /^allow:([^:]+)/  } @patterns) || "^\$";  verbose "forbidden tokens: $forbidden";  verbose "forbidden token : $_ => $forbidden{$_}"    foreach (sort keys %forbidden);  verbose "allowed   tokens: $allowed";  # Read the (cached) raw M4 output, produce the actual result.  We  # have to use the 2nd arg to have Autom4te::XFile honor the third, but then  # stdout is to be handled by hand :(.  Don't use fdopen as it means  # we will close STDOUT, which we already do in END.  my $out = new Autom4te::XFile;  if ($output eq '-')    {      $out->open (">$output");    }  else    {      $out->open($output, O_CREAT | O_WRONLY | O_TRUNC, oct ($mode));    }  error "cannot create $output: $!"    unless $out;  my $in = new Autom4te::XFile ($ocache . $req->id);  my %prohibited;  my $res;  while ($_ = $in->getline)    {      s/\s+$//;      s/__oline__/$./g;      s/\@<:\@/[/g;      s/\@:>\@/]/g;      s/\@S\|\@/\$/g;      s/\@%:\@/#/g;      $res = $_;      # Don't complain in comments.  Well, until we have something      # better, don't consider `#include' etc. are comments.      s/\#.*//	unless /^\#\s*(if|include|endif|ifdef|ifndef|define)\b/;      foreach (split (/\W+/))	{	  $prohibited{$_} = $.	    if /$forbidden/o && !/$allowed/o && ! exists $prohibited{$_};	}      # Performed *last*: the empty quadrigraph.      $res =~ s/\@&t\@//g;      print $out "$res\n";    }  # If no forbidden words, we're done.  return    if ! %prohibited;  # Locate the forbidden words in the last input file.  # This is unsatisfying but...  my $prohibited = '\b(' . join ('|', keys %prohibited) . ')\b';  my $file = new Autom4te::XFile ($ARGV[$#ARGV]);  $exit_status = 1;  while ($_ = $file->getline)    {      # Don't complain in comments.  Well, until we have something      # better, don't consider `#include' etc. are comments.      s/\#.*//	unless /^\#(if|include|endif|ifdef|ifndef|define)\b/;      # Complain once per word, but possibly several times per line.      while (/$prohibited/)	{	  my $word = $1;	  warn_forbidden ("$ARGV[$#ARGV]:$.", $word, %forbidden);	  delete $prohibited{$word};	  # If we're done, exit.	  return	    if ! %prohibited;	  $prohibited = '\b(' . join ('|', keys %prohibited) . ')\b';	}    }  warn_forbidden ("$output:$prohibited{$_}", $_, %forbidden)    foreach (sort { $prohibited{$a} <=> $prohibited{$b} } keys %prohibited);}## --------------------- #### Handling the traces.  ##

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?