Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>

#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   oseekb;
vlong   iseekb;
vlong   count;

long    files   = 1;
long    ibs     = 512;
long    obs     = 512;
long    bs;
long    cbs;
long    ibc;
long    obc;
long    cbc;
long    nifr;
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(vlong big);
void    cnull(int cc);
void    null(int c);
void    ascii(int cc);
void    unblock(int cc);
void    ebcdic(int cc);
void    ibm(int cc);
void    block(int cc);
void    term(char*);
void    stats(void);

#define iskey(s)        ((key[0] == '-') && (strcmp(key+1, s) == 0))

int
main(int argc, char *argv[])
{
        void (*conv)(int);
        char *ip;
        char *key;
        int a, c;

        conv = null;
        for(c=1; c<argc; c++) {
                key = argv[c++];
                if(c >= argc){
                        fprint(2, "dd: arg %s needs a value\n", key);
                        exits("arg");
                }
                string = argv[c];
                if(iskey("ibs")) {
                        ibs = number(BIG);
                        continue;
                }
                if(iskey("obs")) {
                        obs = number(BIG);
                        continue;
                }
                if(iskey("cbs")) {
                        cbs = number(BIG);
                        continue;
                }
                if(iskey("bs")) {
                        bs = number(BIG);
                        continue;
                }
                if(iskey("if")) {
                        ifile = string;
                        continue;
                }
                if(iskey("of")) {
                        ofile = string;
                        continue;
                }
                if(iskey("trunc")) {
                        dotrunc = number(BIG);
                        continue;
                }
                if(iskey("quiet")) {
                        quiet = number(BIG);
                        continue;
                }
                if(iskey("skip")) {
                        skip = number(VBIG);
                        continue;
                }
                if(iskey("seek") || iskey("oseek")) {
                        oseekn = number(VBIG);
                        continue;
                }
                if(iskey("iseek")) {
                        iseekn = number(VBIG);
                        continue;
                }
                if(iskey("iseekb")) {
                        iseekb = number(VBIG);
                        continue;
                }
                if(iskey("oseekb")) {
                        oseekb = number(VBIG);
                        continue;
                }
                if(iskey("count")) {
                        count = number(VBIG);
                        continue;
                }
                if(iskey("files")) {
                        files = number(BIG);
                        continue;
                }
                if(iskey("conv")) {
                cloop:
                        if(match(","))
                                goto cloop;
                        if(*string == '\0')
                                continue;
                        if(match("ebcdic")) {
                                conv = ebcdic;
                                goto cloop;
                        }
                        if(match("ibm")) {
                                conv = ibm;
                                goto cloop;
                        }
                        if(match("ascii")) {
                                conv = ascii;
                                goto cloop;
                        }
                        if(match("block")) {
                                conv = block;
                                goto cloop;
                        }
                        if(match("unblock")) {
                                conv = unblock;
                                goto cloop;
                        }
                        if(match("lcase")) {
                                cflag |= LCASE;
                                goto cloop;
                        }
                        if(match("ucase")) {
                                cflag |= UCASE;
                                goto cloop;
                        }
                        if(match("swab")) {
                                cflag |= SWAB;
                                goto cloop;
                        }
                        if(match("noerror")) {
                                cflag |= NERR;
                                goto cloop;
                        }
                        if(match("sync")) {
                                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");
        }
        if(conv == null && cflag&(LCASE|UCASE))
                conv = cnull;
        if(ifile)
                ibf = open(ifile, 0);
        else
                ibf = dup(0, -1);
        if(ibf < 0) {
                fprint(2, "dd: open %s: %r\n", ifile);
                exits("open");
        }
        if(ofile){
                if(dotrunc)
                        obf = create(ofile, 1, 0664);
                else
                        obf = open(ofile, 1);
                if(obf < 0) {
                        fprint(2, "dd: create %s: %r\n", ofile);
                        exits("create");
                }
        }else{
                obf = dup(1, -1);
                if(obf < 0) {
                        fprint(2, "dd: can't dup file descriptor: %s: %r\n", ofile);
                        exits("dup");
                }
        }
        if(bs)
                ibs = obs = bs;
        if(ibs == obs && conv == null)
                fflag++;
        if(ibs == 0 || obs == 0) {
                fprint(2, "dd: counts: cannot be zero\n");
                exits("counts");
        }
        ibuf = sbrk(ibs);
        if(fflag)
                obuf = ibuf;
        else
                obuf = sbrk(obs);
        sbrk(64);       /* For good measure */
        if(ibuf == (char *)-1 || obuf == (char *)-1) {
                fprint(2, "dd: not enough memory: %r\n");
                exits("memory");
        }
        ibc = 0;
        obc = 0;
        cbc = 0;
        op = obuf;

/*
        if(signal(SIGINT, SIG_IGN) != SIG_IGN)
                signal(SIGINT, term);
*/
        seek(obf, obs*oseekn, 1);
        seek(ibf, ibs*iseekn, 1);
        if(iseekb)
                seek(ibf, iseekb, 0);
        if(oseekb)
                seek(obf, oseekb, 0);
        while(skip) {
                read(ibf, ibuf, ibs);
                skip--;
        }

        ip = 0;
loop:
        if(ibc-- == 0) {
                ibc = 0;
                if(count==0 || nifr+nipr!=count) {
                        if(cflag&(NERR|SYNC))
                        for(ip=ibuf+ibs; ip>ibuf;)
                                *--ip = 0;
                        ibc = read(ibf, ibuf, ibs);
                }
                if(ibc == -1) {
                        perror("read");
                        if((cflag&NERR) == 0) {
                                flsh();
                                term("errors");
                        }
                        ibc = 0;
                        for(c=0; c<ibs; c++)
                                if(ibuf[c] != 0)
                                        ibc = c+1;
                        seek(ibf, ibs, 1);
                        stats();
                }else if(ibc == 0 && --files<=0) {
                        flsh();
                        term(nil);
                }
                if(ibc != ibs) {
                        nipr++;
                        if(cflag&SYNC)
                                ibc = ibs;
                } else
                        nifr++;
                ip = ibuf;
                c = (ibc>>1) & ~1;
                if(cflag&SWAB && c)
                do {
                        a = *ip++;
                        ip[-1] = *ip;
                        *ip++ = a;
                } while(--c);
                ip = ibuf;
                if(fflag) {
                        obc = ibc;
                        flsh();
                        ibc = 0;
                }
                goto loop;
        }
        c = 0;
        c |= *ip++;
        c &= 0377;
        (*conv)(c);
        goto loop;
}

void
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("errors");
                }
                if(obc == obs)
                        nofr++;
                else
                        nopr++;
                obc = 0;
        }
}

