9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

dd.c (11559B)


      1 #include <u.h>
      2 #include <libc.h>
      3 
      4 #define	BIG	2147483647
      5 #define	LCASE	(1<<0)
      6 #define	UCASE	(1<<1)
      7 #define	SWAB	(1<<2)
      8 #define NERR	(1<<3)
      9 #define SYNC	(1<<4)
     10 int	cflag;
     11 int	fflag;
     12 char	*string;
     13 char	*ifile;
     14 char	*ofile;
     15 char	*ibuf;
     16 char	*obuf;
     17 vlong	skip;
     18 vlong	oseekn;
     19 vlong	iseekn;
     20 vlong	count;
     21 long	files	= 1;
     22 long	ibs	= 512;
     23 long	obs	= 512;
     24 long	bs;
     25 long	cbs;
     26 long	ibc;
     27 long	obc;
     28 long	cbc;
     29 long	nifr;
     30 long	nipr;
     31 long	nofr;
     32 long	nopr;
     33 long	ntrunc;
     34 int dotrunc = 1;
     35 int	ibf;
     36 int	obf;
     37 char	*op;
     38 int	nspace;
     39 uchar	etoa[256];
     40 uchar	atoe[256];
     41 uchar	atoibm[256];
     42 
     43 void	flsh(void);
     44 int	match(char *s);
     45 vlong	number(long big);
     46 void	cnull(int cc);
     47 void	null(int c);
     48 void	ascii(int cc);
     49 void	unblock(int cc);
     50 void	ebcdic(int cc);
     51 void	ibm(int cc);
     52 void	block(int cc);
     53 void	term(void);
     54 void	stats(void);
     55 
     56 #define	iskey(s)	((key[0] == '-') && (strcmp(key+1, s) == 0))
     57 
     58 void
     59 main(int argc, char *argv[])
     60 {
     61 	void (*conv)(int);
     62 	char *ip;
     63 	char *key;
     64 	int a, c;
     65 
     66 	conv = null;
     67 	for(c=1; c<argc; c++) {
     68 		key = argv[c++];
     69 		if(c >= argc){
     70 			fprint(2, "dd: arg %s needs a value\n", key);
     71 			exits("arg");
     72 		}
     73 		string = argv[c];
     74 		if(iskey("ibs")) {
     75 			ibs = number(BIG);
     76 			continue;
     77 		}
     78 		if(iskey("obs")) {
     79 			obs = number(BIG);
     80 			continue;
     81 		}
     82 		if(iskey("cbs")) {
     83 			cbs = number(BIG);
     84 			continue;
     85 		}
     86 		if(iskey("bs")) {
     87 			bs = number(BIG);
     88 			continue;
     89 		}
     90 		if(iskey("if")) {
     91 			ifile = string;
     92 			continue;
     93 		}
     94 		if(iskey("of")) {
     95 			ofile = string;
     96 			continue;
     97 		}
     98 		if(iskey("trunc")) {
     99 			dotrunc = number(BIG);
    100 			continue;
    101 		}
    102 		if(iskey("skip")) {
    103 			skip = number(BIG);
    104 			continue;
    105 		}
    106 		if(iskey("seek") || iskey("oseek")) {
    107 			oseekn = number(BIG);
    108 			continue;
    109 		}
    110 		if(iskey("iseek")) {
    111 			iseekn = number(BIG);
    112 			continue;
    113 		}
    114 		if(iskey("count")) {
    115 			count = number(BIG);
    116 			continue;
    117 		}
    118 		if(iskey("files")) {
    119 			files = number(BIG);
    120 			continue;
    121 		}
    122 		if(iskey("conv")) {
    123 		cloop:
    124 			if(match(","))
    125 				goto cloop;
    126 			if(*string == '\0')
    127 				continue;
    128 			if(match("ebcdic")) {
    129 				conv = ebcdic;
    130 				goto cloop;
    131 			}
    132 			if(match("ibm")) {
    133 				conv = ibm;
    134 				goto cloop;
    135 			}
    136 			if(match("ascii")) {
    137 				conv = ascii;
    138 				goto cloop;
    139 			}
    140 			if(match("block")) {
    141 				conv = block;
    142 				goto cloop;
    143 			}
    144 			if(match("unblock")) {
    145 				conv = unblock;
    146 				goto cloop;
    147 			}
    148 			if(match("lcase")) {
    149 				cflag |= LCASE;
    150 				goto cloop;
    151 			}
    152 			if(match("ucase")) {
    153 				cflag |= UCASE;
    154 				goto cloop;
    155 			}
    156 			if(match("swab")) {
    157 				cflag |= SWAB;
    158 				goto cloop;
    159 			}
    160 			if(match("noerror")) {
    161 				cflag |= NERR;
    162 				goto cloop;
    163 			}
    164 			if(match("sync")) {
    165 				cflag |= SYNC;
    166 				goto cloop;
    167 			}
    168 		}
    169 		fprint(2, "dd: bad arg: %s\n", key);
    170 		exits("arg");
    171 	}
    172 	if(conv == null && cflag&(LCASE|UCASE))
    173 		conv = cnull;
    174 	if(ifile)
    175 		ibf = open(ifile, 0);
    176 	else
    177 		ibf = dup(0, -1);
    178 	if(ibf < 0) {
    179 		fprint(2, "dd: open %s: %r\n", ifile);
    180 		exits("open");
    181 	}
    182 	if(ofile){
    183 		if(dotrunc)
    184 			obf = create(ofile, 1, 0664);
    185 		else
    186 			obf = open(ofile, 1);
    187 		if(obf < 0) {
    188 			fprint(2, "dd: create %s: %r\n", ofile);
    189 			exits("create");
    190 		}
    191 	}else{
    192 		obf = dup(1, -1);
    193 		if(obf < 0) {
    194 			fprint(2, "dd: can't dup file descriptor: %s: %r\n", ofile);
    195 			exits("dup");
    196 		}
    197 	}
    198 	if(bs)
    199 		ibs = obs = bs;
    200 	if(ibs == obs && conv == null)
    201 		fflag++;
    202 	if(ibs == 0 || obs == 0) {
    203 		fprint(2, "dd: counts: cannot be zero\n");
    204 		exits("counts");
    205 	}
    206 	ibuf = malloc(ibs);
    207 	if(fflag)
    208 		obuf = ibuf;
    209 	else
    210 		obuf = malloc(obs);
    211 	if(ibuf == NULL || obuf == NULL) {
    212 		fprint(2, "dd: not enough memory: %r\n");
    213 		exits("memory");
    214 	}
    215 	ibc = 0;
    216 	obc = 0;
    217 	cbc = 0;
    218 	op = obuf;
    219 
    220 /*
    221 	if(signal(SIGINT, SIG_IGN) != SIG_IGN)
    222 		signal(SIGINT, term);
    223 */
    224 	seek(obf, obs*oseekn, 1);
    225 	seek(ibf, ibs*iseekn, 1);
    226 	while(skip) {
    227 		read(ibf, ibuf, ibs);
    228 		skip--;
    229 	}
    230 
    231 	ip = 0;
    232 loop:
    233 	if(ibc-- == 0) {
    234 		ibc = 0;
    235 		if(count==0 || nifr+nipr!=count) {
    236 			if(cflag&(NERR|SYNC))
    237 			for(ip=ibuf+ibs; ip>ibuf;)
    238 				*--ip = 0;
    239 			ibc = read(ibf, ibuf, ibs);
    240 		}
    241 		if(ibc == -1) {
    242 			perror("read");
    243 			if((cflag&NERR) == 0) {
    244 				flsh();
    245 				term();
    246 			}
    247 			ibc = 0;
    248 			for(c=0; c<ibs; c++)
    249 				if(ibuf[c] != 0)
    250 					ibc = c;
    251 			stats();
    252 		}
    253 		if(ibc == 0 && --files<=0) {
    254 			flsh();
    255 			term();
    256 		}
    257 		if(ibc != ibs) {
    258 			nipr++;
    259 			if(cflag&SYNC)
    260 				ibc = ibs;
    261 		} else
    262 			nifr++;
    263 		ip = ibuf;
    264 		c = (ibc>>1) & ~1;
    265 		if(cflag&SWAB && c)
    266 		do {
    267 			a = *ip++;
    268 			ip[-1] = *ip;
    269 			*ip++ = a;
    270 		} while(--c);
    271 		ip = ibuf;
    272 		if(fflag) {
    273 			obc = ibc;
    274 			flsh();
    275 			ibc = 0;
    276 		}
    277 		goto loop;
    278 	}
    279 	c = 0;
    280 	c |= *ip++;
    281 	c &= 0377;
    282 	(*conv)(c);
    283 	goto loop;
    284 }
    285 
    286 void
    287 flsh(void)
    288 {
    289 	int c;
    290 
    291 	if(obc) {
    292 		c = write(obf, obuf, obc);
    293 		if(c != obc) {
    294 			if(c > 0)
    295 				++nopr;
    296 			perror("write");
    297 			term();
    298 		}
    299 		if(obc == obs)
    300 			nofr++;
    301 		else
    302 			nopr++;
    303 		obc = 0;
    304 	}
    305 }
    306 
    307 int
    308 match(char *s)
    309 {
    310 	char *cs;
    311 
    312 	cs = string;
    313 	while(*cs++ == *s)
    314 		if(*s++ == '\0')
    315 			goto true;
    316 	if(*s != '\0')
    317 		return 0;
    318 
    319 true:
    320 	cs--;
    321 	string = cs;
    322 	return 1;
    323 }
    324 
    325 vlong
    326 number(long big)
    327 {
    328 	char *cs;
    329 	vlong n;
    330 
    331 	cs = string;
    332 	n = 0;
    333 	while(*cs >= '0' && *cs <= '9')
    334 		n = n*10 + *cs++ - '0';
    335 	for(;;)
    336 	switch(*cs++) {
    337 
    338 	case 'k':
    339 		n *= 1024;
    340 		continue;
    341 
    342 /*	case 'w':
    343 		n *= sizeof(int);
    344 		continue;
    345 */
    346 
    347 	case 'b':
    348 		n *= 512;
    349 		continue;
    350 
    351 /*	case '*':*/
    352 	case 'x':
    353 		string = cs;
    354 		n *= number(BIG);
    355 
    356 	case '\0':
    357 		if(n>=big || n<0) {
    358 			fprint(2, "dd: argument %lld out of range\n", n);
    359 			exits("range");
    360 		}
    361 		return n;
    362 	}
    363 	/* never gets here */
    364 }
    365 
    366 void
    367 cnull(int cc)
    368 {
    369 	int c;
    370 
    371 	c = cc;
    372 	if((cflag&UCASE) && c>='a' && c<='z')
    373 		c += 'A'-'a';
    374 	if((cflag&LCASE) && c>='A' && c<='Z')
    375 		c += 'a'-'A';
    376 	null(c);
    377 }
    378 
    379 void
    380 null(int c)
    381 {
    382 
    383 	*op = c;
    384 	op++;
    385 	if(++obc >= obs) {
    386 		flsh();
    387 		op = obuf;
    388 	}
    389 }
    390 
    391 void
    392 ascii(int cc)
    393 {
    394 	int c;
    395 
    396 	c = etoa[cc];
    397 	if(cbs == 0) {
    398 		cnull(c);
    399 		return;
    400 	}
    401 	if(c == ' ') {
    402 		nspace++;
    403 		goto out;
    404 	}
    405 	while(nspace > 0) {
    406 		null(' ');
    407 		nspace--;
    408 	}
    409 	cnull(c);
    410 
    411 out:
    412 	if(++cbc >= cbs) {
    413 		null('\n');
    414 		cbc = 0;
    415 		nspace = 0;
    416 	}
    417 }
    418 
    419 void
    420 unblock(int cc)
    421 {
    422 	int c;
    423 
    424 	c = cc & 0377;
    425 	if(cbs == 0) {
    426 		cnull(c);
    427 		return;
    428 	}
    429 	if(c == ' ') {
    430 		nspace++;
    431 		goto out;
    432 	}
    433 	while(nspace > 0) {
    434 		null(' ');
    435 		nspace--;
    436 	}
    437 	cnull(c);
    438 
    439 out:
    440 	if(++cbc >= cbs) {
    441 		null('\n');
    442 		cbc = 0;
    443 		nspace = 0;
    444 	}
    445 }
    446 
    447 void
    448 ebcdic(int cc)
    449 {
    450 	int c;
    451 
    452 	c = cc;
    453 	if(cflag&UCASE && c>='a' && c<='z')
    454 		c += 'A'-'a';
    455 	if(cflag&LCASE && c>='A' && c<='Z')
    456 		c += 'a'-'A';
    457 	c = atoe[c];
    458 	if(cbs == 0) {
    459 		null(c);
    460 		return;
    461 	}
    462 	if(cc == '\n') {
    463 		while(cbc < cbs) {
    464 			null(atoe[' ']);
    465 			cbc++;
    466 		}
    467 		cbc = 0;
    468 		return;
    469 	}
    470 	if(cbc == cbs)
    471 		ntrunc++;
    472 	cbc++;
    473 	if(cbc <= cbs)
    474 		null(c);
    475 }
    476 
    477 void
    478 ibm(int cc)
    479 {
    480 	int c;
    481 
    482 	c = cc;
    483 	if(cflag&UCASE && c>='a' && c<='z')
    484 		c += 'A'-'a';
    485 	if(cflag&LCASE && c>='A' && c<='Z')
    486 		c += 'a'-'A';
    487 	c = atoibm[c] & 0377;
    488 	if(cbs == 0) {
    489 		null(c);
    490 		return;
    491 	}
    492 	if(cc == '\n') {
    493 		while(cbc < cbs) {
    494 			null(atoibm[' ']);
    495 			cbc++;
    496 		}
    497 		cbc = 0;
    498 		return;
    499 	}
    500 	if(cbc == cbs)
    501 		ntrunc++;
    502 	cbc++;
    503 	if(cbc <= cbs)
    504 		null(c);
    505 }
    506 
    507 void
    508 block(int cc)
    509 {
    510 	int c;
    511 
    512 	c = cc;
    513 	if(cflag&UCASE && c>='a' && c<='z')
    514 		c += 'A'-'a';
    515 	if(cflag&LCASE && c>='A' && c<='Z')
    516 		c += 'a'-'A';
    517 	c &= 0377;
    518 	if(cbs == 0) {
    519 		null(c);
    520 		return;
    521 	}
    522 	if(cc == '\n') {
    523 		while(cbc < cbs) {
    524 			null(' ');
    525 			cbc++;
    526 		}
    527 		cbc = 0;
    528 		return;
    529 	}
    530 	if(cbc == cbs)
    531 		ntrunc++;
    532 	cbc++;
    533 	if(cbc <= cbs)
    534 		null(c);
    535 }
    536 
    537 void
    538 term(void)
    539 {
    540 
    541 	stats();
    542 	exits(0);
    543 }
    544 
    545 void
    546 stats(void)
    547 {
    548 
    549 	fprint(2, "%lud+%lud records in\n", nifr, nipr);
    550 	fprint(2, "%lud+%lud records out\n", nofr, nopr);
    551 	if(ntrunc)
    552 		fprint(2, "%lud truncated records\n", ntrunc);
    553 }
    554 
    555 uchar	etoa[] =
    556 {
    557 	0000,0001,0002,0003,0234,0011,0206,0177,
    558 	0227,0215,0216,0013,0014,0015,0016,0017,
    559 	0020,0021,0022,0023,0235,0205,0010,0207,
    560 	0030,0031,0222,0217,0034,0035,0036,0037,
    561 	0200,0201,0202,0203,0204,0012,0027,0033,
    562 	0210,0211,0212,0213,0214,0005,0006,0007,
    563 	0220,0221,0026,0223,0224,0225,0226,0004,
    564 	0230,0231,0232,0233,0024,0025,0236,0032,
    565 	0040,0240,0241,0242,0243,0244,0245,0246,
    566 	0247,0250,0133,0056,0074,0050,0053,0041,
    567 	0046,0251,0252,0253,0254,0255,0256,0257,
    568 	0260,0261,0135,0044,0052,0051,0073,0136,
    569 	0055,0057,0262,0263,0264,0265,0266,0267,
    570 	0270,0271,0174,0054,0045,0137,0076,0077,
    571 	0272,0273,0274,0275,0276,0277,0300,0301,
    572 	0302,0140,0072,0043,0100,0047,0075,0042,
    573 	0303,0141,0142,0143,0144,0145,0146,0147,
    574 	0150,0151,0304,0305,0306,0307,0310,0311,
    575 	0312,0152,0153,0154,0155,0156,0157,0160,
    576 	0161,0162,0313,0314,0315,0316,0317,0320,
    577 	0321,0176,0163,0164,0165,0166,0167,0170,
    578 	0171,0172,0322,0323,0324,0325,0326,0327,
    579 	0330,0331,0332,0333,0334,0335,0336,0337,
    580 	0340,0341,0342,0343,0344,0345,0346,0347,
    581 	0173,0101,0102,0103,0104,0105,0106,0107,
    582 	0110,0111,0350,0351,0352,0353,0354,0355,
    583 	0175,0112,0113,0114,0115,0116,0117,0120,
    584 	0121,0122,0356,0357,0360,0361,0362,0363,
    585 	0134,0237,0123,0124,0125,0126,0127,0130,
    586 	0131,0132,0364,0365,0366,0367,0370,0371,
    587 	0060,0061,0062,0063,0064,0065,0066,0067,
    588 	0070,0071,0372,0373,0374,0375,0376,0377,
    589 };
    590 uchar	atoe[] =
    591 {
    592 	0000,0001,0002,0003,0067,0055,0056,0057,
    593 	0026,0005,0045,0013,0014,0015,0016,0017,
    594 	0020,0021,0022,0023,0074,0075,0062,0046,
    595 	0030,0031,0077,0047,0034,0035,0036,0037,
    596 	0100,0117,0177,0173,0133,0154,0120,0175,
    597 	0115,0135,0134,0116,0153,0140,0113,0141,
    598 	0360,0361,0362,0363,0364,0365,0366,0367,
    599 	0370,0371,0172,0136,0114,0176,0156,0157,
    600 	0174,0301,0302,0303,0304,0305,0306,0307,
    601 	0310,0311,0321,0322,0323,0324,0325,0326,
    602 	0327,0330,0331,0342,0343,0344,0345,0346,
    603 	0347,0350,0351,0112,0340,0132,0137,0155,
    604 	0171,0201,0202,0203,0204,0205,0206,0207,
    605 	0210,0211,0221,0222,0223,0224,0225,0226,
    606 	0227,0230,0231,0242,0243,0244,0245,0246,
    607 	0247,0250,0251,0300,0152,0320,0241,0007,
    608 	0040,0041,0042,0043,0044,0025,0006,0027,
    609 	0050,0051,0052,0053,0054,0011,0012,0033,
    610 	0060,0061,0032,0063,0064,0065,0066,0010,
    611 	0070,0071,0072,0073,0004,0024,0076,0341,
    612 	0101,0102,0103,0104,0105,0106,0107,0110,
    613 	0111,0121,0122,0123,0124,0125,0126,0127,
    614 	0130,0131,0142,0143,0144,0145,0146,0147,
    615 	0150,0151,0160,0161,0162,0163,0164,0165,
    616 	0166,0167,0170,0200,0212,0213,0214,0215,
    617 	0216,0217,0220,0232,0233,0234,0235,0236,
    618 	0237,0240,0252,0253,0254,0255,0256,0257,
    619 	0260,0261,0262,0263,0264,0265,0266,0267,
    620 	0270,0271,0272,0273,0274,0275,0276,0277,
    621 	0312,0313,0314,0315,0316,0317,0332,0333,
    622 	0334,0335,0336,0337,0352,0353,0354,0355,
    623 	0356,0357,0372,0373,0374,0375,0376,0377,
    624 };
    625 uchar	atoibm[] =
    626 {
    627 	0000,0001,0002,0003,0067,0055,0056,0057,
    628 	0026,0005,0045,0013,0014,0015,0016,0017,
    629 	0020,0021,0022,0023,0074,0075,0062,0046,
    630 	0030,0031,0077,0047,0034,0035,0036,0037,
    631 	0100,0132,0177,0173,0133,0154,0120,0175,
    632 	0115,0135,0134,0116,0153,0140,0113,0141,
    633 	0360,0361,0362,0363,0364,0365,0366,0367,
    634 	0370,0371,0172,0136,0114,0176,0156,0157,
    635 	0174,0301,0302,0303,0304,0305,0306,0307,
    636 	0310,0311,0321,0322,0323,0324,0325,0326,
    637 	0327,0330,0331,0342,0343,0344,0345,0346,
    638 	0347,0350,0351,0255,0340,0275,0137,0155,
    639 	0171,0201,0202,0203,0204,0205,0206,0207,
    640 	0210,0211,0221,0222,0223,0224,0225,0226,
    641 	0227,0230,0231,0242,0243,0244,0245,0246,
    642 	0247,0250,0251,0300,0117,0320,0241,0007,
    643 	0040,0041,0042,0043,0044,0025,0006,0027,
    644 	0050,0051,0052,0053,0054,0011,0012,0033,
    645 	0060,0061,0032,0063,0064,0065,0066,0010,
    646 	0070,0071,0072,0073,0004,0024,0076,0341,
    647 	0101,0102,0103,0104,0105,0106,0107,0110,
    648 	0111,0121,0122,0123,0124,0125,0126,0127,
    649 	0130,0131,0142,0143,0144,0145,0146,0147,
    650 	0150,0151,0160,0161,0162,0163,0164,0165,
    651 	0166,0167,0170,0200,0212,0213,0214,0215,
    652 	0216,0217,0220,0232,0233,0234,0235,0236,
    653 	0237,0240,0252,0253,0254,0255,0256,0257,
    654 	0260,0261,0262,0263,0264,0265,0266,0267,
    655 	0270,0271,0272,0273,0274,0275,0276,0277,
    656 	0312,0313,0314,0315,0316,0317,0332,0333,
    657 	0334,0335,0336,0337,0352,0353,0354,0355,
    658 	0356,0357,0372,0373,0374,0375,0376,0377,
    659 };