URI: 
       txd: add -R for runewise dump - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit c665ab76a83dbe4a56410d3f65e02716cd773a6d
   DIR parent 67d25b6fb0ec561de501f2df969c9cad999672d0
  HTML Author: Leah Neukirchen <leah@vuxu.org>
       Date:   Tue, 26 Sep 2017 15:48:18 +0200
       
       xd: add -R for runewise dump
       
       Ported from Plan 9 2013-05-21.
       https://github.com/0intro/plan9/commit/b377a116d132865c011a3fb3ea76528ffd32963f
       
       Closes #16.
       
       Diffstat:
         M man/man1/xd.1                       |       7 +++++++
         M src/cmd/xd.c                        |     151 +++++++++++++++++++++++--------
       
       2 files changed, 118 insertions(+), 40 deletions(-)
       ---
   DIR diff --git a/man/man1/xd.1 b/man/man1/xd.1
       t@@ -66,6 +66,13 @@ but print
        .SM ASCII
        representations or C escape sequences where possible.
        .TP
       +.B -R
       +Format as
       +.B 1x
       +but print
       +.B Rune
       +representations or C escape sequences where possible.
       +.TP
        .BI -a style
        Print file addresses in the given style (and size 4).
        .TP
   DIR diff --git a/src/cmd/xd.c b/src/cmd/xd.c
       t@@ -3,8 +3,9 @@
        #include <bio.h>
        
        unsigned char        odata[16];
       -unsigned char        data[16];
       +unsigned char        data[32];
        int                ndata;
       +int                nread;
        unsigned long        addr;
        int                repeats;
        int                swizzle;
       t@@ -12,16 +13,20 @@ int                swizzle8;
        int                flush;
        int                abase=2;
        int                xd(char *, int);
       -void                xprint(char *, ulong);
       +void                xprint(char *, ...);
        void                initarg(void), swizz(void), swizz8(void);
        enum{
       -        Narg=10
       +        Narg=10,
       +
       +        TNone=0,
       +        TAscii,
       +        TRune,
        };
        typedef struct Arg Arg;
        typedef void fmtfn(char *);
        struct Arg
        {
       -        int        ascii;                /* 0==none, 1==ascii */
       +        int        chartype;        /* TNone, TAscii, TRunes */
                int        loglen;                /* 0==1, 1==2, 2==4, 3==8 */
                int        base;                /* 0==8, 1==10, 2==16 */
                fmtfn        *fn;                /* function to call with data */
       t@@ -30,7 +35,7 @@ struct Arg
        }arg[Narg];
        int        narg;
        
       -fmtfn        fmt0, fmt1, fmt2, fmt3, fmtc;
       +fmtfn        fmt0, fmt1, fmt2, fmt3, fmtc, fmtr;
        fmtfn *fmt[4] = {
                fmt0,
                fmt1,
       t@@ -46,11 +51,15 @@ char *dfmt[4][3] = {
        };
        
        char *cfmt[3][3] = {
       -        "   %c",        "   %c",         "  %c",
       +        "   %c",        "   %c",        "  %c",
                " %.3s",        " %.3s",        " %.2s",
                " %.3uo",        " %.3ud",        " %.2ux",
        };
        
       +char *rfmt[1][1] = {
       +        " %2.2C",
       +};
       +
        char *afmt[2][3] = {
                "%.7luo ",        "%.7lud ",        "%.7lux ",
                "%7luo ",        "%7lud ",        "%7lux ",
       t@@ -120,7 +129,13 @@ main(int argc, char *argv[])
                        while(argv[0][0]){
                                switch(argv[0][0]){
                                case 'c':
       -                                ap->ascii = 1;
       +                                ap->chartype = TAscii;
       +                                ap->loglen = 0;
       +                                if(argv[0][1] || argv[0][-1]!='-')
       +                                        goto Usage;
       +                                break;
       +                        case 'R':
       +                                ap->chartype = TRune;
                                        ap->loglen = 0;
                                        if(argv[0][1] || argv[0][-1]!='-')
                                                goto Usage;
       t@@ -157,7 +172,9 @@ main(int argc, char *argv[])
                                }
                                argv[0]++;
                        }
       -                if(ap->ascii)
       +                if(ap->chartype == TRune)
       +                        ap->fn = fmtr;
       +                else if(ap->chartype == TAscii)
                                ap->fn = fmtc;
                        else
                                ap->fn = fmt[ap->loglen];
       t@@ -185,7 +202,7 @@ initarg(void)
                        fprint(2, "xd: too many formats (max %d)\n", Narg);
                        exits("usage");
                }
       -        ap->ascii = 0;
       +        ap->chartype = TNone;
                ap->loglen = 2;
                ap->base = 2;
                ap->fn = fmt2;
       t@@ -197,7 +214,7 @@ int
        xd(char *name, int title)
        {
                int fd;
       -        int i, star;
       +        int i, star, nsee, nleft;
                Arg *ap;
                Biobuf *bp;
        
       t@@ -216,21 +233,29 @@ xd(char *name, int title)
                        xprint("%s\n", (long)name);
                addr = 0;
                star = 0;
       -        while((ndata=Bread(bp, data, 16)) >= 0){
       -                if(ndata < 16)
       -                        for(i=ndata; i<16; i++)
       +        nsee = 16;
       +        nleft = 0;
       +        /* read 32 but see only 16 so that runes are happy */
       +        while((ndata=Bread(bp, data + nleft, 32 - nleft)) >= 0){
       +                ndata += nleft;
       +                nleft = 0;
       +                nread = ndata;
       +                if(ndata>nsee)
       +                        ndata = nsee;
       +                else if(ndata<nsee)
       +                        for(i=ndata; i<nsee; i++)
                                        data[i] = 0;
                        if(swizzle)
                                swizz();
                        if(swizzle8)
                                swizz8();
       -                if(ndata==16 && repeats){
       +                if(ndata==nsee && repeats){
                                if(addr>0 && data[0]==odata[0]){
       -                                for(i=1; i<16; i++)
       +                                for(i=1; i<nsee; i++)
                                                if(data[i] != odata[i])
                                                        break;
       -                                if(i == 16){
       -                                        addr += 16;
       +                                if(i == nsee){
       +                                        addr += nsee;
                                                if(star == 0){
                                                        star++;
                                                        xprint("*\n", 0);
       t@@ -238,7 +263,7 @@ xd(char *name, int title)
                                                continue;
                                        }
                                }
       -                        for(i=0; i<16; i++)
       +                        for(i=0; i<nsee; i++)
                                        odata[i] = data[i];
                                star = 0;
                        }
       t@@ -250,13 +275,17 @@ xd(char *name, int title)
                                        Bflush(&bout);
                        }
                        addr += ndata;
       -                if(ndata<16){
       +                if(ndata<nsee){
                                xprint(afmt[0][abase], addr);
                                xprint("\n", 0);
                                if(flush)
                                        Bflush(&bout);
                                break;
                        }
       +                if(nread>nsee){
       +                        nleft = nread - nsee;
       +                        memmove(data, data + nsee, nleft);
       +                }
                }
                Bterm(bp);
                return 0;
       t@@ -353,39 +382,81 @@ fmt3(char *f)
        }
        
        void
       +onefmtc(uchar c)
       +{
       +        switch(c){
       +        case '\t':
       +                xprint(cfmt[1][2], (long)"\\t");
       +                break;
       +        case '\r':
       +                xprint(cfmt[1][2], (long)"\\r");
       +                break;
       +        case '\n':
       +                xprint(cfmt[1][2], (long)"\\n");
       +                break;
       +        case '\b':
       +                xprint(cfmt[1][2], (long)"\\b");
       +                break;
       +        default:
       +                if(c>=0x7F || ' '>c)
       +                        xprint(cfmt[2][2], c);
       +                else
       +                        xprint(cfmt[0][2], c);
       +                break;
       +        }
       +}
       +
       +void
        fmtc(char *f)
        {
                int i;
        
                USED(f);
                for(i=0; i<ndata; i++)
       -                switch(data[i]){
       -                case '\t':
       -                        xprint(cfmt[1][2], (long)"\\t");
       -                        break;
       -                case '\r':
       -                        xprint(cfmt[1][2], (long)"\\r");
       -                        break;
       -                case '\n':
       -                        xprint(cfmt[1][2], (long)"\\n");
       -                        break;
       -                case '\b':
       -                        xprint(cfmt[1][2], (long)"\\b");
       -                        break;
       -                default:
       -                        if(data[i]>=0x7F || ' '>data[i])
       -                                xprint(cfmt[2][2], data[i]);
       -                        else
       -                                xprint(cfmt[0][2], data[i]);
       -                        break;
       +                onefmtc(data[i]);
       +}
       +
       +void
       +fmtr(char *f)
       +{
       +        int i, w, cw;
       +        Rune r;
       +        static int nstart;
       +
       +        USED(f);
       +        if(nstart)
       +                xprint("%*c", 3*nstart, ' ');
       +        for(i=nstart; i<ndata; )
       +                if(data[i] < Runeself)
       +                        onefmtc(data[i++]);
       +                else{
       +                        w = chartorune(&r, (char *)data+i);
       +                        if(w == 1 || i + w>nread)
       +                                onefmtc(data[i++]);
       +                        else{
       +                                cw = w;
       +                                if(i + w>ndata)
       +                                        cw = ndata - i;
       +                                xprint(rfmt[0][0], r);
       +                                xprint("%*c", 3*cw-3, ' ');
       +                                i += w;
       +                        }
                        }
       +        if(i > ndata)
       +                nstart = i - ndata;
       +        else
       +                nstart = 0;
        }
        
        void
       -xprint(char *fmt, ulong d)
       +xprint(char *fmt, ...)
        {
       -        if(Bprint(&bout, fmt, d)<0){
       +        va_list arglist;
       +
       +        va_start(arglist, fmt);
       +        if(Bvprint(&bout, fmt, arglist)<0){
                        fprint(2, "xd: i/o error\n");
                        exits("i/o error");
                }
       +        va_end(arglist);
        }