int
match(char *s)
{
        char *cs;

        cs = string;
        while(*cs++ == *s)
                if(*s++ == '\0')
                        goto true;
        if(*s != '\0')
                return 0;

true:
        cs--;
        string = cs;
        return 1;
}

vlong
number(vlong big)
{
        char *cs;
        uvlong n;

        cs = string;
        n = 0;
        while(*cs >= '0' && *cs <= '9')
                n = n*10 + *cs++ - '0';
        for(;;)
        switch(*cs++) {

        case 'k':
                n *= 1024;
                continue;

        case 'b':
                n *= 512;
                continue;

/*      case '*':*/
        case 'x':
                string = cs;
                n *= number(VBIG);

        case '\0':
                if(n > big) {
                        fprint(2, "dd: argument %llud out of range\n", n);
                        exits("range");
                }
                return n;
        }
        /* never gets here */
}

void
cnull(int cc)
{
        int c;

        c = cc;
        if((cflag&UCASE) && c>='a' && c<='z')
                c += 'A'-'a';
        if((cflag&LCASE) && c>='A' && c<='Z')
                c += 'a'-'A';
        null(c);
}

void
null(int c)
{

        *op = c;
        op++;
        if(++obc >= obs) {
                flsh();
                op = obuf;
        }
}

void
ascii(int cc)
{
        int c;

        c = etoa[cc];
        if(cbs == 0) {
                cnull(c);
                return;
        }
        if(c == ' ') {
                nspace++;
                goto out;
        }
        while(nspace > 0) {
                null(' ');
                nspace--;
        }
        cnull(c);

out:
        if(++cbc >= cbs) {
                null('\n');
                cbc = 0;
                nspace = 0;
        }
}

