Subject: Re: bug#16578: Wish: Support for non-native endianness in od

From: [email-masked] (Niels Möller)
Date: Fri, 31 Jan 2014 09:44:54 +0100

[email-masked] (Niels Möller) writes:

> Pádraig Brady <[email-masked]> writes:
>> I agree this would be useful and easy enough to add.
>> I suppose the interface would be --endian=little|big
>
> Maybe I can have a look at what it takes.

Below is a crude patch (missing: usage message, tests cases, docs,
translation). I think it should work fine for floats too. I see no
obvious and more beautiful way to do it. 

(And I think I have copyright assignment papers for coreutils in place,
since work on factor some year ago).

Regards,
/Niels

diff --git a/src/od.c b/src/od.c
index 514fe50..a71e302 100644
--- a/src/od.c
+++ b/src/od.c
@@ -259,13 +259,16 @@ 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];
 
+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,
 };
 
 static struct option const long_options[] =
@@ -278,6 +281,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},
@@ -406,7 +410,21 @@ N (size_t fields, size_t blank, void const *block,                      \
     {                                                                   \
       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)                                  \
+        {                                                               \
+          int 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 +1682,24 @@ main (int argc, char **argv)
           traditional = true;
           break;
 
+        case ENDIAN_OPTION:
+          if (!strcmp (optarg, "big"))
+            {
+#if !WORDS_BIGENDIAN
+              input_swap = true;
+#endif
+            }
+          else if (!strcmp (optarg, "little"))
+            {
+#if WORDS_BIGENDIAN
+                input_swap = true;
+#endif
+            }
+          else
+            error (EXIT_FAILURE, 0,
+                   _("bad argument '%s' for --endian option"), optarg);
+          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

-- 
Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
Internet email is subject to wholesale government surveillance.