From aad1c1a1f80ea48e182a8b33aa56f926ad16cf7c Mon Sep 17 00:00:00 2001 From: Michael Mikonos <127171689+mknos@users.noreply.github.com> Date: Fri, 14 Jul 2023 17:49:30 +0800 Subject: [PATCH 1/4] od: add -N option: limit input bytes * Standard od has -N which takes a numeric argument that is interpreted as decimal, hex or octal * Initially add support for only decimal argument; this is the default interpretation in the standard * -N 0 is allowed * -j can be used with -N; -j bytes are skipped first before -N bytes are read * Instead of modifying the statement controlling the loop I'm truncating the buffer if it exceeds the limit * Tested against GNU od --- bin/od | 57 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/bin/od b/bin/od index a5d7010b..a3ca7d47 100755 --- a/bin/od +++ b/bin/od @@ -13,11 +13,17 @@ License: perl use strict; -use Getopt::Std; -use vars qw/ $opt_A $opt_b $opt_c $opt_d $opt_f $opt_i $opt_j $opt_l $opt_o -$opt_v $opt_x /; -my ($offset1, $radix, $data, @arr, $len, $fh); +use File::Basename qw(basename); +use Getopt::Std qw(getopts); + +use constant EX_SUCCESS => 0; +use constant EX_FAILURE => 1; + +use vars qw/ $opt_A $opt_b $opt_c $opt_d $opt_f $opt_i $opt_j $opt_l $opt_N +$opt_o $opt_v $opt_x /; + +my ($offset1, $radix, $data, @arr, $len, $fh, $lim); my ($lastline, $upformat, $pffmt, $strfmt, $ml); my %charescs = ( @@ -58,12 +64,30 @@ my %charescs = ( $offset1 = 0; $lastline = ''; -getopts('A:bcdfij:lovx') or help(); +my $Program = basename($0); + +getopts('A:bcdfij:lN:ovx') or help(); defined $opt_A ? ($radix = $opt_A) : ($radix = 'o'); - defined $opt_j && ($offset1 = $opt_j); +if (defined $opt_j) { + if ($opt_j =~ m/\D/) { + warn "$Program: bad argument to -j: '$opt_j'\n"; + exit EX_FAILURE; + } + $offset1 = $opt_j; +} +if (defined $opt_N) { + if ($opt_N =~ m/\D/) { + warn "$Program: bad argument to -N: '$opt_N'\n"; + exit EX_FAILURE; + } + $lim = $opt_N; +} if (defined $ARGV[0] && $ARGV[0] ne '-') { - open($fh, '<', $ARGV[0]) or die "$0: $ARGV[0]: $!\n"; + unless (open $fh, '<', $ARGV[0]) { + warn "$Program: cannot open '$ARGV[0]': $!\n"; + exit EX_FAILURE; + } } else { $fh = *STDIN; @@ -111,6 +135,13 @@ else { } while ($len = read($fh, $data, 16)) { + if (defined $lim) { + $lim -= $len; + if ($lim < 0) { + $len -= abs $lim; + $data = substr $data, 0, $len; + } + } $ml = ''; # multi-line indention if ( &diffdata || $opt_v) { @@ -125,12 +156,16 @@ while ($len = read($fh, $data, 16)) { $offset1 += $len; $lastline = $data . '|'; + last if (defined($lim) && $lim <= 0); +} +if ($!) { + warn "$Program: read error: $!\n"; + exit EX_FAILURE; } -die "$0: read error: $!\n" if $!; printf("%.8$radix\n", $offset1); close $fh; -exit 0; +exit EX_SUCCESS; sub octal1 { $upformat = 'C*'; # for -b @@ -217,7 +252,7 @@ sub diffdata { } sub help { - print "usage: od [-bcdfiloxv] [-A radix] filename\n"; + print "usage: od [-bcdfiloxv] [-A radix] [-j skip_bytes] [-N limit_bytes] filename\n"; exit 1; } __END__ @@ -228,7 +263,7 @@ od - dump files in octal and other formats =head1 SYNOPSIS -B [ I<-abcdfiloxv> ] [I<-j skip_n_bytes>] [ I<-A radix> ] F +B [ I<-abcdfiloxv> ] [I<-j skip_n_bytes>] [I<-N read_n_bytes>] [ I<-A radix> ] F =head1 DESCRIPTION From acafe85438d1b45a1499421c7af15d1d69ffcda3 Mon Sep 17 00:00:00 2001 From: Michael Mikonos <127171689+mknos@users.noreply.github.com> Date: Fri, 14 Jul 2023 20:42:28 +0800 Subject: [PATCH 2/4] follow up -j versus -N * Abandon seek() for -j and simply use read * Raise error for skipping past end of input with -j (found when testing previous commit) * Switch input loop to single byte to avoid hanging waiting for input on a pipe with -N < 16 --- bin/od | 55 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/bin/od b/bin/od index a3ca7d47..8011cb49 100755 --- a/bin/od +++ b/bin/od @@ -19,6 +19,7 @@ use Getopt::Std qw(getopts); use constant EX_SUCCESS => 0; use constant EX_FAILURE => 1; +use constant LINESZ => 16; use vars qw/ $opt_A $opt_b $opt_c $opt_d $opt_f $opt_i $opt_j $opt_l $opt_N $opt_o $opt_v $opt_x /; @@ -94,10 +95,17 @@ else { } binmode $fh; -if ($offset1 && !seek($fh, $offset1, 0)) { +if ($offset1) { foreach (1 .. $offset1) { $len = read $fh, $data, 1; - die "$0: read error: $!\n" if $!; + if ($len == 0) { + warn "$Program: cannot skip past end of input\n"; + exit EX_FAILURE; + } + unless (defined $len) { + warn "$Program: read error: $!\n"; + exit EX_FAILURE; + } undef $data; } } @@ -134,31 +142,32 @@ else { help(); } -while ($len = read($fh, $data, 16)) { - if (defined $lim) { - $lim -= $len; - if ($lim < 0) { - $len -= abs $lim; - $data = substr $data, 0, $len; +my $buf; +my $nread = 0; +while ($len = read($fh, $buf, 1)) { + $data .= $buf; + $nread++; + + my $is_limit = defined($lim) && $nread == $lim; + if (length($data) == LINESZ || $is_limit || eof($fh)) { + $ml = ''; # multi-line indention + if (&diffdata || $opt_v) { + printf("%.8$radix ", $offset1); + &$fmt; + printf("%s$strfmt\n", $ml, @arr); + $ml = ' ' x 9; } - } - $ml = ''; # multi-line indention - - if ( &diffdata || $opt_v) { - printf("%.8$radix ", $offset1); - &$fmt; - printf("%s$strfmt\n", $ml, @arr); - $ml = ' ' x 9; - } - else { - print "*\n"; + else { + print "*\n"; + } + $lastline = $data . '|'; + undef $data; } - $offset1 += $len; - $lastline = $data . '|'; - last if (defined($lim) && $lim <= 0); + $offset1++; + last if $is_limit; } -if ($!) { +unless (defined $len) { warn "$Program: read error: $!\n"; exit EX_FAILURE; } From 7185fd16ad85c58c01f623bd5a18cad86ba788df Mon Sep 17 00:00:00 2001 From: Michael Mikonos <127171689+mknos@users.noreply.github.com> Date: Fri, 14 Jul 2023 20:56:49 +0800 Subject: [PATCH 3/4] fix -N 0 --- bin/od | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/od b/bin/od index 8011cb49..94773205 100755 --- a/bin/od +++ b/bin/od @@ -109,6 +109,11 @@ if ($offset1) { undef $data; } } +if (defined($lim) && $lim == 0) { + printf("%.8$radix\n", $offset1); + close $fh; + exit EX_SUCCESS; +} $opt_o = 1 if ! ($opt_b || $opt_c || $opt_d || $opt_f || $opt_i || $opt_l || $opt_o || $opt_x); From 8628924b3b86aff9602e015c0b6729e24f38ccd1 Mon Sep 17 00:00:00 2001 From: Michael Mikonos <127171689+mknos@users.noreply.github.com> Date: Sat, 15 Jul 2023 10:01:51 +0800 Subject: [PATCH 4/4] consistent symbolic exit code --- bin/od | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/od b/bin/od index 94773205..7f7463a1 100755 --- a/bin/od +++ b/bin/od @@ -267,7 +267,7 @@ sub diffdata { sub help { print "usage: od [-bcdfiloxv] [-A radix] [-j skip_bytes] [-N limit_bytes] filename\n"; - exit 1; + exit EX_FAILURE; } __END__