#!/usr/bin/perl package INF; use strict; use vars qw($VERSION @ISA @EXPORT_OK); use Carp qw(carp); require Exporter; $VERSION = "0.01"; @ISA = qw(Exporter); @EXPORT_OK = qw(read_inf inf_has_key inf_get_key inf_get_keys); # Return true if the hash has the named key. sub inf_has_key { croak("inf_has_key(HASH_REF, KEY)") if @_ != 2; my($hash_ref, $the_key) = @_; $the_key =~ tr/a-z/A-Z/; foreach my $key (keys %{$hash_ref}) { my $key1 = $key; $key1 =~ tr/a-z/A-Z/; return 1 if $key1 eq $the_key; } return 0; } # Return the value associated with the named key. sub inf_get_key { croak("inf_get_key(HASH_REF, KEY)") if @_ != 2; my($hash_ref, $the_key) = @_; $the_key =~ tr/a-z/A-Z/; foreach my $key (keys %{$hash_ref}) { my $key1 = $key; $key1 =~ tr/a-z/A-Z/; return $hash_ref->{$key} if $key1 eq $the_key; } return undef; } # Apply inf_get_key multiple times. sub inf_get_keys { croak("inf_get_keys(HASH_REF, KEY1, [KEY2], ...)") if @_ < 2; my($hash_ref, $first_key, @keys) = @_; my $result = inf_get_key($hash_ref, $first_key); foreach my $key (@keys) { $result = inf_get_key($result, $key); } return $result; } sub store_pair { my($hash, $section, $key, $value) = @_; # Strip leading whitespace from key and value. $key =~ s/^\s+//; $value =~ s/^\s+//; # Handle quotes in the key. if (substr($key, 0, 1) eq '"') { $key =~ s/^"(.*?)"\s*$/$1/; } else { $key =~ s/\s+$//; } # Handle quotes in the value. if (substr($value, 0, 1) eq '"') { $value =~ s/^"(.*?)"\s*$/$1/; } else { $value =~ s/\s+$//; } # Store the key,value pair. $hash->{$section}{$key} = $value; } sub subst_string { my($strings, $str) = @_; my $pos = 0; while ($pos < length($str)) { # Find the next location of a % character. my $percent_pos_1 = index($str, '%', $pos); if ($percent_pos_1 != -1) { my $percent_pos_2 = index($str, '%', $percent_pos_1 + 1); if ($percent_pos_2 != -1) { my $replacement; # Determine what replacement to use. if ($percent_pos_2 - $percent_pos_1 > 0) { my $key = substr($str, $percent_pos_1 + 1, $percent_pos_2 - ($percent_pos_1 + 1)); $replacement = $strings->{$key}; } else { $replacement = "%"; } # Replace the %...% markers with the replacement. substr($str, $percent_pos_1, $percent_pos_2 - $percent_pos_1 + 1) = $replacement; $pos += length($replacement); } else { $pos = length($str); } } else { $pos = length($str); } } return $str; } sub subst_inf { my($inf) = @_; # Retrieve the [Strings] section if it exists. return if not inf_has_key($inf, "Strings"); my $strings = inf_get_key($inf, "Strings"); foreach my $section (keys %{$inf}) { next if $section =~ /^Strings$/i; foreach my $key (keys %{$inf->{$section}}) { my $value = subst_string($strings, $inf->{$section}{$key}); if ($value ne $inf->{$section}{$key}) { $inf->{$section}{$key} = $value; } $value = subst_string($strings, $key); if ($value ne $key) { my $tmp = $inf->{$section}{$key}; delete $inf->{$section}{$key}; $inf->{$section}{$value} = $tmp; } } } } sub read_inf { my($fname) = @_; local(*INF); my $hash = {}; my($line, $linenum, $section); if (! open(INF, "<$fname")) { carp "open: $!\n"; return undef; } $linenum = 0; while (defined($line = )) { # Advance the line number. $linenum++; # Remove trailing newline and leading whitespace. chomp $line; $line =~ s/^\s+//; # Skip over blank lines and comments. next if $line eq ''; next if substr($line, 0, 1) eq ';'; if ($line =~ /^\[(.*)\]\s*$/) { # Handle section markers. Just update the "current" section. $section = $1; $hash->{$section} = {} if not exists $hash->{$section}; } elsif ($line =~ /^(.*?)=(.*)$/) { store_pair($hash, $section, $1, $2); } elsif ($line =~ /^(.+)$/) { store_pair($hash, $section, $1, ""); } else { carp("parse error at $fname:$linenum\n"); return undef; } } close(INF); # Replace any %...% strings in the parsed file. subst_inf($hash); return $hash; } 1;