Print this page
10703 smatch unreachable code checking needs reworking
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/od/od.c
+++ new/usr/src/cmd/od/od.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
14 14 */
15 15
16 16 /*
17 + * Copyright 2019 Joyent, Inc.
18 + */
19 +
20 +/*
17 21 * od - octal dump. Not really just octal anymore; read the POSIX
18 22 * specification for it -- its more complex than you think!
19 23 *
20 24 * NB: We followed the POSIX semantics fairly strictly, where the
21 25 * legacy code's behavior was in conflict. In many cases the legacy
22 26 * Solaris code was so completely broken as to be completely unusable.
23 27 * (For example, the long double support was broken beyond
24 28 * imagination!) Note that GNU coreutils violates POSIX in a few
25 29 * interesting ways, such as changing the numbering of the addresses
26 30 * when skipping. (Address starts should always be at 0, according to
27 31 * the sample output in the Open Group man page.)
28 32 */
29 33
30 34 #include <stdio.h>
31 35 #include <stdlib.h>
32 36 #include <sys/types.h>
33 37 #include <string.h>
34 38 #include <err.h>
35 39 #include <wchar.h>
36 40 #include <locale.h>
37 41 #include <unistd.h>
38 42 #include <sys/stat.h>
39 43
40 44 #define _(x) gettext(x)
41 45
42 46
43 47 #ifndef TEXT_DOMAIN
44 48 #define TEXT_DOMAIN "SYS_TEST"
45 49 #endif
46 50
47 51 /* address format */
48 52 static char *afmt = "%07llo";
49 53 static char *cfmt = " ";
50 54
51 55 static FILE *input = NULL;
52 56 static size_t lcm = 1;
53 57 static size_t blocksize = 16;
54 58 static int numfiles = 0;
55 59 static int curfile = 0;
56 60 static char **files = NULL;
57 61 static off_t limit = -1;
58 62
59 63 /*
60 64 * This structure describes our ring buffer. Its always a power of 2
61 65 * in size to make wrap around calculations fast using a mask instead
62 66 * of doing modulo.
63 67 *
64 68 * The size is calculated thusly: We need three "blocks" of data, as
65 69 * we process a block at a time (one block == one line of od output.)
66 70 *
67 71 * We need lookahead of an extra block to support multibyte chars. We
68 72 * also have a look behind so that we can avoid printing lines that
69 73 * are identical to what we've already printed. Finally, we need the
70 74 * current block.
71 75 *
72 76 * The block size is determined by the least common multiple of the
73 77 * data items being displayed. Usually it will be 16, but sometimes
74 78 * it is 24 (when 12-byte long doubles are presented.)
75 79 *
76 80 * The data buffer is allocaed via memalign to make sure it is
77 81 * properly aligned.
78 82 */
79 83 typedef struct buffer {
80 84 char *data; /* data buffer */
81 85 int prod; /* producer index */
82 86 int cons; /* consumer index */
83 87 int mask; /* buffer size - 1, wraparound index */
84 88 int navail; /* total bytes avail */
85 89 } buffer_t;
86 90
87 91 /*
88 92 * This structure is used to provide information on a specific output
89 93 * format. We link them together in a list representing the output
90 94 * formats that the user has selected.
91 95 */
92 96 typedef struct output {
93 97 int width; /* bytes consumed per call */
94 98 void (*func)(buffer_t *, int); /* output function */
95 99 struct output *next; /* link node */
96 100 } output_t;
97 101
98 102 /*
99 103 * Specifiers
100 104 */
101 105
102 106 typedef unsigned char u8;
103 107 typedef unsigned short u16;
104 108 typedef unsigned int u32;
105 109 typedef unsigned long long u64;
106 110 typedef char s8;
107 111 typedef short s16;
108 112 typedef int s32;
109 113 typedef long long s64;
110 114 typedef float fF;
111 115 typedef double fD;
112 116 typedef long double fL;
113 117
114 118 static void
115 119 usage(void)
116 120 {
117 121 (void) fprintf(stderr, _("usage: od [-bcCdDfFoOsSvxX] "
118 122 "[-t types ]... [-A base] [-j skip] [-N count] [file]...\n"));
119 123 exit(1);
120 124 }
121 125
122 126 #define DECL_GET(typ) \
123 127 static typ \
124 128 get_ ## typ(buffer_t *b, int index) \
125 129 { \
126 130 typ val = *(typ *)(void *)(b->data + index); \
127 131 return (val); \
128 132 }
129 133 DECL_GET(u8)
130 134 DECL_GET(u16)
131 135 DECL_GET(u32)
132 136 DECL_GET(u64)
133 137 DECL_GET(s8)
134 138 DECL_GET(s16)
135 139 DECL_GET(s32)
136 140 DECL_GET(s64)
137 141 DECL_GET(fF)
138 142 DECL_GET(fD)
139 143 DECL_GET(fL)
140 144
141 145 #define DECL_OUT(nm, typ, fmt) \
142 146 static void \
143 147 do_ ## nm(buffer_t *buf, int index) \
144 148 { \
145 149 typ v = get_ ## typ(buf, index); \
146 150 (void) printf(fmt, v); \
147 151 } \
148 152 \
149 153 static output_t output_ ## nm = { \
150 154 sizeof (typ), do_ ## nm \
151 155 };
152 156
153 157 DECL_OUT(oct_b, u8, " %03o")
154 158 DECL_OUT(oct_w, u16, " %06ho")
155 159 DECL_OUT(oct_d, u32, " %011o")
156 160 DECL_OUT(oct_q, u64, " %022llo")
157 161 DECL_OUT(dec_b, u8, " %03u")
158 162 DECL_OUT(dec_w, u16, " %05hu")
159 163 DECL_OUT(dec_d, u32, " %010u")
160 164 DECL_OUT(dec_q, u64, " %020llu")
161 165 DECL_OUT(sig_b, s8, " %03d")
162 166 DECL_OUT(sig_w, s16, " %6.05hd")
163 167 DECL_OUT(sig_d, s32, " %11.010d")
164 168 DECL_OUT(sig_q, s64, " %20.019lld")
165 169 DECL_OUT(hex_b, u8, " %02x")
166 170 DECL_OUT(hex_w, u16, " %04hx")
167 171 DECL_OUT(hex_d, s32, " %08x")
168 172 DECL_OUT(hex_q, s64, " %016llx")
169 173 DECL_OUT(float, fF, " %14.7e")
170 174 DECL_OUT(double, fD, " %21.14e")
171 175 DECL_OUT(ldouble, fL, " %24.14Le")
172 176
173 177 static char *ascii[] = {
174 178 "nul", "soh", "stx", "etx", "eot", "enq", "ack", " be",
175 179 " bs", " ht", " lf", " vt", " ff", " cr", " so", " si",
176 180 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
177 181 "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
178 182 " sp", " !", " \"", " #", " $", " %", " &", " '",
179 183 " (", " )", " *", " +", " ,", " -", " .", " /",
180 184 " 0", " 1", " 2", " 3", " 4", " 5", " 6", " 7",
181 185 " 8", " 9", " :", " ;", " <", " =", " >", " ?",
182 186 " @", " A", " B", " C", " D", " E", " F", " G",
183 187 " H", " I", " J", " K", " L", " M", " N", " O",
184 188 " P", " Q", " R", " S", " T", " U", " V", " W",
185 189 " X", " Y", " Z", " [", " \\", " ]", " ^", " _",
186 190 " `", " a", " b", " c", " d", " e", " f", " g",
187 191 " h", " i", " j", " k", " l", " m", " n", " o",
188 192 " p", " q", " r", " s", " t", " u", " v", " w",
189 193 " x", " y", " z", " {", " |", " }", " ~", "del"
190 194 };
191 195
192 196 static void
193 197 do_ascii(buffer_t *buf, int index)
194 198 {
195 199 uint8_t v = get_u8(buf, index);
196 200
197 201 (void) fputc(' ', stdout);
198 202 (void) fputs(ascii[v & 0x7f], stdout);
199 203 }
200 204
201 205 static output_t output_ascii = {
202 206 1, do_ascii,
203 207 };
204 208
205 209 static void
206 210 do_char(buffer_t *buf, int index)
207 211 {
208 212 static int nresid = 0;
209 213 static int printable = 0;
210 214 int cnt;
211 215 int avail;
212 216 int nb;
213 217 char scratch[10];
214 218 wchar_t wc;
215 219 int which;
216 220
217 221 uint8_t v = get_u8(buf, index);
218 222
219 223 /*
220 224 * If there were residual bytes from an earlier
221 225 * character, then just display the ** continuation
222 226 * indication.
223 227 */
224 228 if (nresid) {
225 229 if (printable) {
226 230 (void) fputs(" **", stdout);
227 231 } else {
228 232 (void) printf(" %03o", v);
229 233 }
230 234 nresid--;
231 235 return;
232 236 }
233 237
234 238 /*
235 239 * Peek ahead up to MB_CUR_MAX characters. This has to be
236 240 * done carefully because we might need to look into the next
237 241 * block to really know for sure.
238 242 */
239 243 scratch[0] = v;
240 244 avail = buf->navail;
241 245 if (avail > MB_CUR_MAX)
242 246 avail = MB_CUR_MAX;
243 247 for (cnt = 1, which = index + 1; cnt < avail; cnt++, which++) {
244 248 scratch[cnt] = buf->data[which & buf->mask];
245 249 }
246 250
247 251 /* now see if the value is a real character */
248 252 nresid = 0;
249 253 wc = 0;
250 254 nb = mbtowc(&wc, scratch, avail);
251 255 if (nb < 0) {
252 256 (void) printf(" %03o", v);
253 257 return;
254 258 }
255 259 if (nb == 0) {
256 260 (void) fputs(" \\0", stdout);
257 261 return;
258 262 }
259 263 nresid = nb - 1;
260 264 if (nb && iswprint(wc)) {
261 265 scratch[nb] = 0;
262 266 (void) fputs(" ", stdout);
263 267 (void) fputs(scratch, stdout);
264 268 printable = 1;
265 269 return;
266 270 }
267 271 printable = 0;
268 272 if (wc == 0) {
269 273 (void) fputs(" \\0", stdout);
270 274 } else if (wc == '\b') {
271 275 (void) fputs(" \\b", stdout);
272 276 } else if (wc == '\f') {
273 277 (void) fputs(" \\f", stdout);
274 278 } else if (wc == '\n') {
275 279 (void) fputs(" \\n", stdout);
276 280 } else if (wc == '\r') {
277 281 (void) fputs(" \\r", stdout);
278 282 } else if (wc == '\t') {
279 283 (void) fputs(" \\t", stdout);
280 284 } else {
281 285 (void) printf(" %03o", v);
282 286 }
283 287 }
284 288
285 289 static output_t output_char = {
286 290 1, do_char,
287 291 };
288 292
289 293 /*
290 294 * List of output formatting structures.
291 295 */
292 296 static output_t *head = NULL;
293 297 static output_t **tailp = &head;
294 298
295 299 static void
296 300 add_out(output_t *src)
297 301 {
298 302 output_t *out;
299 303 int m;
300 304
301 305 if ((out = calloc(1, sizeof (*src))) == NULL) {
302 306 err(1, "malloc");
303 307 }
304 308
305 309 m = lcm;
306 310 while ((m % src->width) != 0) {
307 311 m += lcm;
308 312 }
309 313 lcm = m;
310 314 blocksize = lcm;
311 315 while (blocksize < 16)
312 316 blocksize *= 2;
313 317
314 318 (void) memcpy(out, src, sizeof (*src));
315 319 *tailp = out;
316 320 tailp = &out->next;
317 321 }
318 322
319 323 static FILE *
320 324 next_input(void)
321 325 {
322 326 for (;;) {
323 327 if (curfile >= numfiles)
324 328 return (NULL);
325 329
326 330 if (input != NULL) {
327 331 if ((input = freopen(files[curfile], "r", input)) !=
328 332 NULL) {
329 333 curfile++;
330 334 return (input);
331 335 }
332 336 } else {
333 337 if ((input = fopen(files[curfile], "r")) != NULL) {
334 338 curfile++;
335 339 return (input);
336 340 }
337 341 }
338 342 warn("open: %s", files[curfile]);
339 343 curfile++;
340 344 }
341 345 }
342 346
343 347 static void
344 348 refill(buffer_t *b)
345 349 {
346 350 int n;
347 351 int want;
348 352 int zero;
349 353
350 354 /*
351 355 * If we have 2 blocks of bytes available, we're done. Note
352 356 * that each iteration usually loads up 16 bytes, unless we
353 357 * run out of data.
354 358 */
355 359 while ((input != NULL) && (b->navail < (2 * blocksize))) {
356 360
357 361 /* we preload the next one in advance */
358 362
359 363 if (limit == 0) {
360 364 (void) fclose(input);
361 365 input = NULL;
362 366 continue;
363 367 }
364 368
365 369 /* we want to read a whole block if possible */
366 370 want = blocksize;
367 371 if ((limit >= 0) && (want > limit)) {
368 372 want = limit;
369 373 }
370 374 zero = blocksize;
371 375
372 376 while (want && input) {
373 377 int c;
374 378 b->prod &= b->mask;
375 379 c = (b->prod + want > (b->mask + 1)) ?
376 380 b->mask - b->prod :
377 381 want;
378 382
379 383 n = fread(b->data + b->prod, 1, c, input);
380 384 if (n < 0) {
381 385 warn("read: %s",
382 386 files ? files[curfile-1] : "stdin");
383 387 input = next_input();
384 388 continue;
385 389 }
386 390 if (n == 0) {
387 391 input = next_input();
388 392 continue;
389 393 }
390 394 if (limit >= 0)
391 395 limit -= n;
392 396 b->navail += n;
393 397 b->prod += n;
394 398 want -= n;
395 399 zero -= n;
396 400 }
397 401
398 402 while (zero) {
399 403 b->data[b->prod & b->mask] = 0;
400 404 b->prod++;
401 405 b->prod &= b->mask;
402 406 zero--;
403 407 }
404 408 }
405 409 }
406 410
407 411 #define STR1 "C1"
408 412 #define STR2 "S2"
409 413 #ifdef _LP64
410 414 #define STR8 "L8"
411 415 #define STR4 "I4"
412 416 #else
413 417 #define STR8 "8"
414 418 #define STR4 "IL4"
415 419 #endif
416 420
417 421 static void
418 422 do_type_string(char *typestr)
419 423 {
420 424 if (*typestr == 0) {
421 425 errx(1, _("missing type string"));
422 426 }
423 427 while (*typestr) {
424 428 switch (*typestr) {
425 429 case 'a':
426 430 typestr++;
427 431 add_out(&output_ascii);
428 432 break;
429 433 case 'c':
430 434 add_out(&output_char);
431 435 typestr++;
432 436 break;
433 437 case 'f':
434 438 typestr++;
435 439 switch (*typestr) {
436 440 case 'F':
437 441 case '4':
438 442 add_out(&output_float);
439 443 typestr++;
440 444 break;
441 445 case '8':
442 446 case 'D':
443 447 add_out(&output_double);
444 448 typestr++;
445 449 break;
446 450 case 'L':
447 451 add_out(&output_ldouble);
448 452 typestr++;
449 453 break;
450 454 default:
451 455 add_out(&output_float);
452 456 break;
453 457 }
454 458 break;
455 459
456 460
457 461 case 'd':
458 462 typestr++;
459 463 if (strchr(STR1, *typestr)) {
460 464 typestr++;
461 465 add_out(&output_sig_b);
462 466 } else if (strchr(STR2, *typestr)) {
463 467 typestr++;
464 468 add_out(&output_sig_w);
465 469 } else if (strchr(STR4, *typestr)) {
466 470 typestr++;
467 471 add_out(&output_sig_d);
468 472 } else if (strchr(STR8, *typestr)) {
469 473 typestr++;
470 474 add_out(&output_sig_q);
471 475 } else {
472 476 add_out(&output_sig_d);
473 477 }
474 478 break;
475 479
476 480 case 'u':
477 481 typestr++;
478 482 if (strchr(STR1, *typestr)) {
479 483 typestr++;
480 484 add_out(&output_dec_b);
481 485 } else if (strchr(STR2, *typestr)) {
482 486 typestr++;
483 487 add_out(&output_dec_w);
484 488 } else if (strchr(STR4, *typestr)) {
485 489 typestr++;
486 490 add_out(&output_dec_d);
487 491 } else if (strchr(STR8, *typestr)) {
488 492 typestr++;
489 493 add_out(&output_dec_q);
490 494 } else {
491 495 add_out(&output_dec_d);
492 496 }
493 497 break;
494 498
495 499 case 'o':
496 500 typestr++;
497 501 if (strchr(STR1, *typestr)) {
498 502 typestr++;
499 503 add_out(&output_oct_b);
500 504 } else if (strchr(STR2, *typestr)) {
501 505 typestr++;
502 506 add_out(&output_oct_w);
503 507 } else if (strchr(STR4, *typestr)) {
504 508 typestr++;
505 509 add_out(&output_oct_d);
506 510 } else if (strchr(STR8, *typestr)) {
507 511 typestr++;
508 512 add_out(&output_oct_q);
509 513 } else {
510 514 add_out(&output_oct_d);
511 515 }
512 516 break;
513 517
514 518 case 'x':
515 519 typestr++;
516 520 if (strchr(STR1, *typestr)) {
517 521 typestr++;
518 522 add_out(&output_hex_b);
519 523 } else if (strchr(STR2, *typestr)) {
520 524 typestr++;
521 525 add_out(&output_hex_w);
522 526 } else if (strchr(STR4, *typestr)) {
523 527 typestr++;
524 528 add_out(&output_hex_d);
525 529 } else if (strchr(STR8, *typestr)) {
↓ open down ↓ |
499 lines elided |
↑ open up ↑ |
526 530 typestr++;
527 531 add_out(&output_hex_q);
528 532 } else {
529 533 add_out(&output_hex_d);
530 534 }
531 535 break;
532 536
533 537 default:
534 538 errx(1, _("unrecognized type string character: %c"),
535 539 *typestr);
536 - exit(1);
537 540 }
538 541 }
539 542 }
540 543
541 544 int
542 545 main(int argc, char **argv)
543 546 {
544 547 int c;
545 548 int i;
546 549 buffer_t buffer;
547 550 boolean_t first = B_TRUE;
548 551 boolean_t doall = B_FALSE;
549 552 boolean_t same = B_FALSE;
550 553 boolean_t newarg = B_FALSE;
551 554 off_t offset = 0;
552 555 off_t skip = 0;
553 556 char *eptr;
554 557 char *offstr = 0;
555 558
556 559 input = stdin;
557 560
558 561 (void) setlocale(LC_ALL, "");
559 562 (void) textdomain(TEXT_DOMAIN);
560 563
561 564 while ((c = getopt(argc, argv, "A:bCcdDfFj:N:oOsSxXvt:")) != EOF) {
562 565 switch (c) {
563 566 case 'A':
564 567 newarg = B_TRUE;
565 568 if (strlen(optarg) > 1) {
566 569 afmt = NULL;
567 570 }
568 571 switch (*optarg) {
569 572 case 'o':
570 573 afmt = "%07llo";
571 574 cfmt = " ";
572 575 break;
573 576 case 'd':
574 577 afmt = "%07lld";
575 578 cfmt = " ";
576 579 break;
577 580 case 'x':
578 581 afmt = "%07llx";
579 582 cfmt = " ";
580 583 break;
581 584 case 'n':
582 585 /*
583 586 * You could argue that the code should
584 587 * use the same 7 spaces. Legacy uses 8
585 588 * though. Oh well. Better to avoid
586 589 * gratuitous change.
587 590 */
588 591 afmt = " ";
589 592 cfmt = " ";
590 593 break;
591 594 default:
592 595 afmt = NULL;
593 596 break;
594 597 }
595 598 if (strlen(optarg) != 1) {
596 599 afmt = NULL;
597 600 }
598 601 if (afmt == NULL)
599 602 warnx(_("invalid address base, "
600 603 "must be o, d, x, or n"));
601 604 break;
602 605
603 606 case 'b':
604 607 add_out(&output_oct_b);
605 608 break;
606 609
607 610 case 'c':
608 611 case 'C':
609 612 add_out(&output_char);
610 613 break;
611 614
612 615 case 'f':
613 616 add_out(&output_float);
614 617 break;
615 618
616 619 case 'F':
617 620 add_out(&output_double);
618 621 break;
619 622
620 623 case 'd':
621 624 add_out(&output_dec_w);
622 625 break;
623 626
624 627 case 'D':
625 628 add_out(&output_dec_d);
626 629 break;
627 630
628 631 case 't':
629 632 newarg = B_TRUE;
630 633 do_type_string(optarg);
631 634 break;
632 635
633 636 case 'o':
634 637 add_out(&output_oct_w);
635 638 break;
636 639
637 640 case 'O':
638 641 add_out(&output_oct_d);
639 642 break;
640 643
641 644 case 's':
642 645 add_out(&output_sig_w);
643 646 break;
644 647
645 648 case 'S':
646 649 add_out(&output_sig_d);
647 650 break;
648 651
649 652 case 'x':
650 653 add_out(&output_hex_w);
651 654 break;
652 655
653 656 case 'X':
654 657 add_out(&output_hex_d);
655 658 break;
656 659
657 660 case 'v':
658 661 doall = B_TRUE;
659 662 break;
660 663
661 664 case 'j':
662 665 newarg = B_TRUE;
663 666 skip = strtoll(optarg, &eptr, 0);
664 667 if (*eptr == 'b') {
665 668 skip <<= 9; /* 512 bytes */
666 669 eptr++;
667 670 } else if (*eptr == 'k') {
668 671 skip <<= 10; /* 1k */
669 672 eptr++;
670 673 } else if (*eptr == 'm') {
671 674 skip <<= 20; /* 1m */
672 675 eptr++;
673 676 } else if (*eptr == 'g') {
674 677 skip <<= 30; /* 1g */
675 678 eptr++;
676 679 }
677 680 if ((skip < 0) || (eptr[0] != 0)) {
678 681 warnx(_("invalid skip count '%s' specified"),
679 682 optarg);
680 683 exit(1);
681 684 }
682 685 break;
683 686
684 687 case 'N':
685 688 newarg = B_TRUE;
686 689 limit = strtoll(optarg, &eptr, 0);
687 690 /*
688 691 * POSIX doesn't specify this, but I think these
689 692 * may be helpful.
690 693 */
691 694 if (*eptr == 'b') {
692 695 limit <<= 9;
693 696 eptr++;
694 697 } else if (*eptr == 'k') {
695 698 limit <<= 10;
696 699 eptr++;
697 700 } else if (*eptr == 'm') {
698 701 limit <<= 20;
699 702 eptr++;
700 703 } else if (*eptr == 'g') {
701 704 limit <<= 30;
702 705 eptr++;
703 706 }
704 707 if ((limit < 0) || (eptr[0] != 0)) {
705 708 warnx(_("invalid byte count '%s' specified"),
706 709 optarg);
707 710 exit(1);
708 711 }
709 712 break;
710 713
711 714 default:
712 715 usage();
713 716 break;
714 717 }
715 718 }
716 719
717 720 /* this finds the smallest power of two size we can use */
718 721 buffer.mask = (1 << (ffs(blocksize * 3) + 1)) - 1;
719 722 buffer.data = memalign(16, buffer.mask + 1);
720 723 if (buffer.data == NULL) {
721 724 err(1, "memalign");
722 725 }
723 726
724 727
725 728 /*
726 729 * Wow. This option parsing is hideous.
727 730 *
728 731 * If the we've not seen a new option, and there is just one
729 732 * operand, if it starts with a "+", then treat it as an
730 733 * offset. Otherwise if two operands, and the second operand
731 734 * starts with + or a digit, then it is an offset.
732 735 */
733 736 if (!newarg) {
734 737 if (((argc - optind) == 1) && (argv[optind][0] == '+')) {
735 738 offstr = argv[optind];
736 739 argc--;
737 740 } else if (((argc - optind) == 2) &&
738 741 (strchr("+0123456789", (argv[optind + 1][0])) != NULL)) {
739 742 offstr = argv[optind + 1];
740 743 argc--;
741 744 }
742 745 }
743 746 if (offstr) {
744 747 int base = 0;
745 748 int mult = 1;
746 749 int l;
747 750 if (*offstr == '+') {
748 751 offstr++;
749 752 }
750 753 l = strlen(offstr);
751 754 if ((strncmp(offstr, "0x", 2) == 0)) {
752 755 afmt = "%07llx";
753 756 base = 16;
754 757 offstr += 2;
755 758 if (offstr[l - 1] == 'B') {
756 759 offstr[l - 1] = 0;
757 760 l--;
758 761 mult = 512;
759 762 }
760 763 } else {
761 764 base = 8;
762 765 afmt = "%07llo";
763 766 if ((offstr[l - 1] == 'B') || (offstr[l - 1] == 'b')) {
764 767 offstr[l - 1] = 0;
765 768 l--;
766 769 mult = 512;
767 770 }
768 771 if (offstr[l - 1] == '.') {
769 772 offstr[l - 1] = 0;
770 773 base = 10;
771 774 afmt = "%07lld";
772 775 }
773 776 }
774 777 skip = strtoll(offstr, &eptr, base);
775 778 if (*eptr != '\0') {
776 779 errx(1, _("invalid offset string specified"));
777 780 }
778 781 skip *= mult;
779 782 offset += skip;
780 783 }
781 784
782 785 /*
783 786 * Allocate an array for all the input files.
784 787 */
785 788 if (argc > optind) {
786 789 files = calloc(sizeof (char *), argc - optind);
787 790 for (i = 0; i < argc - optind; i++) {
788 791 files[i] = argv[optind + i];
789 792 numfiles++;
790 793 }
791 794 input = next_input();
792 795 } else {
793 796 input = stdin;
794 797 }
795 798
796 799 /*
797 800 * We need to seek ahead. fseek would be faster.
798 801 */
799 802 while (skip && (input != NULL)) {
800 803 struct stat sbuf;
801 804
802 805 /*
803 806 * Only fseek() on regular files. (Others
804 807 * we have to read().
805 808 */
806 809 if (fstat(fileno(input), &sbuf) < 0) {
807 810 warn("fstat: %s", files[curfile-1]);
808 811 input = next_input();
809 812 continue;
810 813 }
811 814 if (S_ISREG(sbuf.st_mode)) {
812 815 /*
813 816 * No point in seeking a file that is too
814 817 * short to begin with.
815 818 */
816 819 if (sbuf.st_size < skip) {
817 820 skip -= sbuf.st_size;
818 821 input = next_input();
819 822 continue;
820 823 }
821 824 if (fseeko(input, skip, SEEK_SET) < 0) {
822 825 err(1, "fseek:%s", files[curfile-1]);
823 826 }
824 827 /* Done seeking. */
825 828 skip = 0;
826 829 break;
827 830 }
828 831
829 832 /*
830 833 * fgetc seems like it would be slow, but it uses
831 834 * buffered I/O, so it should be fast enough.
832 835 */
833 836 flockfile(input);
834 837 while (skip) {
835 838 if (getc_unlocked(input) == EOF) {
836 839 funlockfile(input);
837 840 if (ferror(input)) {
838 841 warn("read: %s", files[curfile-1]);
839 842 }
840 843 input = next_input();
841 844 if (input != NULL) {
842 845 flockfile(input);
843 846 }
844 847 break;
845 848 }
846 849 skip--;
847 850 }
848 851 if (input != NULL)
849 852 funlockfile(input);
850 853 }
851 854
852 855 if (head == NULL) {
853 856 add_out(&output_oct_w);
854 857 }
855 858
856 859 buffer.navail = 0;
857 860 buffer.prod = 0;
858 861 buffer.cons = 0;
859 862
860 863 for (refill(&buffer); buffer.navail > 0; refill(&buffer)) {
861 864 output_t *out;
862 865 int mx;
863 866 int j, k;
864 867
865 868 /*
866 869 * If this buffer was the same as last, then just
867 870 * dump an asterisk.
868 871 */
869 872 if ((!first) && (buffer.navail >= blocksize) && (!doall)) {
870 873 j = buffer.cons;
871 874 k = j - blocksize;
872 875 for (i = 0; i < blocksize; i++) {
873 876 if (buffer.data[j & buffer.mask] !=
874 877 buffer.data[k & buffer.mask]) {
875 878 break;
876 879 }
877 880 j++;
878 881 k++;
879 882 }
880 883 if (i == blocksize) {
881 884 if (!same) {
882 885 (void) fputs("*\n", stdout);
883 886 same = B_TRUE;
884 887 }
885 888 buffer.navail -= blocksize;
886 889 offset += blocksize;
887 890 buffer.cons += blocksize;
888 891 buffer.cons &= buffer.mask;
889 892 continue;
890 893 }
891 894 }
892 895
893 896 first = B_FALSE;
894 897 same = B_FALSE;
895 898 mx = (buffer.navail > blocksize) ? blocksize : buffer.navail;
896 899
897 900 for (out = head; out != NULL; out = out->next) {
898 901
899 902 if (out == head) {
900 903 /*LINTED E_SEC_PRINTF_VAR_FMT*/
901 904 (void) printf(afmt, offset);
902 905 } else {
903 906 (void) fputs(cfmt, stdout);
904 907 }
905 908 for (i = 0, j = buffer.cons; i < mx; i += out->width) {
906 909 out->func(&buffer, j);
907 910 j += out->width;
908 911 j &= buffer.mask;
909 912 }
910 913 (void) fputs("\n", stdout);
911 914 }
912 915 buffer.cons += mx;
913 916 buffer.cons &= buffer.mask;
914 917 offset += mx;
915 918 buffer.navail -= mx;
916 919 }
917 920 /*LINTED E_SEC_PRINTF_VAR_FMT*/
918 921 (void) printf(afmt, offset);
919 922 (void) fputs("\n", stdout);
920 923 return (0);
921 924 }
↓ open down ↓ |
375 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX