dd: support conv=swab
authorDenys Vlasenko <vda.linux@googlemail.com>
Mon, 19 Aug 2013 07:01:39 +0000 (09:01 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Mon, 19 Aug 2013 07:01:39 +0000 (09:01 +0200)
function                                             old     new   delta
dd_main                                             1482    1520     +38
static.conv_words                                     28      33      +5
packed_usage                                       29377   29375      -2

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
coreutils/dd.c

index 9cb96bb..1732a5c 100644 (file)
 //usage:     "\n       conv=noerror    Continue after read errors"
 //usage:     "\n       conv=sync       Pad blocks with zeros"
 //usage:     "\n       conv=fsync      Physically write data out before finishing"
+//usage:     "\n       conv=swab       Swap every pair of bytes"
 //usage:       )
 //usage:     "\n"
-//usage:     "\nNumbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),"
-//usage:     "\nMD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)"
+//usage:     "\nN may be suffixed by c (1), w (2), b (512), kD (1000), k (1024), MD, M, GD, G"
 //usage:
 //usage:#define dd_example_usage
 //usage:       "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n"
@@ -155,9 +155,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
                FLAG_SYNC    = 1 << 1,
                FLAG_NOERROR = 1 << 2,
                FLAG_FSYNC   = 1 << 3,
+               FLAG_SWAB    = 1 << 4,
                /* end of conv flags */
-               FLAG_TWOBUFS = 1 << 4,
-               FLAG_COUNT   = 1 << 5,
+               FLAG_TWOBUFS = 1 << 5,
+               FLAG_COUNT   = 1 << 6,
        };
        static const char keywords[] ALIGN1 =
                "bs\0""count\0""seek\0""skip\0""if\0""of\0"
@@ -167,7 +168,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
                ;
 #if ENABLE_FEATURE_DD_IBS_OBS
        static const char conv_words[] ALIGN1 =
-               "notrunc\0""sync\0""noerror\0""fsync\0";
+               "notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
 #endif
        enum {
                OP_bs = 0,
@@ -185,11 +186,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
                OP_conv_sync,
                OP_conv_noerror,
                OP_conv_fsync,
+               OP_conv_swab,
        /* Unimplemented conv=XXX: */
        //nocreat       do not create the output file
        //excl          fail if the output file already exists
        //fdatasync     physically write output file data before finishing
-       //swab          swap every pair of input bytes
        //lcase         change upper case to lower case
        //ucase         change lower case to upper case
        //block         pad newline-terminated records with spaces to cbs-size
@@ -197,6 +198,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
        //ascii         from EBCDIC to ASCII
        //ebcdic        from ASCII to EBCDIC
        //ibm           from ASCII to alternate EBCDIC
+       /* Partially implemented: */
+       //swab          swap every pair of input bytes: will abort on non-even reads
 #endif
        };
        int exitcode = EXIT_FAILURE;
@@ -377,6 +380,20 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
                         * conv=noerror just ignores input bad blocks */
                        n = 0;
                }
+               if (flags & FLAG_SWAB) {
+                       /* If n is odd, last byte is not swapped:
+                        *  echo -n "qwe" | dd conv=swab bs=1
+                        * prints "wqe".
+                        * The code does not handle correctly odd-sized reads
+                        * in the *middle* of the input. FIXME.
+                        */
+                       uint16_t *p16 = (void*) ibuf;
+                       uint16_t *end = (void*) (ibuf + (n & ~(ssize_t)1));
+                       while (p16 < end) {
+                               *p16 = bswap_16(*p16);
+                               p16++;
+                       }
+               }
                if ((size_t)n == ibs)
                        G.in_full++;
                else {