mirror of
https://github.com/coreutils/coreutils.git
synced 2024-11-24 10:23:31 +08:00
od: add an --endian option to control byte swapping
* src/od.c (main): Handle the new --endian option, taking "little" and "big" as parameters. (usage): Describe the new option. (PRINT_FIELDS): Adjust to swap bytes if required. * tests/misc/od-endian.sh: A new test to verify the byte swapping operations for hex (ints) and floats for all sizes between 1 and 16 inclusive. * test/local.mk: Reference the new test. * doc/coreutils.texi (od invocation): Describe the new option. * NEWS: Mention the new feature.
This commit is contained in:
parent
b938b6e289
commit
b370924c03
5
NEWS
5
NEWS
@ -18,6 +18,11 @@ GNU coreutils NEWS -*- outline -*-
|
||||
it would display an error, requiring --no-dereference to avoid the issue.
|
||||
[bug introduced in coreutils-5.3.0]
|
||||
|
||||
** New features
|
||||
|
||||
od accepts a new option: --endian=TYPE to handle inputs with different byte
|
||||
orders, or to provide consistent output on systems with disparate endianness.
|
||||
|
||||
** Improvements
|
||||
|
||||
stat and tail work better with HFS+ and HFSX. stat -f --format=%T now reports
|
||||
|
@ -1868,6 +1868,16 @@ none (do not print offsets).
|
||||
|
||||
The default is octal.
|
||||
|
||||
@item --endian=@var{order}
|
||||
@opindex --endian
|
||||
@cindex byte-swapping
|
||||
@cindex endianness
|
||||
Reorder input bytes, to handle inputs with differing byte orders,
|
||||
or to provide consistent output independent of the endian convention
|
||||
of the current system. Swapping is performed according to the
|
||||
specified @option{--type} size and endian @var{order}, which can be
|
||||
@samp{little} or @samp{big}.
|
||||
|
||||
@item -j @var{bytes}
|
||||
@itemx --skip-bytes=@var{bytes}
|
||||
@opindex -j
|
||||
|
59
src/od.c
59
src/od.c
@ -23,6 +23,7 @@
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
#include "argmatch.h"
|
||||
#include "error.h"
|
||||
#include "ftoastr.h"
|
||||
#include "quote.h"
|
||||
@ -259,13 +260,37 @@ static enum size_spec integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1];
|
||||
#define MAX_FP_TYPE_SIZE sizeof (long double)
|
||||
static enum size_spec fp_type_size[MAX_FP_TYPE_SIZE + 1];
|
||||
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
# define WORDS_BIGENDIAN 0
|
||||
#endif
|
||||
|
||||
/* Use native endianess by default. */
|
||||
static bool input_swap;
|
||||
|
||||
static char const short_options[] = "A:aBbcDdeFfHhIij:LlN:OoS:st:vw::Xx";
|
||||
|
||||
/* For long options that have no equivalent short option, use a
|
||||
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
|
||||
enum
|
||||
{
|
||||
TRADITIONAL_OPTION = CHAR_MAX + 1
|
||||
TRADITIONAL_OPTION = CHAR_MAX + 1,
|
||||
ENDIAN_OPTION,
|
||||
};
|
||||
|
||||
enum endian_type
|
||||
{
|
||||
endian_little,
|
||||
endian_big
|
||||
};
|
||||
|
||||
static char const *const endian_args[] =
|
||||
{
|
||||
"little", "big", NULL
|
||||
};
|
||||
|
||||
static enum endian_type const endian_types[] =
|
||||
{
|
||||
endian_little, endian_big
|
||||
};
|
||||
|
||||
static struct option const long_options[] =
|
||||
@ -278,6 +303,7 @@ static struct option const long_options[] =
|
||||
{"strings", optional_argument, NULL, 'S'},
|
||||
{"traditional", no_argument, NULL, TRADITIONAL_OPTION},
|
||||
{"width", optional_argument, NULL, 'w'},
|
||||
{"endian", required_argument, NULL, ENDIAN_OPTION },
|
||||
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
@ -318,6 +344,7 @@ suffixes may be . for octal and b for multiply by 512.\n\
|
||||
fputs (_("\
|
||||
-A, --address-radix=RADIX output format for file offsets; RADIX is one\n\
|
||||
of [doxn], for Decimal, Octal, Hex or None\n\
|
||||
--endian={big|little} swap input bytes according the specified order\n\
|
||||
-j, --skip-bytes=BYTES skip BYTES input bytes first\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
@ -400,13 +427,27 @@ N (size_t fields, size_t blank, void const *block, \
|
||||
char const *FMT_STRING, int width, int pad) \
|
||||
{ \
|
||||
T const *p = block; \
|
||||
uintmax_t i; \
|
||||
uintmax_t i; \
|
||||
int pad_remaining = pad; \
|
||||
for (i = fields; blank < i; i--) \
|
||||
{ \
|
||||
int next_pad = pad * (i - 1) / fields; \
|
||||
int adjusted_width = pad_remaining - next_pad + width; \
|
||||
T x = *p++; \
|
||||
T x; \
|
||||
if (input_swap && sizeof (T) > 1) \
|
||||
{ \
|
||||
size_t j; \
|
||||
union { \
|
||||
T x; \
|
||||
char b[sizeof (T)]; \
|
||||
} u; \
|
||||
for (j = 0; j < sizeof (T); j++) \
|
||||
u.b[j] = ((const char *) p)[sizeof (T) - 1 - j]; \
|
||||
x = u.x; \
|
||||
} \
|
||||
else \
|
||||
x = *p; \
|
||||
p++; \
|
||||
ACTION; \
|
||||
pad_remaining = next_pad; \
|
||||
} \
|
||||
@ -1664,6 +1705,18 @@ main (int argc, char **argv)
|
||||
traditional = true;
|
||||
break;
|
||||
|
||||
case ENDIAN_OPTION:
|
||||
switch (XARGMATCH ("--endian", optarg, endian_args, endian_types))
|
||||
{
|
||||
case endian_big:
|
||||
input_swap = ! WORDS_BIGENDIAN;
|
||||
break;
|
||||
case endian_little:
|
||||
input_swap = WORDS_BIGENDIAN;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* The next several cases map the traditional format
|
||||
specification options to the corresponding modern format
|
||||
specs. GNU od accepts any combination of old- and
|
||||
|
@ -239,6 +239,7 @@ all_tests = \
|
||||
tests/misc/xstrtol.pl \
|
||||
tests/tail-2/pid.sh \
|
||||
tests/misc/od.pl \
|
||||
tests/misc/od-endian.sh \
|
||||
tests/misc/od-float.sh \
|
||||
tests/misc/mktemp.pl \
|
||||
tests/misc/arch.sh \
|
||||
|
46
tests/misc/od-endian.sh
Executable file
46
tests/misc/od-endian.sh
Executable file
@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
# verify that od --endian works properly
|
||||
|
||||
# Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
|
||||
print_ver_ od
|
||||
|
||||
in='0123456789abcdef'
|
||||
|
||||
# rev(1) is not generally available, so here's a simplistic
|
||||
# implementation sufficient for our purposes.
|
||||
rev() {
|
||||
while read line; do
|
||||
printf '%s' "$line" | sed 's/./&\n/g' | tac | paste -s -d ''
|
||||
done
|
||||
}
|
||||
|
||||
in_swapped() { printf '%s' "$in" | sed "s/.\{$1\}/&\\n/g" | rev | tr -d '\n'; }
|
||||
|
||||
for e in little big; do
|
||||
test $e = little && eo=big || eo=little
|
||||
for s in 1 2 4 8 16; do
|
||||
for t in x f; do
|
||||
od -t $t$s --endian=$e /dev/null > /dev/null 2>&1 || continue
|
||||
printf '%s' "$in" | od -An -t $t$s --endian=$e > out1
|
||||
in_swapped "$s" | od -An -t $t$s --endian=$eo > out2
|
||||
compare out1 out2 || fail=1
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
Exit $fail
|
Loading…
Reference in New Issue
Block a user