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