The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/local/bin/perl
# browse - Pogo database browser
# 1999 Sey Nakajima <sey@jkc.co.jp>
use Pogo;
use strict;

$| = 1;
my $Cfgfile = shift || usage();
my(%Data, %Parent);
main($Cfgfile);

sub usage {
	print "usage: $0 cfgfilename\n";
	exit(1);
}

sub main {
	my($cfgfile) = @_;
	
	$cfgfile = "$cfgfile.cfg" if !-f $cfgfile && -f "$cfgfile.cfg";
	die "not exist $cfgfile\n" unless -f $cfgfile;
	die "cfgfilename must have a '.cfg' extension\n" unless $cfgfile =~ /\.cfg$/;
	
	my $pogo = new Pogo $cfgfile;
	print "$cfgfile opened\n";
	
	my $root = $pogo->root_tie;
	my $location = 'root';
	my $data = $root;
	while(1) {
		($location, $data) = browse($location, $data);
		last if $location eq 'exit';
		($location, $data) = ('root', $root) if $location eq 'root';
	}
}

sub type {
	my($data) = @_;
	my($type, $class, $tiedclass) = Pogo::type_of($data);
	my $oid = sprintf("%x", Pogo::object_id($data));
	my $hashtype = 
		$tiedclass eq 'Pogo::Hash' ? '(Hash)' :
		$tiedclass eq 'Pogo::Htree' ? '(Htree)' :
		$tiedclass eq 'Pogo::Btree' ? '(Btree)' :
		$tiedclass eq 'Pogo::Ntree' ? '(Ntree)' : '';
	($type, $class, $hashtype, $oid);
}

sub browse {
	my($location, $data) = @_;
	$Data{$location} = $data;
	my($type, $class, $hashtype, $oid) = type($data);
	my $prompt = "$location=$class($type$hashtype($oid))>";
	while(1) {
		print $prompt;
		my $input = <STDIN>;
		my($cmd, $arg) = $input =~ /(\w+)\s*([\w\.]*)/;
		if( $cmd eq '' ) {
			next;
		} elsif( $cmd eq 'exit' ) {
			return ('exit');
		} elsif( $cmd eq 'ls' ) {
			ls($data, $type, $arg);
		} elsif( $cmd eq 'cd' ) {
			my($loc, $dt) = cd($location, $data, $type, $arg);
			return ($loc, $dt) if $loc || $dt;
		} else {
			help();
		}
	}
}

sub ls {
	my($data, $type, $arg) = @_;
	$arg ||= '.';
	if( $type eq 'SCALAR' ) {
		my $dt = $$data;
		my($ref, $class, $hashtype, $oid) = type($dt);
		if( !defined $dt ) { print ". = undef\n"; }
		elsif( $ref ) { print ". = $class($ref$hashtype($oid))\n"; } 
		else { print ". = \"$dt\"\n"; }
	} elsif( $type eq 'ARRAY' ) {
		for(my $j = 0; $j < @$data; $j++ ) {
			if( $j =~ /$arg/ ) {
				my $dt = $data->[$j];
				my($ref, $class, $hashtype, $oid) = type($dt);
				if( !defined $dt ) { print "[$j] = undef\n"; }
				elsif( $ref ) { print "[$j] = $class($ref$hashtype($oid))\n"; } 
				else { print "[$j] = \"$dt\"\n"; }
			}
		}
	} elsif( $type eq 'HASH' ) {
		while( my($k, $v) = each %$data ) {
			if( $k =~ /$arg/ ) {
				my($ref, $class, $hashtype, $oid) = type($v);
				if( !defined $v ) { print "{$k} = undef\n"; }
				elsif( $ref ) { print "{$k} = $class($ref$hashtype($oid))\n"; } 
				else { print "{$k} = \"$v\"\n"; }
			}
		}
	}
}

sub cd {
	my($location, $data, $type, $arg) = @_;
	my($loc, $dt) = ();
	if( $arg eq '' ) {
		$loc = 'root';
	} elsif( $arg eq '..' ) {
		$loc = $Parent{$location};
		$dt = $Data{$loc};
	} elsif( $type eq 'SCALAR' && $arg eq '.' ) {
		if( ref($$data) ) {
			$loc = "$location.";
			$Parent{$loc} = $location;
			$dt = $$data;
		}
	} elsif( $type eq 'ARRAY' && $arg >= 0 && $arg < @$data ) {
		if( ref($data->[$arg]) ) {
			$loc = "$location\[$arg\]";
			$Parent{$loc} = $location;
			$dt = $data->[$arg];
		}
	} elsif( $type eq 'HASH' && exists $data->{$arg} ) {
		if( ref($data->{$arg}) ) {
			$loc = "$location\{$arg\}";
			$Parent{$loc} = $location;
			$dt = $data->{$arg};
		}
	}
	($loc, $dt);
}

sub help {
	print <<END;
  ls [pattern]
       print key value pairs that key matches the pattern
         a string value   : key = "value"
         a reference value: key ->CLASS(TYPE)
       key is index number(for array) or key string(for hash)
       pattern is a regular expression
       no pattern means all
  cd [key]
       change current data to a reference which is specified by the key
       cannot change to a string value
       key is . or .. or index number(for array) or key string(for hash)
       no key means root
  exit
END
}