Blame maint/extractstrings

Packit Service c5cf8c
#! /usr/bin/env perl
Packit Service c5cf8c
# -*- Mode: perl; -*-
Packit Service c5cf8c
# 
Packit Service c5cf8c
# This script is a replacement for several scripts that process source
Packit Service c5cf8c
# files, extracting information from them.  This file provides a set 
Packit Service c5cf8c
# of routines for processing files and maintaining a cache of the results.
Packit Service c5cf8c
# It uses a more sophisticated
Packit Service c5cf8c
# approach to avoid rescanning all files by keeping track of local changes
Packit Service c5cf8c
# It does this on a directory-by-directory basis as a comprimise between
Packit Service c5cf8c
# doing the minimal work but limiting the number and size of the "extra"
Packit Service c5cf8c
# files.  In this case, for each directory, the following dot file is 
Packit Service c5cf8c
# produced (with a <name> provided depending on use:
Packit Service c5cf8c
#   .<name>-cache
Packit Service c5cf8c
# This file contains lines of the form
Packit Service c5cf8c
# <dir>
Packit Service c5cf8c
# <file name="filename" info="date or md5 hash"/>
Packit Service c5cf8c
# ...
Packit Service c5cf8c
# </dir>
Packit Service c5cf8c
# <data>
Packit Service c5cf8c
# <fileinfo name="filename">
Packit Service c5cf8c
# data for this file extracted from file
Packit Service c5cf8c
# </fileinfo>
Packit Service c5cf8c
# ...
Packit Service c5cf8c
# </data>
Packit Service c5cf8c
# The file has a separate directory to speed reading of the list of 
Packit Service c5cf8c
# know files so that the comparisons for updates can be 
Packit Service c5cf8c
# computed quickly.
Packit Service c5cf8c
#
Packit Service c5cf8c
# In addition, this allows us to create lists of information by
Packit Service c5cf8c
# combining the directories in which we're interested, rather than
Packit Service c5cf8c
# all of the directories.  This will also make it possible to 
Packit Service c5cf8c
# update these tables at configure time with modules provided by other
Packit Service c5cf8c
# developers.
Packit Service c5cf8c
#
Packit Service c5cf8c
# Algorithm:
Packit Service c5cf8c
# For each directory (use readdir)
Packit Service c5cf8c
#    Get a list of matching files (filename pattern supplied, default is
Packit Service c5cf8c
#    *.[chi])
Packit Service c5cf8c
#    if a cache file is found 
Packit Service c5cf8c
#        read cache file directory
Packit Service c5cf8c
#        compare with source files
Packit Service c5cf8c
#            for each out-of-date or new file, extract information (see below)
Packit Service c5cf8c
#            else mark file as unchanged
Packit Service c5cf8c
#            check for deleted files
Packit Service c5cf8c
#        if any changes
Packit Service c5cf8c
#            read old cache file for info from unchanged files
Packit Service c5cf8c
#            write new directory and data entries
Packit Service c5cf8c
#    else
Packit Service c5cf8c
#       for each file
Packit Service c5cf8c
#            extract information
Packit Service c5cf8c
#       write new directory and data entries
Packit Service c5cf8c
#    (optional) if specified, call routine to process cache file contents
Packit Service c5cf8c
#      (e.g., generate a derived file).
Packit Service c5cf8c
#
Packit Service c5cf8c
# Data structures
Packit Service c5cf8c
# Within a directory
Packit Service c5cf8c
#   fileInfo{filename} = extracted info
Packit Service c5cf8c
#   filesUpdated[]     = array of file names that match critera
Packit Service c5cf8c
#   fileInCache{filename} = comparison info
Packit Service c5cf8c
#   
Packit Service c5cf8c
# -------------------------------------------------------------------------
Packit Service c5cf8c
use warnings;
Packit Service c5cf8c
Packit Service c5cf8c
$gDebug     = 0;
Packit Service c5cf8c
# verbose of 1 gives the least amount of data, higher values give
Packit Service c5cf8c
# increasing amount of detail. (0, of course, gives no detail)
Packit Service c5cf8c
$gVerbose   = 0;
Packit Service c5cf8c
$gUpdateAll = 0;
Packit Service c5cf8c
# -------------------------------------------------------------------------
Packit Service c5cf8c
# Return an array of regular files in the named directory
Packit Service c5cf8c
sub GetFileNamesInDirectory {
Packit Service c5cf8c
    my ($dir,$pattern) = @_;
Packit Service c5cf8c
    my @filesFound = ();
Packit Service c5cf8c
Packit Service c5cf8c
    opendir DIR, $dir || die "Could not open $dir\n";
Packit Service c5cf8c
    for my $file (sort readdir DIR) {
Packit Service c5cf8c
	if (! -f "$dir/$file") { next; }
Packit Service c5cf8c
	if ($file =~ /^\.$/ || $file =~ /^\.\.$/) { next; }
Packit Service c5cf8c
	if ($file =~ /$pattern/) {
Packit Service c5cf8c
	    $filesFound[$#filesFound+1] = $file;
Packit Service c5cf8c
	}
Packit Service c5cf8c
    }
Packit Service c5cf8c
    closedir DIR;
Packit Service c5cf8c
    return @filesFound;
Packit Service c5cf8c
}
Packit Service c5cf8c
# Return a hash of files and their comparison information
Packit Service c5cf8c
sub ReadCacheDirectory {
Packit Service c5cf8c
    my ($dir, $cachefile) = @_;
Packit Service c5cf8c
    my %fileInCache = ();
Packit Service c5cf8c
    my $found = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    if (! -f "$dir/$cachefile") { return %fileInCache; }
Packit Service c5cf8c
    open CFD, "<$dir/$cachefile" || return %fileInCache;
Packit Service c5cf8c
    # Look for directory
Packit Service c5cf8c
    while (<CFD>) {
Packit Service c5cf8c
	if (/<dir>/) { $found = 1; last; }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if ($found) {
Packit Service c5cf8c
	while (<CFD>) {
Packit Service c5cf8c
	    if (/<\/dir>/) { last; }
Packit Service c5cf8c
	    if (/<file\s+name=\"([^\"]+)\"\s+info=\"([^\"]+)\"\s*\/>/) {
Packit Service c5cf8c
		$fileInCache{$1} = $2;
Packit Service c5cf8c
		print "Found file $1 in cache\n" if $gDebug;
Packit Service c5cf8c
	    }
Packit Service c5cf8c
	}
Packit Service c5cf8c
    }
Packit Service c5cf8c
    close CFD;
Packit Service c5cf8c
Packit Service c5cf8c
    return %fileInCache;
Packit Service c5cf8c
}
Packit Service c5cf8c
# Return a hash of information from each, indexed by filename
Packit Service c5cf8c
sub ReadCacheContents {
Packit Service c5cf8c
    my ($dir, $cachefile) = @_;
Packit Service c5cf8c
    my %fileInfo = ();
Packit Service c5cf8c
    my $found = 0;
Packit Service c5cf8c
    
Packit Service c5cf8c
    if (! -f "$dir/$cachefile") { return %fileInfo; }
Packit Service c5cf8c
    open CFD, "<$dir/$cachefile" || return %fileInfo;
Packit Service c5cf8c
    # Look for data
Packit Service c5cf8c
    while (<CFD>) {
Packit Service c5cf8c
	if (/<data>/) { $found = 1; last; }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if ($found) {
Packit Service c5cf8c
	while (<CFD>) {
Packit Service c5cf8c
	    if (/<\/data>/) { last; }
Packit Service c5cf8c
	    if (/<fileinfo\s+name=\"([^\"]+)\">/) {
Packit Service c5cf8c
		my $filename = $1;
Packit Service c5cf8c
		my $info = "";
Packit Service c5cf8c
		while (<CFD>) {
Packit Service c5cf8c
		    if (/<\/fileinfo>/) { last; }
Packit Service c5cf8c
		    $info .= $_;
Packit Service c5cf8c
		}
Packit Service c5cf8c
		$fileInfo{$filename} = $info;
Packit Service c5cf8c
	    }
Packit Service c5cf8c
	}
Packit Service c5cf8c
    }
Packit Service c5cf8c
    close CFD;
Packit Service c5cf8c
Packit Service c5cf8c
    return %fileInfo;
Packit Service c5cf8c
}
Packit Service c5cf8c
# Print the cache.  Pass fileInfo by reference (\%fileInfo)
Packit Service c5cf8c
sub PrintCacheFile {
Packit Service c5cf8c
    my ($dir,$cachefile,$fileInfo) = @_;
Packit Service c5cf8c
Packit Service c5cf8c
    open CFD, ">$dir/$cachefile" || die "Could not open $dir/$cachefile\n";
Packit Service c5cf8c
Packit Service c5cf8c
    print CFD "<dir>\n";
Packit Service c5cf8c
    foreach my $file (keys(%$fileInfo)) {
Packit Service c5cf8c
	my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime) = 
Packit Service c5cf8c
	    stat "$dir/$file";
Packit Service c5cf8c
	print CFD "<file name=\"$file\" info=\"$mtime\"/>\n";
Packit Service c5cf8c
    }
Packit Service c5cf8c
    print CFD "</dir>\n";
Packit Service c5cf8c
    print CFD "<data>\n";
Packit Service c5cf8c
    foreach my $file (keys(%$fileInfo)) {
Packit Service c5cf8c
	print CFD "<fileinfo name=\"$file\">\n";
Packit Service c5cf8c
	print CFD $$fileInfo{$file};
Packit Service c5cf8c
	print CFD "</fileinfo>\n";
Packit Service c5cf8c
    }
Packit Service c5cf8c
    print CFD "</data>\n";
Packit Service c5cf8c
    close CFD;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
sub processFiles {
Packit Service c5cf8c
    my ($dir,$cachefile,$pattern) = @_;
Packit Service c5cf8c
Packit Service c5cf8c
    my @files = &GetFileNamesInDirectory( $dir, $pattern );
Packit Service c5cf8c
    my %filesInCache = &ReadCacheDirectory( $dir, $cachefile );
Packit Service c5cf8c
    
Packit Service c5cf8c
    my @filesToScan = ();
Packit Service c5cf8c
    my @filesDeleted = ();
Packit Service c5cf8c
    my @filesUnchanged = ();
Packit Service c5cf8c
    my %filesInDir = ();
Packit Service c5cf8c
Packit Service c5cf8c
    print "Number of files matching pattern in $dir is $#files\n" if $gDebug;
Packit Service c5cf8c
    for (my $i=0; $i <= $#files; $i++) {
Packit Service c5cf8c
	$filesInDir{$files[$i]} = 1;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    foreach my $file (keys(%filesInCache)) {
Packit Service c5cf8c
	# Get info on file
Packit Service c5cf8c
	if (-f "$dir/$file") {
Packit Service c5cf8c
	    print "Found $file\n" if $gDebug;
Packit Service c5cf8c
	    delete $filesInDir{$file};
Packit Service c5cf8c
	    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime) = 
Packit Service c5cf8c
		stat "$dir/$file";
Packit Service c5cf8c
	    if ($mtime > $filesInCache{$file} || $gUpdateAll) {
Packit Service c5cf8c
		# File has been changed since last update
Packit Service c5cf8c
		$filesToScan[$#filesToScan+1] = $file;
Packit Service c5cf8c
	    }
Packit Service c5cf8c
	    else {
Packit Service c5cf8c
		$filesUnchanged[$#filesUnchanged+1] = $file;
Packit Service c5cf8c
	    }
Packit Service c5cf8c
	}
Packit Service c5cf8c
	else {
Packit Service c5cf8c
	    # This file has been deleted
Packit Service c5cf8c
	    print "File $dir/$file has been deleted since the cache was created\n" if $gDebug;
Packit Service c5cf8c
	    $filesDeleted[$#filesDeleted+1] = $file;
Packit Service c5cf8c
	}
Packit Service c5cf8c
    }
Packit Service c5cf8c
    my @filesCreated = keys(%filesInDir);
Packit Service c5cf8c
    
Packit Service c5cf8c
    # Check for unchanged
Packit Service c5cf8c
    if ($#filesCreated == -1 &&
Packit Service c5cf8c
	$#filesDeleted == -1 &&
Packit Service c5cf8c
	$#filesToScan  == -1) {
Packit Service c5cf8c
	# Nothing to do, we can leave the cache file as is
Packit Service c5cf8c
	print "Cache in $dir unchanged\n" if $gDebug || $gVerbose > 1;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    else {
Packit Service c5cf8c
	if ($gDebug || $gVerbose > 0) {
Packit Service c5cf8c
	    # Give a detailed description
Packit Service c5cf8c
	    my $sep = "";
Packit Service c5cf8c
	    print "Changes in dir $dir: ";
Packit Service c5cf8c
	    if ($#fileCreated >= 0) {
Packit Service c5cf8c
		my $num = $#filesCreated + 1;
Packit Service c5cf8c
		print "created = $num";
Packit Service c5cf8c
		$sep = ", ";
Packit Service c5cf8c
		}
Packit Service c5cf8c
	    if ($#filesDeleted >= 0) {
Packit Service c5cf8c
		my $num = $#filesDeleted + 1;
Packit Service c5cf8c
		print "${sep}deleted = $num";
Packit Service c5cf8c
		$sep = ", ";
Packit Service c5cf8c
	    }
Packit Service c5cf8c
	    if ($#filesToScan >= 0) {
Packit Service c5cf8c
		my $num = $#filesToScan + 1;
Packit Service c5cf8c
		print "${sep}changed = $num";
Packit Service c5cf8c
	    }
Packit Service c5cf8c
	    print "\n";
Packit Service c5cf8c
	}
Packit Service c5cf8c
	# We need to scan some files, adding their info to fileInfo
Packit Service c5cf8c
	my %fileInfo = &ReadCacheContents( $dir, $cachefile );
Packit Service c5cf8c
	for (my $i=0; $i<=$#filesDeleted; $i++) {
Packit Service c5cf8c
	    delete $fileInfo{$filesDeleted[$i]};
Packit Service c5cf8c
	}
Packit Service c5cf8c
	foreach $file (@filesCreated,@filesToScan) {
Packit Service c5cf8c
	    print "Scanning file $dir/$file\n" if $gDebug;
Packit Service c5cf8c
	    $fileInfo{$file} = &$scanFile( "$dir/$file" );
Packit Service c5cf8c
	}
Packit Service c5cf8c
	&PrintCacheFile( $dir, $cachefile, \%fileInfo );
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
sub processDirs {
Packit Service c5cf8c
    my ($dir, $cachefile, $pattern) = @_;
Packit Service c5cf8c
Packit Service c5cf8c
    print "Processing $dir...\n" if $gDebug;
Packit Service c5cf8c
    my @dirs = ();
Packit Service c5cf8c
    # Find the directories
Packit Service c5cf8c
    opendir DIR, "$dir" || die "Cannot open $dir\n";
Packit Service c5cf8c
    for my $file (sort readdir DIR) {
Packit Service c5cf8c
	if (! -d "$dir/$file") { next; }
Packit Service c5cf8c
	if ($file =~ /^\./) { next; }
Packit Service c5cf8c
	if ($file =~ /^.svn/) { next; }
Packit Service c5cf8c
	if ($file =~ /autom4te.cache/) { next; }
Packit Service c5cf8c
	$dirs[$#dirs+1] = "$file";
Packit Service c5cf8c
    }
Packit Service c5cf8c
    closedir DIR;
Packit Service c5cf8c
    
Packit Service c5cf8c
    # For each of these, process it
Packit Service c5cf8c
    for (my $i=0; $i<=$#dirs; $i++) {
Packit Service c5cf8c
	my $ndir = "$dir/$dirs[$i]";
Packit Service c5cf8c
	&processDirs( $ndir, $cachefile, $pattern );
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    # process the files in this directory
Packit Service c5cf8c
    &processFiles( $dir, $cachefile, $pattern );
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# This is a general routine to process directories
Packit Service c5cf8c
sub processDirsAndAction {
Packit Service c5cf8c
    my ($dir, $action, $actionData) = @_;
Packit Service c5cf8c
Packit Service c5cf8c
    print "Processing $dir...\n" if $gDebug;
Packit Service c5cf8c
    my @dirs = ();
Packit Service c5cf8c
    # Find the directories
Packit Service c5cf8c
    opendir DIR, "$dir" || die "Cannot open $dir\n";
Packit Service c5cf8c
    for my $file (sort readdir DIR) {
Packit Service c5cf8c
	if (! -d "$dir/$file") { next; }
Packit Service c5cf8c
	if ($file =~ /^\./) { next; }
Packit Service c5cf8c
	if ($file =~ /^.svn/) { next; }
Packit Service c5cf8c
	if ($file =~ /autom4te.cache/) { next; }
Packit Service c5cf8c
	$dirs[$#dirs+1] = "$file";
Packit Service c5cf8c
    }
Packit Service c5cf8c
    closedir DIR;
Packit Service c5cf8c
    
Packit Service c5cf8c
    # For each of these, process it
Packit Service c5cf8c
    for (my $i=0; $i<=$#dirs; $i++) {
Packit Service c5cf8c
	my $ndir = "$dir/$dirs[$i]";
Packit Service c5cf8c
	&processDirsAndAction( $ndir, $action, $actionData );
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    # process the files in this directory
Packit Service c5cf8c
    &$action( $dir, $actionData );
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
1;