Thanks for your tips; they led to some experiments and gradual understanding of 
references.  I'm still puzzled by the error messages.

BACKGROUND
Substantively, I am trying to modify Debian's adduser code so that it pays 
attention  to a template of values from a previous system, to preserve the name 
-> [gu]id mapping as well as group membership.  Line 272 checks if such a 
template is present; 274 checks that the template is consistent with the 
current system values and populates %template with the desired values; 275 
merges the group information from the template into the present system if that 
hasn't already been done.

%template is a hash with various tables in it. $template{uname} is a reference 
to another hash that has user names as keys and a reference to an array of 
values from the passwd file as values.

I am having trouble keeping the various levels of indirection straight.

EXPERIMENTS
Here's a simpler example (excerpts) that fails, with a final version that works:
--------------------------------------------------
use warnings;
use strict;

my %passwd;

open PASSWD, "/mnt/lenny/etc/passwd";
while (<PASSWD>) {
    my @line = split /:/;
    $passwd{$line[0]} = \@line;
    }
close(PASSWD);

my %template;
$template{uname} = \%passwd;

## below, the statement is followed by its output when run

print '$template{uname}{ross} =' , $template{uname}{ross}, "\n";
#$template{uname}{ross} =ARRAY(0x20f41d8)
# I'm still surprised this worked.  Somehow we've gone 2 levels down with one $.

print '${$template{uname}}{ross} =' , ${$template{uname}}{ross}, "\n";
#${$template{uname}}{ross} =ARRAY(0x20f41d8)
# and thought this syntax was necessary

print '$${$template{uname}}{ross} =' , $${$template{uname}}{ross}, "\n";        
                                          
#Not a SCALAR reference at testuser line 51.
                                                                         
print '@${$template{uname}}{ross} =' , @${$template{uname}}{ross}, "\n";        
                                          
#Not a SCALAR reference at testuser line 53.                                    
                                           
# My thinking here is that 
print '@$${$template{uname}}{ross} =' , @$${$template{uname}}{ross}, "\n";
#Not a SCALAR reference at testuser line 55.                                    
                                           

print '@${${$template{uname}}{ross}} =' , @${${$template{uname}}{ross}}, "\n";
#Not a SCALAR reference at testuser line 55.  
  
print ${$template{uname}{ross}}, "\n";                                          
                                          
# Not a SCALAR reference at testuser line 59.                                   
                                           

print @{$template{uname}{ross}}, "\n";
#rossx10001000Ross Boylan,,,/home/ross/bin/bash                                 
                                                                                
                                      
-------------------------------------------------------------------------

SOLUTION (?)
After studying perlreftut, I think my basic confusion was that I thought an 
additional level of $ was necessary.
For example, my logic was that if ${$template{uname}}{ross} was a reference to 
an array then $${$template{uname}}{ross} was the array itself.  When that 
didn't work I tried adding an @ in front.

So I'll fix my syntax problems, but I'm still puzzled why the error messages 
aren't more helpful


MORE BACKGROUND AND A QUESTION
$new_name is the name of the new user that was requested when adduser was 
invoked.
280 attempts to retrieve the array of information associated with the user in 
the template.
So $template{uname} gets the reference to a hash. $($template{uname}) is the 
2nd level hash itself [wrong],
and $$($template{uname}){$new_name} the reference to the array for $new_name 
[not quite].
This interpretation makes my original code, assigning to $old, seem more 
reasonable, since the result is a reference to an array, not an array.  As 
noted in my original message, that version didn't work either.

If 280 alone generates a syntax error, why wasn't one reported for 280 by perl 
-c?

%template{uname} may not exist, and if it does it may not have entry for 
$new_name.  284 was relying on failure being null and failing tests, 
specifically at 280.

