#!/usr/bin/perl -w

use strict ;
use warnings ;
use Carp ;

=head1 NAME 

 $> hdr - hexdump range

=head1 USAGE

 $> hdr -r range_definitions file_to_dump
 
 $> hdr file_to_dump -r 'header,40, yellow:padding,24:magic,16,red:size,4:data,100:footer,16' -o ver

head1 OPTIONS

 range_description|r             file name containing a description
                                 or a string description formated as:
			                   'color:name,size:name,size,...'
					    
 offset                          position in the data where to start dumping
 max_size                        amount of data to dump
 
 orientation|o                   'horizontal' or 'vertical'
 display_column_names|col        display columns names
 display_ruler|rul               display horizontal ruler
 format|f                        'ANSI' or 'ASCII' or 'HTML' 
 color                           'bw' or 'cycle',
 data_width|w                     number of bytes per dump line
 
 offset_format                   'hex' or 'dec' 
 display_offset                   0 == no the offset display
 display_cumulative_offset        0 == no cumulative offset display
 display_zero_size_range          0 == no display of range with size 0
 display_zero_size_range_warning  0 == no warnings about ranges with size 0
 
 display_range_name               1 == display of the range name
 maximum_range_name_size          truncate range name if longer
 display_range_size               1 == prepend the range size to the name
 
 display_hex_dump                 1 == display hexadecimal dump column
 display_dec_dump                 1 == display decimal dump column
 display_ascii_dump               1 == display ASCII dump column
 display_user_information         1 == display user information columns
 
 display_bitfields                1 == display bitfields
 display_source                   1 == display source for bitfields 
 
 h|help                           display this scripts help page
 

=head1 EXIT STATUS

Non zero if an error occured.

=head1 AUTHOR

  Nadim ibn hamouda el Khemir
  CPAN ID: NKH
  mailto: nkh@cpan.org

=cut

#------------------------------------------------------------------------------------------------------------------------

use Getopt::Long ;
use English qw( -no_match_vars ) ;

use File::Slurp ;
use IO::Select ;

use Data::HexDump::Range qw() ;
use Term::Bash::Completion::Generator ;

our $VERSION = '0.03' ;

#------------------------------------------------------------------------------------------------------------------------

my @options = 
	(
	'range_description|r=s' => \ my $range_description,
	'dump_range_description|d' =>\my $dump_range_description,

	'offset=i' =>  \my $offset,
	'max_size=i' =>  \my $max_size,
	'orientation|o=s' => \my $orientation,
	'display_column_names|col' => \my $display_column_names,
	'display_ruler|rul' => \my $display_ruler,

	'format|f=s' => \my $format,
	'color=s' => \my $color,
	'data_width=i' =>  \my $data_width,

	'offset_format=s' => \my $offset_format,
	'display_offset=i' => \my $display_offset,
	'display_cumulative_offset=i' => \my $display_cumulative_offset,
	'display_zero_size_range=i' => \my $display_zero_size_range,
	'display_zero_size_range_warning=i' => \my $display_zero_size_range_warning,

	'display_range_name=i' => \my $display_range_name,
	'maximum_range_name_size=i' => \my$maximum_range_name_size,
	'display_range_size=i' => \my $display_range_size,

	'display_hex_dump=i' => \my $display_hex_dump,
	'display_dec_dump=i' => \my $display_dec_dump,
	'display_ascii_dump=i' => \my $display_ascii_dump,
	'display_user_information=i' => \my $display_user_information,

	'display_bitfields=i' => \my $display_bitfields,
	'display_bitfield_source=i' => \my $display_bitfield_source,

	'h|help' => \&display_help, 
	'generate_completion_script|bash' => \my $generatebash_completion,
	) ;

display_help() unless GetOptions(@options) ;

generate_completion_script(@options) if $generatebash_completion ;

my $data ;

my $io_select = IO::Select->new(\*STDIN) ;
if($io_select->can_read(0))
	{
	$/ = undef ;
	$data =  <STDIN> ; ## no critic (InputOutput::ProhibitExplicitStdin)
	}
