package RISCOS::Clone;


require Exporter;
use strict;
use vars qw (@ISA @EXPORT_OK $VERSION);

@ISA = qw(Exporter);
@EXPORT_OK = qw(Clone clone);
$VERSION = 0.01;

sub Clone {	# aka clone-hash
    my ($new, $old) = ({}, $_[0]);
    # This is where we break if someone makes a class which doesn't
    # store stuff in a hash
    while (my ($key, $value) = each %$old) {
	# This is where we break if key is supposed to be
	# stringifed version of value (where value is a hash)
	$$new{$key} = clone ($value);
    }
    ref ($old) eq 'HASH' ? $new : bless ($new, ref $old)
}
sub clone {
    # Beware:
    # 0	Will loop on structures that refer to themselves
    # 1	Will copy things that may not want duplication (eg RISCOS::Font objects
    #	have a dummy clone method to stop this)
    # 2	Will screw up if hashes are supposed to be keyed with a stringified
    #	reference.
    # 3	Will screw up if blessed references are not hash references.
    #
    # For all of the above define a more clever cloner.

    my @result = @_;	# Copy it so as not to scribble all over it
    foreach my $thing (@result) {
	if ((not ref $thing) or ref ($thing) eq 'CODE'
		  or ref ($thing) eq 'GLOB')
	{
	    # undef, scalars, code refs and globs are unchanged
	    # hum. globs.
	} elsif (ref ($thing) eq 'SCALAR' or ref ($thing) eq 'LVALUE') {
	    $thing = $$thing;
	    $thing = \$thing;
	} elsif (ref ($thing) eq 'ARRAY') {
	    $thing = [clone (@$thing)];
	} else {
	    # Assume its a hash
	    if (ref ($thing) ne 'HASH' and $thing->can('Clone')) {
		$thing = $thing->Clone();
	    } else {
		$thing = Clone ($thing);
	    }
	}
    }
    wantarray ? @result : $result[0];
}
__END__

=head1 NAME

RISCOS::Clone -- copy nested structures.

=head1 SYNOPSIS

    use RISCOS::Clone qw(clone);
    @copy = clone (@original);

    $copy = $original->Clone();

=head1 DESCRIPTION

This module provides functions to copy structures.

=over 4

=item Clone <hash_ref>

copies a hash reference, C<bless>ing the returned hash with the class (if any)
of the original. C<Clone> uses <clone> to copy each hash value.

=item clone <object> ...

recursively copies the objects passed in. In list contest returns the copied
objects, in scalar context returns the first object. C<clone> copies C<undef>,
scalars, code referencess and globs unchanged, scalar references are copied as
a reference to scalar containing the identical value. Array references are
passed recursively to C<clone>, hash references to C<Clone>. Blessed references
that posses a C<Clone> method have this method called, else C<Clone> is called
to make a copy.

C<clone> is simpleminded and will go wrong as follows.

	clone will loop on structures that refer to themselves
	clone will copy things that may not want duplication
	  (eg RISCOS::Font objects have a dummy Clone method to stop this)
	clone will not work correctly if hashes are supposed to be keyed with a
	  stringified reference.
	Clone will C<die> if blessed references are not hash references.

For objects these problems can be overcome by writing a custom C<Clone> method.

=back

=head1 BUGS

Caveats as noted above. Not tested enough yet.

=head1 AUTHOR

Nicholas Clark <F<nick@unfortu.net>>

=cut
