Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Confused: Hashrefs in TieRegistry

by Maze (Sexton)
on Aug 15, 2006 at 20:40 UTC ( [id://567551]=perlquestion: print w/replies, xml ) Need Help??

Maze has asked for the wisdom of the Perl Monks concerning the following question:

Simply put can anyone tell me why this:
#!/usr/bin/perl use warnings; use strict; use Win32::TieRegistry (Delimiter => "/"); use Data::Dumper; my $val; my $val2; my @set = (1,2); my $watchcode = 0; my $error; unless (defined($ARGV[0])){ foreach $val (keys %{ $Registry->{"Classes/"} }){ if ($val =~ /^[.]/) { my %RegHash = %{ $Registry->{"Classes/$val"} }; Dumper %RegHash = $error; while (@set = 2){ @set = each %RegHash or die "failure to read registry +: $! \nlast contents of Registry Hash = $error \n"; if ($set[1] eq "/"){ print "$val = $set[0]\n"; $watchcode = 1; } } if ($watchcode == 0){ die "failure to recognise association list: $!"; } } } };

doesn't work...

it's supposed to be part of a direct lookalike of the plain 'assoc' utility in Windows 2000/XP which, when invoked on it's own, lists the extensions and the associated filetypes on the system.

what actually happens when I exectute is this:

Odd number of elements in hash assignment at E:\workspaces\perl\asoc.p +l line 17. Use of uninitialized value in list assignment at E:\workspaces\perl\as +oc.pl line 17. Use of uninitialized value in string eq at E:\workspaces\perl\asoc.pl +line 20. Use of uninitialized value in concatenation (.) or string at E:\worksp +aces\perl\ asoc.pl line 19. failure to read registry: last contents of Registry Hash =
which suggests that the $registry reference isn't behaving as I expect it too when it's fed to the 'each' function, however this is strange, because it works fine with 'keys' and 'values'... except when i try to get it too read the default value under the key "/".

*sigh* i'm beginning to understand where perl gets it's name from, I must seriously be missing something about references or objects or TiedHashes excetera

I also think i might be missing something about how the TieRegistry module does work (or doesn't as the case may be)

Replies are listed 'Best First'.
Re: Confused: Hashrefs in TieRegistry
by GrandFather (Saint) on Aug 15, 2006 at 21:08 UTC

    What are you trying to do with:

    Dumper %RegHash = $error;

    It looks like you are assigning a scalar to a hash to me and that is not going to work.

    If I edit your while loop and environs a little to give:

    # Dumper %RegHash = $error; # while (@set = 2) { @set = each %RegHash or die "failure to read registry: + $! \nlast contents of Registry Hash = $error \n"; last if @set != 2; if ($set[0] eq "/"){ print "$val = $set[0]\n"; $watchcode = 1; } next; # added }

    then I get output tht looks like:

    .3/ = / .386/ = / .A51/ = / .ac3/ = / .aca/ = / .ace/ = / .acf/ = / ...

    Update: The following is probably closer to what you actually want:

    #!/usr/bin/perl use warnings; use strict; use Win32::TieRegistry (Delimiter => "/"); exit if defined($ARGV[0]); # Why btw? foreach my $class (sort keys %{ $Registry->{"Classes/"} }){ next unless $class =~ /^[.]/; my %RegHash = %{ $Registry->{"Classes/$class"} }; print "$class = $RegHash{'/'}\n" if exists $RegHash{'/'}; }

    Prints:

    .3/ = 3_auto_file .323/ = h323file .386/ = vxdfile .3g2/ = QuickTime.3g2 .3gp/ = QuickTime.3gp .3gp2/ = QuickTime.3gp2 ...

    Update: Doh! replaced inner loop per ikegami

    Note that missing associations is not an error so no warning or dies. The if exists modifier could be changed to a full blown if and note the missing association in the else part.


    DWIM is Perl's answer to Gödel
Re: Confused: Hashrefs in TieRegistry
by runrig (Abbot) on Aug 15, 2006 at 20:56 UTC
    What are you expecting "Dumper %RegHash = $error;" to do? You seem to be overwriting %RegHash that was assigned to earlier.

    And the "usual" way to use each is:

    while (my ($key, $value) = each %hash) { #...process $key, $value... }
    The way you are using each, you will always hit the die when you run out of keys and values. If you want to make sure you have some keys and values, put a counter in the loop, and check the count after the loop.
Re: Confused: Hashrefs in TieRegistry
by ikegami (Patriarch) on Aug 15, 2006 at 21:14 UTC
    I must seriously be missing something about references or objects or TiedHashes excetera

    No, that part was fine. There are plenty of problems, however.

    • I have no idea what = $error is doing in
      Dumper %RegHash = $error;
      and you discard Dumper's output. Did you mean
      print(Dumper(%RegHash));

    • @set = 2
      should be
      @set == 2

    • $error is printed, but nothing is ever assigned to it.

    • each returns false when there is no more data (which is not an error), so
      each %RegHash or die
      can't be right. Anyway, it's easier to work with foreach keys than while each because since can only use last safely with the former.

    • Why do you store a key in a variable called $val? $key would be better. $class would be ideal.

    • $watchcode isn't reset for each class, but it should be.

    • You print $! when it doesn't contain anything meaningful.

    • To use die when you can't find an association is quite brutal. warn (and maybe nothing at all) would be more appropriate.

    Fix:

    #!/usr/bin/perl use warnings; use strict; use Win32::TieRegistry (Delimiter => "/"); use Data::Dumper; foreach my $class (keys %{ $Registry->{"Classes/"} }) { next unless substr($class, 0, 1) eq '.'; my $watchcode; my $RegHash = $Registry->{"Classes/$class"}; foreach my $key (keys %$RegHash) { next if $key ne "/"; my $val = $RegHash->{$key}; print "$class = $val\n"; $watchcode = 1; last; } warn "failure to recognise association list\n" unless $watchcode; }

    Notes:

    • I used next (twice) to avoid excessive nesting/indenting.

    • I added last in the inner loop. It's no use searching for a second key called /.

    • I made $RegHash a reference instead of an actual hash (%RegHash). It's much more efficient to refer to something than to make a copy of it.

    Update: Fixed reference to $key that wasn't changed to $class (my mistake). $key swapped with $val (OP's mistake).

    Update: The inner loop can be replaced with ifexists.

    foreach my $ext (keys %{ $Registry->{"Classes/"} }) { next unless substr($ext, 0, 1) eq '.'; my $RegHash = $Registry->{"Classes/$ext"}; if (not exists $RegHash->{'/'}) { warn "Unable to recognise association list for $ext\n"; next; } my $class = $RegHash->{'/'}; print "$ext is a $class\n"; }

    Tested.

      whahey - the code works, a big list of associations and extenstions scrolls by, albiet puntuated with complaints about being unable to recognise association list and use of unitialised values or string in concatenation...

      but yeah, the job that ikegami did was great - I need to go and look up the next and substr and then I can use this as a lesson for further mongering.

      out of curiosity my own tangled efforts had reached here:

      my $class; my $val; my $key; my $watchnum = 0; my $error; unless (defined($ARGV[0])){ foreach $class (keys %{ $Registry->{"Classes:"} }){ if ($class =~ /^[.]/) { my %RegHash = %{ $Registry->{"Classes:$class"} }; $error = Dumper %RegHash; while (my ($key, $val) = each(%RegHash)){#or die "failure +to read registry: $! \nlast contents of Registry Hash = $error \n"; if ($val eq ":"){ print "$class = $key\n"; $watchnum = 1; } } if ($watchnum == 0){ die "failure to recognise association list: $!"; } } } }

      which just outputs: failure to recognise association list
      any clues as to why that is... maybe because I invoked die... perhaps I should use warn instead... hmmm *goes and sees if that's the problem*

      on another note I now just need to mod this so that it can accept some arguments and ergo change associations - I'm trying to make a setup that will automatically change the default browser on an ME system, I thought a cool way to do that would be to re-write the Windows 2000+ ftypeand assoc in perl (it's mainly just the ftype association that dictates main browser) So some additional args and repeat the trick for ftype. It has also occured to me too check whether there's a CPAN module for associations...
      update:I managed to get this to work without squaking:

      #!/usr/bin/perl use warnings; use strict; use Win32::TieRegistry (Delimiter => ":"); use Data::Dumper; my $class; my $val; my $key; my $error; unless (defined($ARGV[0])){ foreach $class (keys %{ $Registry->{"Classes:"} }){ if ($class =~ /^[.]/) { my $RegHash = $Registry->{"Classes:$class"}; #$error = Dumper %RegHash; while (my ($key, $val) = each(%$RegHash)){#or die "failure + to read registry: $! \nlast contents of Registry Hash = $error \n"; if ($key eq ":"){ print "$class = $val\n"; } #else{ # warn "unable to recognise association for $class" #} } } } }
      It's ugly and I don't know if it's complete, will have to analyse further - if i din't comment out the warns, it would squak at every single subkey and value under the $class, so if exists is probably best...
        whahey - the code works, a big list of associations and extenstions scrolls by, albiet puntuated with complaints about being unable to recognise association list and use of unitialised values or string in concatenation...

        "unable to recognise association list" is not an error. I'd remove the line that outputs that, but I didn't know if you were planning on focusing on a specific extention later on.

        The uninitalized value is because you ran it without strict, and because I accidently used used $class where I should have $ext. (Copy and paste error.)

        on another note I now just need to mod this so that it can accept some arguments and ergo change associations - I'm trying to make a setup that will automatically change the default browser on an ME system

        Why are you looping if you are looking for a specific extention?

        whahey - the code works, a big list of associations and extenstions scrolls by, albiet puntuated with complaints about being unable to recognise association list and use of unitialised values or string in concatenation...

        "unable to recognise association list" is not an error. I'd remove the line that outputs that, but I didn't know if you were planning on focusing on a specific extention later on.

        The uninitalized value is because you ran it without strict, and because I accidently used used $class where I should have $ext. (Copy and paste error.)

        on another note I now just need to mod this so that it can accept some arguments and ergo change associations - I'm trying to make a setup that will automatically change the default browser on an ME system

        Why are you looping if you are looking for a specific extention?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://567551]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (3)
As of 2024-04-19 23:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found