else
	{
	display_help() unless @ARGV ;
	$data = read_file shift @ARGV ;
	}

$offset ||= 0 ;

my $range ;

if(defined $range_description )
	{
	if($range_description =~ /,/)
		{
		$range = $range_description ;
		}
	else
		{
		# a file
		$range  = do $range_description || ['hdr: range error', 16 * 16 ] ;
		}
	}
else
	{
	$range = ['no range definition', length($data) ] ;
	$display_range_name = 0 ;
	$display_bitfield_source = 0 ;
	}
	
my $hdr = Data::HexDump::Range->new
			(
			ORIENTATION => $orientation || 'horizontal',
			DISPLAY_COLUMN_NAMES => defined $display_column_names ? $display_column_names : 0,
			DISPLAY_RULER => defined $display_ruler ? $display_ruler : 0,
			
			FORMAT => $format || 'ANSI',
			COLOR => defined $color ? $color : 'cycle',
			
			OFFSET_FORMAT => $offset_format || 'hex',
			DATA_WIDTH => $data_width || 16,
			
			DISPLAY_RANGE_NAME => defined $display_range_name ? $display_range_name : 1 ,
			DUMP_RANGE_DESCRIPTION => defined $dump_range_description ? $dump_range_description : 0 ,
			MAXIMUM_RANGE_NAME_SIZE => defined $maximum_range_name_size ? $maximum_range_name_size : 16,
			DISPLAY_RANGE_SIZE => defined $display_range_size ? $display_range_size : 0,
			
			DISPLAY_OFFSET  => defined $display_offset ? $display_offset : 1 ,
			DISPLAY_CUMULATIVE_OFFSET  => defined $display_cumulative_offset ? $display_cumulative_offset : 1 ,
			DISPLAY_HEX_DUMP => defined $display_hex_dump ? $display_hex_dump : 1,
			DISPLAY_DEC_DUMP => defined $display_dec_dump ? $display_dec_dump : 0,
			DISPLAY_ASCII_DUMP => defined $display_ascii_dump ? $display_ascii_dump :  1 ,
			DISPLAY_USER_INFORMATION => defined $display_user_information ? $display_user_information :  0 ,
			DISPLAY_ZERO_SIZE_RANGE => defined $display_zero_size_range ? $display_zero_size_range : 1,
			DISPLAY_ZERO_SIZE_RANGE_WARNING => defined  $display_zero_size_range_warning ? $display_zero_size_range_warning : 1,
			
			DISPLAY_BITFIELDS => defined $display_bitfields ? $display_bitfields : 1,
			DISPLAY_BITFIELD_SOURCE => defined $display_bitfield_source ? $display_bitfield_source : 1,

			) ;

print $hdr->dump( $range, $data, $offset, $max_size) ;

#------------------------------------------------------------------------------------------------------------------------

sub display_help
{

#~ =head2 display_help()

#~ I<Arguments> - None

#~ I<Returns> - Nothing

#~ I<Exceptions> - exits with status code B<1>

#~ =cut

my ($this_script) = ($PROGRAM_NAME =~m/(.*)/sxm ) ;

print {*STDERR} `perldoc $this_script`  or croak 'Error: Can\'t display help!' ; ## no critic (InputOutput::ProhibitBacktickOperators)
exit(1) ;
}

#------------------------------------------------------------------------------------------------------------------------

sub generate_completion_script
{
#~ =head2 generate_completion_script(@definitions)

#~ I<Arguments> - @definitions - getop options description

#~ I<Returns> - Nothing

#~ I<Exceptions> - exits with status code B<1> after emitting the completion script on stdout

#~ =cut

my (@definitions) = @_ ;

my $flip = 0 ;
my @options = grep {++$flip % 2} @definitions ;

print Term::Bash::Completion::Generator::generate_bash_completion_function('hdr', [@options], undef, 1) ;

exit(0) ;
}

