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