Blame autoscan.pl

Packit 1ca270
#! @PERL@
Packit 1ca270
# autoscan - Create configure.scan (a preliminary configure.in) for a package.
Packit 1ca270
# Copyright (C) 1994 Free Software Foundation, Inc.
Packit 1ca270
Packit 1ca270
# This program is free software; you can redistribute it and/or modify
Packit 1ca270
# it under the terms of the GNU General Public License as published by
Packit 1ca270
# the Free Software Foundation; either version 2, or (at your option)
Packit 1ca270
# any later version.
Packit 1ca270
Packit 1ca270
# This program is distributed in the hope that it will be useful,
Packit 1ca270
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 1ca270
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 1ca270
# GNU General Public License for more details.
Packit 1ca270
Packit 1ca270
# You should have received a copy of the GNU General Public License
Packit 1ca270
# along with this program; if not, write to the Free Software
Packit 1ca270
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
Packit 1ca270
# 02111-1307, USA.
Packit 1ca270
Packit 1ca270
# Written by David MacKenzie <djm@gnu.ai.mit.edu>.
Packit 1ca270
Packit 1ca270
require "find.pl";
Packit 1ca270
Packit 1ca270
$datadir = $ENV{"AC_MACRODIR"} || "@datadir@";
Packit 1ca270
$verbose = 0;
Packit 1ca270
# Reference these variables to pacify perl -w.
Packit 1ca270
undef %identifiers_macros;
Packit 1ca270
undef %makevars_macros;
Packit 1ca270
undef %programs_macros;
Packit 1ca270
Packit 1ca270
&parse_args;
Packit 1ca270
&init_tables;
Packit 1ca270
&find('.');
Packit 1ca270
&scan_files;
Packit 1ca270
&output;
Packit 1ca270
Packit 1ca270
exit 0;
Packit 1ca270
Packit 1ca270
# Process any command line arguments.
Packit 1ca270
sub parse_args
Packit 1ca270
{
Packit 1ca270
    local ($usage) =
Packit 1ca270
	"Usage: autoscan [--macrodir=dir] [--help] [--verbose] [--version] [srcdir]\n"; 
Packit 1ca270
Packit 1ca270
    foreach $_ (@ARGV) {
Packit 1ca270
	if (/^--m[a-z]*=(.*)/) {
Packit 1ca270
	    $datadir = $1;
Packit 1ca270
	} elsif (/^--h/) {
Packit 1ca270
	    print "$usage";
Packit 1ca270
	    exit 0;
Packit 1ca270
	} elsif (/^--verb/) {
Packit 1ca270
	    $verbose = 1;
Packit 1ca270
	} elsif (/^--vers/) {
Packit 1ca270
	    &version;
Packit 1ca270
	} elsif (/^[^-]/) {
Packit 1ca270
	    die "$usage" if defined($srcdir);
Packit 1ca270
	    # Top level directory of the package being autoscanned.
Packit 1ca270
	    $srcdir = $_;
Packit 1ca270
	} else {
Packit 1ca270
	    die "$usage";
Packit 1ca270
	}
Packit 1ca270
    }
Packit 1ca270
Packit 1ca270
    $srcdir="." if !defined($srcdir);
Packit 1ca270
Packit 1ca270
    print "srcdir=$srcdir\n" if $verbose;
Packit 1ca270
    chdir $srcdir || die "$0: cannot cd to $srcdir: $!\n";
Packit 1ca270
Packit 1ca270
    open(CONF, ">configure.scan") ||
Packit 1ca270
	die "$0: cannot create configure.scan: $!\n";
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
# Print the version number and exit.
Packit 1ca270
sub version
Packit 1ca270
{
Packit 1ca270
    open(ACG, "<$datadir/acgeneral.m4") ||
Packit 1ca270
	die "$0: cannot open $datadir/acgeneral.m4: $!\n";
Packit 1ca270
    while (<ACG>) {
Packit 1ca270
	if (/define.AC_ACVERSION.\s*([0-9.]+)/) {
Packit 1ca270
	    print "Autoconf version $1\n";
Packit 1ca270
	    exit 0;
Packit 1ca270
	}
Packit 1ca270
    }
Packit 1ca270
    die "Autoconf version unknown\n";
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
# Put values in the tables of what to do with each token.
Packit 1ca270
sub init_tables
Packit 1ca270
{
Packit 1ca270
    local($kind, $word, $macro);
Packit 1ca270
Packit 1ca270
    # Initialize a table of C keywords (to ignore).
Packit 1ca270
    # Taken from K&R 1st edition p. 180.
Packit 1ca270
    # ANSI C, GNU C, and C++ keywords can introduce portability problems,
Packit 1ca270
    # so don't ignore them.
Packit 1ca270
    foreach $word ('int', 'char', 'float', 'double', 'struct', 'union',
Packit 1ca270
		   'long', 'short', 'unsigned', 'auto', 'extern', 'register',
Packit 1ca270
		   'typedef', 'static', 'goto', 'return', 'sizeof', 'break',
Packit 1ca270
		   'continue', 'if', 'else', 'for', 'do', 'while', 'switch',
Packit 1ca270
		   'case', 'default') {
Packit 1ca270
	$c_keywords{$word} = 0;
Packit 1ca270
    }
Packit 1ca270
Packit 1ca270
    # The data file format supports only one line of macros per function.
Packit 1ca270
    # If more than that is required for a common portability problem,
Packit 1ca270
    # a new Autoconf macro should probably be written for that case,
Packit 1ca270
    # instead of duplicating the code in lots of configure.in files.
Packit 1ca270
Packit 1ca270
    foreach $kind ('functions', 'headers', 'identifiers', 'programs',
Packit 1ca270
		   'makevars') {
Packit 1ca270
	open(TABLE, "<$datadir/ac$kind") ||
Packit 1ca270
	    die "$0: cannot open $datadir/ac$kind: $!\n";
Packit 1ca270
	while () {
Packit 1ca270
	    next if /^\s*$/ || /^\s*#/; # Ignore blank lines and comments.
Packit 1ca270
	    ($word, $macro) = split;
Packit 1ca270
	    eval "\$$kind" . "_macros{\$word} = \$macro";
Packit 1ca270
	}
Packit 1ca270
	close(TABLE);
Packit 1ca270
    }
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
# Collect names of various kinds of files in the package.
Packit 1ca270
# Called by &find on each file.
Packit 1ca270
sub wanted
Packit 1ca270
{
Packit 1ca270
    if (/^.*\.[chlymC]$/ || /^.*\.cc$/) {
Packit 1ca270
	$name =~ s?^\./??; push(@cfiles, $name);
Packit 1ca270
    }
Packit 1ca270
    elsif (/^[Mm]akefile$/ || /^[Mm]akefile\.in$/ || /^GNUmakefile$/) {
Packit 1ca270
	$name =~ s?^\./??; push(@makefiles, $name);
Packit 1ca270
    }
Packit 1ca270
    elsif (/^.*\.sh$/) {
Packit 1ca270
	$name =~ s?^\./??; push(@shfiles, $name);
Packit 1ca270
    }
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
# Read through the files and collect lists of tokens in them
Packit 1ca270
# that might create nonportabilities.
Packit 1ca270
sub scan_files
Packit 1ca270
{
Packit 1ca270
    $initfile = $cfiles[0];		# Pick one at random.
Packit 1ca270
Packit 1ca270
    if ($verbose) {
Packit 1ca270
	print "cfiles:", join(" ", @cfiles), "\n";
Packit 1ca270
	print "makefiles:", join(" ", @makefiles), "\n";
Packit 1ca270
	print "shfiles:", join(" ", @shfiles), "\n";
Packit 1ca270
    }
Packit 1ca270
Packit 1ca270
    foreach $file (@cfiles) {
Packit 1ca270
	&scan_c_file($file);
Packit 1ca270
    }
Packit 1ca270
Packit 1ca270
    foreach $file (@makefiles) {
Packit 1ca270
	&scan_makefile($file);
Packit 1ca270
    }
Packit 1ca270
Packit 1ca270
    foreach $file (@shfiles) {
Packit 1ca270
	&scan_sh_file($file);
Packit 1ca270
    }
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
sub scan_c_file
Packit 1ca270
{
Packit 1ca270
    local($file) = @_;
Packit 1ca270
    local($in_comment) = 0;	# Nonzero if in a multiline comment.
Packit 1ca270
Packit 1ca270
    open(CFILE, "<$file") || die "$0: cannot open $file: $!\n";
Packit 1ca270
    while (<CFILE>) {
Packit 1ca270
	# Strip out comments, approximately.
Packit 1ca270
	# Ending on this line.
Packit 1ca270
	if ($in_comment && m,\*/,) {
Packit 1ca270
	    s,.*\*/,,;
Packit 1ca270
	    $in_comment = 0;
Packit 1ca270
	}
Packit 1ca270
	# All on one line.
Packit 1ca270
	s,/\*.*\*/,,g;
Packit 1ca270
	# Starting on this line.
Packit 1ca270
	if (m,/\*,) {
Packit 1ca270
	    $in_comment = 1;
Packit 1ca270
	}
Packit 1ca270
	# Continuing on this line.
Packit 1ca270
	next if $in_comment;
Packit 1ca270
Packit 1ca270
	# Preprocessor directives.
Packit 1ca270
	if (/^\s*#\s*include\s*<([^>]*)>/) {
Packit 1ca270
	    $headers{$1}++;
Packit 1ca270
	}
Packit 1ca270
	# Ignore other preprocessor directives.
Packit 1ca270
	next if /^\s*#/;
Packit 1ca270
Packit 1ca270
	# Remove string and character constants.
Packit 1ca270
	s,\"[^\"]*\",,g;
Packit 1ca270
        s,\'[^\']*\',,g;
Packit 1ca270
Packit 1ca270
	# Tokens in the code.
Packit 1ca270
	# Maybe we should ignore function definitions (in column 0)?
Packit 1ca270
	while (s/\W([a-zA-Z_]\w*)\s*\(/ /) {
Packit 1ca270
	    $functions{$1}++ if !defined($c_keywords{$1});
Packit 1ca270
	}
Packit 1ca270
	while (s/\W([a-zA-Z_]\w*)\W/ /) {
Packit 1ca270
	    $identifiers{$1}++ if !defined($c_keywords{$1});
Packit 1ca270
	}
Packit 1ca270
    }
Packit 1ca270
    close(CFILE);
Packit 1ca270
Packit 1ca270
    if ($verbose) {
Packit 1ca270
	local($word);
Packit 1ca270
Packit 1ca270
	print "\n$file functions:\n";
Packit 1ca270
	foreach $word (sort keys %functions) {
Packit 1ca270
	    print "$word $functions{$word}\n";
Packit 1ca270
	}
Packit 1ca270
Packit 1ca270
	print "\n$file identifiers:\n";
Packit 1ca270
	foreach $word (sort keys %identifiers) {
Packit 1ca270
	    print "$word $identifiers{$word}\n";
Packit 1ca270
	}
Packit 1ca270
Packit 1ca270
	print "\n$file headers:\n";
Packit 1ca270
	foreach $word (sort keys %headers) {
Packit 1ca270
	    print "$word $headers{$word}\n";
Packit 1ca270
	}
Packit 1ca270
    }
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
sub scan_makefile
Packit 1ca270
{
Packit 1ca270
    local($file) = @_;
Packit 1ca270
Packit 1ca270
    open(MFILE, "<$file") || die "$0: cannot open $file: $!\n";
Packit 1ca270
    while (<MFILE>) {
Packit 1ca270
	# Strip out comments and variable references.
Packit 1ca270
	s/#.*//;
Packit 1ca270
	s/\$\([^\)]*\)//g;
Packit 1ca270
	s/\${[^\}]*}//g;
Packit 1ca270
	s/@[^@]*@//g;
Packit 1ca270
Packit 1ca270
	# Variable assignments.
Packit 1ca270
	while (s/\W([a-zA-Z_]\w*)\s*=/ /) {
Packit 1ca270
	    $makevars{$1}++;
Packit 1ca270
	}
Packit 1ca270
	# Libraries.
Packit 1ca270
	while (s/\W-l([a-zA-Z_]\w*)\W/ /) {
Packit 1ca270
	    $libraries{$1}++;
Packit 1ca270
	}
Packit 1ca270
	# Tokens in the code.
Packit 1ca270
	while (s/\W([a-zA-Z_]\w*)\W/ /) {
Packit 1ca270
	    $programs{$1}++;
Packit 1ca270
	}
Packit 1ca270
    }
Packit 1ca270
    close(MFILE);
Packit 1ca270
Packit 1ca270
    if ($verbose) {
Packit 1ca270
	local($word);
Packit 1ca270
Packit 1ca270
	print "\n$file makevars:\n";
Packit 1ca270
	foreach $word (sort keys %makevars) {
Packit 1ca270
	    print "$word $makevars{$word}\n";
Packit 1ca270
	}
Packit 1ca270
Packit 1ca270
	print "\n$file libraries:\n";
Packit 1ca270
	foreach $word (sort keys %libraries) {
Packit 1ca270
	    print "$word $libraries{$word}\n";
Packit 1ca270
	}
Packit 1ca270
Packit 1ca270
	print "\n$file programs:\n";
Packit 1ca270
	foreach $word (sort keys %programs) {
Packit 1ca270
	    print "$word $programs{$word}\n";
Packit 1ca270
	}
Packit 1ca270
    }
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
sub scan_sh_file
Packit 1ca270
{
Packit 1ca270
    local($file) = @_;
Packit 1ca270
Packit 1ca270
    open(MFILE, "<$file") || die "$0: cannot open $file: $!\n";
Packit 1ca270
    while (<MFILE>) {
Packit 1ca270
	# Strip out comments and variable references.
Packit 1ca270
	s/#.*//;
Packit 1ca270
	s/\${[^\}]*}//g;
Packit 1ca270
	s/@[^@]*@//g;
Packit 1ca270
Packit 1ca270
	# Tokens in the code.
Packit 1ca270
	while (s/\W([a-zA-Z_]\w*)\W/ /) {
Packit 1ca270
	    $programs{$1}++;
Packit 1ca270
	}
Packit 1ca270
    }
Packit 1ca270
    close(MFILE);
Packit 1ca270
Packit 1ca270
    if ($verbose) {
Packit 1ca270
	local($word);
Packit 1ca270
Packit 1ca270
	print "\n$file programs:\n";
Packit 1ca270
	foreach $word (sort keys %programs) {
Packit 1ca270
	    print "$word $programs{$word}\n";
Packit 1ca270
	}
Packit 1ca270
    }
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
# Print a configure.in.
Packit 1ca270
sub output
Packit 1ca270
{
Packit 1ca270
    local (%unique_makefiles);
Packit 1ca270
Packit 1ca270
    print CONF "dnl Process this file with autoconf to produce a configure script.\n";
Packit 1ca270
    print CONF "AC_INIT($initfile)\n";
Packit 1ca270
Packit 1ca270
    &output_programs;
Packit 1ca270
    &output_headers;
Packit 1ca270
    &output_identifiers;
Packit 1ca270
    &output_functions;
Packit 1ca270
Packit 1ca270
    # Change DIR/Makefile.in to DIR/Makefile.
Packit 1ca270
    foreach $_ (@makefiles) {
Packit 1ca270
	s/\.in$//;
Packit 1ca270
	$unique_makefiles{$_}++;
Packit 1ca270
    }
Packit 1ca270
    print CONF "\nAC_OUTPUT(", join(" ", keys(%unique_makefiles)), ")\n";
Packit 1ca270
Packit 1ca270
    close CONF;
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
# Print Autoconf macro $1 if it's not undef and hasn't been printed already.
Packit 1ca270
sub print_unique
Packit 1ca270
{
Packit 1ca270
    local($macro) = @_;
Packit 1ca270
Packit 1ca270
    if (defined($macro) && !defined($printed{$macro})) {
Packit 1ca270
	print CONF "$macro\n";
Packit 1ca270
	$printed{$macro} = 1;
Packit 1ca270
    }
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
sub output_programs
Packit 1ca270
{
Packit 1ca270
    local ($word);
Packit 1ca270
Packit 1ca270
    print CONF "\ndnl Checks for programs.\n";
Packit 1ca270
    foreach $word (sort keys %programs) {
Packit 1ca270
	&print_unique($programs_macros{$word});
Packit 1ca270
    }
Packit 1ca270
    foreach $word (sort keys %makevars) {
Packit 1ca270
	&print_unique($makevars_macros{$word});
Packit 1ca270
    }
Packit 1ca270
    print CONF "\ndnl Checks for libraries.\n";
Packit 1ca270
    foreach $word (sort keys %libraries) {
Packit 1ca270
	print CONF "dnl Replace `\main\' with a function in -l$word:\n";
Packit 1ca270
	print CONF "AC_CHECK_LIB($word, main)\n";
Packit 1ca270
    }
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
sub output_headers
Packit 1ca270
{
Packit 1ca270
    local ($word);
Packit 1ca270
Packit 1ca270
    print CONF "\ndnl Checks for header files.\n";
Packit 1ca270
    foreach $word (sort keys %headers) {
Packit 1ca270
	if (defined($headers_macros{$word}) &&
Packit 1ca270
	    $headers_macros{$word} eq 'AC_CHECK_HEADERS') {
Packit 1ca270
	    push(@have_headers, $word);
Packit 1ca270
	} else {	
Packit 1ca270
	    &print_unique($headers_macros{$word});
Packit 1ca270
	}
Packit 1ca270
    }
Packit 1ca270
    print CONF "AC_CHECK_HEADERS(" . join(' ', sort(@have_headers)) . ")\n"
Packit 1ca270
	if defined(@have_headers);
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
sub output_identifiers
Packit 1ca270
{
Packit 1ca270
    local ($word);
Packit 1ca270
Packit 1ca270
    print CONF "\ndnl Checks for typedefs, structures, and compiler characteristics.\n";
Packit 1ca270
    foreach $word (sort keys %identifiers) {
Packit 1ca270
	&print_unique($identifiers_macros{$word});
Packit 1ca270
    }
Packit 1ca270
}
Packit 1ca270
Packit 1ca270
sub output_functions
Packit 1ca270
{
Packit 1ca270
    local ($word);
Packit 1ca270
Packit 1ca270
    print CONF "\ndnl Checks for library functions.\n";
Packit 1ca270
    foreach $word (sort keys %functions) {
Packit 1ca270
	if (defined($functions_macros{$word}) &&
Packit 1ca270
	    $functions_macros{$word} eq 'AC_CHECK_FUNCS') {
Packit 1ca270
	    push(@have_funcs, $word);
Packit 1ca270
	} else {	
Packit 1ca270
	    &print_unique($functions_macros{$word});
Packit 1ca270
	}
Packit 1ca270
    }
Packit 1ca270
    print CONF "AC_CHECK_FUNCS(" . join(' ', sort(@have_funcs)) . ")\n"
Packit 1ca270
	if defined(@have_funcs);
Packit 1ca270
}