tdd: update from Plan 9 - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 11a3ce57b1bb19192acd653ccee5039159f7727e
 (DIR) parent dcdc3af143bb85012efc42c6c91f3bc7548944eb
 (HTM) Author: David du Colombier <0intro@gmail.com>
       Date:   Tue, 16 Aug 2011 16:11:39 -0400
       
       dd: update from Plan 9
       
       R=rsc
       CC=plan9port.codebot
       http://codereview.appspot.com/4850052
       
       Diffstat:
         A man/man1/dd.1                       |     198 +++++++++++++++++++++++++++++++
         M src/cmd/dd.c                        |      69 ++++++++++++++++++-------------
       
       2 files changed, 239 insertions(+), 28 deletions(-)
       ---
 (DIR) diff --git a/man/man1/dd.1 b/man/man1/dd.1
       t@@ -0,0 +1,198 @@
       +.TH DD 1
       +.SH NAME
       +dd \- convert and copy a file
       +.SH SYNOPSIS
       +.B dd
       +[
       +.I option value
       +]
       +\&...
       +.SH DESCRIPTION
       +.I Dd\^
       +copies the specified input file
       +to the specified output with
       +possible conversions.
       +The standard input and output are used by default.
       +The input and output block size may be
       +specified to take advantage of raw physical I/O.
       +The options are
       +.TF "quiet\ \ \fIn
       +.PD
       +.TP
       +.BI -if\  f
       +Open file
       +.I f
       +for input.
       +.TP
       +.BI -of\  f
       +Open file
       +.I f
       +for output.
       +.TP
       +.BI -ibs\  n\^
       +Set input block size to
       +.I n\^
       +bytes (default 512).
       +.TP
       +.BI -obs\  n\^
       +Set output block size (default 512).
       +.TP
       +.BI -bs\  n\^
       +Set both input and output block size,
       +superseding
       +.I ibs\^
       +and
       +.IR obs .
       +If no conversion is specified,
       +preserve the input block size instead of packing short blocks
       +into the output buffer.
       +This is particularly efficient since no in-core copy need be done.
       +.TP
       +.BI -cbs\  n\^
       +Set conversion buffer size.
       +.TP
       +.BI -skip\  n\^
       +Skip
       +.I n
       +input records before copying.
       +.TP
       +.BI -iseek\  n\^
       +Seek
       +.I n
       +records forward on input file
       +before copying.
       +.TP
       +.BI -files\  n\^
       +Catenate
       +.I n 
       +input files (useful only for magnetic tape or similar input device).
       +.TP
       +.BI -oseek\  n\^
       +Seek
       +.I n\^
       +records from beginning of output file before copying.
       +.TP
       +.BI -count\  n\^
       +Copy only
       +.I n
       +input records.
       +.TP
       +.BI -trunc\  n\^
       +By default,
       +.I dd
       +truncates the output file when it opens it;
       +.B -trunc
       +.B 0
       +opens it without truncation.
       +.TP
       +.BI -quiet\  n\^
       +By default,
       +.I dd
       +prints the number of blocks read and written
       +once it is finished.
       +.B -quiet
       +.B 1
       +silences this summary.
       +.HP
       +\fL-conv\ ascii\ \ \ \ \fRConvert
       +.SM EBCDIC
       +to
       +.SM ASCII.
       +.PD0
       +.RS "\w'\fLconv\ \fP'u"
       +.TP "\w'\fLunblock\ \ \fP'u"
       +.B ebcdic
       +Convert
       +.SM ASCII
       +to
       +.SM EBCDIC.
       +.TP
       +.B ibm
       +Like
       +.B ebcdic
       +but with a slightly different character map.
       +.TP
       +.B block
       +Convert variable length
       +.SM ASCII
       +records to fixed length.
       +.TP
       +.B unblock
       +Convert fixed length
       +.SM ASCII
       +records to variable length.
       +.TP
       +.B lcase
       +Map alphabetics to lower case.
       +.TP
       +.B ucase
       +Map alphabetics to upper case.
       +.TP
       +.B swab
       +Swap every pair of bytes.
       +.TP
       +.B noerror
       +Do not stop processing on an error.
       +.TP
       +.B sync
       +Pad every input record to
       +.I  ibs\^
       +bytes.
       +.RE
       +.PD
       +.PP
       +.fi
       +Where sizes are specified,
       +a number of bytes is expected.
       +A number may end with
       +.L k
       +or
       +.LR b
       +to specify multiplication by
       +1024 or 512 respectively;
       +a pair of numbers may be separated by
       +.L x
       +to indicate a product.
       +Multiple conversions may be specified in the style:
       +.LR "-conv ebcdic,ucase" .
       +.PP
       +.L Cbs\^
       +is used only if
       +.LR ascii\^ ,
       +.LR unblock\^ ,
       +.LR ebcdic\^ ,
       +.LR ibm\^ ,
       +or
       +.L block\^
       +conversion is specified.
       +In the first two cases,
       +.I n
       +characters are copied into the conversion buffer, any specified
       +character mapping is done,
       +trailing blanks are trimmed and new-line is added
       +before sending the line to the output.
       +In the latter three cases, characters are read into the
       +conversion buffer and blanks are added to make up an
       +output record of size
       +.IR n .
       +If
       +.L cbs\^
       +is unspecified or zero, the
       +.LR ascii\^ ,
       +.LR ebcdic\^ ,
       +and
       +.L ibm\^
       +options convert the character set without changing the block
       +structure of the input file; the
       +.L unblock\^
       +and
       +.L block\^
       +options become a simple file copy.
       +.SH SOURCE
       +.B \*9/src/cmd/dd.c
       +.SH "SEE ALSO"
       +.IR cp (1)
       +.SH DIAGNOSTICS
       +.I Dd
       +reports the number of full + partial input and output
       +blocks handled.
 (DIR) diff --git a/src/cmd/dd.c b/src/cmd/dd.c
       t@@ -1,23 +1,28 @@
        #include <u.h>
        #include <libc.h>
        
       -#define        BIG        2147483647
       +#define        BIG        ((1UL<<31)-1)
       +#define VBIG        ((1ULL<<63)-1)
        #define        LCASE        (1<<0)
        #define        UCASE        (1<<1)
        #define        SWAB        (1<<2)
        #define NERR        (1<<3)
        #define SYNC        (1<<4)
       +
        int        cflag;
        int        fflag;
       +
        char        *string;
        char        *ifile;
        char        *ofile;
        char        *ibuf;
        char        *obuf;
       +
        vlong        skip;
        vlong        oseekn;
        vlong        iseekn;
        vlong        count;
       +
        long        files        = 1;
        long        ibs        = 512;
        long        obs        = 512;
       t@@ -31,18 +36,23 @@ long        nipr;
        long        nofr;
        long        nopr;
        long        ntrunc;
       +
        int dotrunc = 1;
        int        ibf;
        int        obf;
       +
        char        *op;
        int        nspace;
       +
        uchar        etoa[256];
        uchar        atoe[256];
        uchar        atoibm[256];
        
       +int        quiet;
       +
        void        flsh(void);
        int        match(char *s);
       -vlong        number(long big);
       +vlong        number(vlong big);
        void        cnull(int cc);
        void        null(int c);
        void        ascii(int cc);
       t@@ -50,12 +60,12 @@ void        unblock(int cc);
        void        ebcdic(int cc);
        void        ibm(int cc);
        void        block(int cc);
       -void        term(void);
       +void        term(char*);
        void        stats(void);
        
        #define        iskey(s)        ((key[0] == '-') && (strcmp(key+1, s) == 0))
        
       -void
       +int
        main(int argc, char *argv[])
        {
                void (*conv)(int);
       t@@ -99,20 +109,24 @@ main(int argc, char *argv[])
                                dotrunc = number(BIG);
                                continue;
                        }
       +                if(iskey("quiet")) {
       +                        quiet = number(BIG);
       +                        continue;
       +                }
                        if(iskey("skip")) {
       -                        skip = number(BIG);
       +                        skip = number(VBIG);
                                continue;
                        }
                        if(iskey("seek") || iskey("oseek")) {
       -                        oseekn = number(BIG);
       +                        oseekn = number(VBIG);
                                continue;
                        }
                        if(iskey("iseek")) {
       -                        iseekn = number(BIG);
       +                        iseekn = number(VBIG);
                                continue;
                        }
                        if(iskey("count")) {
       -                        count = number(BIG);
       +                        count = number(VBIG);
                                continue;
                        }
                        if(iskey("files")) {
       t@@ -165,6 +179,8 @@ main(int argc, char *argv[])
                                        cflag |= SYNC;
                                        goto cloop;
                                }
       +                        fprint(2, "dd: bad conv %s\n", argv[c]);
       +                        exits("arg");
                        }
                        fprint(2, "dd: bad arg: %s\n", key);
                        exits("arg");
       t@@ -243,17 +259,17 @@ loop:
                                perror("read");
                                if((cflag&NERR) == 0) {
                                        flsh();
       -                                term();
       +                                term("errors");
                                }
                                ibc = 0;
                                for(c=0; c<ibs; c++)
                                        if(ibuf[c] != 0)
       -                                        ibc = c;
       +                                        ibc = c+1;
       +                        seek(ibf, ibs, 1);
                                stats();
       -                }
       -                if(ibc == 0 && --files<=0) {
       +                }else if(ibc == 0 && --files<=0) {
                                flsh();
       -                        term();
       +                        term(nil);
                        }
                        if(ibc != ibs) {
                                nipr++;
       t@@ -290,12 +306,14 @@ flsh(void)
                int c;
        
                if(obc) {
       +                /* don't perror dregs of previous errors on a short write */
       +                werrstr("");
                        c = write(obf, obuf, obc);
                        if(c != obc) {
                                if(c > 0)
                                        ++nopr;
                                perror("write");
       -                        term();
       +                        term("errors");
                        }
                        if(obc == obs)
                                nofr++;
       t@@ -324,10 +342,10 @@ true:
        }
        
        vlong
       -number(long big)
       +number(vlong big)
        {
                char *cs;
       -        vlong n;
       +        uvlong n;
        
                cs = string;
                n = 0;
       t@@ -340,11 +358,6 @@ number(long big)
                        n *= 1024;
                        continue;
        
       -/*        case 'w':
       -                n *= sizeof(int);
       -                continue;
       -*/
       -
                case 'b':
                        n *= 512;
                        continue;
       t@@ -352,11 +365,11 @@ number(long big)
        /*        case '*':*/
                case 'x':
                        string = cs;
       -                n *= number(BIG);
       +                n *= number(VBIG);
        
                case '\0':
       -                if(n>=big || n<0) {
       -                        fprint(2, "dd: argument %lld out of range\n", n);
       +                if(n > big) {
       +                        fprint(2, "dd: argument %llud out of range\n", n);
                                exits("range");
                        }
                        return n;
       t@@ -536,17 +549,17 @@ block(int cc)
        }
        
        void
       -term(void)
       +term(char *status)
        {
       -
                stats();
       -        exits(0);
       +        exits(status);
        }
        
        void
        stats(void)
        {
       -
       +        if(quiet)
       +                return;
                fprint(2, "%lud+%lud records in\n", nifr, nipr);
                fprint(2, "%lud+%lud records out\n", nofr, nopr);
                if(ntrunc)