void
unblock(int cc)
{
        int c;

        c = cc & 0377;
        if(cbs == 0) {
                cnull(c);
                return;
        }
        if(c == ' ') {
                nspace++;
                goto out;
        }
        while(nspace > 0) {
                null(' ');
                nspace--;
        }
        cnull(c);

out:
        if(++cbc >= cbs) {
                null('\n');
                cbc = 0;
                nspace = 0;
        }
}

void
ebcdic(int cc)
{
        int c;

        c = cc;
        if(cflag&UCASE && c>='a' && c<='z')
                c += 'A'-'a';
        if(cflag&LCASE && c>='A' && c<='Z')
                c += 'a'-'A';
        c = atoe[c];
        if(cbs == 0) {
                null(c);
                return;
        }
        if(cc == '\n') {
                while(cbc < cbs) {
                        null(atoe[' ']);
                        cbc++;
                }
                cbc = 0;
                return;
        }
        if(cbc == cbs)
                ntrunc++;
        cbc++;
        if(cbc <= cbs)
                null(c);
}

void
ibm(int cc)
{
        int c;

        c = cc;
        if(cflag&UCASE && c>='a' && c<='z')
                c += 'A'-'a';
        if(cflag&LCASE && c>='A' && c<='Z')
                c += 'a'-'A';
        c = atoibm[c] & 0377;
        if(cbs == 0) {
                null(c);
                return;
        }
        if(cc == '\n') {
                while(cbc < cbs) {
                        null(atoibm[' ']);
                        cbc++;
                }
                cbc = 0;
                return;
        }
        if(cbc == cbs)
                ntrunc++;
        cbc++;
        if(cbc <= cbs)
                null(c);
}

void
block(int cc)
{
        int c;

        c = cc;
        if(cflag&UCASE && c>='a' && c<='z')
                c += 'A'-'a';
        if(cflag&LCASE && c>='A' && c<='Z')
                c += 'a'-'A';
        c &= 0377;
        if(cbs == 0) {
                null(c);
                return;
        }
        if(cc == '\n') {
                while(cbc < cbs) {
                        null(' ');
                        cbc++;
                }
                cbc = 0;
                return;
        }
        if(cbc == cbs)
                ntrunc++;
        cbc++;
        if(cbc <= cbs)
                null(c);
}

void
term(char *status)
{
        stats();
        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)
                fprint(2, "%lud truncated records\n", ntrunc);
}

