| 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 |  | 93 | use strict; | 
|  | 16 |  |  |  |  | 33 |  | 
|  | 16 |  |  |  |  | 767 |  | 
| 8 | 16 |  |  | 16 |  | 150 | use warnings; | 
|  | 16 |  |  |  |  | 33 |  | 
|  | 16 |  |  |  |  | 10650 |  | 
| 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 | 200 | my ($message, $preamble, $obj, $prefix) = @_; | 
| 30 |  |  |  |  |  |  | # a private function for formatting a line number and a file name | 
| 31 | 86 |  |  | 592 |  | 468 | my $format = sub { " [at line $_[0] in $_[1]]" }; | 
|  | 592 |  |  |  |  | 4963 |  | 
| 32 |  |  |  |  |  |  | # get a textual representation of the object | 
| 33 | 86 | 50 |  |  |  | 358 | 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 |  |  |  | 1097 | ($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 |  |  |  |  | 390 | 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 |  |  |  | 301 | 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 |  |  |  |  | 969 | my (undef, $filename, $line) = caller(1); | 
| 48 | 86 |  |  |  |  | 340 | push @stacktrace, "0: --> \"$message\"" . &$format($line, $filename); | 
| 49 |  |  |  |  |  |  | # loop over all frames with depth larger than one | 
| 50 | 86 |  |  |  |  | 452 | 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 | 506 |  |  |  |  | 829 | my @info = eval { package DB; caller(1+$depth) }; | 
|  | 506 |  |  |  |  | 4227 |  | 
| 55 | 506 |  |  |  |  | 1530 | 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 | 506 | 100 |  |  |  | 1070 | for (@arguments) { $_ = 'undef' unless defined; | 
|  | 1295 |  |  |  |  | 3343 |  | 
| 60 | 1295 |  |  |  |  | 2821 | s/[\000-\037\177-\377]/sprintf "\\%02x",ord($&)/eg; | 
|  | 0 |  |  |  |  | 0 |  | 
| 61 | 1295 | 100 | 100 |  |  | 13314 | s/^(.*)$/'$1'/ unless /^-?\d+\.?\d*$/ || /undef/; } | 
| 62 | 506 |  |  |  |  | 1244 | my $args = join ', ', @arguments; | 
| 63 |  |  |  |  |  |  | # extract subroutine names, line numbers and file names | 
| 64 | 506 |  |  |  |  | 1242 | my (undef, $filename, $line, $subroutine) = @info; | 
| 65 |  |  |  |  |  |  | # detect the case of an eval statement | 
| 66 | 506 | 100 |  |  |  | 1175 | 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 | 506 | 100 |  |  |  | 2043 | 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 |  |  |  |  | 624 | $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 |  |  |  |  | 181 | for (@stacktrace) {	s/'$objstring'/self/g; | 
|  | 678 |  |  |  |  | 3630 |  | 
| 78 | 678 | 100 |  |  |  | 3879 | s/$prefix:{2}//g unless /\[obj .*\]/; } | 
| 79 |  |  |  |  |  |  | # returne all lines joined into one "\n"-separated string + bars | 
| 80 | 86 |  |  |  |  | 2121 | return join "\n", ('='x78, @stacktrace, '='x78, ''); | 
| 81 |  |  |  |  |  |  | } | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | # successful package load | 
| 84 |  |  |  |  |  |  | 1; |