| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  |  | 
| 2 |  |  |  |  |  |  | package Data::HexDump::Range ; ## no critic (Modules::RequireFilenameMatchesPackage) | 
| 3 |  |  |  |  |  |  |  | 
| 4 | 2 |  |  | 2 |  | 8 | use strict; | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 68 |  | 
| 5 | 2 |  |  | 2 |  | 7 | use warnings ; | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 45 |  | 
| 6 | 2 |  |  | 2 |  | 6 | use Carp ; | 
|  | 2 |  |  |  |  | 2 |  | 
|  | 2 |  |  |  |  | 122 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | BEGIN | 
| 9 | 2 |  |  | 2 |  | 29 | { | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 2 |  |  |  |  | 18 | use Sub::Exporter -setup => | 
| 12 |  |  |  |  |  |  | { | 
| 13 |  |  |  |  |  |  | exports => [ qw() ], | 
| 14 |  |  |  |  |  |  | groups  => | 
| 15 |  |  |  |  |  |  | { | 
| 16 |  |  |  |  |  |  | all  => [ qw() ], | 
| 17 |  |  |  |  |  |  | } | 
| 18 | 2 |  |  | 2 |  | 8 | }; | 
|  | 2 |  |  |  |  | 1 |  | 
| 19 |  |  |  |  |  |  |  | 
| 20 | 2 |  |  | 2 |  | 902 | use vars qw ($VERSION); | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 63 |  | 
| 21 |  |  |  |  |  |  | } | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 24 |  |  |  |  |  |  |  | 
| 25 | 2 |  |  | 2 |  | 8 | use English qw( -no_match_vars ) ; | 
|  | 2 |  |  |  |  | 2 |  | 
|  | 2 |  |  |  |  | 11 |  | 
| 26 |  |  |  |  |  |  |  | 
| 27 | 2 |  |  | 2 |  | 593 | use Readonly ; | 
|  | 2 |  |  |  |  | 2 |  | 
|  | 2 |  |  |  |  | 105 |  | 
| 28 |  |  |  |  |  |  | Readonly my $EMPTY_STRING => q{} ; | 
| 29 |  |  |  |  |  |  |  | 
| 30 | 2 |  |  | 2 |  | 9 | use Carp qw(carp croak confess) ; | 
|  | 2 |  |  |  |  | 2 |  | 
|  | 2 |  |  |  |  | 72 |  | 
| 31 | 2 |  |  | 2 |  | 1107 | use Text::Pluralize ; | 
|  | 2 |  |  |  |  | 1217 |  | 
|  | 2 |  |  |  |  | 9134 |  | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | =head1 NAME | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | Data::HexDump::Range::Split - Handles formating for Data::HexDump::Range | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | =head1 DOCUMENTATION | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | =head1 SUBROUTINES/METHODS | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | Subroutines prefixed with B<[P]> are not part of the public API and shall not be used directly. | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | =cut | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | sub split | 
| 54 |  |  |  |  |  |  | { | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | =head2 [P] split($collected_data) | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  | Split the collected data into lines | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | I - | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | =over 2 | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | =item * $container - Collected data | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | =back | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | I -  An Array  containing column elements | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | I | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | =cut | 
| 73 |  |  |  |  |  |  |  | 
| 74 | 0 |  |  | 0 | 0 |  | my ($self, $collected_data) = @_ ; | 
| 75 |  |  |  |  |  |  |  | 
| 76 | 0 | 0 |  |  |  |  | if($self->{ORIENTATION} =~ /^hor/) | 
| 77 |  |  |  |  |  |  | { | 
| 78 | 0 |  |  |  |  |  | return $self->_split_horizontal($collected_data) ; | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  | else | 
| 81 |  |  |  |  |  |  | { | 
| 82 | 0 |  |  |  |  |  | return $self->_split_vertical($collected_data) ; | 
| 83 |  |  |  |  |  |  | } | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | sub _split_horizontal | 
| 89 |  |  |  |  |  |  | { | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | =head2 [P] _split_horizontal($collected_data) | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | Split the collected data into horizontal lines | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | I - | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | =over 2 | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | =item * $container - Collected data | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | =back | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | I -  An Array  containing column elements | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | I | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | =cut | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 0 |  |  | 0 |  |  | my ($self, $collected_data) = @_ ; | 
| 111 |  |  |  |  |  |  |  | 
| 112 | 0 |  |  |  |  |  | my @lines ; | 
| 113 | 0 |  |  |  |  |  | my $line = {} ; | 
| 114 | 0 |  |  |  |  |  | my $wrapped_line = 0 ; | 
| 115 |  |  |  |  |  |  |  | 
| 116 | 0 |  |  |  |  |  | my $current_offset = 0 ; | 
| 117 | 0 |  |  |  |  |  | my $total_dumped_data =  $self->{OFFSET_START} ; | 
| 118 | 0 |  |  |  |  |  | my $room_left = $self->{DATA_WIDTH} ; | 
| 119 |  |  |  |  |  |  |  | 
| 120 | 0 |  |  |  |  |  | my $lines_since_header = 0 ; | 
| 121 |  |  |  |  |  |  |  | 
| 122 | 0 |  |  |  |  |  | my $max_range_name_size = $self->{MAXIMUM_RANGE_NAME_SIZE} ; | 
| 123 | 0 |  |  |  |  |  | my $user_information_size = $self->{MAXIMUM_USER_INFORMATION_SIZE} ; | 
| 124 | 0 |  |  |  |  |  | my $range_source = ['?', 'white'] ; | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 0 |  |  |  |  |  | my @found_bitfields ; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 0 |  |  |  |  |  | my $last_range = (grep {!  $_->{IS_BITFIELD}}@{$collected_data})[-1] ; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  |  | 
| 130 | 0 |  |  |  |  |  | my @collected_data_to_dump = @{$collected_data} ; | 
|  | 0 |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  |  | 
| 132 | 0 | 0 |  |  |  |  | if($self->{OFFSET_START}) | 
| 133 |  |  |  |  |  |  | { | 
| 134 | 0 |  |  |  |  |  | my $range = {} ; | 
| 135 | 0 |  |  |  |  |  | $range->{NAME} =  '>>' ; | 
| 136 | 0 |  |  |  |  |  | $range->{DATA} = '?' x $self->{DATA_WIDTH} ; | 
| 137 |  |  |  |  |  |  |  | 
| 138 | 0 |  |  |  |  |  | my $left_pad_size = $self->{OFFSET_START} % $self->{DATA_WIDTH} ; | 
| 139 | 0 |  |  |  |  |  | my $aligned_start_offset = $self->{OFFSET_START} - $left_pad_size ; | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | =pod | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | =item * $self - | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | =item * $visible - Boolean - wether the range elements will be visible or not. used for alignment | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | =item * $range - the range structure created by Gather | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | =item * $line - container for the range strings to be displayed | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | =item * $last_range - Boolean - wether the range is the last one to be displayed | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | =item * $total_dumped_data - Integer -  the amount of total data dumped so far | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | =item * $dumped_data - Integer - the amount of byte dumped from the range so far | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | =item *  $size_to_dump - Integer - the amount of data to extract from the range | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | =item * $room_left - Integer - the amount of space left in the line for the dimped data | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | =cut | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 0 |  |  |  |  |  | $self->_dump_range_horizontal(0, $range, $line, 0, $aligned_start_offset, 0, $left_pad_size, $self->{DATA_WIDTH}) ; | 
| 164 |  |  |  |  |  |  |  | 
| 165 | 0 |  |  |  |  |  | $current_offset += $self->{OFFSET_START} ; | 
| 166 | 0 |  |  |  |  |  | $room_left = $self->{DATA_WIDTH} - $left_pad_size ; | 
| 167 |  |  |  |  |  |  | } | 
| 168 |  |  |  |  |  |  |  | 
| 169 | 0 |  |  |  |  |  | while (my $range = shift @collected_data_to_dump) | 
| 170 |  |  |  |  |  |  | { | 
| 171 | 0 | 0 |  |  |  |  | my $data_length = defined $range->{DATA} ? length($range->{DATA}) : 0 ; | 
| 172 | 0 | 0 |  |  |  |  | my ($start_quote, $end_quote) = $range->{IS_COMMENT} ? ('"', '"') : ('<', '>') ; | 
| 173 |  |  |  |  |  |  |  | 
| 174 | 0 | 0 |  |  |  |  | $range->{SOURCE} = $range_source  if $range->{IS_BITFIELD} ; | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  |  | 
| 177 | 0 | 0 |  |  |  |  | if($range->{IS_BITFIELD}) | 
| 178 |  |  |  |  |  |  | { | 
| 179 | 0 |  |  |  |  |  | $range->{COLOR} = $range_source->[1] ; | 
| 180 | 0 |  |  |  |  |  | push @found_bitfields, $self->get_bitfield_lines($range) ; | 
| 181 | 0 |  |  |  |  |  | next ; | 
| 182 |  |  |  |  |  |  | } | 
| 183 |  |  |  |  |  |  |  | 
| 184 | 0 |  |  |  |  |  | $range->{COLOR} = $self->get_default_color($range->{COLOR}) ; | 
| 185 |  |  |  |  |  |  |  | 
| 186 | 0 | 0 |  |  |  |  | if($room_left == $self->{DATA_WIDTH}) | 
| 187 |  |  |  |  |  |  | { | 
| 188 | 0 |  |  |  |  |  | push @lines,  @found_bitfields ; | 
| 189 | 0 |  |  |  |  |  | @found_bitfields = () ; | 
| 190 |  |  |  |  |  |  | } | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | # remember what range we process in case next range is bitfield | 
| 193 | 0 | 0 |  |  |  |  | unless($range->{IS_COMMENT}) | 
| 194 |  |  |  |  |  |  | { | 
| 195 | 0 |  |  |  |  |  | $range_source = [$range->{NAME}, $range->{COLOR}]  ; | 
| 196 |  |  |  |  |  |  | } | 
| 197 |  |  |  |  |  |  |  | 
| 198 | 0 |  |  |  |  |  | my $dumped_data = 0 ; | 
| 199 |  |  |  |  |  |  |  | 
| 200 | 0 | 0 | 0 |  |  |  | if(0 == $data_length && $self->{DISPLAY_RANGE_NAME}) | 
| 201 |  |  |  |  |  |  | { | 
| 202 | 0 |  |  |  |  |  | my $display_range_name = 0 ; | 
| 203 |  |  |  |  |  |  |  | 
| 204 | 0 | 0 |  |  |  |  | if($range->{IS_COMMENT}) | 
| 205 |  |  |  |  |  |  | { | 
| 206 | 0 | 0 |  |  |  |  | $display_range_name++ if $self->{DISPLAY_COMMENT_RANGE} ; | 
| 207 |  |  |  |  |  |  | } | 
| 208 |  |  |  |  |  |  | else | 
| 209 |  |  |  |  |  |  | { | 
| 210 | 0 | 0 |  |  |  |  | $display_range_name++ if $self->{DISPLAY_ZERO_SIZE_RANGE} ; | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  |  | 
| 213 | 0 | 0 |  |  |  |  | if($display_range_name) | 
| 214 |  |  |  |  |  |  | { | 
| 215 | 0 |  |  |  |  |  | my $name_size_quoted = $max_range_name_size - 2 ; | 
| 216 | 0 | 0 |  |  |  |  | $name_size_quoted =  2 if $name_size_quoted < 2 ; | 
| 217 |  |  |  |  |  |  |  | 
| 218 | 0 |  |  |  |  |  | push @{$line->{RANGE_NAME}}, | 
|  | 0 |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | { | 
| 220 |  |  |  |  |  |  | 'RANGE_NAME' => $start_quote . sprintf("%.${name_size_quoted}s", $range->{NAME}) . $end_quote, | 
| 221 |  |  |  |  |  |  | 'RANGE_NAME_COLOR' => $range->{COLOR}, | 
| 222 |  |  |  |  |  |  | }, | 
| 223 |  |  |  |  |  |  | { | 
| 224 |  |  |  |  |  |  | 'RANGE_NAME_COLOR' => undef, | 
| 225 |  |  |  |  |  |  | 'RANGE_NAME' => ', ', | 
| 226 |  |  |  |  |  |  | } ; | 
| 227 |  |  |  |  |  |  | } | 
| 228 |  |  |  |  |  |  | } | 
| 229 |  |  |  |  |  |  |  | 
| 230 | 0 | 0 |  |  |  |  | if($range->{IS_HEADER}) | 
| 231 |  |  |  |  |  |  | { | 
| 232 | 0 |  |  |  |  |  | $range->{NAME} =  '@' . $range->{NAME} ; | 
| 233 | 0 |  |  |  |  |  | $range->{DATA} = '0' x $self->{DATA_WIDTH} ; | 
| 234 |  |  |  |  |  |  |  | 
| 235 |  |  |  |  |  |  | # justify on the right | 
| 236 | 0 |  |  |  |  |  | $self->_dump_range_horizontal(0, $range, $line, $last_range, $current_offset, $dumped_data, $room_left, $room_left) ; | 
| 237 | 0 |  |  |  |  |  | $line->{NEW_LINE}++ ; | 
| 238 | 0 |  |  |  |  |  | push @lines, $line ; | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | # display header | 
| 241 | 0 |  |  |  |  |  | $line = {} ; | 
| 242 | 0 |  |  |  |  |  | push @lines, $self->get_information(\@lines, $range->{COLOR}) ; | 
| 243 |  |  |  |  |  |  |  | 
| 244 |  |  |  |  |  |  | # justify on the left | 
| 245 | 0 |  |  |  |  |  | $line = {} ; | 
| 246 |  |  |  |  |  |  |  | 
| 247 | 0 |  |  |  |  |  | my $left_pad_size = $self->{DATA_WIDTH} - $room_left ; | 
| 248 | 0 |  |  |  |  |  | $self->_dump_range_horizontal(0, $range, $line, $last_range, $current_offset -$left_pad_size , $dumped_data, $left_pad_size, $self->{DATA_WIDTH}) ; | 
| 249 |  |  |  |  |  |  |  | 
| 250 | 0 |  |  |  |  |  | next ; | 
| 251 |  |  |  |  |  |  | } | 
| 252 |  |  |  |  |  |  |  | 
| 253 | 0 | 0 |  |  |  |  | if($range->{IS_SKIP}) | 
| 254 |  |  |  |  |  |  | { | 
| 255 | 0 |  |  |  |  |  | $range->{NAME} =  '>>' . $range->{NAME} ; | 
| 256 | 0 |  |  |  |  |  | $range->{DATA} = ' '  x $self->{DATA_WIDTH} ; | 
| 257 |  |  |  |  |  |  |  | 
| 258 | 0 |  | 0 |  |  |  | my $size_to_dump = min($room_left, $data_length - $dumped_data) || 0 ; | 
| 259 | 0 |  |  |  |  |  | $room_left -= $size_to_dump ; | 
| 260 |  |  |  |  |  |  |  | 
| 261 |  |  |  |  |  |  | # justify on the right | 
| 262 | 0 |  |  |  |  |  | $self->_dump_range_horizontal(0, $range, $line, $last_range, $current_offset, $dumped_data, $size_to_dump, $room_left) ; | 
| 263 |  |  |  |  |  |  |  | 
| 264 | 0 |  |  |  |  |  | my $data_left = $data_length - $size_to_dump ; | 
| 265 | 0 |  |  |  |  |  | $current_offset += $size_to_dump ; | 
| 266 |  |  |  |  |  |  |  | 
| 267 | 0 | 0 |  |  |  |  | if ($data_left) | 
| 268 |  |  |  |  |  |  | { | 
| 269 |  |  |  |  |  |  | # justify on the left | 
| 270 | 0 |  |  |  |  |  | $line->{NEW_LINE}++ ; | 
| 271 | 0 |  |  |  |  |  | push @lines, $line ; | 
| 272 |  |  |  |  |  |  |  | 
| 273 | 0 |  |  |  |  |  | my $lines_to_skip = int($data_left / $self->{DATA_WIDTH}) ; | 
| 274 | 0 |  |  |  |  |  | my $data_bytes_on_line = $data_left - ($lines_to_skip * $self->{DATA_WIDTH}) ; | 
| 275 | 0 |  |  |  |  |  | my $left_data_offset = $current_offset + ($lines_to_skip * $self->{DATA_WIDTH}) ; | 
| 276 |  |  |  |  |  |  |  | 
| 277 | 0 |  |  |  |  |  | $line = {} ; | 
| 278 | 0 |  |  |  |  |  | $self->_dump_range_horizontal(0, $range, $line, $last_range, $left_data_offset, $dumped_data, $data_bytes_on_line, $self->{DATA_WIDTH}) ; | 
| 279 |  |  |  |  |  |  |  | 
| 280 | 0 |  |  |  |  |  | $room_left = $self->{DATA_WIDTH} - $data_bytes_on_line ; | 
| 281 | 0 |  |  |  |  |  | $current_offset += $data_left ; | 
| 282 |  |  |  |  |  |  | } | 
| 283 |  |  |  |  |  |  |  | 
| 284 | 0 |  |  |  |  |  | next ; | 
| 285 |  |  |  |  |  |  | } | 
| 286 |  |  |  |  |  |  |  | 
| 287 | 0 |  |  |  |  |  | while ($dumped_data < $data_length) | 
| 288 |  |  |  |  |  |  | { | 
| 289 | 0 |  | 0 |  |  |  | my $size_to_dump = min($room_left, $data_length - $dumped_data) || 0 ; | 
| 290 |  |  |  |  |  |  |  | 
| 291 | 0 |  |  |  |  |  | $room_left -= $size_to_dump ; | 
| 292 |  |  |  |  |  |  |  | 
| 293 | 0 |  |  |  |  |  | $self->_dump_range_horizontal(1, $range, $line, $last_range, $current_offset, $dumped_data, $size_to_dump, $room_left) ; | 
| 294 |  |  |  |  |  |  |  | 
| 295 | 0 |  |  |  |  |  | $dumped_data += $size_to_dump ; | 
| 296 | 0 |  |  |  |  |  | $current_offset += $size_to_dump ; | 
| 297 |  |  |  |  |  |  |  | 
| 298 | 0 | 0 | 0 |  |  |  | if($room_left == 0 || $last_range == $range) | 
| 299 |  |  |  |  |  |  | { | 
| 300 | 0 |  |  |  |  |  | $line->{NEW_LINE}++ ; | 
| 301 | 0 |  |  |  |  |  | push @lines, $line ; | 
| 302 |  |  |  |  |  |  |  | 
| 303 | 0 |  |  |  |  |  | $line = {} ; | 
| 304 | 0 |  |  |  |  |  | $room_left = $self->{DATA_WIDTH} ; | 
| 305 |  |  |  |  |  |  |  | 
| 306 | 0 |  |  |  |  |  | push @lines,  @found_bitfields ; | 
| 307 | 0 |  |  |  |  |  | @found_bitfields = () ; | 
| 308 |  |  |  |  |  |  | } | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  | } | 
| 311 |  |  |  |  |  |  |  | 
| 312 | 0 | 0 |  |  |  |  | if(@found_bitfields) | 
| 313 |  |  |  |  |  |  | { | 
| 314 | 0 |  |  |  |  |  | push @lines,  @found_bitfields ; | 
| 315 | 0 |  |  |  |  |  | @found_bitfields = () ; | 
| 316 |  |  |  |  |  |  | } | 
| 317 |  |  |  |  |  |  |  | 
| 318 | 0 |  |  |  |  |  | return \@lines ; | 
| 319 |  |  |  |  |  |  | } | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | sub _split_vertical | 
| 324 |  |  |  |  |  |  | { | 
| 325 |  |  |  |  |  |  |  | 
| 326 |  |  |  |  |  |  | =head2 [P] _split_vertical($collected_data) | 
| 327 |  |  |  |  |  |  |  | 
| 328 |  |  |  |  |  |  | Split the collected data into vertical lines | 
| 329 |  |  |  |  |  |  |  | 
| 330 |  |  |  |  |  |  | I - | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | =over 2 | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | =item * $container - Collected data | 
| 335 |  |  |  |  |  |  |  | 
| 336 |  |  |  |  |  |  | =back | 
| 337 |  |  |  |  |  |  |  | 
| 338 |  |  |  |  |  |  | I -  An Array  containing column elements | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | I | 
| 341 |  |  |  |  |  |  |  | 
| 342 |  |  |  |  |  |  | =cut | 
| 343 |  |  |  |  |  |  |  | 
| 344 | 0 |  |  | 0 |  |  | my ($self, $collected_data) = @_ ; | 
| 345 |  |  |  |  |  |  |  | 
| 346 | 0 |  |  |  |  |  | my @lines ; | 
| 347 | 0 |  |  |  |  |  | my $line = {} ; | 
| 348 | 0 |  |  |  |  |  | my $wrapped_line = 0 ; | 
| 349 |  |  |  |  |  |  |  | 
| 350 | 0 |  |  |  |  |  | my $current_offset = 0 ; | 
| 351 | 0 |  |  |  |  |  | my $total_dumped_data =  $self->{OFFSET_START} ; | 
| 352 | 0 |  |  |  |  |  | my $room_left = $self->{DATA_WIDTH} ; | 
| 353 |  |  |  |  |  |  |  | 
| 354 | 0 |  |  |  |  |  | my $lines_since_header = 0 ; | 
| 355 |  |  |  |  |  |  |  | 
| 356 | 0 |  |  |  |  |  | my $max_range_name_size = $self->{MAXIMUM_RANGE_NAME_SIZE} ; | 
| 357 | 0 |  |  |  |  |  | my $user_information_size = $self->{MAXIMUM_USER_INFORMATION_SIZE} ; | 
| 358 | 0 |  |  |  |  |  | my $range_source = ['?', 'white'] ; | 
| 359 |  |  |  |  |  |  |  | 
| 360 | 0 |  |  |  |  |  | my @found_bitfields ; | 
| 361 |  |  |  |  |  |  |  | 
| 362 | 0 |  |  |  |  |  | my $last_range = (grep {!  $_->{IS_BITFIELD}}@{$collected_data})[-1] ; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  |  | 
| 364 | 0 |  |  |  |  |  | my @collected_data_to_dump = @{$collected_data} ; | 
|  | 0 |  |  |  |  |  |  | 
| 365 |  |  |  |  |  |  |  | 
| 366 | 0 |  |  |  |  |  | while (my $range = shift @collected_data_to_dump) | 
| 367 |  |  |  |  |  |  | { | 
| 368 | 0 | 0 |  |  |  |  | my $data_length = defined $range->{DATA} ? length($range->{DATA}) : 0 ; | 
| 369 | 0 | 0 |  |  |  |  | my ($start_quote, $end_quote) = $range->{IS_COMMENT} ? ('"', '"') : ('<', '>') ; | 
| 370 |  |  |  |  |  |  |  | 
| 371 | 0 | 0 |  |  |  |  | $range->{SOURCE} = $range_source  if $range->{IS_BITFIELD} ; | 
| 372 |  |  |  |  |  |  |  | 
| 373 |  |  |  |  |  |  | # vertical mode | 
| 374 |  |  |  |  |  |  |  | 
| 375 | 0 |  |  |  |  |  | $range->{COLOR} = $self->get_default_color($range->{COLOR}) ; | 
| 376 |  |  |  |  |  |  |  | 
| 377 | 0 |  |  |  |  |  | $line = {} ; | 
| 378 |  |  |  |  |  |  |  | 
| 379 | 0 |  |  |  |  |  | my $dumped_data = 0 ; | 
| 380 | 0 |  |  |  |  |  | my $current_range = '' ; | 
| 381 |  |  |  |  |  |  |  | 
| 382 | 0 | 0 | 0 |  |  |  | if(!$range->{IS_BITFIELD} && 0 == $data_length && $self->{DISPLAY_RANGE_NAME}) # && $self->{DISPLAY_RANGE_NAME}) | 
|  |  |  | 0 |  |  |  |  | 
| 383 |  |  |  |  |  |  | { | 
| 384 | 0 |  |  |  |  |  | my $display_range_name = 0 ; | 
| 385 |  |  |  |  |  |  |  | 
| 386 | 0 | 0 |  |  |  |  | if($range->{IS_COMMENT}) | 
| 387 |  |  |  |  |  |  | { | 
| 388 | 0 | 0 |  |  |  |  | $display_range_name++ if $self->{DISPLAY_COMMENT_RANGE} ; | 
| 389 |  |  |  |  |  |  | } | 
| 390 |  |  |  |  |  |  | else | 
| 391 |  |  |  |  |  |  | { | 
| 392 | 0 | 0 |  |  |  |  | $display_range_name++ if $self->{DISPLAY_ZERO_SIZE_RANGE} ; | 
| 393 |  |  |  |  |  |  | } | 
| 394 |  |  |  |  |  |  |  | 
| 395 | 0 | 0 |  |  |  |  | if($display_range_name) | 
| 396 |  |  |  |  |  |  | { | 
| 397 | 0 |  |  |  |  |  | push @{$line->{RANGE_NAME}}, | 
|  | 0 |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | { | 
| 399 |  |  |  |  |  |  | 'RANGE_NAME_COLOR' => $range->{COLOR}, | 
| 400 |  |  |  |  |  |  | 'RANGE_NAME' => "$start_quote$range->{NAME}$end_quote", | 
| 401 |  |  |  |  |  |  | } ; | 
| 402 |  |  |  |  |  |  |  | 
| 403 | 0 |  |  |  |  |  | $line->{NEW_LINE} ++ ; | 
| 404 | 0 |  |  |  |  |  | push @lines, $line ; | 
| 405 | 0 |  |  |  |  |  | $line = {}; | 
| 406 |  |  |  |  |  |  | } | 
| 407 |  |  |  |  |  |  | } | 
| 408 |  |  |  |  |  |  |  | 
| 409 | 0 | 0 |  |  |  |  | if($range->{IS_HEADER}) | 
| 410 |  |  |  |  |  |  | { | 
| 411 |  |  |  |  |  |  | # display the header | 
| 412 | 0 |  |  |  |  |  | push @lines, $self->get_information(\@lines, $range->{COLOR}) ; | 
| 413 | 0 |  |  |  |  |  | next ; | 
| 414 |  |  |  |  |  |  | } | 
| 415 |  |  |  |  |  |  |  | 
| 416 | 0 | 0 |  |  |  |  | if($range->{IS_SKIP}) | 
| 417 |  |  |  |  |  |  | { | 
| 418 | 0 |  |  |  |  |  | my $next_data_offset = $total_dumped_data + $data_length - 1 ; | 
| 419 |  |  |  |  |  |  |  | 
| 420 | 0 |  |  |  |  |  | $range->{NAME} = '>>' . $range->{NAME} ; | 
| 421 |  |  |  |  |  |  |  | 
| 422 | 0 |  |  | 0 |  |  | for my  $field_type | 
|  | 0 |  |  |  |  |  |  | 
| 423 |  |  |  |  |  |  | ( | 
| 424 | 0 |  |  | 0 |  |  | ['RANGE_NAME',  sub {sprintf "%-${max_range_name_size}.${max_range_name_size}s", $range->{NAME} }, $range->{COLOR}, $max_range_name_size] , | 
| 425 | 0 |  |  | 0 |  |  | ['OFFSET', sub {sprintf $self->{OFFSET_FORMAT}, $total_dumped_data}, undef, 8], | 
| 426 | 0 |  |  | 0 |  |  | ['CUMULATIVE_OFFSET', sub {sprintf $self->{OFFSET_FORMAT}, $next_data_offset}, undef, 8], | 
| 427 |  |  |  |  |  |  | ['BITFIELD_SOURCE', sub {' ' x 8}, undef, 8], | 
| 428 |  |  |  |  |  |  | [ | 
| 429 |  |  |  |  |  |  | 'HEX_DUMP', | 
| 430 |  |  |  |  |  |  | sub | 
| 431 |  |  |  |  |  |  | { | 
| 432 | 0 |  |  | 0 |  |  | my @bytes = unpack("(H2)*", pack("N", $data_length)); | 
| 433 | 0 |  |  |  |  |  | pluralize("Skipped @bytes byte(s)", $data_length) ; | 
| 434 |  |  |  |  |  |  | }, | 
| 435 |  |  |  |  |  |  | $range->{COLOR}, | 
| 436 |  |  |  |  |  |  | 3 * $self->{DATA_WIDTH}, | 
| 437 |  |  |  |  |  |  | ], | 
| 438 |  |  |  |  |  |  | [ | 
| 439 |  |  |  |  |  |  | 'HEXASCII_DUMP', | 
| 440 |  |  |  |  |  |  | sub | 
| 441 |  |  |  |  |  |  | { | 
| 442 | 0 |  |  | 0 |  |  | my @bytes = unpack("(H2)*", pack("N", $data_length)); | 
| 443 | 0 |  |  |  |  |  | pluralize("Skipped @bytes byte(s)", $data_length) ; | 
| 444 |  |  |  |  |  |  | }, | 
| 445 |  |  |  |  |  |  | $range->{COLOR}, | 
| 446 |  |  |  |  |  |  | 3 * $self->{DATA_WIDTH}, | 
| 447 |  |  |  |  |  |  | ], | 
| 448 |  |  |  |  |  |  | [ | 
| 449 |  |  |  |  |  |  | 'DEC_DUMP', | 
| 450 |  |  |  |  |  |  | sub | 
| 451 |  |  |  |  |  |  | { | 
| 452 | 0 |  |  | 0 |  |  | pluralize("Skipped $data_length byte(s)", $data_length)  ; | 
| 453 |  |  |  |  |  |  | }, | 
| 454 | 0 |  |  | 0 |  |  | $range->{COLOR}, | 
| 455 |  |  |  |  |  |  | 4 * $self->{DATA_WIDTH} | 
| 456 |  |  |  |  |  |  | ], | 
| 457 |  |  |  |  |  |  | ['ASCII_DUMP', sub {$EMPTY_STRING}, $range->{COLOR}, $self->{DATA_WIDTH}], | 
| 458 | 0 |  | 0 | 0 |  |  | ['USER_INFORMATION', sub { sprintf '%-20.20s', $range->{USER_INFORMATION} || ''}, $range->{COLOR}, 20], | 
| 459 |  |  |  |  |  |  | ) | 
| 460 |  |  |  |  |  |  | { | 
| 461 | 0 |  |  |  |  |  | my ($field_name, $field_data_formater, $color, $field_text_size) = @{$field_type} ; | 
|  | 0 |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  |  | 
| 463 | 0 | 0 |  |  |  |  | if($self->{"DISPLAY_$field_name"}) | 
| 464 |  |  |  |  |  |  | { | 
| 465 | 0 |  |  |  |  |  | my $field_text = $field_data_formater->([]) ; | 
| 466 | 0 |  |  |  |  |  | my $pad = ' ' x ($field_text_size -  length($field_text)) ; | 
| 467 |  |  |  |  |  |  |  | 
| 468 | 0 |  |  |  |  |  | push @{$line->{$field_name}}, | 
|  | 0 |  |  |  |  |  |  | 
| 469 |  |  |  |  |  |  | { | 
| 470 |  |  |  |  |  |  | $field_name . '_COLOR' => $color, | 
| 471 |  |  |  |  |  |  | $field_name =>  $field_text .  $pad, | 
| 472 |  |  |  |  |  |  | } ; | 
| 473 |  |  |  |  |  |  | } | 
| 474 |  |  |  |  |  |  | } | 
| 475 |  |  |  |  |  |  |  | 
| 476 | 0 |  |  |  |  |  | $total_dumped_data += $data_length ; | 
| 477 |  |  |  |  |  |  |  | 
| 478 | 0 |  |  |  |  |  | $line->{NEW_LINE} ++ ; | 
| 479 | 0 |  |  |  |  |  | push @lines, $line ; | 
| 480 | 0 |  |  |  |  |  | $line = {}; | 
| 481 |  |  |  |  |  |  |  | 
| 482 | 0 |  |  |  |  |  | next ; | 
| 483 |  |  |  |  |  |  | } | 
| 484 |  |  |  |  |  |  |  | 
| 485 | 0 |  |  |  |  |  | while ($dumped_data < $data_length) | 
| 486 |  |  |  |  |  |  | { | 
| 487 | 0 | 0 |  |  |  |  | last if($range->{IS_BITFIELD}) ; | 
| 488 |  |  |  |  |  |  |  | 
| 489 | 0 |  |  |  |  |  | my $left_offset = $total_dumped_data % $self->{DATA_WIDTH} ; | 
| 490 |  |  |  |  |  |  |  | 
| 491 | 0 | 0 |  |  |  |  | if($left_offset) | 
| 492 |  |  |  |  |  |  | { | 
| 493 |  |  |  |  |  |  | # previous range did not end on DATA_WIDTH offset, align | 
| 494 | 0 |  |  |  |  |  | local $range->{DATA} = '0' x $self->{DATA_WIDTH} ; | 
| 495 |  |  |  |  |  |  |  | 
| 496 | 0 |  |  |  |  |  | $self->_dump_range_vertical(0, $range, $line, 0, 0, $left_offset) ; | 
| 497 |  |  |  |  |  |  |  | 
| 498 | 0 |  |  |  |  |  | $room_left -= $left_offset ; | 
| 499 |  |  |  |  |  |  | } | 
| 500 |  |  |  |  |  |  |  | 
| 501 | 0 |  |  |  |  |  | my $size_to_dump = min($room_left, length($range->{DATA}) - $dumped_data) ; | 
| 502 | 0 |  |  |  |  |  | $room_left -= $size_to_dump ; | 
| 503 | 0 |  |  |  |  |  | $self->_dump_range_vertical(1, $range, $line, $dumped_data, $total_dumped_data, $size_to_dump) ; | 
| 504 |  |  |  |  |  |  |  | 
| 505 | 0 | 0 |  |  |  |  | if($room_left) | 
| 506 |  |  |  |  |  |  | { | 
| 507 | 0 |  |  |  |  |  | local $range->{DATA} = '0' x $self->{DATA_WIDTH} ; | 
| 508 |  |  |  |  |  |  |  | 
| 509 | 0 |  |  |  |  |  | $self->_dump_range_vertical(0, $range, $line, 0, 0, $room_left) ; | 
| 510 |  |  |  |  |  |  |  | 
| 511 | 0 |  |  |  |  |  | $room_left = 0 ; | 
| 512 |  |  |  |  |  |  | } | 
| 513 |  |  |  |  |  |  |  | 
| 514 | 0 |  |  |  |  |  | $dumped_data += $size_to_dump ; | 
| 515 | 0 |  |  |  |  |  | $total_dumped_data += $size_to_dump ; | 
| 516 |  |  |  |  |  |  |  | 
| 517 | 0 |  |  |  |  |  | $line->{NEW_LINE} ++ ; | 
| 518 | 0 |  |  |  |  |  | push @lines, $line ; | 
| 519 | 0 |  |  |  |  |  | $line = {}; | 
| 520 | 0 |  |  |  |  |  | $room_left = $self->{DATA_WIDTH} ; | 
| 521 |  |  |  |  |  |  | } | 
| 522 |  |  |  |  |  |  |  | 
| 523 | 0 | 0 |  |  |  |  | if($range->{IS_BITFIELD}) | 
| 524 |  |  |  |  |  |  | { | 
| 525 | 0 |  |  |  |  |  | push @lines, $self->get_bitfield_lines($range)  ; | 
| 526 |  |  |  |  |  |  | } | 
| 527 |  |  |  |  |  |  | else | 
| 528 |  |  |  |  |  |  | { | 
| 529 | 0 |  |  |  |  |  | $range_source = [$range->{NAME}, $range->{COLOR}]  ; | 
| 530 |  |  |  |  |  |  | } | 
| 531 |  |  |  |  |  |  | } | 
| 532 |  |  |  |  |  |  |  | 
| 533 | 0 | 0 |  |  |  |  | if(@found_bitfields) | 
| 534 |  |  |  |  |  |  | { | 
| 535 | 0 |  |  |  |  |  | push @lines,  @found_bitfields ; | 
| 536 | 0 |  |  |  |  |  | @found_bitfields = () ; | 
| 537 |  |  |  |  |  |  | } | 
| 538 |  |  |  |  |  |  |  | 
| 539 | 0 |  |  |  |  |  | return \@lines ; | 
| 540 |  |  |  |  |  |  | } | 
| 541 |  |  |  |  |  |  |  | 
| 542 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 543 |  |  |  |  |  |  |  | 
| 544 |  |  |  |  |  |  | sub _dump_range_horizontal | 
| 545 |  |  |  |  |  |  | { | 
| 546 |  |  |  |  |  |  | =head2 [P] _dump_range_horizontal(...) | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | Splits a range into a structure used for horizontal display | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | I - | 
| 551 |  |  |  |  |  |  |  | 
| 552 |  |  |  |  |  |  | =over 2 | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | =item * $self - | 
| 555 |  |  |  |  |  |  |  | 
| 556 |  |  |  |  |  |  | =item * $visible - Boolean - wether the range elements will be visible or not. used for alignment | 
| 557 |  |  |  |  |  |  |  | 
| 558 |  |  |  |  |  |  | =item * $range - the range structure created by Gather | 
| 559 |  |  |  |  |  |  |  | 
| 560 |  |  |  |  |  |  | =item * $line - container for the range strings to be displayed | 
| 561 |  |  |  |  |  |  |  | 
| 562 |  |  |  |  |  |  | =item * $last_range - Boolean - wether the range is the last one to be displayed | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  | =item * $total_dumped_data - Integer -  the amount of total data dumped so far | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | =item * $dumped_data - Integer - the amount of byte dumped from the range so far | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | =item *  $size_to_dump - Integer - the amount of data to extract from the range | 
| 569 |  |  |  |  |  |  |  | 
| 570 |  |  |  |  |  |  | =item * $room_left - Integer - the amount of space left in the line for the dimped data | 
| 571 |  |  |  |  |  |  |  | 
| 572 |  |  |  |  |  |  | =back | 
| 573 |  |  |  |  |  |  |  | 
| 574 |  |  |  |  |  |  | I -  Nothing. Stores the result in the $line argument | 
| 575 |  |  |  |  |  |  |  | 
| 576 |  |  |  |  |  |  | I | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | =cut | 
| 579 |  |  |  |  |  |  |  | 
| 580 | 0 |  |  | 0 |  |  | my ($self, $visible, $range, $line, $last_range, $total_dumped_data, $dumped_data, $size_to_dump, $room_left) = @_ ; | 
| 581 |  |  |  |  |  |  |  | 
| 582 | 0 |  |  |  |  |  | my @range_unpacked_data = unpack("x$dumped_data C$size_to_dump", $range->{DATA}) ; | 
| 583 | 0 |  |  |  |  |  | my $max_range_name_size = $self->{MAXIMUM_RANGE_NAME_SIZE} ; | 
| 584 |  |  |  |  |  |  |  | 
| 585 | 0 | 0 |  | 0 |  |  | for my  $field_type | 
|  | 0 |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | ( | 
| 587 | 0 | 0 |  | 0 |  |  | ['OFFSET', sub {exists $line->{OFFSET} ? '' : sprintf $self->{OFFSET_FORMAT}, $total_dumped_data}, $self->get_bg_color(), 0], | 
| 588 | 0 |  |  | 0 |  |  | ['BITFIELD_SOURCE', sub {exists $line->{BITFIELD_SOURCE} ? '' : ' ' x 8}, $self->get_bg_color(), 0], | 
| 589 | 0 |  |  | 0 |  |  | ['HEX_DUMP', sub {sprintf '%02x ' x $size_to_dump, @_}, $range->{COLOR}, 3], | 
| 590 | 0 | 0 |  |  |  |  | ['DEC_DUMP', sub {sprintf '%03u ' x $size_to_dump, @_}, $range->{COLOR}, 4], | 
| 591 | 0 | 0 |  | 0 |  |  | ['ASCII_DUMP', sub {sprintf '%c' x $size_to_dump, map{$_ < 30 ? ord('.') : $_ } @_}, $range->{COLOR}, 1], | 
|  | 0 |  |  |  |  |  |  | 
| 592 | 0 |  |  | 0 |  |  | ['HEXASCII_DUMP', sub {sprintf q~%02x/%c ~ x $size_to_dump, map{$_ < 30 ? ($_, ord('.')) : ($_, $_) } @_}, $range->{COLOR}, 5], | 
|  | 0 |  |  |  |  |  |  | 
| 593 | 0 |  |  | 0 |  |  | ['RANGE_NAME',sub {sprintf "%.${max_range_name_size}s", $range->{NAME}}, $range->{COLOR}, 0], | 
| 594 |  |  |  |  |  |  | ['RANGE_NAME', sub {', '}, undef, 0], | 
| 595 |  |  |  |  |  |  | ) | 
| 596 |  |  |  |  |  |  | { | 
| 597 | 0 |  |  |  |  |  | my ($field_name, $field_data_formater, $color, $pad_size) = @{$field_type} ; | 
|  | 0 |  |  |  |  |  |  | 
| 598 |  |  |  |  |  |  |  | 
| 599 | 0 | 0 |  |  |  |  | if($self->{"DISPLAY_$field_name"}) | 
| 600 |  |  |  |  |  |  | { | 
| 601 | 0 |  |  |  |  |  | my $field_text = $field_data_formater->(@range_unpacked_data) ; | 
| 602 |  |  |  |  |  |  |  | 
| 603 | 0 | 0 |  |  |  |  | my $pad = $last_range == $range ? $pad_size  ? ' ' x ($room_left * $pad_size) : '' : '' ; | 
|  |  | 0 |  |  |  |  |  | 
| 604 |  |  |  |  |  |  |  | 
| 605 | 0 |  |  |  |  |  | my $text = $field_text . $pad ; | 
| 606 |  |  |  |  |  |  |  | 
| 607 | 0 | 0 |  |  |  |  | unless($visible) | 
| 608 |  |  |  |  |  |  | { | 
| 609 | 0 | 0 | 0 |  |  |  | if($field_name eq 'ASCII_DUMP' || $field_name eq 'HEX_DUMP'  || $field_name eq 'HEXASCII_DUMP'  || $field_name eq 'DEC_DUMP' ) | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 610 |  |  |  |  |  |  | { | 
| 611 | 0 |  |  |  |  |  | $text = ' ' x length($text) | 
| 612 |  |  |  |  |  |  | } | 
| 613 |  |  |  |  |  |  | } | 
| 614 |  |  |  |  |  |  |  | 
| 615 | 0 |  |  |  |  |  | push @{$line->{$field_name}}, | 
|  | 0 |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  | { | 
| 617 |  |  |  |  |  |  | $field_name . '_COLOR' => $color, | 
| 618 |  |  |  |  |  |  | $field_name => $text | 
| 619 |  |  |  |  |  |  | } ; | 
| 620 |  |  |  |  |  |  | } | 
| 621 |  |  |  |  |  |  | } | 
| 622 |  |  |  |  |  |  | } | 
| 623 |  |  |  |  |  |  |  | 
| 624 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 625 |  |  |  |  |  |  |  | 
| 626 |  |  |  |  |  |  | sub _dump_range_vertical | 
| 627 |  |  |  |  |  |  | { | 
| 628 |  |  |  |  |  |  | =head2 [P] _dump_range_vertical() | 
| 629 |  |  |  |  |  |  |  | 
| 630 |  |  |  |  |  |  | Splits a range into a structure used for vertical display | 
| 631 |  |  |  |  |  |  |  | 
| 632 |  |  |  |  |  |  | I - | 
| 633 |  |  |  |  |  |  |  | 
| 634 |  |  |  |  |  |  | =over 2 | 
| 635 |  |  |  |  |  |  |  | 
| 636 |  |  |  |  |  |  | =item * $self - | 
| 637 |  |  |  |  |  |  |  | 
| 638 |  |  |  |  |  |  | =item * $visible - Boolean - wether the range elements will be visible or not. used for alignment | 
| 639 |  |  |  |  |  |  |  | 
| 640 |  |  |  |  |  |  | =item * $range - the range structure created by Gather | 
| 641 |  |  |  |  |  |  |  | 
| 642 |  |  |  |  |  |  | =item * $line - container for the range strings to be displayed | 
| 643 |  |  |  |  |  |  |  | 
| 644 |  |  |  |  |  |  | =item * $dumped_data - Integer - the amount of byte dumped from the range so far | 
| 645 |  |  |  |  |  |  |  | 
| 646 |  |  |  |  |  |  | =item * $total_dumped_data - Integer -  the amount of total data dumped so far | 
| 647 |  |  |  |  |  |  |  | 
| 648 |  |  |  |  |  |  | =item *  $size_to_dump - Integer - the amount of data to extract from the range | 
| 649 |  |  |  |  |  |  |  | 
| 650 |  |  |  |  |  |  | =back | 
| 651 |  |  |  |  |  |  |  | 
| 652 |  |  |  |  |  |  | I - | 
| 653 |  |  |  |  |  |  |  | 
| 654 |  |  |  |  |  |  | I | 
| 655 |  |  |  |  |  |  |  | 
| 656 |  |  |  |  |  |  | =cut | 
| 657 |  |  |  |  |  |  |  | 
| 658 | 0 |  |  | 0 |  |  | my ($self, $visible, $range, $line, $dumped_data, $total_dumped_data, $size_to_dump) = @_ ; | 
| 659 |  |  |  |  |  |  |  | 
| 660 | 0 |  |  |  |  |  | my @range_data = unpack("x$dumped_data C$size_to_dump", $range->{DATA}) ; | 
| 661 | 0 |  |  |  |  |  | my $max_range_name_size = $self->{MAXIMUM_RANGE_NAME_SIZE} ; | 
| 662 | 0 |  |  |  |  |  | my $user_information_size = $self->{MAXIMUM_USER_INFORMATION_SIZE} ; | 
| 663 |  |  |  |  |  |  |  | 
| 664 | 0 |  |  | 0 |  |  | for my  $field_type | 
|  | 0 |  |  |  |  |  |  | 
| 665 |  |  |  |  |  |  | ( | 
| 666 | 0 |  |  | 0 |  |  | ['RANGE_NAME',  sub {sprintf "%-${max_range_name_size}.${max_range_name_size}s", $range->{NAME} ; }, $range->{COLOR}, $max_range_name_size] , | 
| 667 | 0 | 0 |  | 0 |  |  | ['OFFSET', sub {sprintf $self->{OFFSET_FORMAT}, $total_dumped_data}, $self->get_bg_color(), 8], | 
| 668 | 0 |  |  | 0 |  |  | ['CUMULATIVE_OFFSET', sub {$dumped_data ? sprintf($self->{OFFSET_FORMAT}, $dumped_data) : ''}, $self->get_bg_color(), 8], | 
| 669 | 0 |  |  |  |  |  | ['BITFIELD_SOURCE', sub {'' x 8}, undef, 8], | 
| 670 | 0 | 0 |  | 0 |  |  | ['HEX_DUMP', sub {sprintf '%02x ' x $size_to_dump, @{$_[0]}}, $range->{COLOR}, 3 * $size_to_dump], | 
|  | 0 |  |  |  |  |  |  | 
| 671 | 0 |  |  | 0 |  |  | ['HEXASCII_DUMP', sub {sprintf q~%02x/%c ~ x $size_to_dump, map{$_ < 30 ? ($_, ord('.')) : ($_, $_) } @{ $_[0]}}, $range->{COLOR}, 5 * $size_to_dump], | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 672 | 0 | 0 |  | 0 |  |  | ['DEC_DUMP', sub {sprintf '%03u ' x $size_to_dump, @{ $_[0] }}, $range->{COLOR}, 4 * $size_to_dump], | 
|  | 0 |  |  |  |  |  |  | 
| 673 | 0 |  |  | 0 |  |  | ['ASCII_DUMP', sub {sprintf '%c' x $size_to_dump, map{$_ < 30 ? ord('.') : $_ } @{$_[0]}}, $range->{COLOR}, $size_to_dump], | 
|  | 0 |  |  |  |  |  |  | 
| 674 | 0 |  | 0 | 0 |  |  | ['USER_INFORMATION', sub { sprintf "%-${user_information_size}.${user_information_size}s", $range->{USER_INFORMATION} || ''}, $range->{COLOR}, $user_information_size], | 
| 675 |  |  |  |  |  |  | ) | 
| 676 |  |  |  |  |  |  | { | 
| 677 | 0 |  |  |  |  |  | my ($field_name, $field_data_formater, $color, $field_text_size) = @{$field_type} ; | 
|  | 0 |  |  |  |  |  |  | 
| 678 |  |  |  |  |  |  |  | 
| 679 | 0 | 0 |  |  |  |  | if($self->{"DISPLAY_$field_name"}) | 
| 680 |  |  |  |  |  |  | { | 
| 681 | 0 |  |  |  |  |  | my $field_text = $field_data_formater->(\@range_data) ; | 
| 682 | 0 |  |  |  |  |  | my $pad = ' ' x ($field_text_size -  length($field_text)) ; | 
| 683 |  |  |  |  |  |  |  | 
| 684 | 0 |  |  |  |  |  | my $text = $field_text .  $pad ; | 
| 685 |  |  |  |  |  |  |  | 
| 686 | 0 | 0 |  |  |  |  | unless($visible) | 
| 687 |  |  |  |  |  |  | { | 
| 688 | 0 | 0 | 0 |  |  |  | if($field_name eq 'ASCII_DUMP' || $field_name eq 'HEX_DUMP'  || $field_name eq 'DEC_DUMP'  || $field_name eq 'HEXASCII_DUMP' ) | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 689 |  |  |  |  |  |  | { | 
| 690 | 0 |  |  |  |  |  | $text = ' ' x length($text) ; | 
| 691 |  |  |  |  |  |  | } | 
| 692 |  |  |  |  |  |  | else | 
| 693 |  |  |  |  |  |  | { | 
| 694 | 0 |  |  |  |  |  | $text = '' ; | 
| 695 |  |  |  |  |  |  | } | 
| 696 |  |  |  |  |  |  | } | 
| 697 |  |  |  |  |  |  |  | 
| 698 | 0 |  |  |  |  |  | push @{$line->{$field_name}}, | 
|  | 0 |  |  |  |  |  |  | 
| 699 |  |  |  |  |  |  | { | 
| 700 |  |  |  |  |  |  | $field_name . '_COLOR' => $color, | 
| 701 |  |  |  |  |  |  | $field_name =>  $text, | 
| 702 |  |  |  |  |  |  | } ; | 
| 703 |  |  |  |  |  |  | } | 
| 704 |  |  |  |  |  |  | } | 
| 705 |  |  |  |  |  |  | } | 
| 706 |  |  |  |  |  |  |  | 
| 707 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 708 |  |  |  |  |  |  |  | 
| 709 |  |  |  |  |  |  | sub get_bitfield_lines | 
| 710 |  |  |  |  |  |  | { | 
| 711 |  |  |  |  |  |  |  | 
| 712 |  |  |  |  |  |  | =head2 [P] get_bitfield_lines($bitfield_description) | 
| 713 |  |  |  |  |  |  |  | 
| 714 |  |  |  |  |  |  | Split the collected data into lines | 
| 715 |  |  |  |  |  |  |  | 
| 716 |  |  |  |  |  |  | I - | 
| 717 |  |  |  |  |  |  |  | 
| 718 |  |  |  |  |  |  | =over 2 | 
| 719 |  |  |  |  |  |  |  | 
| 720 |  |  |  |  |  |  | =item * $self - a Data::HexDump::Range object | 
| 721 |  |  |  |  |  |  |  | 
| 722 |  |  |  |  |  |  | =item * $bitfield_description - | 
| 723 |  |  |  |  |  |  |  | 
| 724 |  |  |  |  |  |  | =back | 
| 725 |  |  |  |  |  |  |  | 
| 726 |  |  |  |  |  |  | I - An Array  containing column elements, | 
| 727 |  |  |  |  |  |  |  | 
| 728 |  |  |  |  |  |  | I None but will embed an error in the element if any is found | 
| 729 |  |  |  |  |  |  |  | 
| 730 |  |  |  |  |  |  | =cut | 
| 731 |  |  |  |  |  |  |  | 
| 732 | 0 |  |  | 0 | 0 |  | my ($self, $bitfield_description) = @_ ; | 
| 733 |  |  |  |  |  |  |  | 
| 734 |  |  |  |  |  |  | #~ use Data::TreeDumper ; | 
| 735 |  |  |  |  |  |  | #~ print DumpTree $bitfield_description, '$bitfield_description', QUOTE_VALUES => 1 ; | 
| 736 |  |  |  |  |  |  |  | 
| 737 | 0 | 0 |  |  |  |  | return unless $self->{DISPLAY_BITFIELDS} ; | 
| 738 |  |  |  |  |  |  |  | 
| 739 | 0 |  |  |  |  |  | my ($line, @lines) = ({}) ; | 
| 740 | 0 |  |  |  |  |  | my $digits_or_hex = '(?:(?:0x[0-9a-fA-F]+)|(?:\d+))' ; | 
| 741 |  |  |  |  |  |  |  | 
| 742 | 0 |  |  |  |  |  | my ($byte_offset, $offset, $size) = $bitfield_description->{IS_BITFIELD} =~ /^\s*(X$digits_or_hex)?\s*(x$digits_or_hex)?\s*(b$digits_or_hex)\s*$/ ; | 
| 743 |  |  |  |  |  |  |  | 
| 744 | 0 | 0 |  |  |  |  | if(defined $byte_offset) | 
| 745 |  |  |  |  |  |  | { | 
| 746 | 0 |  |  |  |  |  | substr($byte_offset, 0, 1, '')  ; | 
| 747 | 0 | 0 |  |  |  |  | $byte_offset = hex($byte_offset) if  $byte_offset=~ /^0x/ ; | 
| 748 |  |  |  |  |  |  | } | 
| 749 |  |  |  |  |  |  |  | 
| 750 | 0 | 0 |  |  |  |  | if(defined $offset) | 
| 751 |  |  |  |  |  |  | { | 
| 752 | 0 |  |  |  |  |  | substr($offset, 0, 1, '')  ; | 
| 753 | 0 | 0 |  |  |  |  | $offset = hex($offset) if  $offset=~ /^0x/ ; | 
| 754 |  |  |  |  |  |  | } | 
| 755 |  |  |  |  |  |  |  | 
| 756 | 0 | 0 |  |  |  |  | if(defined $size) | 
| 757 |  |  |  |  |  |  | { | 
| 758 | 0 |  |  |  |  |  | substr($size, 0, 1, '')  ; | 
| 759 | 0 | 0 |  |  |  |  | $size = hex($size) if  $size =~ /^0x/ ; | 
| 760 |  |  |  |  |  |  | } | 
| 761 |  |  |  |  |  |  |  | 
| 762 | 0 |  | 0 |  |  |  | $byte_offset ||= 0 ; | 
| 763 | 0 |  | 0 |  |  |  | $offset ||= 0 ; $offset += $byte_offset * 8 ; | 
|  | 0 |  |  |  |  |  |  | 
| 764 | 0 |  | 0 |  |  |  | $size ||= 1 ; | 
| 765 |  |  |  |  |  |  |  | 
| 766 | 0 |  |  |  |  |  | my $max_range_name_size = $self->{MAXIMUM_RANGE_NAME_SIZE} ; | 
| 767 | 0 |  |  |  |  |  | my $max_bitfield_source_size = $self->{MAXIMUM_BITFIELD_SOURCE_SIZE} ; | 
| 768 |  |  |  |  |  |  |  | 
| 769 | 0 |  |  |  |  |  | my %always_display_field = map {$_ => 1} qw(RANGE_NAME OFFSET CUMULATIVE_OFFSET BITFIELD_SOURCE USER_INFORMATION) ; | 
|  | 0 |  |  |  |  |  |  | 
| 770 | 0 |  |  |  |  |  | my $bitfield_warning_displayed = 0 ; | 
| 771 |  |  |  |  |  |  |  | 
| 772 |  |  |  |  |  |  | #~ print DumpTree {length => length($bitfield_description->{DATA}), offset => $offset, size => $size, BF => $bitfield_description} ; | 
| 773 |  |  |  |  |  |  | my $ascii_bitfield_dump_sub = | 
| 774 |  |  |  |  |  |  | sub | 
| 775 |  |  |  |  |  |  | { | 
| 776 | 0 |  |  | 0 |  |  | my ($binary, @binary , @chars) ; | 
| 777 |  |  |  |  |  |  |  | 
| 778 | 0 | 0 |  |  |  |  | if($self->{BIT_ZERO_ON_LEFT}) | 
| 779 |  |  |  |  |  |  | { | 
| 780 | 0 |  |  |  |  |  | @binary = split '', unpack("B*",  $_[0]->{DATA}) ; | 
| 781 | 0 |  |  |  |  |  | splice(@binary, 0, $offset) ; | 
| 782 | 0 |  |  |  |  |  | splice(@binary, $size) ; | 
| 783 |  |  |  |  |  |  | } | 
| 784 |  |  |  |  |  |  | else | 
| 785 |  |  |  |  |  |  | { | 
| 786 | 0 |  |  |  |  |  | @binary = split '', unpack("B*",  $_[0]->{DATA}) ; | 
| 787 | 0 | 0 |  |  |  |  | splice(@binary, -$offset) unless $offset == 0 ; | 
| 788 | 0 |  |  |  |  |  | @binary = splice(@binary, - $size) ; | 
| 789 |  |  |  |  |  |  | } | 
| 790 |  |  |  |  |  |  |  | 
| 791 | 0 |  |  |  |  |  | $binary = join('', @binary) ; | 
| 792 | 0 | 0 |  |  |  |  | @chars = map{$_ < 30 ? '.' : chr($_) } unpack("C*", pack("B32", substr("0" x 32 . $binary, -32))); | 
|  | 0 |  |  |  |  |  |  | 
| 793 |  |  |  |  |  |  |  | 
| 794 | 0 | 0 |  |  |  |  | my $number_of_bytes = @binary > 24 ? 4 : @binary > 16 ? 3 : @binary > 8 ? 2 : 1 ; | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 795 | 0 |  |  |  |  |  | splice @chars, 0 , (4 - $number_of_bytes), map {'-'} 1 .. (4 - $number_of_bytes) ; | 
|  | 0 |  |  |  |  |  |  | 
| 796 |  |  |  |  |  |  |  | 
| 797 | 0 |  |  |  |  |  | '.bitfield: '.  join('',  @chars) | 
| 798 | 0 |  |  |  |  |  | } ; | 
| 799 |  |  |  |  |  |  |  | 
| 800 | 0 |  |  | 0 |  |  | for my  $field_type | 
|  | 0 |  |  |  |  |  |  | 
| 801 |  |  |  |  |  |  | ( | 
| 802 | 0 |  |  | 0 |  |  | ['RANGE_NAME',  sub {sprintf "%-${max_range_name_size}.${max_range_name_size}s", '.' . $_[0]->{NAME} ; }, undef, $max_range_name_size ] , | 
| 803 | 0 |  |  | 0 |  |  | ['OFFSET', sub {sprintf '%02u .. %02u', $offset, ($offset + $size) - 1}, undef, 8], | 
| 804 | 0 |  |  | 0 |  |  | ['CUMULATIVE_OFFSET', sub {''}, undef, 8], | 
| 805 |  |  |  |  |  |  | ['BITFIELD_SOURCE', sub {sprintf "%-${max_bitfield_source_size}.${max_bitfield_source_size}s", $_[0]->{SOURCE}[0]}, $bitfield_description->{SOURCE}[1], 8], | 
| 806 |  |  |  |  |  |  | ['HEX_DUMP', | 
| 807 |  |  |  |  |  |  | sub | 
| 808 |  |  |  |  |  |  | { | 
| 809 | 0 |  |  | 0 |  |  | my ($binary, @binary , $binary_dashed) ; | 
| 810 |  |  |  |  |  |  |  | 
| 811 | 0 | 0 |  |  |  |  | if($self->{BIT_ZERO_ON_LEFT}) | 
| 812 |  |  |  |  |  |  | { | 
| 813 | 0 |  |  |  |  |  | @binary = split '', unpack("B*",  $_[0]->{DATA}) ; | 
| 814 | 0 |  |  |  |  |  | splice(@binary, 0, $offset) ; | 
| 815 | 0 |  |  |  |  |  | splice(@binary, $size) ; | 
| 816 |  |  |  |  |  |  |  | 
| 817 | 0 |  |  |  |  |  | $binary = join('', @binary) ; | 
| 818 |  |  |  |  |  |  |  | 
| 819 | 0 |  |  |  |  |  | $binary_dashed = '-' x $offset . $binary . '-' x (32 - ($size + $offset)) ; | 
| 820 | 0 |  |  |  |  |  | $binary_dashed  = substr($binary_dashed , -32) ; | 
| 821 | 0 |  |  |  |  |  | $binary_dashed = substr($binary_dashed, 0, 8) . ' ' . substr($binary_dashed, 8, 8) . ' ' .substr($binary_dashed, 16, 8) . ' ' .substr($binary_dashed, 24, 8) ; | 
| 822 |  |  |  |  |  |  | } | 
| 823 |  |  |  |  |  |  | else | 
| 824 |  |  |  |  |  |  | { | 
| 825 | 0 |  |  |  |  |  | @binary = split '', unpack("B*",  $_[0]->{DATA}) ; | 
| 826 | 0 | 0 |  |  |  |  | splice(@binary, -$offset) unless $offset == 0 ; | 
| 827 | 0 |  |  |  |  |  | @binary = splice(@binary, - $size) ; | 
| 828 |  |  |  |  |  |  |  | 
| 829 | 0 |  |  |  |  |  | $binary = join('',  @binary) ; | 
| 830 |  |  |  |  |  |  |  | 
| 831 | 0 |  |  |  |  |  | $binary_dashed = '-' x (32 - ($size + $offset)) . $binary . '-' x $offset  ; | 
| 832 | 0 |  |  |  |  |  | $binary_dashed  = substr($binary_dashed , 0, 32) ; | 
| 833 | 0 |  |  |  |  |  | $binary_dashed = substr($binary_dashed, 0, 8) . ' ' . substr($binary_dashed, 8, 8) . ' ' .substr($binary_dashed, 16, 8) . ' ' .substr($binary_dashed, 24, 8) ; | 
| 834 |  |  |  |  |  |  | } | 
| 835 |  |  |  |  |  |  |  | 
| 836 | 0 | 0 |  |  |  |  | my $bytes = $size > 24 ? 4 : $size > 16 ? 3 : $size > 8 ? 2 : 1 ; | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 837 |  |  |  |  |  |  |  | 
| 838 | 0 |  |  |  |  |  | my @bytes = unpack("(H2)*", pack("B32", substr("0" x 32 . $binary, -32))); | 
| 839 |  |  |  |  |  |  |  | 
| 840 | 0 | 0 |  |  |  |  | my $number_of_bytes = @binary > 24 ? 4 : @binary > 16 ? 3 : @binary > 8 ? 2 : 1 ; | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 841 | 0 |  |  |  |  |  | splice @bytes, 0 , (4 - $number_of_bytes), map {'--'} 1 .. (4 - $number_of_bytes) ; | 
|  | 0 |  |  |  |  |  |  | 
| 842 |  |  |  |  |  |  |  | 
| 843 | 0 |  |  |  |  |  | join(' ', @bytes) . ' ' . $binary_dashed; | 
| 844 |  |  |  |  |  |  | }, | 
| 845 |  |  |  |  |  |  |  | 
| 846 |  |  |  |  |  |  | undef, 3 * $self->{DATA_WIDTH}], | 
| 847 |  |  |  |  |  |  | ['HEXASCII_DUMP', | 
| 848 |  |  |  |  |  |  | sub | 
| 849 |  |  |  |  |  |  | { | 
| 850 | 0 |  |  | 0 |  |  | my $ascii_bitfield_dump = $ascii_bitfield_dump_sub->(@_) ; | 
| 851 |  |  |  |  |  |  |  | 
| 852 |  |  |  |  |  |  |  | 
| 853 | 0 |  |  |  |  |  | my ($binary, @binary , $binary_dashed) ; | 
| 854 |  |  |  |  |  |  |  | 
| 855 | 0 | 0 |  |  |  |  | if($self->{BIT_ZERO_ON_LEFT}) | 
| 856 |  |  |  |  |  |  | { | 
| 857 | 0 |  |  |  |  |  | @binary = split '', unpack("B*",  $_[0]->{DATA}) ; | 
| 858 | 0 |  |  |  |  |  | splice(@binary, 0, $offset) ; | 
| 859 | 0 |  |  |  |  |  | splice(@binary, $size) ; | 
| 860 |  |  |  |  |  |  |  | 
| 861 | 0 |  |  |  |  |  | $binary = join('', @binary) ; | 
| 862 |  |  |  |  |  |  |  | 
| 863 | 0 |  |  |  |  |  | $binary_dashed = '-' x $offset . $binary . '-' x (32 - ($size + $offset)) ; | 
| 864 | 0 |  |  |  |  |  | $binary_dashed  = substr($binary_dashed , -32) ; | 
| 865 | 0 |  |  |  |  |  | $binary_dashed = substr($binary_dashed, 0, 8) . ' ' . substr($binary_dashed, 8, 8) . ' ' .substr($binary_dashed, 16, 8) . ' ' .substr($binary_dashed, 24, 8) ; | 
| 866 |  |  |  |  |  |  | } | 
| 867 |  |  |  |  |  |  | else | 
| 868 |  |  |  |  |  |  | { | 
| 869 | 0 |  |  |  |  |  | @binary = split '', unpack("B*",  $_[0]->{DATA}) ; | 
| 870 | 0 | 0 |  |  |  |  | splice(@binary, -$offset) unless $offset == 0 ; | 
| 871 | 0 |  |  |  |  |  | @binary = splice(@binary, - $size) ; | 
| 872 |  |  |  |  |  |  |  | 
| 873 | 0 |  |  |  |  |  | $binary = join('',  @binary) ; | 
| 874 |  |  |  |  |  |  |  | 
| 875 | 0 |  |  |  |  |  | $binary_dashed = '-' x (32 - ($size + $offset)) . $binary . '-' x $offset  ; | 
| 876 | 0 |  |  |  |  |  | $binary_dashed  = substr($binary_dashed , 0, 32) ; | 
| 877 | 0 |  |  |  |  |  | $binary_dashed = substr($binary_dashed, 0, 8) . ' ' . substr($binary_dashed, 8, 8) . ' ' .substr($binary_dashed, 16, 8) . ' ' .substr($binary_dashed, 24, 8) ; | 
| 878 |  |  |  |  |  |  | } | 
| 879 |  |  |  |  |  |  |  | 
| 880 | 0 | 0 |  |  |  |  | my $bytes = $size > 24 ? 4 : $size > 16 ? 3 : $size > 8 ? 2 : 1 ; | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 881 |  |  |  |  |  |  |  | 
| 882 | 0 |  |  |  |  |  | my @bytes = unpack("(H2)*", pack("B32", substr("0" x 32 . $binary, -32))); | 
| 883 |  |  |  |  |  |  |  | 
| 884 | 0 | 0 |  |  |  |  | my $number_of_bytes = @binary > 24 ? 4 : @binary > 16 ? 3 : @binary > 8 ? 2 : 1 ; | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 885 | 0 |  |  |  |  |  | splice @bytes, 0 , (4 - $number_of_bytes), map {'--'} 1 .. (4 - $number_of_bytes) ; | 
|  | 0 |  |  |  |  |  |  | 
| 886 |  |  |  |  |  |  |  | 
| 887 | 0 |  |  |  |  |  | join(' ', @bytes) . '    ' . $binary_dashed . '     ' . $ascii_bitfield_dump ; | 
| 888 |  |  |  |  |  |  |  | 
| 889 |  |  |  |  |  |  |  | 
| 890 |  |  |  |  |  |  | }, | 
| 891 |  |  |  |  |  |  |  | 
| 892 |  |  |  |  |  |  | undef, 5 * $self->{DATA_WIDTH}], | 
| 893 |  |  |  |  |  |  | ['DEC_DUMP', | 
| 894 |  |  |  |  |  |  | sub | 
| 895 |  |  |  |  |  |  | { | 
| 896 | 0 |  |  | 0 |  |  | my ($binary, @binary , $value) ; | 
| 897 |  |  |  |  |  |  |  | 
| 898 | 0 | 0 |  |  |  |  | if($self->{BIT_ZERO_ON_LEFT}) | 
| 899 |  |  |  |  |  |  | { | 
| 900 | 0 |  |  |  |  |  | @binary = split '', unpack("B*",  $_[0]->{DATA}) ; | 
| 901 | 0 |  |  |  |  |  | splice(@binary, 0, $offset) ; | 
| 902 | 0 |  |  |  |  |  | splice(@binary, $size) ; | 
| 903 | 0 |  |  |  |  |  | $binary = join('', @binary) ; | 
| 904 | 0 |  |  |  |  |  | $value = unpack("N", pack("B32", substr("0" x 32 . $binary, -32))); | 
| 905 |  |  |  |  |  |  | } | 
| 906 |  |  |  |  |  |  | else | 
| 907 |  |  |  |  |  |  | { | 
| 908 | 0 |  |  |  |  |  | @binary = split '', unpack("B*",  $_[0]->{DATA}) ; | 
| 909 | 0 | 0 |  |  |  |  | splice(@binary, -$offset) unless $offset == 0 ; | 
| 910 | 0 |  |  |  |  |  | @binary = splice(@binary, - $size) ; | 
| 911 | 0 |  |  |  |  |  | $binary = join('', @binary) ; | 
| 912 | 0 |  |  |  |  |  | $value = unpack("N", pack("B32", substr("0" x 32 . $binary, -32))); | 
| 913 |  |  |  |  |  |  | } | 
| 914 |  |  |  |  |  |  |  | 
| 915 | 0 |  |  |  |  |  | my @values = map {sprintf '%03u', $_} unpack("W*", pack("B32", substr("0" x 32 . $binary, -32))); | 
|  | 0 |  |  |  |  |  |  | 
| 916 |  |  |  |  |  |  |  | 
| 917 | 0 | 0 |  |  |  |  | my $number_of_bytes = @binary > 24 ? 4 : @binary > 16 ? 3 : @binary > 8 ? 2 : 1 ; | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 918 | 0 |  |  |  |  |  | splice @values, 0 , (4 - $number_of_bytes), map {'---'} 1 .. (4 - $number_of_bytes) ; | 
|  | 0 |  |  |  |  |  |  | 
| 919 |  |  |  |  |  |  |  | 
| 920 | 0 |  |  |  |  |  | join(' ',  @values) . ' ' . "value: $value"  ; | 
| 921 |  |  |  |  |  |  | }, | 
| 922 |  |  |  |  |  |  |  | 
| 923 |  |  |  |  |  |  | $bitfield_description->{COLOR}, 4 * $self->{DATA_WIDTH}], | 
| 924 |  |  |  |  |  |  |  | 
| 925 |  |  |  |  |  |  | ['ASCII_DUMP', | 
| 926 |  |  |  |  |  |  | $ascii_bitfield_dump_sub, | 
| 927 |  |  |  |  |  |  | undef, $self->{DATA_WIDTH}], | 
| 928 |  |  |  |  |  |  |  | 
| 929 |  |  |  |  |  |  | ['USER_INFORMATION', | 
| 930 | 0 |  | 0 | 0 |  |  | sub { sprintf '%-20.20s', $_[0]->{USER_INFORMATION} || ''}, | 
| 931 |  |  |  |  |  |  | $bitfield_description->{COLOR}, 20], | 
| 932 |  |  |  |  |  |  |  | 
| 933 |  |  |  |  |  |  | ) | 
| 934 |  |  |  |  |  |  | { | 
| 935 | 0 |  |  |  |  |  | my ($field_name, $field_data_formater, $color, $field_text_size) = @{$field_type} ; | 
|  | 0 |  |  |  |  |  |  | 
| 936 |  |  |  |  |  |  |  | 
| 937 |  |  |  |  |  |  | #~ print "($field_name, $field_data_formater, $color, $field_text_size)\n"; | 
| 938 | 0 |  | 0 |  |  |  | $color ||= $bitfield_description->{COLOR} ; | 
| 939 |  |  |  |  |  |  |  | 
| 940 | 0 | 0 |  |  |  |  | if($self->{"DISPLAY_$field_name"}) | 
| 941 |  |  |  |  |  |  | { | 
| 942 | 0 |  |  |  |  |  | my ($bitfield_error, $field_text) = (0) ; | 
| 943 |  |  |  |  |  |  |  | 
| 944 | 0 | 0 |  |  |  |  | if($always_display_field{$field_name}) | 
| 945 |  |  |  |  |  |  | { | 
| 946 | 0 |  |  |  |  |  | $field_text = $field_data_formater->($bitfield_description) ; | 
| 947 |  |  |  |  |  |  | } | 
| 948 |  |  |  |  |  |  | else | 
| 949 |  |  |  |  |  |  | { | 
| 950 | 0 | 0 |  |  |  |  | if($size > 32) | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 951 |  |  |  |  |  |  | { | 
| 952 | 0 | 0 |  |  |  |  | $self->{INTERACTION}{WARN} | 
| 953 |  |  |  |  |  |  | ( | 
| 954 |  |  |  |  |  |  | "Warning: bitfield description '$bitfield_description->{NAME}' is more than 32 bits long ($size)\n" | 
| 955 |  |  |  |  |  |  | )  unless $bitfield_warning_displayed++ ; | 
| 956 |  |  |  |  |  |  |  | 
| 957 | 0 |  |  |  |  |  | $field_text = sprintf("%.${field_text_size}s", "Error: bitfield is more than 32 bits long ($size)") ; | 
| 958 |  |  |  |  |  |  | } | 
| 959 |  |  |  |  |  |  | elsif($EMPTY_STRING eq $bitfield_description->{DATA}) | 
| 960 |  |  |  |  |  |  | { | 
| 961 | 0 | 0 |  |  |  |  | $self->{INTERACTION}{WARN} | 
| 962 |  |  |  |  |  |  | ( | 
| 963 |  |  |  |  |  |  | "Warning: bitfield description '$bitfield_description->{NAME}' can't be applied to empty source\n" | 
| 964 |  |  |  |  |  |  | )  unless $bitfield_warning_displayed++ ; | 
| 965 |  |  |  |  |  |  |  | 
| 966 | 0 |  |  |  |  |  | $field_text = sprintf("%.${field_text_size}s", "Error: Empty source") ; | 
| 967 |  |  |  |  |  |  | } | 
| 968 |  |  |  |  |  |  | elsif(length($bitfield_description->{DATA}) * 8 < ($offset + $size)) | 
| 969 |  |  |  |  |  |  | { | 
| 970 | 0 |  |  |  |  |  | my $bits_missing_message = ($offset + $size) . " bits needed but only " . length($bitfield_description->{DATA}) * 8 . ' bits available' ; | 
| 971 |  |  |  |  |  |  |  | 
| 972 | 0 | 0 |  |  |  |  | $self->{INTERACTION}{WARN} | 
| 973 |  |  |  |  |  |  | ( | 
| 974 |  |  |  |  |  |  | "Warning: bitfield description '$bitfield_description->{NAME}' can't be applied " | 
| 975 |  |  |  |  |  |  | . "to source '$bitfield_description->{SOURCE}[0]':\n" | 
| 976 |  |  |  |  |  |  | . "\t$bits_missing_message\n" | 
| 977 |  |  |  |  |  |  | )  unless $bitfield_warning_displayed++ ; | 
| 978 |  |  |  |  |  |  |  | 
| 979 | 0 |  |  |  |  |  | $field_text = sprintf("%.${field_text_size}s", 'Error: ' . $bits_missing_message) ; | 
| 980 |  |  |  |  |  |  | } | 
| 981 |  |  |  |  |  |  | else | 
| 982 |  |  |  |  |  |  | { | 
| 983 | 0 |  |  |  |  |  | $field_text = $field_data_formater->($bitfield_description) ; | 
| 984 |  |  |  |  |  |  | } | 
| 985 |  |  |  |  |  |  | } | 
| 986 |  |  |  |  |  |  |  | 
| 987 | 0 |  |  |  |  |  | my $pad_size = $field_text_size -  length($field_text) ; | 
| 988 | 0 |  |  |  |  |  | push @{$line->{$field_name}}, | 
|  | 0 |  |  |  |  |  |  | 
| 989 |  |  |  |  |  |  | { | 
| 990 |  |  |  |  |  |  | $field_name . '_COLOR' => $color, | 
| 991 |  |  |  |  |  |  | $field_name =>  $field_text . ' ' x $pad_size, | 
| 992 |  |  |  |  |  |  | } ; | 
| 993 |  |  |  |  |  |  | } | 
| 994 |  |  |  |  |  |  | } | 
| 995 |  |  |  |  |  |  |  | 
| 996 | 0 |  |  |  |  |  | $line->{NEW_LINE} ++ ; | 
| 997 | 0 |  |  |  |  |  | push @lines, $line ; | 
| 998 |  |  |  |  |  |  |  | 
| 999 | 0 |  |  |  |  |  | return @lines ; | 
| 1000 |  |  |  |  |  |  | } | 
| 1001 |  |  |  |  |  |  |  | 
| 1002 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 1003 |  |  |  |  |  |  |  | 
| 1004 |  |  |  |  |  |  | sub add_information | 
| 1005 |  |  |  |  |  |  | { | 
| 1006 |  |  |  |  |  |  |  | 
| 1007 |  |  |  |  |  |  | =head2 [P] add_information($split_data) | 
| 1008 |  |  |  |  |  |  |  | 
| 1009 |  |  |  |  |  |  | Add information, according to the options passed to the constructor, to the internal data. | 
| 1010 |  |  |  |  |  |  |  | 
| 1011 |  |  |  |  |  |  | I - See L | 
| 1012 |  |  |  |  |  |  |  | 
| 1013 |  |  |  |  |  |  | =over 2 | 
| 1014 |  |  |  |  |  |  |  | 
| 1015 |  |  |  |  |  |  | =item * $split_data - data returned by _gather() | 
| 1016 |  |  |  |  |  |  |  | 
| 1017 |  |  |  |  |  |  | =back | 
| 1018 |  |  |  |  |  |  |  | 
| 1019 |  |  |  |  |  |  | I - Nothing | 
| 1020 |  |  |  |  |  |  |  | 
| 1021 |  |  |  |  |  |  | I - None | 
| 1022 |  |  |  |  |  |  |  | 
| 1023 |  |  |  |  |  |  | =cut | 
| 1024 |  |  |  |  |  |  |  | 
| 1025 | 0 |  |  | 0 | 0 |  | my ($self, $split_data) = @_ ; | 
| 1026 |  |  |  |  |  |  |  | 
| 1027 | 0 |  |  |  |  |  | unshift @{$split_data}, $self->get_information($split_data) ; | 
|  | 0 |  |  |  |  |  |  | 
| 1028 |  |  |  |  |  |  |  | 
| 1029 |  |  |  |  |  |  | } | 
| 1030 |  |  |  |  |  |  |  | 
| 1031 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 1032 |  |  |  |  |  |  |  | 
| 1033 |  |  |  |  |  |  | sub get_information | 
| 1034 |  |  |  |  |  |  | { | 
| 1035 |  |  |  |  |  |  |  | 
| 1036 |  |  |  |  |  |  | =head2 [P] get_information($split_data) | 
| 1037 |  |  |  |  |  |  |  | 
| 1038 |  |  |  |  |  |  | Returns information, according to the options passed to the constructor, to the internal data. | 
| 1039 |  |  |  |  |  |  |  | 
| 1040 |  |  |  |  |  |  | I - See L | 
| 1041 |  |  |  |  |  |  |  | 
| 1042 |  |  |  |  |  |  | =over 2 | 
| 1043 |  |  |  |  |  |  |  | 
| 1044 |  |  |  |  |  |  | =item * $split_data - data returned by _gather() | 
| 1045 |  |  |  |  |  |  |  | 
| 1046 |  |  |  |  |  |  | =back | 
| 1047 |  |  |  |  |  |  |  | 
| 1048 |  |  |  |  |  |  | I - Nothing | 
| 1049 |  |  |  |  |  |  |  | 
| 1050 |  |  |  |  |  |  | I - None | 
| 1051 |  |  |  |  |  |  |  | 
| 1052 |  |  |  |  |  |  | =cut | 
| 1053 |  |  |  |  |  |  |  | 
| 1054 | 0 |  |  | 0 | 0 |  | my ($self, $split_data, $range_color) = @_ ; | 
| 1055 | 0 |  | 0 |  |  |  | $range_color ||= '' , | 
| 1056 |  |  |  |  |  |  |  | 
| 1057 |  |  |  |  |  |  | my @information ; | 
| 1058 |  |  |  |  |  |  |  | 
| 1059 | 0 | 0 |  |  |  |  | if($self->{DISPLAY_COLUMN_NAMES}) | 
| 1060 |  |  |  |  |  |  | { | 
| 1061 | 0 |  |  |  |  |  | my $information = '' ; | 
| 1062 |  |  |  |  |  |  |  | 
| 1063 | 0 |  |  |  |  |  | for my $field_name (@{$self->{FIELDS_TO_DISPLAY}}) | 
|  | 0 |  |  |  |  |  |  | 
| 1064 |  |  |  |  |  |  | { | 
| 1065 | 0 | 0 |  |  |  |  | if(exists $split_data->[0]{$field_name}) | 
| 1066 |  |  |  |  |  |  | { | 
| 1067 | 0 |  | 0 |  |  |  | my $length = $self->{FIELD_LENGTH}{$field_name} || croak "Error: undefined field length" ; | 
| 1068 |  |  |  |  |  |  |  | 
| 1069 | 0 |  |  |  |  |  | $information .= sprintf "%-${length}.${length}s ", $field_name | 
| 1070 |  |  |  |  |  |  | } | 
| 1071 |  |  |  |  |  |  | } | 
| 1072 |  |  |  |  |  |  |  | 
| 1073 | 0 |  |  |  |  |  | push @information, | 
| 1074 |  |  |  |  |  |  | { | 
| 1075 |  |  |  |  |  |  | INFORMATION => [ {INFORMATION_COLOR => $range_color, INFORMATION => $information} ], | 
| 1076 |  |  |  |  |  |  | NEW_LINE => 1, | 
| 1077 |  |  |  |  |  |  | } ; | 
| 1078 |  |  |  |  |  |  | } | 
| 1079 |  |  |  |  |  |  |  | 
| 1080 | 0 | 0 |  |  |  |  | if($self->{DISPLAY_RULER}) | 
| 1081 |  |  |  |  |  |  | { | 
| 1082 | 0 |  |  |  |  |  | my $information = '' ; | 
| 1083 |  |  |  |  |  |  |  | 
| 1084 | 0 |  |  |  |  |  | for my $field_name (@{$self->{FIELDS_TO_DISPLAY}}) | 
|  | 0 |  |  |  |  |  |  | 
| 1085 |  |  |  |  |  |  | { | 
| 1086 | 0 | 0 |  |  |  |  | if(exists $split_data->[0]{$field_name}) | 
| 1087 |  |  |  |  |  |  | { | 
| 1088 | 0 |  |  |  |  |  | for ($field_name) | 
| 1089 |  |  |  |  |  |  | { | 
| 1090 |  |  |  |  |  |  | /HEX_DUMP/ and do | 
| 1091 | 0 | 0 |  |  |  |  | { | 
| 1092 | 0 |  |  |  |  |  | $information .= $self->{OFFSET_FORMAT} =~ /x$/ | 
| 1093 | 0 |  |  |  |  |  | ? join '', map {sprintf '%x  ' , $ _ % 16} (0 .. $self->{DATA_WIDTH} - 1) | 
| 1094 | 0 | 0 |  |  |  |  | : join '', map {sprintf '%d  ' , $ _ % 10} (0 .. $self->{DATA_WIDTH} - 1) ; | 
| 1095 |  |  |  |  |  |  |  | 
| 1096 | 0 |  |  |  |  |  | $information .= ' ' ; | 
| 1097 | 0 |  |  |  |  |  | last ; | 
| 1098 |  |  |  |  |  |  | } ; | 
| 1099 |  |  |  |  |  |  |  | 
| 1100 |  |  |  |  |  |  | /DEC_DUMP/ and do | 
| 1101 | 0 | 0 |  |  |  |  | { | 
| 1102 | 0 |  |  |  |  |  | $information .= $self->{OFFSET_FORMAT} =~ /x$/ | 
| 1103 | 0 |  |  |  |  |  | ? join '', map {sprintf '%x   ' , $ _ % 16} (0 .. $self->{DATA_WIDTH} - 1) | 
| 1104 | 0 | 0 |  |  |  |  | : join '', map {sprintf '%d   ' , $ _ % 10} (0 .. $self->{DATA_WIDTH} - 1) ; | 
| 1105 |  |  |  |  |  |  |  | 
| 1106 | 0 |  |  |  |  |  | $information .= ' ' ; | 
| 1107 | 0 |  |  |  |  |  | last ; | 
| 1108 |  |  |  |  |  |  | } ; | 
| 1109 |  |  |  |  |  |  |  | 
| 1110 |  |  |  |  |  |  | /HEXASCII_DUMP/ and do | 
| 1111 | 0 | 0 |  |  |  |  | { | 
| 1112 | 0 |  |  |  |  |  | $information .= $self->{OFFSET_FORMAT} =~ /x$/ | 
| 1113 | 0 |  |  |  |  |  | ? join '', map {sprintf '%x    ' , $ _ % 16} (0 .. $self->{DATA_WIDTH} - 1) | 
| 1114 | 0 | 0 |  |  |  |  | : join '', map {sprintf '%d    ' , $ _ % 10} (0 .. $self->{DATA_WIDTH} - 1) ; | 
| 1115 | 0 |  |  |  |  |  | $information .= ' ' ; | 
| 1116 | 0 |  |  |  |  |  | last ; | 
| 1117 |  |  |  |  |  |  | } ; | 
| 1118 |  |  |  |  |  |  |  | 
| 1119 |  |  |  |  |  |  | /ASCII_DUMP/ and do | 
| 1120 | 0 | 0 |  |  |  |  | { | 
| 1121 | 0 |  |  |  |  |  | $information .= $self->{OFFSET_FORMAT} =~ /x$/ | 
| 1122 | 0 |  |  |  |  |  | ? join '', map {sprintf '%x', $ _ % 16} (0 .. $self->{DATA_WIDTH} - 1) | 
| 1123 | 0 | 0 |  |  |  |  | : join '', map {$ _ % 10} (0 .. $self->{DATA_WIDTH} - 1) ; | 
| 1124 | 0 |  |  |  |  |  | $information .= ' ' ; | 
| 1125 | 0 |  |  |  |  |  | last ; | 
| 1126 |  |  |  |  |  |  | } ; | 
| 1127 |  |  |  |  |  |  |  | 
| 1128 | 0 |  |  |  |  |  | $information .= ' ' x $self->{FIELD_LENGTH}{$field_name}  . ' ' ; | 
| 1129 |  |  |  |  |  |  | } | 
| 1130 |  |  |  |  |  |  | } | 
| 1131 |  |  |  |  |  |  | } | 
| 1132 |  |  |  |  |  |  |  | 
| 1133 | 0 |  |  |  |  |  | push @information, | 
| 1134 |  |  |  |  |  |  | { | 
| 1135 |  |  |  |  |  |  | RULER => [ { RULER_COLOR => $range_color, RULER=> $information} ], | 
| 1136 |  |  |  |  |  |  | NEW_LINE => 1, | 
| 1137 |  |  |  |  |  |  | } ; | 
| 1138 |  |  |  |  |  |  | } | 
| 1139 |  |  |  |  |  |  |  | 
| 1140 | 0 |  |  |  |  |  | return @information ; | 
| 1141 |  |  |  |  |  |  | } | 
| 1142 |  |  |  |  |  |  |  | 
| 1143 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 1144 |  |  |  |  |  |  |  | 
| 1145 |  |  |  |  |  |  | 1 ; | 
| 1146 |  |  |  |  |  |  |  | 
| 1147 |  |  |  |  |  |  | =head1 BUGS AND LIMITATIONS | 
| 1148 |  |  |  |  |  |  |  | 
| 1149 |  |  |  |  |  |  | None so far. | 
| 1150 |  |  |  |  |  |  |  | 
| 1151 |  |  |  |  |  |  | =head1 AUTHOR | 
| 1152 |  |  |  |  |  |  |  | 
| 1153 |  |  |  |  |  |  | Nadim ibn hamouda el Khemir | 
| 1154 |  |  |  |  |  |  | CPAN ID: NKH | 
| 1155 |  |  |  |  |  |  | mailto: nadim@cpan.org | 
| 1156 |  |  |  |  |  |  |  | 
| 1157 |  |  |  |  |  |  | =head1 COPYRIGHT AND LICENSE | 
| 1158 |  |  |  |  |  |  |  | 
| 1159 |  |  |  |  |  |  | Copyright Nadim Khemir 2010. | 
| 1160 |  |  |  |  |  |  |  | 
| 1161 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or | 
| 1162 |  |  |  |  |  |  | modify it under the terms of either: | 
| 1163 |  |  |  |  |  |  |  | 
| 1164 |  |  |  |  |  |  | =over 4 | 
| 1165 |  |  |  |  |  |  |  | 
| 1166 |  |  |  |  |  |  | =item * the GNU General Public License as published by the Free | 
| 1167 |  |  |  |  |  |  | Software Foundation; either version 1, or (at your option) any | 
| 1168 |  |  |  |  |  |  | later version, or | 
| 1169 |  |  |  |  |  |  |  | 
| 1170 |  |  |  |  |  |  | =item * the Artistic License version 2.0. | 
| 1171 |  |  |  |  |  |  |  | 
| 1172 |  |  |  |  |  |  | =back | 
| 1173 |  |  |  |  |  |  |  | 
| 1174 |  |  |  |  |  |  | =head1 SUPPORT | 
| 1175 |  |  |  |  |  |  |  | 
| 1176 |  |  |  |  |  |  | You can find documentation for this module with the perldoc command. | 
| 1177 |  |  |  |  |  |  |  | 
| 1178 |  |  |  |  |  |  | perldoc Data::HexDump::Range | 
| 1179 |  |  |  |  |  |  |  | 
| 1180 |  |  |  |  |  |  | You can also look for information at: | 
| 1181 |  |  |  |  |  |  |  | 
| 1182 |  |  |  |  |  |  | =over 4 | 
| 1183 |  |  |  |  |  |  |  | 
| 1184 |  |  |  |  |  |  | =item * AnnoCPAN: Annotated CPAN documentation | 
| 1185 |  |  |  |  |  |  |  | 
| 1186 |  |  |  |  |  |  | L | 
| 1187 |  |  |  |  |  |  |  | 
| 1188 |  |  |  |  |  |  | =item * RT: CPAN's request tracker | 
| 1189 |  |  |  |  |  |  |  | 
| 1190 |  |  |  |  |  |  | Please report any bugs or feature requests to  L . | 
| 1191 |  |  |  |  |  |  |  | 
| 1192 |  |  |  |  |  |  | We will be notified, and then you'll automatically be notified of progress on | 
| 1193 |  |  |  |  |  |  | your bug as we make changes. | 
| 1194 |  |  |  |  |  |  |  | 
| 1195 |  |  |  |  |  |  | =item * Search CPAN | 
| 1196 |  |  |  |  |  |  |  | 
| 1197 |  |  |  |  |  |  | L | 
| 1198 |  |  |  |  |  |  |  | 
| 1199 |  |  |  |  |  |  | =back | 
| 1200 |  |  |  |  |  |  |  | 
| 1201 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 1202 |  |  |  |  |  |  |  | 
| 1203 |  |  |  |  |  |  | L | 
| 1204 |  |  |  |  |  |  |  | 
| 1205 |  |  |  |  |  |  | =cut |