| #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 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("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); |
| 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; |
| |
| return 0; // shut up apple gcc |
| } |
| |
| 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, |
| }; |