101335b0dSGarrett D'Amore /*
201335b0dSGarrett D'Amore * This file and its contents are supplied under the terms of the
301335b0dSGarrett D'Amore * Common Development and Distribution License ("CDDL"), version 1.0.
45aec55ebSGarrett D'Amore * You may only use this file in accordance with the terms of version
501335b0dSGarrett D'Amore * 1.0 of the CDDL.
601335b0dSGarrett D'Amore *
701335b0dSGarrett D'Amore * A full copy of the text of the CDDL should have accompanied this
801335b0dSGarrett D'Amore * source. A copy of the CDDL is also available via the Internet
901335b0dSGarrett D'Amore * http://www.illumos.org/license/CDDL.
1001335b0dSGarrett D'Amore */
1101335b0dSGarrett D'Amore
1201335b0dSGarrett D'Amore /*
1301335b0dSGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
1401335b0dSGarrett D'Amore */
1501335b0dSGarrett D'Amore
16*44bf619dSJohn Levon /*
17*44bf619dSJohn Levon * Copyright 2019 Joyent, Inc.
18*44bf619dSJohn Levon */
19*44bf619dSJohn Levon
2001335b0dSGarrett D'Amore /*
2101335b0dSGarrett D'Amore * od - octal dump. Not really just octal anymore; read the POSIX
2201335b0dSGarrett D'Amore * specification for it -- its more complex than you think!
2301335b0dSGarrett D'Amore *
2401335b0dSGarrett D'Amore * NB: We followed the POSIX semantics fairly strictly, where the
2501335b0dSGarrett D'Amore * legacy code's behavior was in conflict. In many cases the legacy
2601335b0dSGarrett D'Amore * Solaris code was so completely broken as to be completely unusable.
2701335b0dSGarrett D'Amore * (For example, the long double support was broken beyond
2801335b0dSGarrett D'Amore * imagination!) Note that GNU coreutils violates POSIX in a few
2901335b0dSGarrett D'Amore * interesting ways, such as changing the numbering of the addresses
3001335b0dSGarrett D'Amore * when skipping. (Address starts should always be at 0, according to
3101335b0dSGarrett D'Amore * the sample output in the Open Group man page.)
3201335b0dSGarrett D'Amore */
3301335b0dSGarrett D'Amore
3401335b0dSGarrett D'Amore #include <stdio.h>
3501335b0dSGarrett D'Amore #include <stdlib.h>
3601335b0dSGarrett D'Amore #include <sys/types.h>
3701335b0dSGarrett D'Amore #include <string.h>
3801335b0dSGarrett D'Amore #include <err.h>
3901335b0dSGarrett D'Amore #include <wchar.h>
4001335b0dSGarrett D'Amore #include <locale.h>
4101335b0dSGarrett D'Amore #include <unistd.h>
4201335b0dSGarrett D'Amore #include <sys/stat.h>
4301335b0dSGarrett D'Amore
4401335b0dSGarrett D'Amore #define _(x) gettext(x)
4501335b0dSGarrett D'Amore
4684441f85SGarrett D'Amore
4784441f85SGarrett D'Amore #ifndef TEXT_DOMAIN
4884441f85SGarrett D'Amore #define TEXT_DOMAIN "SYS_TEST"
4984441f85SGarrett D'Amore #endif
5084441f85SGarrett D'Amore
5101335b0dSGarrett D'Amore /* address format */
5201335b0dSGarrett D'Amore static char *afmt = "%07llo";
5301335b0dSGarrett D'Amore static char *cfmt = " ";
5401335b0dSGarrett D'Amore
5501335b0dSGarrett D'Amore static FILE *input = NULL;
5601335b0dSGarrett D'Amore static size_t lcm = 1;
5701335b0dSGarrett D'Amore static size_t blocksize = 16;
5801335b0dSGarrett D'Amore static int numfiles = 0;
5901335b0dSGarrett D'Amore static int curfile = 0;
6001335b0dSGarrett D'Amore static char **files = NULL;
6101335b0dSGarrett D'Amore static off_t limit = -1;
6201335b0dSGarrett D'Amore
6301335b0dSGarrett D'Amore /*
6401335b0dSGarrett D'Amore * This structure describes our ring buffer. Its always a power of 2
6501335b0dSGarrett D'Amore * in size to make wrap around calculations fast using a mask instead
6601335b0dSGarrett D'Amore * of doing modulo.
6701335b0dSGarrett D'Amore *
6801335b0dSGarrett D'Amore * The size is calculated thusly: We need three "blocks" of data, as
6901335b0dSGarrett D'Amore * we process a block at a time (one block == one line of od output.)
7001335b0dSGarrett D'Amore *
7101335b0dSGarrett D'Amore * We need lookahead of an extra block to support multibyte chars. We
7201335b0dSGarrett D'Amore * also have a look behind so that we can avoid printing lines that
7301335b0dSGarrett D'Amore * are identical to what we've already printed. Finally, we need the
7401335b0dSGarrett D'Amore * current block.
7501335b0dSGarrett D'Amore *
7601335b0dSGarrett D'Amore * The block size is determined by the least common multiple of the
7701335b0dSGarrett D'Amore * data items being displayed. Usually it will be 16, but sometimes
7801335b0dSGarrett D'Amore * it is 24 (when 12-byte long doubles are presented.)
7901335b0dSGarrett D'Amore *
8001335b0dSGarrett D'Amore * The data buffer is allocaed via memalign to make sure it is
8101335b0dSGarrett D'Amore * properly aligned.
8201335b0dSGarrett D'Amore */
8301335b0dSGarrett D'Amore typedef struct buffer {
8401335b0dSGarrett D'Amore char *data; /* data buffer */
8501335b0dSGarrett D'Amore int prod; /* producer index */
8601335b0dSGarrett D'Amore int cons; /* consumer index */
8701335b0dSGarrett D'Amore int mask; /* buffer size - 1, wraparound index */
8801335b0dSGarrett D'Amore int navail; /* total bytes avail */
8901335b0dSGarrett D'Amore } buffer_t;
9001335b0dSGarrett D'Amore
9101335b0dSGarrett D'Amore /*
9201335b0dSGarrett D'Amore * This structure is used to provide information on a specific output
9301335b0dSGarrett D'Amore * format. We link them together in a list representing the output
9401335b0dSGarrett D'Amore * formats that the user has selected.
9501335b0dSGarrett D'Amore */
9601335b0dSGarrett D'Amore typedef struct output {
9701335b0dSGarrett D'Amore int width; /* bytes consumed per call */
9801335b0dSGarrett D'Amore void (*func)(buffer_t *, int); /* output function */
9901335b0dSGarrett D'Amore struct output *next; /* link node */
10001335b0dSGarrett D'Amore } output_t;
10101335b0dSGarrett D'Amore
10201335b0dSGarrett D'Amore /*
10301335b0dSGarrett D'Amore * Specifiers
10401335b0dSGarrett D'Amore */
10501335b0dSGarrett D'Amore
10601335b0dSGarrett D'Amore typedef unsigned char u8;
10701335b0dSGarrett D'Amore typedef unsigned short u16;
10801335b0dSGarrett D'Amore typedef unsigned int u32;
10901335b0dSGarrett D'Amore typedef unsigned long long u64;
11001335b0dSGarrett D'Amore typedef char s8;
11101335b0dSGarrett D'Amore typedef short s16;
11201335b0dSGarrett D'Amore typedef int s32;
11301335b0dSGarrett D'Amore typedef long long s64;
11401335b0dSGarrett D'Amore typedef float fF;
11501335b0dSGarrett D'Amore typedef double fD;
11601335b0dSGarrett D'Amore typedef long double fL;
11701335b0dSGarrett D'Amore
11801335b0dSGarrett D'Amore static void
usage(void)11901335b0dSGarrett D'Amore usage(void)
12001335b0dSGarrett D'Amore {
12101335b0dSGarrett D'Amore (void) fprintf(stderr, _("usage: od [-bcCdDfFoOsSvxX] "
12201335b0dSGarrett D'Amore "[-t types ]... [-A base] [-j skip] [-N count] [file]...\n"));
12301335b0dSGarrett D'Amore exit(1);
12401335b0dSGarrett D'Amore }
12501335b0dSGarrett D'Amore
12601335b0dSGarrett D'Amore #define DECL_GET(typ) \
12701335b0dSGarrett D'Amore static typ \
12801335b0dSGarrett D'Amore get_ ## typ(buffer_t *b, int index) \
12901335b0dSGarrett D'Amore { \
13001335b0dSGarrett D'Amore typ val = *(typ *)(void *)(b->data + index); \
13101335b0dSGarrett D'Amore return (val); \
13201335b0dSGarrett D'Amore }
13301335b0dSGarrett D'Amore DECL_GET(u8)
13401335b0dSGarrett D'Amore DECL_GET(u16)
13501335b0dSGarrett D'Amore DECL_GET(u32)
13601335b0dSGarrett D'Amore DECL_GET(u64)
13701335b0dSGarrett D'Amore DECL_GET(s8)
13801335b0dSGarrett D'Amore DECL_GET(s16)
13901335b0dSGarrett D'Amore DECL_GET(s32)
14001335b0dSGarrett D'Amore DECL_GET(s64)
14101335b0dSGarrett D'Amore DECL_GET(fF)
14201335b0dSGarrett D'Amore DECL_GET(fD)
14301335b0dSGarrett D'Amore DECL_GET(fL)
14401335b0dSGarrett D'Amore
14501335b0dSGarrett D'Amore #define DECL_OUT(nm, typ, fmt) \
14601335b0dSGarrett D'Amore static void \
14701335b0dSGarrett D'Amore do_ ## nm(buffer_t *buf, int index) \
14801335b0dSGarrett D'Amore { \
14901335b0dSGarrett D'Amore typ v = get_ ## typ(buf, index); \
15001335b0dSGarrett D'Amore (void) printf(fmt, v); \
15101335b0dSGarrett D'Amore } \
15201335b0dSGarrett D'Amore \
15301335b0dSGarrett D'Amore static output_t output_ ## nm = { \
15401335b0dSGarrett D'Amore sizeof (typ), do_ ## nm \
15501335b0dSGarrett D'Amore };
15601335b0dSGarrett D'Amore
15701335b0dSGarrett D'Amore DECL_OUT(oct_b, u8, " %03o")
15801335b0dSGarrett D'Amore DECL_OUT(oct_w, u16, " %06ho")
15901335b0dSGarrett D'Amore DECL_OUT(oct_d, u32, " %011o")
16001335b0dSGarrett D'Amore DECL_OUT(oct_q, u64, " %022llo")
16101335b0dSGarrett D'Amore DECL_OUT(dec_b, u8, " %03u")
16201335b0dSGarrett D'Amore DECL_OUT(dec_w, u16, " %05hu")
16301335b0dSGarrett D'Amore DECL_OUT(dec_d, u32, " %010u")
16401335b0dSGarrett D'Amore DECL_OUT(dec_q, u64, " %020llu")
16501335b0dSGarrett D'Amore DECL_OUT(sig_b, s8, " %03d")
16601335b0dSGarrett D'Amore DECL_OUT(sig_w, s16, " %6.05hd")
16701335b0dSGarrett D'Amore DECL_OUT(sig_d, s32, " %11.010d")
16801335b0dSGarrett D'Amore DECL_OUT(sig_q, s64, " %20.019lld")
16901335b0dSGarrett D'Amore DECL_OUT(hex_b, u8, " %02x")
17001335b0dSGarrett D'Amore DECL_OUT(hex_w, u16, " %04hx")
17101335b0dSGarrett D'Amore DECL_OUT(hex_d, s32, " %08x")
17201335b0dSGarrett D'Amore DECL_OUT(hex_q, s64, " %016llx")
17301335b0dSGarrett D'Amore DECL_OUT(float, fF, " %14.7e")
17401335b0dSGarrett D'Amore DECL_OUT(double, fD, " %21.14e")
17501335b0dSGarrett D'Amore DECL_OUT(ldouble, fL, " %24.14Le")
17601335b0dSGarrett D'Amore
17701335b0dSGarrett D'Amore static char *ascii[] = {
17801335b0dSGarrett D'Amore "nul", "soh", "stx", "etx", "eot", "enq", "ack", " be",
17901335b0dSGarrett D'Amore " bs", " ht", " lf", " vt", " ff", " cr", " so", " si",
18001335b0dSGarrett D'Amore "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
18101335b0dSGarrett D'Amore "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
18201335b0dSGarrett D'Amore " sp", " !", " \"", " #", " $", " %", " &", " '",
18301335b0dSGarrett D'Amore " (", " )", " *", " +", " ,", " -", " .", " /",
18401335b0dSGarrett D'Amore " 0", " 1", " 2", " 3", " 4", " 5", " 6", " 7",
18501335b0dSGarrett D'Amore " 8", " 9", " :", " ;", " <", " =", " >", " ?",
18601335b0dSGarrett D'Amore " @", " A", " B", " C", " D", " E", " F", " G",
18701335b0dSGarrett D'Amore " H", " I", " J", " K", " L", " M", " N", " O",
18801335b0dSGarrett D'Amore " P", " Q", " R", " S", " T", " U", " V", " W",
18901335b0dSGarrett D'Amore " X", " Y", " Z", " [", " \\", " ]", " ^", " _",
19001335b0dSGarrett D'Amore " `", " a", " b", " c", " d", " e", " f", " g",
19101335b0dSGarrett D'Amore " h", " i", " j", " k", " l", " m", " n", " o",
19201335b0dSGarrett D'Amore " p", " q", " r", " s", " t", " u", " v", " w",
19301335b0dSGarrett D'Amore " x", " y", " z", " {", " |", " }", " ~", "del"
19401335b0dSGarrett D'Amore };
19501335b0dSGarrett D'Amore
19601335b0dSGarrett D'Amore static void
do_ascii(buffer_t * buf,int index)19701335b0dSGarrett D'Amore do_ascii(buffer_t *buf, int index)
19801335b0dSGarrett D'Amore {
19901335b0dSGarrett D'Amore uint8_t v = get_u8(buf, index);
20001335b0dSGarrett D'Amore
20101335b0dSGarrett D'Amore (void) fputc(' ', stdout);
20201335b0dSGarrett D'Amore (void) fputs(ascii[v & 0x7f], stdout);
20301335b0dSGarrett D'Amore }
20401335b0dSGarrett D'Amore
20501335b0dSGarrett D'Amore static output_t output_ascii = {
20601335b0dSGarrett D'Amore 1, do_ascii,
20701335b0dSGarrett D'Amore };
20801335b0dSGarrett D'Amore
20901335b0dSGarrett D'Amore static void
do_char(buffer_t * buf,int index)21001335b0dSGarrett D'Amore do_char(buffer_t *buf, int index)
21101335b0dSGarrett D'Amore {
21201335b0dSGarrett D'Amore static int nresid = 0;
21301335b0dSGarrett D'Amore static int printable = 0;
21401335b0dSGarrett D'Amore int cnt;
21501335b0dSGarrett D'Amore int avail;
21601335b0dSGarrett D'Amore int nb;
21701335b0dSGarrett D'Amore char scratch[10];
21801335b0dSGarrett D'Amore wchar_t wc;
21901335b0dSGarrett D'Amore int which;
22001335b0dSGarrett D'Amore
22101335b0dSGarrett D'Amore uint8_t v = get_u8(buf, index);
22201335b0dSGarrett D'Amore
22301335b0dSGarrett D'Amore /*
22401335b0dSGarrett D'Amore * If there were residual bytes from an earlier
22501335b0dSGarrett D'Amore * character, then just display the ** continuation
22601335b0dSGarrett D'Amore * indication.
22701335b0dSGarrett D'Amore */
22801335b0dSGarrett D'Amore if (nresid) {
22901335b0dSGarrett D'Amore if (printable) {
23001335b0dSGarrett D'Amore (void) fputs(" **", stdout);
23101335b0dSGarrett D'Amore } else {
23201335b0dSGarrett D'Amore (void) printf(" %03o", v);
23301335b0dSGarrett D'Amore }
23401335b0dSGarrett D'Amore nresid--;
23501335b0dSGarrett D'Amore return;
23601335b0dSGarrett D'Amore }
23701335b0dSGarrett D'Amore
23801335b0dSGarrett D'Amore /*
23901335b0dSGarrett D'Amore * Peek ahead up to MB_CUR_MAX characters. This has to be
24001335b0dSGarrett D'Amore * done carefully because we might need to look into the next
24101335b0dSGarrett D'Amore * block to really know for sure.
24201335b0dSGarrett D'Amore */
24301335b0dSGarrett D'Amore scratch[0] = v;
24401335b0dSGarrett D'Amore avail = buf->navail;
24501335b0dSGarrett D'Amore if (avail > MB_CUR_MAX)
24601335b0dSGarrett D'Amore avail = MB_CUR_MAX;
24701335b0dSGarrett D'Amore for (cnt = 1, which = index + 1; cnt < avail; cnt++, which++) {
24801335b0dSGarrett D'Amore scratch[cnt] = buf->data[which & buf->mask];
24901335b0dSGarrett D'Amore }
25001335b0dSGarrett D'Amore
25101335b0dSGarrett D'Amore /* now see if the value is a real character */
25201335b0dSGarrett D'Amore nresid = 0;
25301335b0dSGarrett D'Amore wc = 0;
25401335b0dSGarrett D'Amore nb = mbtowc(&wc, scratch, avail);
25501335b0dSGarrett D'Amore if (nb < 0) {
25601335b0dSGarrett D'Amore (void) printf(" %03o", v);
25701335b0dSGarrett D'Amore return;
25801335b0dSGarrett D'Amore }
25901335b0dSGarrett D'Amore if (nb == 0) {
26001335b0dSGarrett D'Amore (void) fputs(" \\0", stdout);
26101335b0dSGarrett D'Amore return;
26201335b0dSGarrett D'Amore }
26301335b0dSGarrett D'Amore nresid = nb - 1;
26401335b0dSGarrett D'Amore if (nb && iswprint(wc)) {
26501335b0dSGarrett D'Amore scratch[nb] = 0;
26601335b0dSGarrett D'Amore (void) fputs(" ", stdout);
26701335b0dSGarrett D'Amore (void) fputs(scratch, stdout);
26801335b0dSGarrett D'Amore printable = 1;
26901335b0dSGarrett D'Amore return;
27001335b0dSGarrett D'Amore }
27101335b0dSGarrett D'Amore printable = 0;
27201335b0dSGarrett D'Amore if (wc == 0) {
27301335b0dSGarrett D'Amore (void) fputs(" \\0", stdout);
27401335b0dSGarrett D'Amore } else if (wc == '\b') {
27501335b0dSGarrett D'Amore (void) fputs(" \\b", stdout);
27601335b0dSGarrett D'Amore } else if (wc == '\f') {
27701335b0dSGarrett D'Amore (void) fputs(" \\f", stdout);
27801335b0dSGarrett D'Amore } else if (wc == '\n') {
27901335b0dSGarrett D'Amore (void) fputs(" \\n", stdout);
28001335b0dSGarrett D'Amore } else if (wc == '\r') {
28101335b0dSGarrett D'Amore (void) fputs(" \\r", stdout);
28201335b0dSGarrett D'Amore } else if (wc == '\t') {
28301335b0dSGarrett D'Amore (void) fputs(" \\t", stdout);
28401335b0dSGarrett D'Amore } else {
28501335b0dSGarrett D'Amore (void) printf(" %03o", v);
28601335b0dSGarrett D'Amore }
28701335b0dSGarrett D'Amore }
28801335b0dSGarrett D'Amore
28901335b0dSGarrett D'Amore static output_t output_char = {
29001335b0dSGarrett D'Amore 1, do_char,
29101335b0dSGarrett D'Amore };
29201335b0dSGarrett D'Amore
29301335b0dSGarrett D'Amore /*
29401335b0dSGarrett D'Amore * List of output formatting structures.
29501335b0dSGarrett D'Amore */
29601335b0dSGarrett D'Amore static output_t *head = NULL;
29701335b0dSGarrett D'Amore static output_t **tailp = &head;
29801335b0dSGarrett D'Amore
29901335b0dSGarrett D'Amore static void
add_out(output_t * src)30001335b0dSGarrett D'Amore add_out(output_t *src)
30101335b0dSGarrett D'Amore {
30201335b0dSGarrett D'Amore output_t *out;
30301335b0dSGarrett D'Amore int m;
30401335b0dSGarrett D'Amore
30501335b0dSGarrett D'Amore if ((out = calloc(1, sizeof (*src))) == NULL) {
30601335b0dSGarrett D'Amore err(1, "malloc");
30701335b0dSGarrett D'Amore }
30801335b0dSGarrett D'Amore
30901335b0dSGarrett D'Amore m = lcm;
31001335b0dSGarrett D'Amore while ((m % src->width) != 0) {
31101335b0dSGarrett D'Amore m += lcm;
31201335b0dSGarrett D'Amore }
31301335b0dSGarrett D'Amore lcm = m;
31401335b0dSGarrett D'Amore blocksize = lcm;
31501335b0dSGarrett D'Amore while (blocksize < 16)
31601335b0dSGarrett D'Amore blocksize *= 2;
31701335b0dSGarrett D'Amore
31801335b0dSGarrett D'Amore (void) memcpy(out, src, sizeof (*src));
31901335b0dSGarrett D'Amore *tailp = out;
32001335b0dSGarrett D'Amore tailp = &out->next;
32101335b0dSGarrett D'Amore }
32201335b0dSGarrett D'Amore
32301335b0dSGarrett D'Amore static FILE *
next_input(void)32401335b0dSGarrett D'Amore next_input(void)
32501335b0dSGarrett D'Amore {
32601335b0dSGarrett D'Amore for (;;) {
32701335b0dSGarrett D'Amore if (curfile >= numfiles)
32801335b0dSGarrett D'Amore return (NULL);
32901335b0dSGarrett D'Amore
33001335b0dSGarrett D'Amore if (input != NULL) {
33101335b0dSGarrett D'Amore if ((input = freopen(files[curfile], "r", input)) !=
33201335b0dSGarrett D'Amore NULL) {
33301335b0dSGarrett D'Amore curfile++;
33401335b0dSGarrett D'Amore return (input);
33501335b0dSGarrett D'Amore }
33601335b0dSGarrett D'Amore } else {
33701335b0dSGarrett D'Amore if ((input = fopen(files[curfile], "r")) != NULL) {
33801335b0dSGarrett D'Amore curfile++;
33901335b0dSGarrett D'Amore return (input);
34001335b0dSGarrett D'Amore }
34101335b0dSGarrett D'Amore }
34201335b0dSGarrett D'Amore warn("open: %s", files[curfile]);
34301335b0dSGarrett D'Amore curfile++;
34401335b0dSGarrett D'Amore }
34501335b0dSGarrett D'Amore }
34601335b0dSGarrett D'Amore
34701335b0dSGarrett D'Amore static void
refill(buffer_t * b)34801335b0dSGarrett D'Amore refill(buffer_t *b)
34901335b0dSGarrett D'Amore {
35001335b0dSGarrett D'Amore int n;
35101335b0dSGarrett D'Amore int want;
35201335b0dSGarrett D'Amore int zero;
35301335b0dSGarrett D'Amore
35401335b0dSGarrett D'Amore /*
35501335b0dSGarrett D'Amore * If we have 2 blocks of bytes available, we're done. Note
35601335b0dSGarrett D'Amore * that each iteration usually loads up 16 bytes, unless we
35701335b0dSGarrett D'Amore * run out of data.
35801335b0dSGarrett D'Amore */
35901335b0dSGarrett D'Amore while ((input != NULL) && (b->navail < (2 * blocksize))) {
36001335b0dSGarrett D'Amore
36101335b0dSGarrett D'Amore /* we preload the next one in advance */
36201335b0dSGarrett D'Amore
36301335b0dSGarrett D'Amore if (limit == 0) {
36401335b0dSGarrett D'Amore (void) fclose(input);
36501335b0dSGarrett D'Amore input = NULL;
36601335b0dSGarrett D'Amore continue;
36701335b0dSGarrett D'Amore }
36801335b0dSGarrett D'Amore
36901335b0dSGarrett D'Amore /* we want to read a whole block if possible */
37001335b0dSGarrett D'Amore want = blocksize;
37101335b0dSGarrett D'Amore if ((limit >= 0) && (want > limit)) {
37201335b0dSGarrett D'Amore want = limit;
37301335b0dSGarrett D'Amore }
37401335b0dSGarrett D'Amore zero = blocksize;
37501335b0dSGarrett D'Amore
37601335b0dSGarrett D'Amore while (want && input) {
37701335b0dSGarrett D'Amore int c;
37801335b0dSGarrett D'Amore b->prod &= b->mask;
37901335b0dSGarrett D'Amore c = (b->prod + want > (b->mask + 1)) ?
38001335b0dSGarrett D'Amore b->mask - b->prod :
38101335b0dSGarrett D'Amore want;
38201335b0dSGarrett D'Amore
38301335b0dSGarrett D'Amore n = fread(b->data + b->prod, 1, c, input);
38401335b0dSGarrett D'Amore if (n < 0) {
38501335b0dSGarrett D'Amore warn("read: %s",
38601335b0dSGarrett D'Amore files ? files[curfile-1] : "stdin");
38701335b0dSGarrett D'Amore input = next_input();
38801335b0dSGarrett D'Amore continue;
38901335b0dSGarrett D'Amore }
39001335b0dSGarrett D'Amore if (n == 0) {
39101335b0dSGarrett D'Amore input = next_input();
39201335b0dSGarrett D'Amore continue;
39301335b0dSGarrett D'Amore }
39401335b0dSGarrett D'Amore if (limit >= 0)
39501335b0dSGarrett D'Amore limit -= n;
39601335b0dSGarrett D'Amore b->navail += n;
39701335b0dSGarrett D'Amore b->prod += n;
39801335b0dSGarrett D'Amore want -= n;
39901335b0dSGarrett D'Amore zero -= n;
40001335b0dSGarrett D'Amore }
40101335b0dSGarrett D'Amore
40201335b0dSGarrett D'Amore while (zero) {
40301335b0dSGarrett D'Amore b->data[b->prod & b->mask] = 0;
40401335b0dSGarrett D'Amore b->prod++;
40501335b0dSGarrett D'Amore b->prod &= b->mask;
40601335b0dSGarrett D'Amore zero--;
40701335b0dSGarrett D'Amore }
40801335b0dSGarrett D'Amore }
40901335b0dSGarrett D'Amore }
41001335b0dSGarrett D'Amore
41101335b0dSGarrett D'Amore #define STR1 "C1"
41201335b0dSGarrett D'Amore #define STR2 "S2"
41301335b0dSGarrett D'Amore #ifdef _LP64
41401335b0dSGarrett D'Amore #define STR8 "L8"
41501335b0dSGarrett D'Amore #define STR4 "I4"
41601335b0dSGarrett D'Amore #else
41701335b0dSGarrett D'Amore #define STR8 "8"
41801335b0dSGarrett D'Amore #define STR4 "IL4"
41901335b0dSGarrett D'Amore #endif
42001335b0dSGarrett D'Amore
42101335b0dSGarrett D'Amore static void
do_type_string(char * typestr)42201335b0dSGarrett D'Amore do_type_string(char *typestr)
42301335b0dSGarrett D'Amore {
42401335b0dSGarrett D'Amore if (*typestr == 0) {
42501335b0dSGarrett D'Amore errx(1, _("missing type string"));
42601335b0dSGarrett D'Amore }
42701335b0dSGarrett D'Amore while (*typestr) {
42801335b0dSGarrett D'Amore switch (*typestr) {
42901335b0dSGarrett D'Amore case 'a':
43001335b0dSGarrett D'Amore typestr++;
43101335b0dSGarrett D'Amore add_out(&output_ascii);
43201335b0dSGarrett D'Amore break;
43301335b0dSGarrett D'Amore case 'c':
43401335b0dSGarrett D'Amore add_out(&output_char);
43501335b0dSGarrett D'Amore typestr++;
43601335b0dSGarrett D'Amore break;
43701335b0dSGarrett D'Amore case 'f':
43801335b0dSGarrett D'Amore typestr++;
43901335b0dSGarrett D'Amore switch (*typestr) {
44001335b0dSGarrett D'Amore case 'F':
44101335b0dSGarrett D'Amore case '4':
44201335b0dSGarrett D'Amore add_out(&output_float);
44301335b0dSGarrett D'Amore typestr++;
44401335b0dSGarrett D'Amore break;
44501335b0dSGarrett D'Amore case '8':
44601335b0dSGarrett D'Amore case 'D':
44701335b0dSGarrett D'Amore add_out(&output_double);
44801335b0dSGarrett D'Amore typestr++;
44901335b0dSGarrett D'Amore break;
45001335b0dSGarrett D'Amore case 'L':
45101335b0dSGarrett D'Amore add_out(&output_ldouble);
45201335b0dSGarrett D'Amore typestr++;
45301335b0dSGarrett D'Amore break;
45401335b0dSGarrett D'Amore default:
45501335b0dSGarrett D'Amore add_out(&output_float);
45601335b0dSGarrett D'Amore break;
45701335b0dSGarrett D'Amore }
45801335b0dSGarrett D'Amore break;
45901335b0dSGarrett D'Amore
46001335b0dSGarrett D'Amore
46101335b0dSGarrett D'Amore case 'd':
46201335b0dSGarrett D'Amore typestr++;
46301335b0dSGarrett D'Amore if (strchr(STR1, *typestr)) {
46401335b0dSGarrett D'Amore typestr++;
46501335b0dSGarrett D'Amore add_out(&output_sig_b);
46601335b0dSGarrett D'Amore } else if (strchr(STR2, *typestr)) {
46701335b0dSGarrett D'Amore typestr++;
46801335b0dSGarrett D'Amore add_out(&output_sig_w);
46901335b0dSGarrett D'Amore } else if (strchr(STR4, *typestr)) {
47001335b0dSGarrett D'Amore typestr++;
47101335b0dSGarrett D'Amore add_out(&output_sig_d);
47201335b0dSGarrett D'Amore } else if (strchr(STR8, *typestr)) {
47301335b0dSGarrett D'Amore typestr++;
47401335b0dSGarrett D'Amore add_out(&output_sig_q);
47501335b0dSGarrett D'Amore } else {
47601335b0dSGarrett D'Amore add_out(&output_sig_d);
47701335b0dSGarrett D'Amore }
47801335b0dSGarrett D'Amore break;
47901335b0dSGarrett D'Amore
48001335b0dSGarrett D'Amore case 'u':
48101335b0dSGarrett D'Amore typestr++;
48201335b0dSGarrett D'Amore if (strchr(STR1, *typestr)) {
48301335b0dSGarrett D'Amore typestr++;
48401335b0dSGarrett D'Amore add_out(&output_dec_b);
48501335b0dSGarrett D'Amore } else if (strchr(STR2, *typestr)) {
48601335b0dSGarrett D'Amore typestr++;
48701335b0dSGarrett D'Amore add_out(&output_dec_w);
48801335b0dSGarrett D'Amore } else if (strchr(STR4, *typestr)) {
48901335b0dSGarrett D'Amore typestr++;
49001335b0dSGarrett D'Amore add_out(&output_dec_d);
49101335b0dSGarrett D'Amore } else if (strchr(STR8, *typestr)) {
49201335b0dSGarrett D'Amore typestr++;
49301335b0dSGarrett D'Amore add_out(&output_dec_q);
49401335b0dSGarrett D'Amore } else {
49501335b0dSGarrett D'Amore add_out(&output_dec_d);
49601335b0dSGarrett D'Amore }
49701335b0dSGarrett D'Amore break;
49801335b0dSGarrett D'Amore
49901335b0dSGarrett D'Amore case 'o':
50001335b0dSGarrett D'Amore typestr++;
50101335b0dSGarrett D'Amore if (strchr(STR1, *typestr)) {
50201335b0dSGarrett D'Amore typestr++;
50301335b0dSGarrett D'Amore add_out(&output_oct_b);
50401335b0dSGarrett D'Amore } else if (strchr(STR2, *typestr)) {
50501335b0dSGarrett D'Amore typestr++;
50601335b0dSGarrett D'Amore add_out(&output_oct_w);
50701335b0dSGarrett D'Amore } else if (strchr(STR4, *typestr)) {
50801335b0dSGarrett D'Amore typestr++;
50901335b0dSGarrett D'Amore add_out(&output_oct_d);
51001335b0dSGarrett D'Amore } else if (strchr(STR8, *typestr)) {
51101335b0dSGarrett D'Amore typestr++;
51201335b0dSGarrett D'Amore add_out(&output_oct_q);
51301335b0dSGarrett D'Amore } else {
51401335b0dSGarrett D'Amore add_out(&output_oct_d);
51501335b0dSGarrett D'Amore }
51601335b0dSGarrett D'Amore break;
51701335b0dSGarrett D'Amore
51801335b0dSGarrett D'Amore case 'x':
51901335b0dSGarrett D'Amore typestr++;
52001335b0dSGarrett D'Amore if (strchr(STR1, *typestr)) {
52101335b0dSGarrett D'Amore typestr++;
52201335b0dSGarrett D'Amore add_out(&output_hex_b);
52301335b0dSGarrett D'Amore } else if (strchr(STR2, *typestr)) {
52401335b0dSGarrett D'Amore typestr++;
52501335b0dSGarrett D'Amore add_out(&output_hex_w);
52601335b0dSGarrett D'Amore } else if (strchr(STR4, *typestr)) {
52701335b0dSGarrett D'Amore typestr++;
52801335b0dSGarrett D'Amore add_out(&output_hex_d);
52901335b0dSGarrett D'Amore } else if (strchr(STR8, *typestr)) {
53001335b0dSGarrett D'Amore typestr++;
53101335b0dSGarrett D'Amore add_out(&output_hex_q);
53201335b0dSGarrett D'Amore } else {
53301335b0dSGarrett D'Amore add_out(&output_hex_d);
53401335b0dSGarrett D'Amore }
53501335b0dSGarrett D'Amore break;
53601335b0dSGarrett D'Amore
53701335b0dSGarrett D'Amore default:
53801335b0dSGarrett D'Amore errx(1, _("unrecognized type string character: %c"),
53901335b0dSGarrett D'Amore *typestr);
54001335b0dSGarrett D'Amore }
54101335b0dSGarrett D'Amore }
54201335b0dSGarrett D'Amore }
54301335b0dSGarrett D'Amore
54401335b0dSGarrett D'Amore int
main(int argc,char ** argv)54501335b0dSGarrett D'Amore main(int argc, char **argv)
54601335b0dSGarrett D'Amore {
54701335b0dSGarrett D'Amore int c;
54801335b0dSGarrett D'Amore int i;
54901335b0dSGarrett D'Amore buffer_t buffer;
55001335b0dSGarrett D'Amore boolean_t first = B_TRUE;
55101335b0dSGarrett D'Amore boolean_t doall = B_FALSE;
55201335b0dSGarrett D'Amore boolean_t same = B_FALSE;
55301335b0dSGarrett D'Amore boolean_t newarg = B_FALSE;
55401335b0dSGarrett D'Amore off_t offset = 0;
55501335b0dSGarrett D'Amore off_t skip = 0;
55601335b0dSGarrett D'Amore char *eptr;
55701335b0dSGarrett D'Amore char *offstr = 0;
55801335b0dSGarrett D'Amore
55901335b0dSGarrett D'Amore input = stdin;
56001335b0dSGarrett D'Amore
56101335b0dSGarrett D'Amore (void) setlocale(LC_ALL, "");
56284441f85SGarrett D'Amore (void) textdomain(TEXT_DOMAIN);
56301335b0dSGarrett D'Amore
56401335b0dSGarrett D'Amore while ((c = getopt(argc, argv, "A:bCcdDfFj:N:oOsSxXvt:")) != EOF) {
56501335b0dSGarrett D'Amore switch (c) {
56601335b0dSGarrett D'Amore case 'A':
56701335b0dSGarrett D'Amore newarg = B_TRUE;
56801335b0dSGarrett D'Amore if (strlen(optarg) > 1) {
56901335b0dSGarrett D'Amore afmt = NULL;
57001335b0dSGarrett D'Amore }
57101335b0dSGarrett D'Amore switch (*optarg) {
57201335b0dSGarrett D'Amore case 'o':
57301335b0dSGarrett D'Amore afmt = "%07llo";
57401335b0dSGarrett D'Amore cfmt = " ";
57501335b0dSGarrett D'Amore break;
57601335b0dSGarrett D'Amore case 'd':
57701335b0dSGarrett D'Amore afmt = "%07lld";
57801335b0dSGarrett D'Amore cfmt = " ";
57901335b0dSGarrett D'Amore break;
58001335b0dSGarrett D'Amore case 'x':
58101335b0dSGarrett D'Amore afmt = "%07llx";
58201335b0dSGarrett D'Amore cfmt = " ";
58301335b0dSGarrett D'Amore break;
58401335b0dSGarrett D'Amore case 'n':
58501335b0dSGarrett D'Amore /*
58601335b0dSGarrett D'Amore * You could argue that the code should
58701335b0dSGarrett D'Amore * use the same 7 spaces. Legacy uses 8
58801335b0dSGarrett D'Amore * though. Oh well. Better to avoid
58901335b0dSGarrett D'Amore * gratuitous change.
59001335b0dSGarrett D'Amore */
59101335b0dSGarrett D'Amore afmt = " ";
59201335b0dSGarrett D'Amore cfmt = " ";
59301335b0dSGarrett D'Amore break;
59401335b0dSGarrett D'Amore default:
59501335b0dSGarrett D'Amore afmt = NULL;
59601335b0dSGarrett D'Amore break;
59701335b0dSGarrett D'Amore }
59801335b0dSGarrett D'Amore if (strlen(optarg) != 1) {
59901335b0dSGarrett D'Amore afmt = NULL;
60001335b0dSGarrett D'Amore }
60101335b0dSGarrett D'Amore if (afmt == NULL)
60201335b0dSGarrett D'Amore warnx(_("invalid address base, "
60301335b0dSGarrett D'Amore "must be o, d, x, or n"));
60401335b0dSGarrett D'Amore break;
60501335b0dSGarrett D'Amore
60601335b0dSGarrett D'Amore case 'b':
60701335b0dSGarrett D'Amore add_out(&output_oct_b);
60801335b0dSGarrett D'Amore break;
60901335b0dSGarrett D'Amore
61001335b0dSGarrett D'Amore case 'c':
61101335b0dSGarrett D'Amore case 'C':
61201335b0dSGarrett D'Amore add_out(&output_char);
61301335b0dSGarrett D'Amore break;
61401335b0dSGarrett D'Amore
61501335b0dSGarrett D'Amore case 'f':
61601335b0dSGarrett D'Amore add_out(&output_float);
61701335b0dSGarrett D'Amore break;
61801335b0dSGarrett D'Amore
61901335b0dSGarrett D'Amore case 'F':
62001335b0dSGarrett D'Amore add_out(&output_double);
62101335b0dSGarrett D'Amore break;
62201335b0dSGarrett D'Amore
62301335b0dSGarrett D'Amore case 'd':
62401335b0dSGarrett D'Amore add_out(&output_dec_w);
62501335b0dSGarrett D'Amore break;
62601335b0dSGarrett D'Amore
62701335b0dSGarrett D'Amore case 'D':
62801335b0dSGarrett D'Amore add_out(&output_dec_d);
62901335b0dSGarrett D'Amore break;
63001335b0dSGarrett D'Amore
63101335b0dSGarrett D'Amore case 't':
63201335b0dSGarrett D'Amore newarg = B_TRUE;
63301335b0dSGarrett D'Amore do_type_string(optarg);
63401335b0dSGarrett D'Amore break;
63501335b0dSGarrett D'Amore
63601335b0dSGarrett D'Amore case 'o':
63701335b0dSGarrett D'Amore add_out(&output_oct_w);
63801335b0dSGarrett D'Amore break;
63901335b0dSGarrett D'Amore
64001335b0dSGarrett D'Amore case 'O':
64101335b0dSGarrett D'Amore add_out(&output_oct_d);
64201335b0dSGarrett D'Amore break;
64301335b0dSGarrett D'Amore
64401335b0dSGarrett D'Amore case 's':
64501335b0dSGarrett D'Amore add_out(&output_sig_w);
64601335b0dSGarrett D'Amore break;
64701335b0dSGarrett D'Amore
64801335b0dSGarrett D'Amore case 'S':
64901335b0dSGarrett D'Amore add_out(&output_sig_d);
65001335b0dSGarrett D'Amore break;
65101335b0dSGarrett D'Amore
65201335b0dSGarrett D'Amore case 'x':
65301335b0dSGarrett D'Amore add_out(&output_hex_w);
65401335b0dSGarrett D'Amore break;
65501335b0dSGarrett D'Amore
65601335b0dSGarrett D'Amore case 'X':
65701335b0dSGarrett D'Amore add_out(&output_hex_d);
65801335b0dSGarrett D'Amore break;
65901335b0dSGarrett D'Amore
66001335b0dSGarrett D'Amore case 'v':
66101335b0dSGarrett D'Amore doall = B_TRUE;
66201335b0dSGarrett D'Amore break;
66301335b0dSGarrett D'Amore
66401335b0dSGarrett D'Amore case 'j':
66501335b0dSGarrett D'Amore newarg = B_TRUE;
66601335b0dSGarrett D'Amore skip = strtoll(optarg, &eptr, 0);
66701335b0dSGarrett D'Amore if (*eptr == 'b') {
66801335b0dSGarrett D'Amore skip <<= 9; /* 512 bytes */
66901335b0dSGarrett D'Amore eptr++;
67001335b0dSGarrett D'Amore } else if (*eptr == 'k') {
67101335b0dSGarrett D'Amore skip <<= 10; /* 1k */
67201335b0dSGarrett D'Amore eptr++;
67301335b0dSGarrett D'Amore } else if (*eptr == 'm') {
67401335b0dSGarrett D'Amore skip <<= 20; /* 1m */
67501335b0dSGarrett D'Amore eptr++;
67601335b0dSGarrett D'Amore } else if (*eptr == 'g') {
67701335b0dSGarrett D'Amore skip <<= 30; /* 1g */
67801335b0dSGarrett D'Amore eptr++;
67901335b0dSGarrett D'Amore }
68001335b0dSGarrett D'Amore if ((skip < 0) || (eptr[0] != 0)) {
68101335b0dSGarrett D'Amore warnx(_("invalid skip count '%s' specified"),
68201335b0dSGarrett D'Amore optarg);
68301335b0dSGarrett D'Amore exit(1);
68401335b0dSGarrett D'Amore }
68501335b0dSGarrett D'Amore break;
68601335b0dSGarrett D'Amore
68701335b0dSGarrett D'Amore case 'N':
68801335b0dSGarrett D'Amore newarg = B_TRUE;
68901335b0dSGarrett D'Amore limit = strtoll(optarg, &eptr, 0);
69001335b0dSGarrett D'Amore /*
69101335b0dSGarrett D'Amore * POSIX doesn't specify this, but I think these
69201335b0dSGarrett D'Amore * may be helpful.
69301335b0dSGarrett D'Amore */
69401335b0dSGarrett D'Amore if (*eptr == 'b') {
69501335b0dSGarrett D'Amore limit <<= 9;
69601335b0dSGarrett D'Amore eptr++;
69701335b0dSGarrett D'Amore } else if (*eptr == 'k') {
69801335b0dSGarrett D'Amore limit <<= 10;
69901335b0dSGarrett D'Amore eptr++;
70001335b0dSGarrett D'Amore } else if (*eptr == 'm') {
70101335b0dSGarrett D'Amore limit <<= 20;
70201335b0dSGarrett D'Amore eptr++;
70301335b0dSGarrett D'Amore } else if (*eptr == 'g') {
70401335b0dSGarrett D'Amore limit <<= 30;
70501335b0dSGarrett D'Amore eptr++;
70601335b0dSGarrett D'Amore }
70701335b0dSGarrett D'Amore if ((limit < 0) || (eptr[0] != 0)) {
70801335b0dSGarrett D'Amore warnx(_("invalid byte count '%s' specified"),
70901335b0dSGarrett D'Amore optarg);
71001335b0dSGarrett D'Amore exit(1);
71101335b0dSGarrett D'Amore }
71201335b0dSGarrett D'Amore break;
71301335b0dSGarrett D'Amore
71401335b0dSGarrett D'Amore default:
71501335b0dSGarrett D'Amore usage();
71601335b0dSGarrett D'Amore break;
71701335b0dSGarrett D'Amore }
71801335b0dSGarrett D'Amore }
71901335b0dSGarrett D'Amore
72001335b0dSGarrett D'Amore /* this finds the smallest power of two size we can use */
72101335b0dSGarrett D'Amore buffer.mask = (1 << (ffs(blocksize * 3) + 1)) - 1;
72201335b0dSGarrett D'Amore buffer.data = memalign(16, buffer.mask + 1);
72301335b0dSGarrett D'Amore if (buffer.data == NULL) {
72401335b0dSGarrett D'Amore err(1, "memalign");
72501335b0dSGarrett D'Amore }
72601335b0dSGarrett D'Amore
72701335b0dSGarrett D'Amore
72801335b0dSGarrett D'Amore /*
72901335b0dSGarrett D'Amore * Wow. This option parsing is hideous.
73001335b0dSGarrett D'Amore *
73101335b0dSGarrett D'Amore * If the we've not seen a new option, and there is just one
73201335b0dSGarrett D'Amore * operand, if it starts with a "+", then treat it as an
73301335b0dSGarrett D'Amore * offset. Otherwise if two operands, and the second operand
73401335b0dSGarrett D'Amore * starts with + or a digit, then it is an offset.
73501335b0dSGarrett D'Amore */
73601335b0dSGarrett D'Amore if (!newarg) {
73701335b0dSGarrett D'Amore if (((argc - optind) == 1) && (argv[optind][0] == '+')) {
73801335b0dSGarrett D'Amore offstr = argv[optind];
73901335b0dSGarrett D'Amore argc--;
74001335b0dSGarrett D'Amore } else if (((argc - optind) == 2) &&
74101335b0dSGarrett D'Amore (strchr("+0123456789", (argv[optind + 1][0])) != NULL)) {
74201335b0dSGarrett D'Amore offstr = argv[optind + 1];
74301335b0dSGarrett D'Amore argc--;
74401335b0dSGarrett D'Amore }
74501335b0dSGarrett D'Amore }
74601335b0dSGarrett D'Amore if (offstr) {
74701335b0dSGarrett D'Amore int base = 0;
74801335b0dSGarrett D'Amore int mult = 1;
74901335b0dSGarrett D'Amore int l;
75001335b0dSGarrett D'Amore if (*offstr == '+') {
75101335b0dSGarrett D'Amore offstr++;
75201335b0dSGarrett D'Amore }
75301335b0dSGarrett D'Amore l = strlen(offstr);
75401335b0dSGarrett D'Amore if ((strncmp(offstr, "0x", 2) == 0)) {
75501335b0dSGarrett D'Amore afmt = "%07llx";
75601335b0dSGarrett D'Amore base = 16;
75701335b0dSGarrett D'Amore offstr += 2;
75801335b0dSGarrett D'Amore if (offstr[l - 1] == 'B') {
75901335b0dSGarrett D'Amore offstr[l - 1] = 0;
76001335b0dSGarrett D'Amore l--;
76101335b0dSGarrett D'Amore mult = 512;
76201335b0dSGarrett D'Amore }
76301335b0dSGarrett D'Amore } else {
76401335b0dSGarrett D'Amore base = 8;
76501335b0dSGarrett D'Amore afmt = "%07llo";
76601335b0dSGarrett D'Amore if ((offstr[l - 1] == 'B') || (offstr[l - 1] == 'b')) {
76701335b0dSGarrett D'Amore offstr[l - 1] = 0;
76801335b0dSGarrett D'Amore l--;
76901335b0dSGarrett D'Amore mult = 512;
77001335b0dSGarrett D'Amore }
77101335b0dSGarrett D'Amore if (offstr[l - 1] == '.') {
77201335b0dSGarrett D'Amore offstr[l - 1] = 0;
77301335b0dSGarrett D'Amore base = 10;
77401335b0dSGarrett D'Amore afmt = "%07lld";
77501335b0dSGarrett D'Amore }
77601335b0dSGarrett D'Amore }
77701335b0dSGarrett D'Amore skip = strtoll(offstr, &eptr, base);
77801335b0dSGarrett D'Amore if (*eptr != '\0') {
77901335b0dSGarrett D'Amore errx(1, _("invalid offset string specified"));
78001335b0dSGarrett D'Amore }
78101335b0dSGarrett D'Amore skip *= mult;
78201335b0dSGarrett D'Amore offset += skip;
78301335b0dSGarrett D'Amore }
78401335b0dSGarrett D'Amore
78501335b0dSGarrett D'Amore /*
78601335b0dSGarrett D'Amore * Allocate an array for all the input files.
78701335b0dSGarrett D'Amore */
78801335b0dSGarrett D'Amore if (argc > optind) {
78901335b0dSGarrett D'Amore files = calloc(sizeof (char *), argc - optind);
79001335b0dSGarrett D'Amore for (i = 0; i < argc - optind; i++) {
79101335b0dSGarrett D'Amore files[i] = argv[optind + i];
79201335b0dSGarrett D'Amore numfiles++;
79301335b0dSGarrett D'Amore }
79401335b0dSGarrett D'Amore input = next_input();
79501335b0dSGarrett D'Amore } else {
79601335b0dSGarrett D'Amore input = stdin;
79701335b0dSGarrett D'Amore }
79801335b0dSGarrett D'Amore
79901335b0dSGarrett D'Amore /*
80001335b0dSGarrett D'Amore * We need to seek ahead. fseek would be faster.
80101335b0dSGarrett D'Amore */
80201335b0dSGarrett D'Amore while (skip && (input != NULL)) {
80301335b0dSGarrett D'Amore struct stat sbuf;
80401335b0dSGarrett D'Amore
80501335b0dSGarrett D'Amore /*
80601335b0dSGarrett D'Amore * Only fseek() on regular files. (Others
80701335b0dSGarrett D'Amore * we have to read().
80801335b0dSGarrett D'Amore */
80901335b0dSGarrett D'Amore if (fstat(fileno(input), &sbuf) < 0) {
81001335b0dSGarrett D'Amore warn("fstat: %s", files[curfile-1]);
81101335b0dSGarrett D'Amore input = next_input();
81201335b0dSGarrett D'Amore continue;
81301335b0dSGarrett D'Amore }
81401335b0dSGarrett D'Amore if (S_ISREG(sbuf.st_mode)) {
81501335b0dSGarrett D'Amore /*
81601335b0dSGarrett D'Amore * No point in seeking a file that is too
81701335b0dSGarrett D'Amore * short to begin with.
81801335b0dSGarrett D'Amore */
81901335b0dSGarrett D'Amore if (sbuf.st_size < skip) {
82001335b0dSGarrett D'Amore skip -= sbuf.st_size;
82101335b0dSGarrett D'Amore input = next_input();
82201335b0dSGarrett D'Amore continue;
82301335b0dSGarrett D'Amore }
82401335b0dSGarrett D'Amore if (fseeko(input, skip, SEEK_SET) < 0) {
82501335b0dSGarrett D'Amore err(1, "fseek:%s", files[curfile-1]);
82601335b0dSGarrett D'Amore }
82701335b0dSGarrett D'Amore /* Done seeking. */
82801335b0dSGarrett D'Amore skip = 0;
82901335b0dSGarrett D'Amore break;
83001335b0dSGarrett D'Amore }
83101335b0dSGarrett D'Amore
83201335b0dSGarrett D'Amore /*
83301335b0dSGarrett D'Amore * fgetc seems like it would be slow, but it uses
83401335b0dSGarrett D'Amore * buffered I/O, so it should be fast enough.
83501335b0dSGarrett D'Amore */
83601335b0dSGarrett D'Amore flockfile(input);
83701335b0dSGarrett D'Amore while (skip) {
83801335b0dSGarrett D'Amore if (getc_unlocked(input) == EOF) {
83901335b0dSGarrett D'Amore funlockfile(input);
84001335b0dSGarrett D'Amore if (ferror(input)) {
84101335b0dSGarrett D'Amore warn("read: %s", files[curfile-1]);
84201335b0dSGarrett D'Amore }
84301335b0dSGarrett D'Amore input = next_input();
84401335b0dSGarrett D'Amore if (input != NULL) {
84501335b0dSGarrett D'Amore flockfile(input);
84601335b0dSGarrett D'Amore }
84701335b0dSGarrett D'Amore break;
84801335b0dSGarrett D'Amore }
84901335b0dSGarrett D'Amore skip--;
85001335b0dSGarrett D'Amore }
85101335b0dSGarrett D'Amore if (input != NULL)
85201335b0dSGarrett D'Amore funlockfile(input);
85301335b0dSGarrett D'Amore }
85401335b0dSGarrett D'Amore
85501335b0dSGarrett D'Amore if (head == NULL) {
85601335b0dSGarrett D'Amore add_out(&output_oct_w);
85701335b0dSGarrett D'Amore }
85801335b0dSGarrett D'Amore
85901335b0dSGarrett D'Amore buffer.navail = 0;
86001335b0dSGarrett D'Amore buffer.prod = 0;
86101335b0dSGarrett D'Amore buffer.cons = 0;
86201335b0dSGarrett D'Amore
86301335b0dSGarrett D'Amore for (refill(&buffer); buffer.navail > 0; refill(&buffer)) {
86401335b0dSGarrett D'Amore output_t *out;
86501335b0dSGarrett D'Amore int mx;
86601335b0dSGarrett D'Amore int j, k;
86701335b0dSGarrett D'Amore
86801335b0dSGarrett D'Amore /*
86901335b0dSGarrett D'Amore * If this buffer was the same as last, then just
87001335b0dSGarrett D'Amore * dump an asterisk.
87101335b0dSGarrett D'Amore */
87201335b0dSGarrett D'Amore if ((!first) && (buffer.navail >= blocksize) && (!doall)) {
87301335b0dSGarrett D'Amore j = buffer.cons;
87401335b0dSGarrett D'Amore k = j - blocksize;
87501335b0dSGarrett D'Amore for (i = 0; i < blocksize; i++) {
87601335b0dSGarrett D'Amore if (buffer.data[j & buffer.mask] !=
87701335b0dSGarrett D'Amore buffer.data[k & buffer.mask]) {
87801335b0dSGarrett D'Amore break;
87901335b0dSGarrett D'Amore }
88001335b0dSGarrett D'Amore j++;
88101335b0dSGarrett D'Amore k++;
88201335b0dSGarrett D'Amore }
88301335b0dSGarrett D'Amore if (i == blocksize) {
88401335b0dSGarrett D'Amore if (!same) {
88501335b0dSGarrett D'Amore (void) fputs("*\n", stdout);
88601335b0dSGarrett D'Amore same = B_TRUE;
88701335b0dSGarrett D'Amore }
88801335b0dSGarrett D'Amore buffer.navail -= blocksize;
88901335b0dSGarrett D'Amore offset += blocksize;
89001335b0dSGarrett D'Amore buffer.cons += blocksize;
89101335b0dSGarrett D'Amore buffer.cons &= buffer.mask;
89201335b0dSGarrett D'Amore continue;
89301335b0dSGarrett D'Amore }
89401335b0dSGarrett D'Amore }
89501335b0dSGarrett D'Amore
89601335b0dSGarrett D'Amore first = B_FALSE;
89701335b0dSGarrett D'Amore same = B_FALSE;
89801335b0dSGarrett D'Amore mx = (buffer.navail > blocksize) ? blocksize : buffer.navail;
89901335b0dSGarrett D'Amore
90001335b0dSGarrett D'Amore for (out = head; out != NULL; out = out->next) {
90101335b0dSGarrett D'Amore
90201335b0dSGarrett D'Amore if (out == head) {
90301335b0dSGarrett D'Amore /*LINTED E_SEC_PRINTF_VAR_FMT*/
90401335b0dSGarrett D'Amore (void) printf(afmt, offset);
90501335b0dSGarrett D'Amore } else {
90601335b0dSGarrett D'Amore (void) fputs(cfmt, stdout);
90701335b0dSGarrett D'Amore }
90801335b0dSGarrett D'Amore for (i = 0, j = buffer.cons; i < mx; i += out->width) {
90901335b0dSGarrett D'Amore out->func(&buffer, j);
91001335b0dSGarrett D'Amore j += out->width;
91101335b0dSGarrett D'Amore j &= buffer.mask;
91201335b0dSGarrett D'Amore }
91301335b0dSGarrett D'Amore (void) fputs("\n", stdout);
91401335b0dSGarrett D'Amore }
91501335b0dSGarrett D'Amore buffer.cons += mx;
91601335b0dSGarrett D'Amore buffer.cons &= buffer.mask;
91701335b0dSGarrett D'Amore offset += mx;
91801335b0dSGarrett D'Amore buffer.navail -= mx;
91901335b0dSGarrett D'Amore }
92001335b0dSGarrett D'Amore /*LINTED E_SEC_PRINTF_VAR_FMT*/
92101335b0dSGarrett D'Amore (void) printf(afmt, offset);
92201335b0dSGarrett D'Amore (void) fputs("\n", stdout);
92301335b0dSGarrett D'Amore return (0);
92401335b0dSGarrett D'Amore }
925