04eb1ec210
2008/03/28 15:55:33 rt 1.4.1038.1: #i87441# Change license header to LPGL v3.
300 lines
7.8 KiB
Perl
300 lines
7.8 KiB
Perl
#*************************************************************************
|
|
#
|
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
#
|
|
# Copyright 2008 by Sun Microsystems, Inc.
|
|
#
|
|
# OpenOffice.org - a multi-platform office productivity suite
|
|
#
|
|
# $RCSfile: GenInfoParser.pm,v $
|
|
#
|
|
# $Revision: 1.5 $
|
|
#
|
|
# This file is part of OpenOffice.org.
|
|
#
|
|
# OpenOffice.org is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Lesser General Public License version 3
|
|
# only, as published by the Free Software Foundation.
|
|
#
|
|
# OpenOffice.org is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Lesser General Public License version 3 for more details
|
|
# (a copy is included in the LICENSE file that accompanied this code).
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
# version 3 along with OpenOffice.org. If not, see
|
|
# <http://www.openoffice.org/license.html>
|
|
# for a copy of the LGPLv3 License.
|
|
#
|
|
#*************************************************************************
|
|
|
|
#*************************************************************************
|
|
#
|
|
# GenInfoParser - Perl extension for parsing general info databases
|
|
#
|
|
# usage: see below
|
|
#
|
|
#*************************************************************************
|
|
|
|
package GenInfoParser;
|
|
|
|
use strict;
|
|
|
|
use Carp;
|
|
|
|
##### profiling #####
|
|
# use Benchmark;
|
|
|
|
##### ctor #####
|
|
|
|
sub new {
|
|
my $proto = shift;
|
|
my $class = ref($proto) || $proto;
|
|
my $self = {};
|
|
$self->{'LIST'} = undef;
|
|
$self->{'DATA'} = {};
|
|
bless ($self, $class);
|
|
return $self;
|
|
}
|
|
|
|
##### methods #####
|
|
|
|
sub load_list
|
|
{
|
|
# load list into memory
|
|
my $self = shift;
|
|
my $list_file = shift;
|
|
|
|
if ( $self->parse_list($list_file) ) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
sub get_keys
|
|
{
|
|
# return a sorted list of keys, the sorting is case insensitive
|
|
my $self = shift;
|
|
my $access_path = shift;
|
|
|
|
my ($key, $value, $sub_data_ref) = $self->walk_accesspath($access_path);
|
|
|
|
my @keys = ();
|
|
if ( $sub_data_ref ) {
|
|
my @normalized_keys = keys %$sub_data_ref;
|
|
foreach my $normalized_key (sort keys %$sub_data_ref) {
|
|
push(@keys, $$sub_data_ref{$normalized_key}[0]);
|
|
}
|
|
} elsif ( $value ) {
|
|
chomp $value;
|
|
push @keys, ($value);
|
|
}
|
|
return @keys;
|
|
}
|
|
|
|
sub get_key
|
|
{
|
|
# returns the key corresponding to the access_path
|
|
my $self = shift;
|
|
my $access_path = shift;
|
|
|
|
my ($key, $value, $sub_data_ref) = $self->walk_accesspath($access_path);
|
|
return undef if !$key;
|
|
return $key;
|
|
}
|
|
|
|
sub get_value
|
|
{
|
|
# returns the value corresponding to the access_path
|
|
my $self = shift;
|
|
my $access_path = shift;
|
|
|
|
my ($key, $value, $sub_data_ref) = $self->walk_accesspath($access_path);
|
|
return undef if !$key;
|
|
$value = "" if !defined($value);
|
|
# trim line ends
|
|
$value =~ tr/\r\n//d;
|
|
# trim trailing whitespace
|
|
$value =~ s/\s+$//;
|
|
return $value;
|
|
}
|
|
|
|
##### private methods #####
|
|
|
|
sub parse_list
|
|
{
|
|
# parse complete list
|
|
my $self = shift;
|
|
my $list_file = shift;
|
|
my @list_data;
|
|
|
|
return 0 if ! -r $list_file;
|
|
|
|
open(FILE, "<$list_file") or croak("can't open $list_file: $!");
|
|
# my $t0 = new Benchmark;
|
|
$self->parse_block(\*FILE, $self->{'DATA'});
|
|
# my $t1 = new Benchmark;
|
|
# print STDERR "parsing $list_file took: ", timestr(timediff($t1, $t0)), "\n";
|
|
close(FILE);
|
|
}
|
|
|
|
sub parse_block
|
|
{
|
|
# parse each sub block and place it in a hash
|
|
# used data structure:
|
|
# $hash{$normalized_key} = [ $key, $value, 0 | $sub_hash_ref ]
|
|
my $self = shift;
|
|
my $glob_ref = shift;
|
|
my $data_ref = shift;
|
|
|
|
my $current_key = 0;
|
|
my $line;
|
|
while( $line = <$glob_ref> ) {
|
|
# this is the inner loop, any additional pattern matching will
|
|
# have a notable affect on runtime behavior
|
|
# clean up of $value is done in get_value()
|
|
my ($key, $value) = split(' ', $line, 2);
|
|
next if !$key; # skip empty lines
|
|
my $chr = substr($key, 0, 1);
|
|
next if $chr eq '#'; # skip comment lines
|
|
last if $chr eq '}'; # return from block;
|
|
if ( $chr eq '{' ) {
|
|
if ( !$current_key ) {
|
|
croak("unexpected block start");
|
|
}
|
|
else {
|
|
# create empty hash and start sub block parse
|
|
$$data_ref{$current_key}[2] = {};
|
|
$self->parse_block($glob_ref, $$data_ref{$current_key}[2]);
|
|
next;
|
|
}
|
|
}
|
|
# sanity check
|
|
croak("key $key is not well formed") if $key =~ /\//;
|
|
# normalize key for hash lookup
|
|
$current_key = lc($key);
|
|
# but we have to keep the original - not normalized - key, too
|
|
$$data_ref{($current_key)} = [$key, $value, 0];
|
|
}
|
|
}
|
|
|
|
sub walk_accesspath
|
|
{
|
|
# returns the key, value and sub_data_ref which
|
|
# corresponds to the access_path
|
|
|
|
my $self = shift;
|
|
my $access_path = shift;
|
|
|
|
my $sub_data_ref = $self->{'DATA'};
|
|
|
|
if ( $access_path ) {
|
|
my $lookup_ref = 0;
|
|
# normalize key
|
|
$access_path = lc($access_path);
|
|
my @key_sequence = split(/\//, $access_path);
|
|
foreach my $key_element (@key_sequence) {
|
|
# at least one more key element, but no sub_hash, accesspath invalid
|
|
return () if !$sub_data_ref;
|
|
$lookup_ref = $$sub_data_ref{$key_element};
|
|
# lookup failed, accesspath invalid
|
|
return () if !defined($lookup_ref);
|
|
# we've got a valid key
|
|
$sub_data_ref = $$lookup_ref[2];
|
|
}
|
|
return ($$lookup_ref[0], $$lookup_ref[1], $sub_data_ref);
|
|
}
|
|
else {
|
|
# empty access path is only vlaid for getting top level key list
|
|
return ( undef, undef, $sub_data_ref );
|
|
}
|
|
}
|
|
|
|
##### finish #####
|
|
|
|
1; # needed by use or require
|
|
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
GenInfoParser - Perl extension for parsing general info databases
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
# example that will load a general info database called 'stand.lst'
|
|
|
|
use GenInfoParser;
|
|
|
|
# Create a new instance of the parser:
|
|
$a = GenInfoParser->new();
|
|
|
|
# Load the database into the parser:
|
|
$a->load_list('ssrc633.ini');
|
|
|
|
# get top level keys from database
|
|
@top_level_keys = $a->get_keys();
|
|
|
|
# get sub list keys
|
|
@sub_list_keys = $a->get_keys('src633/Drives/o:/Projects');
|
|
|
|
# get key/value pair
|
|
$key = $a->get_key('src633/Comment/build');
|
|
$value = $a->get_value('src633/Comment/build');
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
GenInfoParser is a perl extension to load and parse General Info Databses.
|
|
It uses a simple object oriented interface to retrieve the information stored
|
|
in the database.
|
|
|
|
Methods:
|
|
|
|
GenInfoParser::new()
|
|
|
|
Creates a new instance of the parser. Can't fail.
|
|
|
|
|
|
GenInfoParser::load_list($database)
|
|
|
|
Loads and parses $database. Returns 1 on success and 0 on failure
|
|
|
|
|
|
GenInfoParser::get_keys($path)
|
|
|
|
Returns a sorted list of keys from the path $path. Returns an emtpy list if $path
|
|
has no sublist. If there is no $path spcified, the method will return the
|
|
primary key list. $path can be specified case insensitive. Sorting is done case
|
|
insensitive.
|
|
|
|
GenInfoParser::get_key($path)
|
|
|
|
Returns the key to $path or 'undef' if an invalid path is given.
|
|
Example: $path = 'src633/comment/build' will return 'Build' as key.
|
|
Note: $path can be specified case insensitive, but the returned key will
|
|
have the exact case as in the database.
|
|
|
|
GenInfoParser::get_value($path)
|
|
|
|
Returns the value to $path or 'undef' is invalid path is given.
|
|
|
|
|
|
=head2 EXPORT
|
|
|
|
GenInfoParser::new()
|
|
GenInfoParser::load_list($database)
|
|
GenInfoParser::get_keys($path)
|
|
GenInfoParser::get_key($path)
|
|
GenInfoParser::get_value($path)
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
Jens-Heiner Rechtien, rechtien@sun.com
|
|
|
|
=head1 SEE ALSO
|
|
|
|
perl(1).
|
|
|
|
=cut
|