tags:

views:

73

answers:

1

I know that caller will give me the file name and line number where a function was called, but how can I get the character or byte offset? It is okay if I must drop down to XS for it (the function will probably wind up being XS anyway).

What I am trying to do is uniquely identify all of the calls to a function, so, if there is a better method than location in the source, I am open to other routes.

The basic intent is to make an each function that can safely iterate over the same hash. Here is a pure Perl version that is similar to what I am thinking about:

#!/usr/bin/perl

use 5.012;
use warnings;
use Scalar::Util qw/refaddr/;

sub safe_each(\%) {
    my $h    = shift;
    my $key  = join "/", (caller)[1,2], refaddr $h;
    state %iter;

    unless (exists $iter{$key}) {
        $iter{$key} = [ keys %$h ];
    }

    unless (@{$iter{$key}}) {
        delete $iter{$key};
        return;
    }

    my $cur = shift @{$iter{$key}};

    return wantarray ? ($cur, $h->{$cur}) : $cur;
}

my %h = (a => 1, b => 2);
while (my ($k, $v) = safe_each %h) {
    say "$k => $v";
    while (my ($k, $v) = safe_each %h) {
        say "\t$k => $v";
    }
}
+1  A: 

The perl debugger loads all lines of the source files that it needs into the main symbol table under the entry

@::{"_<$path_to_file"}

This way when you reach a breakpoint at line LINE in file FILE, the debugger can display the line of code you are about to execute:

$::{"_<FILE"}[LINE]

But you could also use this information to compute the current character offset into your source file.

sub _get_offset_into_file {
    my ($file,$line) = @_;
    my *teh_codez = @::{"_<$file"};

    my $offset = 0;
    # the debugger spoofs line $teh_codez[0], so don't include it in offset calc
    $offset += length $_ for @teh_codez[1 .. $line-1];
    return $offset
}

You could either run your code under the debugger, or emulate what the debugger does and load the files into memory yourself (then you wouldn't have to use the same "_<" + filename convention, or even use the symbol table at all).

Sorry if this is an answer to a completely different question than the one you are asking.

mobrule
I was trying to avoid loading the source files, I think I would rather let it misidentify the second call.
Chas. Owens
Oh, then just knowing the line number of the caller won't help anyway.
mobrule