#!/usr/bin/perl -w
#-
# Copyright (c) 2001-2008 Dag-Erling Coïdan Smørgrav
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer
#    in this position and unchanged.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#

use strict;
use Data::Dumper;
use Fcntl;
use Getopt::Std;
use vars qw(@exclude @include $verbose);

@exclude = ();			# Tags to exclude
@include = ();			# Tags to include
$verbose = 0;			# Verbose mode

sub fixtags($$) {
    my $ifn = shift;		# File name
    my $ofn = shift;		# Output file

    my $tmpfn;			# Temp file name
    local *IFILE;		# Input file
    local *OFILE;		# Output file
    my $phase = 1;		# Phase of operation
    my $tag;			# Symbolic tag
    my @sb;			# File status

    $tmpfn = $ofn;
    $tmpfn =~ s|([^/]*)$|,$$,$1|;
    
    sysopen(IFILE, $ifn, O_RDONLY)
	or die("$ifn: open(): $!\n");
    sysopen(OFILE, $tmpfn, O_RDWR|O_CREAT|O_TRUNC, 0600)
	or die("$tmpfn: open(): $!\n");
    while (<IFILE>) {
	if ($phase == 1) {
	    if (m/^symbols/) {
		++$phase;
	    }
	} elsif ($phase == 2) {
	    if (m/^\t([^:]+):([0-9.]+);?\s*$/) {
		$tag = $1;
		if ($tag !~ m/\./ && # skip vendor tags
		    (!@exclude || !grep({ $_ eq $tag } @exclude)) &&
		    (!@include || grep({ $_ eq $tag } @include))) {
		    print("    $tag -> old_$tag\n")
			if $verbose;
		    s/(\S)/old_$1/;
		}
	    } else {
		++$phase;
	    }
	}
	print(OFILE $_);
    }
    close(OFILE)
	or die("$ifn: close(): $!\n");
    close(IFILE)
	or die("$tmpfn: close(): $!\n");

    if (@sb = stat($ifn)) {
	chown($sb[4], $sb[5], $tmpfn);
	chmod($sb[2], $tmpfn);
    }
    
    rename($tmpfn, $ofn)
	or die("$ofn: rename(): $!\n");
}

sub readlist($) {
    my $fn = shift;		# File name

    local *FILE;		# File handle
    my @items;			# List items

    return () unless defined($fn);
    sysopen(FILE, $fn, O_RDONLY)
	or die("$fn: open(): $!\n");
    @items = <FILE>;
    close(FILE);
    map({ chomp(); s/^\s*(.*?)\s*$/$1/; $_; } @items);
}

sub usage() {
    
    print(STDERR
	  "Usage: fixtags [-v] [-e excludefrom] ",
	  "[-i includefrom] [-o output] file ...\n");
    exit(1);
}

MAIN:{
    my %opts;			# Options
    my $file;			# File name
    my $dst;			# Destination

    if (!getopts("e:i:o:v", \%opts) || !@ARGV) {
	usage();
    }

    @exclude = readlist($opts{'e'});
    @include = readlist($opts{'i'});
    $verbose = defined($opts{'v'});

    foreach $file (@ARGV) {
	print("$file\n");
	eval {
	    $dst = $opts{'o'} || $file;
	    if (-d $dst) {
		@_ = split('/', $file);
		$dst .= "/$_[-1]";
	    }
	    fixtags($file, $dst);
	};
	if ($@) {
	    warn("$file failed: $@\n");
	}
    }
}
