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