File Coverage

blib/lib/Image/MetaData/JPEG/Backtrace.pm
Criterion Covered Total %
statement 32 33 96.9
branch 13 16 81.2
condition 3 3 100.0
subroutine 4 4 100.0
pod 0 1 0.0
total 52 57 91.2


line stmt bran cond sub pod time code
1             ###########################################################
2             # A Perl package for showing/modifying JPEG (meta)data. #
3             # Copyright (C) 2004,2005,2006 Stefano Bettelli #
4             # See the COPYING and LICENSE files for license terms. #
5             ###########################################################
6             package Image::MetaData::JPEG::Backtrace;
7 16     16   65 use strict;
  16         17  
  16         574  
8 16     16   56 use warnings;
  16         21  
  16         7658  
9              
10             ###########################################################
11             # The following variables belong to the JPEG package. #
12             # They are used as global switches for selecting #
13             # backtrace verbosity in various situations: #
14             # $show_warnings --> if false, warnings should be muted #
15             ###########################################################
16             { package Image::MetaData::JPEG;
17             our $show_warnings = 1; }
18              
19             ###########################################################
20             # This is a private customisable function for creating an #
21             # error (or warning) message with the current stack trace #
22             # attached. It uses additional information returned by #
23             # the built-in Perl function 'caller' when it is called #
24             # from within the 'DB' package (is this dangerous?). #
25             # ------------------------------------------------------- #
26             # To be used by JPEG, JPEG::Segment, JPEG::Record ... #
27             ###########################################################
28             sub backtrace {
29 86     86 0 115 my ($message, $preamble, $obj, $prefix) = @_;
30             # a private function for formatting a line number and a file name
31 86     595   346 my $format = sub { " [at line $_[0] in $_[1]]" };
  595         2539  
32             # get a textual representation of the object
33 86 50       241 my $objstring = defined $obj ? "$obj" : '';
34             # get the prefix in the package name (before the last ::);
35             # this variable can be overridden by the caller
36 86 50       720 ($prefix = $objstring) =~ s/^(.*)::[^:]*$/$1/ unless $prefix;
37             # write the user preamble (e.g., 'Error' or 'Warning') as well as
38             # the object's textual representation at the beginning of the output
39 86         237 my @stacktrace = ("$preamble [obj $objstring]");
40             # we assume that this function is called by a "warn" or "die"
41             # method of some package, so it does not make sense to have
42             # less than two stack frames here.
43 86 50       224 die "Error in backtrace: cannot backtrace!" unless caller(1);
44             # detect where this function was called from (the function name is
45             # not important, maybe "warn" or "die"); use this info to format a
46             # "0-th" frame with the error message instead of the subroutine name
47 86         496 my (undef, $filename, $line) = caller(1);
48 86         250 push @stacktrace, "0: --> \"$message\"" . &$format($line, $filename);
49             # loop over all frames with depth larger than one
50 86         246 for (my $depth = 2; caller($depth); ++$depth) {
51             # get information about this stack frame from the built-in Perl
52             # function 'caller'; we need to call it from within the DB package
53             # to access the list of arguments later (in @DB::args).
54 509         415 my @info = eval { package DB; caller(1+$depth) };
  509         2423  
55 509         848 my @arguments = @DB::args;
56             # create a string with a representation of the argument values;
57             # undefined values are rendered as 'undef', non-numeric values
58             # become strings, non-printable characters are translated.
59 509 100       535 for (@arguments) { $_ = 'undef' unless defined;
  1311         1910  
60 1311         1513 s/[\000-\037\177-\377]/sprintf "\\%02x",ord($&)/eg;
  0         0  
61 1311 100 100     7954 s/^(.*)$/'$1'/ unless /^-?\d+\.?\d*$/ || /undef/; }
62 509         799 my $args = join ', ', @arguments;
63             # extract subroutine names, line numbers and file names
64 509         674 my (undef, $filename, $line, $subroutine) = @info;
65             # detect the case of an eval statement
66 509 100       713 my $iseval = $subroutine eq '(eval)' ? 1 : undef;
67             # create a line for this stack frame; this contains the subroutine
68             # name and its argument values (exception made for eval statements,
69             # where the arguments are meaningless) plus the call location.
70 509 100       1419 push @stacktrace, ($depth-1) . ": " .
71             ($iseval ? '(eval statement)' : "$subroutine($args)") .
72             &$format($line, $filename); }
73             # rework the object representation for inclusion in a regex
74 86         379 $objstring =~ s/([\(\)])/\\$1/g;
75             # replace $this with 'self' and take out the package prefix
76             # (try not to touch the first line, though).
77 86         120 for (@stacktrace) { s/'$objstring'/self/g;
  681         2421  
78 681 100       2406 s/$prefix:{2}//g unless /\[obj .*\]/; }
79             # returne all lines joined into one "\n"-separated string + bars
80 86         1271 return join "\n", ('='x78, @stacktrace, '='x78, '');
81             }
82              
83             # successful package load
84             1;