uchar   etoa[] =
{
        0000,0001,0002,0003,0234,0011,0206,0177,
        0227,0215,0216,0013,0014,0015,0016,0017,
        0020,0021,0022,0023,0235,0205,0010,0207,
        0030,0031,0222,0217,0034,0035,0036,0037,
        0200,0201,0202,0203,0204,0012,0027,0033,
        0210,0211,0212,0213,0214,0005,0006,0007,
        0220,0221,0026,0223,0224,0225,0226,0004,
        0230,0231,0232,0233,0024,0025,0236,0032,
        0040,0240,0241,0242,0243,0244,0245,0246,
        0247,0250,0133,0056,0074,0050,0053,0041,
        0046,0251,0252,0253,0254,0255,0256,0257,
        0260,0261,0135,0044,0052,0051,0073,0136,
        0055,0057,0262,0263,0264,0265,0266,0267,
        0270,0271,0174,0054,0045,0137,0076,0077,
        0272,0273,0274,0275,0276,0277,0300,0301,
        0302,0140,0072,0043,0100,0047,0075,0042,
        0303,0141,0142,0143,0144,0145,0146,0147,
        0150,0151,0304,0305,0306,0307,0310,0311,
        0312,0152,0153,0154,0155,0156,0157,0160,
        0161,0162,0313,0314,0315,0316,0317,0320,
        0321,0176,0163,0164,0165,0166,0167,0170,
        0171,0172,0322,0323,0324,0325,0326,0327,
        0330,0331,0332,0333,0334,0335,0336,0337,
        0340,0341,0342,0343,0344,0345,0346,0347,
        0173,0101,0102,0103,0104,0105,0106,0107,
        0110,0111,0350,0351,0352,0353,0354,0355,
        0175,0112,0113,0114,0115,0116,0117,0120,
        0121,0122,0356,0357,0360,0361,0362,0363,
        0134,0237,0123,0124,0125,0126,0127,0130,
        0131,0132,0364,0365,0366,0367,0370,0371,
        0060,0061,0062,0063,0064,0065,0066,0067,
        0070,0071,0372,0373,0374,0375,0376,0377,
};
uchar   atoe[] =
{
        0000,0001,0002,0003,0067,0055,0056,0057,
        0026,0005,0045,0013,0014,0015,0016,0017,
        0020,0021,0022,0023,0074,0075,0062,0046,
        0030,0031,0077,0047,0034,0035,0036,0037,
        0100,0117,0177,0173,0133,0154,0120,0175,
        0115,0135,0134,0116,0153,0140,0113,0141,
        0360,0361,0362,0363,0364,0365,0366,0367,
        0370,0371,0172,0136,0114,0176,0156,0157,
        0174,0301,0302,0303,0304,0305,0306,0307,
        0310,0311,0321,0322,0323,0324,0325,0326,
        0327,0330,0331,0342,0343,0344,0345,0346,
        0347,0350,0351,0112,0340,0132,0137,0155,
        0171,0201,0202,0203,0204,0205,0206,0207,
        0210,0211,0221,0222,0223,0224,0225,0226,
        0227,0230,0231,0242,0243,0244,0245,0246,
        0247,0250,0251,0300,0152,0320,0241,0007,
        0040,0041,0042,0043,0044,0025,0006,0027,
        0050,0051,0052,0053,0054,0011,0012,0033,
        0060,0061,0032,0063,0064,0065,0066,0010,
        0070,0071,0072,0073,0004,0024,0076,0341,
        0101,0102,0103,0104,0105,0106,0107,0110,
        0111,0121,0122,0123,0124,0125,0126,0127,
        0130,0131,0142,0143,0144,0145,0146,0147,
        0150,0151,0160,0161,0162,0163,0164,0165,
        0166,0167,0170,0200,0212,0213,0214,0215,
        0216,0217,0220,0232,0233,0234,0235,0236,
        0237,0240,0252,0253,0254,0255,0256,0257,
        0260,0261,0262,0263,0264,0265,0266,0267,
        0270,0271,0272,0273,0274,0275,0276,0277,
        0312,0313,0314,0315,0316,0317,0332,0333,
        0334,0335,0336,0337,0352,0353,0354,0355,
        0356,0357,0372,0373,0374,0375,0376,0377,
};
uchar   atoibm[] =
{
        0000,0001,0002,0003,0067,0055,0056,0057,
        0026,0005,0045,0013,0014,0015,0016,0017,
        0020,0021,0022,0023,0074,0075,0062,0046,
        0030,0031,0077,0047,0034,0035,0036,0037,
        0100,0132,0177,0173,0133,0154,0120,0175,
        0115,0135,0134,0116,0153,0140,0113,0141,
        0360,0361,0362,0363,0364,0365,0366,0367,
        0370,0371,0172,0136,0114,0176,0156,0157,
        0174,0301,0302,0303,0304,0305,0306,0307,
        0310,0311,0321,0322,0323,0324,0325,0326,
        0327,0330,0331,0342,0343,0344,0345,0346,
        0347,0350,0351,0255,0340,0275,0137,0155,
        0171,0201,0202,0203,0204,0205,0206,0207,
        0210,0211,0221,0222,0223,0224,0225,0226,
        0227,0230,0231,0242,0243,0244,0245,0246,
        0247,0250,0251,0300,0117,0320,0241,0007,
        0040,0041,0042,0043,0044,0025,0006,0027,
        0050,0051,0052,0053,0054,0011,0012,0033,
        0060,0061,0032,0063,0064,0065,0066,0010,
        0070,0071,0072,0073,0004,0024,0076,0341,
        0101,0102,0103,0104,0105,0106,0107,0110,
        0111,0121,0122,0123,0124,0125,0126,0127,
        0130,0131,0142,0143,0144,0145,0146,0147,
        0150,0151,0160,0161,0162,0163,0164,0165,
        0166,0167,0170,0200,0212,0213,0214,0215,
        0216,0217,0220,0232,0233,0234,0235,0236,
        0237,0240,0252,0253,0254,0255,0256,0257,
        0260,0261,0262,0263,0264,0265,0266,0267,
        0270,0271,0272,0273,0274,0275,0276,0277,
        0312,0313,0314,0315,0316,0317,0332,0333,
        0334,0335,0336,0337,0352,0353,0354,0355,
        0356,0357,0372,0373,0374,0375,0376,0377,
};