I tried
        if (my @old = @$($template{uname}){$new_name}) {
but it the same error at 283 as the first error (the version with scope, not 
statement).
The if test at 284 checks if the user has specified an option giving the new 
uid and, if so, whether it is consistent with the template value. 

Finally,
> Did you really intend to declare and populate an array and throw in a 
> conditional all in a one-liner?
Yes.

> Do you know for instance that my @foo = $some_scalar is the equivalent of 
> just saying:  my @foo = ($some_scalar)
I didn't, though I have been wondering if "return (0);" is the same as "return 
0;".  I guessing that to return a list with 0 in one would need return((0)).  
Is that riight?  Or does it just depend on the context to which the value is 
returned?  How does perl know whether (0) = a scalar expression with 
parentheses for precedence grouping (vacuously in this case); or a single 
element list; or, if a function precedes it, () indicating function arguments?

Ross

P.S. Sorry, my mail client basically forces top-posting.
________________________________________
From: Charles DeRykus [dery...@gmail.com]
Sent: Monday, October 13, 2014 11:08 AM
To: Boylan, Ross
Subject: Re: masks earlier declaration in same scope

On Mon, Oct 13, 2014 at 1:04 AM, Boylan, Ross <ross.boy...@ucsf.edu> wrote:
> perl -c adduser gives its first error as
> "my" variable $new_uid masks earlier declaration in same scope at adduser 
> line 283.
> First, it doesn't seem to me I'm declaring the variable at all at 283.  I 
> suppose it could be an implicit declaration if there wasn't a previous 
> declaration, but there is at 103.
> Second, I don't see any earlier declarations in any scope except the outer 
> one.
> Third, the variiable was declared, with "our $new_uid;" much earlier in the 
> file.
>
> Could anyone explain to me what's going on?  A couple other questions appear 
> after the code.
>     32  use warnings;
>     33  use strict;
>     34  use Debian::AdduserCommon;
>     35  use Getopt::Long;
>     36  use File::Spec::Functions;
>     37  use File::Touch;
> ...
>    103  our $new_uid = undef;
> ....
>    160  # Parse options, sanity checks
>    161  unless ( GetOptions ("quiet|q" => sub { $verbose = 0 },
> ...
>    173              "uid=i" => \$new_uid,  # still in arguments to GetOptions
> Lines 103 and 173 are the only places $new_uid occurs in the text before line 
> 283.
>
>    272  if ($use_template = &use_template) {
>    273      # we are using templates
>    274      if (check_template( $conf_dir, \%template)) {
>    275          merge_template( \%template, \%system)
>    276      }
>    277      # rewrite request as needed
>    278      if defined($new_name) {
>    279          # trying to create a new user
>    280          if (my @old = $$($template{uname}){$new_name}) {
>    281              # requested user is in the template
>    282              my $olduid = $$old[2];
> **283              dief( gtx("Specified UID %d for %s does not match template 
> UID of %d.\n"), $new_uid,
>    284                        $new_name, $olduid) if defined($new_uid) && 
> $new_uid != $olduid;
>    285              $new_uid = $olduid;
>    286              my $oldgid = $$old[3];
>
> Bonus question #1: Where does the relevant scope start?  I think  it's 280, 
> but if none of the if's create scopes it could be the start of  the file.
>
> Bonus question #2: If I change 280 to  to   "if (my $old = ...." I get the 
> error
> "my" variable $old masks earlier declaration in same statement at adduser 
> line 282.
> Why?  I mean, there's only declaration in the statement, and it seems to be 
> on the first line even if the "statement" is everything up to the end of the 
> if .. else .. block.
>
> The archives indicate that syntax errors sometimes produce seemingly 
> unrelated "masks earlier declaration" errors, but even if this is a syntax 
> error (it seems more like a semantic problem to me) the error seems odd.


LIne 280 alone will generate  a syntax error:

$ perl -we 'if (my @old = $$($template{uname}){$new_name}) {}'
         syntax error at -e line 1, near "$$("


Perhaps you meant somethng like:

   if (my @old = ( ${$template{uname}{$new_name}} ) ) { .... }


But that's really bizarre too.  Did you really intend to declare and
populate an array and throw in a conditional all in a one-liner?

Do you know for instance that my @foo = $some_scalar is the equivalent
of just saying:  my @foo = ($some_scalar); The latter is the usual idiom
and is clearer too.

So, just a few thoughts... some more explanation of what that code is
intended to do would help.

--
Charles DeRykus

--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to