1 /* @(#)hdump.c 1.46 21/02/07 Copyright 1986-2021 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)hdump.c 1.46 21/02/07 Copyright 1986-2021 J. Schilling";
6 #endif
7 /*
8 * hex dump for files
9 * od "octal" dump
10 *
11 * This is an attempt to implement POSIX behavior as well as traditional
12 * Solaris od(1) behavior.
13 *
14 * Note that we do not implement bugs and we do not implement apparent
15 * behavior from other implementations but documented behavior for the
16 * programs /usr/bin/od and /usr/xpg4/bin/od on Solaris and we of course
17 * follow the POSIX standard.
18 *
19 * As we use getexecname() to distinct between the POSIX interface and the
20 * traditional Solaris interface, /usr/bin/od and /usr/xpg4/bin/od must be
21 * hard linked. Symlinks would be followed by getexecname().
22 *
23 * Copyright (c) 1986-2021 J. Schilling
24 */
25 /*
26 * The contents of this file are subject to the terms of the
27 * Common Development and Distribution License, Version 1.0 only
28 * (the "License"). You may not use this file except in compliance
29 * with the License.
30 *
31 * See the file CDDL.Schily.txt in this distribution for details.
32 * A copy of the CDDL is also available via the Internet at
33 * http://www.opensource.org/licenses/cddl1.txt
34 *
35 * When distributing Covered Code, include this CDDL HEADER in each
36 * file and include the License file CDDL.Schily.txt from this distribution.
37 */
38
39 #include <schily/stdio.h>
40 #include <schily/standard.h>
41 #include <schily/stdlib.h>
42 #include <schily/unistd.h>
43 #include <schily/fcntl.h> /* O_BINARY */
44 #include <schily/types.h> /* To make off_t available */
45 #include <schily/utypes.h>
46 #include <schily/schily.h>
47 #include <schily/getargs.h>
48 #include <schily/align.h>
49 #include <schily/nlsdefs.h>
50 #include <schily/io.h> /* for setmode() prototype */
51 #include <schily/limits.h> /* for MB_LEN_MAX */
52 #include <schily/ctype.h> /* For isprint() */
53 #include <schily/wchar.h> /* wchar_t */
54 #include <schily/wctype.h> /* For iswprint() */
55
56 /*
57 * K&R cpp does not permit us to use spaces in the K&R concat method below,
58 * so we are forced to use the special CSTYLED comment in order to keep the
59 * indentation lint program "cstyle" quiet.
60 */
61 #if defined(PROTOTYPES)
62 #define CONCAT(a, b) a##b
63 #else
64 /* CSTYLED */
65 #define CONCAT(a, b) a/**/b
66 #endif
67
68 #define octdig(x) (x >= '0' && x <= '7')
69 #ifndef TRUE
70 #define TRUE 1
71 #define FALSE 0
72 #endif
73
74 /*
75 * The current display state
76 */
77 typedef struct dstate {
78 FILE *f; /* The current input file */
79 int imcnt; /* Count from intermediate buffer */
80 int rest; /* Unprinted octets + 1 */
81 BOOL printable; /* Partial character was printable */
82 int blocksize; /* The display buffer size */
83 const char *inname; /* The current input file name */
84 int argc; /* argc for the rest of the files */
85 char *const *argv; /* argv[0] points to current file */
86 int excode; /* The exit code for delayed errors */
87 } dst_t;
88
89 typedef int (*pfun) __PR((const char *fmt, void *valp));
90 typedef int (*pbfun)__PR((int cnt, char *buf, dst_t *dstp));
91
92 typedef struct pr pr_t;
93 struct pr {
94 size_t pr_size; /* Object size for one element */
95 int pr_fieldw; /* Output-fieldwidth for one element */
96 char *pr_fmt; /* Printf() format for pr_out */
97 pfun pr_out; /* Element output function */
98 pbfun pr_block; /* Line-block output function */
99 int pr_fill; /* Number of ' ' fill characters */
100 pr_t *pr_next;
101 };
102
103 /*
104 * The K&R CONCAT does not permit us to put a space after the after the comma
105 * in a CONCAT() call, so we are forced to use the special CSTYLED comment in
106 * order to keep the indentation lint program "cstyle" quiet.
107 */
108 #define DEF_PR(name, width, type, format) \
109 /* CSTYLED */ \
110 LOCAL int CONCAT(pr_,name) __PR((const char *fmt, void *vp));\
111 LOCAL int \
112 /* CSTYLED */ \
113 CONCAT(pr_,name) (fmt, vp) \
114 const char *fmt; \
115 void *vp; \
116 { \
117 return (printf(fmt, *(type *)vp)); \
118 } \
119 /* CSTYLED */ \
120 LOCAL pr_t CONCAT(d_,name) = { sizeof (type), \
121 width, \
122 format, \
123 /* CSTYLED */ \
124 CONCAT(pr_,name), \
125 0, \
126 0, 0 }
127
128
129 LOCAL BOOL is_od = FALSE; /* This is "od" and not "hdump" */
130 LOCAL BOOL is_xpg4 = FALSE; /* Called as /usr/xpg4/bin/od */
131 LOCAL BOOL is_posix = FALSE; /* Used POSIX option (-A/-j/-N/-t) */
132 LOCAL BOOL is_pipe; /* Whether stdout is a pipe */
133 LOCAL int curradix; /* Radix found by myatoll() */
134 LOCAL int maxline = 0; /* Max with in output formats */
135 LOCAL char *addrfmt; /* Address printf() format */
136 LOCAL char *samefmt; /* printf() format for same data */
137 LOCAL off_t pos = (off_t)0; /* Position used for address label */
138
139 LOCAL BOOL dflag = FALSE; /* -d od -tu2 / hdump -d (decimal) */
140 LOCAL BOOL oflag = FALSE; /* -o hdump: switch to octal */
141 LOCAL BOOL lflag = FALSE; /* -l hdump: switch to long */
142 LOCAL BOOL uflag = FALSE; /* -u hdump: switch to unsigned */
143 LOCAL BOOL tflag = FALSE; /* -t was seen, POSIX interface requested */
144 LOCAL BOOL lenflag = FALSE; /* A bytecount limiting argument was seen */
145 LOCAL BOOL vflag = FALSE; /* -v show all input data */
146
147 LOCAL void usage __PR((int exitcode));
148 LOCAL const char *filename __PR((const char *name));
149 EXPORT int main __PR((int ac, char **av));
150 LOCAL void checkfill __PR((dst_t *dstp));
151 LOCAL int gettype __PR((const char *arg, void *valp));
152 LOCAL void add_dout __PR((pr_t *this));
153 LOCAL int add_out __PR((const char *arg, long *valp));
154 LOCAL int add_fmt __PR((const char *arg, long *valp));
155 LOCAL int opt_b __PR((const char *arg, long *valp));
156 LOCAL int opt_c __PR((const char *arg, long *valp));
157 LOCAL int opt_d __PR((const char *arg, long *valp));
158 LOCAL int opt_l __PR((const char *arg, long *valp));
159 LOCAL int opt_o __PR((const char *arg, long *valp));
160 LOCAL int opt_u __PR((const char *arg, long *valp));
161 LOCAL void dump __PR((off_t len, dst_t *dstp));
162 LOCAL void prbuf __PR((int cnt, char *obuf, dst_t *dstp));
163 LOCAL int prasc __PR((int cnt, char *buf, dst_t *dstp));
164 LOCAL int prch __PR((int cnt, char *buf, dst_t *dstp));
165 LOCAL int prmbch __PR((int cnt, char *buf, dst_t *dstp));
166 LOCAL int prcbytes __PR((int cnt, char *buf, dst_t *dstp));
167 LOCAL int prbbytes __PR((int cnt, char *buf, dst_t *dstp));
168 LOCAL int prascii __PR((int cnt, char *buf, dst_t *dstp));
169 LOCAL int prlong __PR((int cnt, char *buf, dst_t *dstp));
170 LOCAL int prshort __PR((int cnt, char *buf, dst_t *dstp));
171 LOCAL BOOL bufeql __PR((long *b1, long *b2, int cnt));
172 LOCAL Llong myatoll __PR((char *s));
173 LOCAL int read_input __PR((dst_t *dstp, char *bp, int cnt));
174 LOCAL BOOL open_next __PR((dst_t *dstp));
175 LOCAL off_t advance __PR((dst_t *dstp, off_t xpos));
176 LOCAL off_t doadvance __PR((FILE *f, off_t xpos, BOOL is_last));
177 LOCAL off_t doskip __PR((FILE *f, off_t xpos));
178 LOCAL BOOL out_ispipe __PR((void));
179 LOCAL int ptype __PR((const char *arg));
180 LOCAL int illsize __PR((int size));
181 LOCAL int illfsize __PR((int size));
182 LOCAL int illtype __PR((int type));
183 LOCAL void setaddrfmt __PR((int Aflag, int lradix));
184
185 /*
186 * These output descriptors are object oriented.
187 * They are called once per element.
188 */
189
190 /*
191 * Decimal formats
192 */
193 DEF_PR(c_d, 4, char, " %3hhd");
194 DEF_PR(s_d, 7, short, " %6.5hd");
195 DEF_PR(i_d, 12, int, " %11.10d");
196 #if SIZEOF_LONG_INT > SIZEOF_INT
197 DEF_PR(l_d, 21, long, " %20.18ld");
198 #else
199 #define d_l_d d_i_d
200 #endif
201 #if SIZEOF_LONG_LONG > SIZEOF_LONG_INT
202 DEF_PR(ll_d, 21, Llong, " %20.18lld");
203 #endif
204
205 /*
206 * Octal formats
207 */
208 DEF_PR(c_o, 4, char, " %3.3hho");
209 DEF_PR(s_o, 7, short, " %6.6ho");
210 DEF_PR(i_o, 12, int, " %11.11o");
211 #if SIZEOF_LONG_INT > SIZEOF_INT
212 DEF_PR(l_o, 23, long, " %22.22lo");
213 #else
214 #define d_l_o d_i_o
215 #endif
216 #if SIZEOF_LONG_LONG > SIZEOF_LONG_INT
217 DEF_PR(ll_o, 23, Llong, " %22.22llo");
218 #endif
219
220 /*
221 * Unsigned decimal formats
222 */
223 DEF_PR(c_u, 4, char, " %3.3hhu");
224 DEF_PR(s_u, 6, short, " %5.5hu");
225 DEF_PR(i_u, 11, int, " %10.10u");
226 #if SIZEOF_LONG_INT > SIZEOF_INT
227 DEF_PR(l_u, 21, long, " %20.20lu");
228 #else
229 #define d_l_u d_i_u
230 #endif
231 #if SIZEOF_LONG_LONG > SIZEOF_LONG_INT
232 DEF_PR(ll_u, 21, Llong, " %20.20llu");
233 #endif
234
235 /*
236 * Hexadecimal formats
237 */
238 DEF_PR(c_x, 3, char, " %2.2hhx");
239 DEF_PR(s_x, 5, short, " %4.4hx");
240 DEF_PR(i_x, 9, int, " %8.8x");
241 #if SIZEOF_LONG_INT > SIZEOF_INT
242 DEF_PR(l_x, 17, long, " %16.16lx");
243 #else
244 #define d_l_x d_i_x
245 #endif
246 #if SIZEOF_LONG_LONG > SIZEOF_LONG_INT
247 DEF_PR(ll_x, 17, Llong, " %16.16llx");
248 #endif
249
250 /*
251 * Floatingpoint formats
252 */
253 #ifndef NO_FLOATINGPOINT
254 #define FLOAT_AS_ON_SUNOS
255 #ifdef FLOAT_AS_ON_SUNOS
256 DEF_PR(f_f, 15, float, " %14.7e");
257 #else
258 DEF_PR(f_f, 14, float, " %13.6e");
259 #endif
260 DEF_PR(d_f, 23, double, " %22.14e");
261 #ifdef HAVE_LONGDOUBLE
262 DEF_PR(ld_f, 24, long double, " %23.14Le");
263 #endif
264 #endif
265
266 /*
267 * These output descriptors are block oriented.
268 * They are called once per line.
269 */
270 LOCAL pr_t d_asc = { sizeof (char), 4, "", 0, prasc }; /* od -ta */
271 LOCAL pr_t d_ch = { sizeof (char), 4, "", 0, prch }; /* od -c */
272 LOCAL pr_t d_mbch = { sizeof (char), 4, "", 0, prmbch }; /* od -C/-tc */
273
274 LOCAL pr_t d_ascii = { sizeof (char), 3, "", 0, prascii }; /* hd -a */
275 LOCAL pr_t d_bbytes = { sizeof (char), 4, "", 0, prbbytes }; /* hd -b */
276 LOCAL pr_t d_cbytes = { sizeof (char), 4, "", 0, prcbytes }; /* hd -c */
277 LOCAL pr_t d_short = { sizeof (short), 4, "", 0, prshort }; /* hd */
278 LOCAL pr_t d_long = { sizeof (long), 4, "", 0, prlong }; /* hd -l */
279
280 LOCAL pr_t *pr_root;
281 LOCAL pr_t **pr_tail = &pr_root;
282
283
284 LOCAL void
usage(exitcode)285 usage(exitcode)
286 int exitcode;
287 {
288 error(_(
289 "Usage: %s [options] [file] [[+]starting address[.][b|B]%s]\n"),
290 is_od?"od":"hdump", is_od?"":_(" [count]]"));
291 error(_(
292 "Usage: %s [options] [-t type]... [-A base] [-j skip] [-N count] [file...]\n"),
293 is_od?"od":"hdump");
294 error(_("Options:\n"));
295 error(_("\t-A c\tSet address base c ('d', 'o', 'n' or 'x')\n"));
296 error(_("\t-j skip\tSkip input for the files\n"));
297 error(_("\t-N n\tOnly process n bytes\n"));
298 error(_("\t-t type\tSpecify output format type\n"));
299 error(_("\t-a\tDisplay content also in characters\n"));
300 error(_("\t-b\tDisplay content in bytes\n"));
301 error(_("\t-c\tDisplay content as %s quoted characters\n"),
302 is_xpg4 ? _("single or multi byte") : _("single byte"));
303 error(_("\t-C\tDisplay content as %s quoted characters\n"),
304 _("single or multi byte"));
305 error(_("\t-d\tDisplay content in decimal%s\n"),
306 is_od ? " -tu2" : "");
307 error(_("\t-D\tDisplay content in decimal -tu4\n"));
308 #ifndef NO_FLOATINGPOINT
309 error(_("\t-f\tDisplay content as floats\n"));
310 error(_("\t-F\tDisplay content as doubles\n"));
311 #endif
312 if (!is_od)
313 error(_("\t-l\tDisplay content as longs\n"));
314 error(_("\t-o\tDisplay content in octal%s\n"),
315 is_od ? " -to2" : "");
316 error(_("\t-O\tDisplay content in octal -to4\n"));
317 error(_("\t-s\tDisplay content in decimal -td2\n"));
318 error(_("\t-S\tDisplay content in decimal -td4\n"));
319 if (!is_od)
320 error(_("\t-u\tDisplay content as unsigned\n"));
321 error(_("\t-v\tShow all data even if it is identical\n"));
322 error(_("\t-x\tDisplay content in hexadecimal -tx2\n"));
323 error(_("\t-X\tDisplay content in hexadecimal -tx4\n"));
324 error(_("\t-help\tPrint this help.\n"));
325 error(_("\t-version\tPrint version number.\n"));
326 error(_("'b' after starting address multiplies with 512\n"));
327 exit(exitcode);
328 }
329
330 #include <schily/string.h>
331 LOCAL const char *
filename(name)332 filename(name)
333 const char *name;
334 {
335 char *p;
336
337 if ((p = strrchr(name, '/')) == NULL)
338 return (name);
339 return (++p);
340 }
341
342 EXPORT int
main(ac,av)343 main(ac, av)
344 int ac;
345 char *av[];
346 {
347 off_t len = (off_t)0;
348 char *options =
349 "A?,j&,N&,t&,a~,b~,c~,C~,d~,D~,f~,F~,l~,o~,O~,s~,S~,u~,v,x~,X~,help,version";
350 BOOL help = FALSE;
351 BOOL prversion = FALSE;
352 BOOL didoffset = FALSE;
353 char Aflag = '\0';
354 Llong skip = 0;
355 Llong nbytes = 0;
356 int lradix = 16; /* hdump defaults to hex. radix */
357 int cac;
358 char * const * cav;
359 #if defined(USE_NLS)
360 char *dir;
361 #endif
362 dst_t dst;
363 struct ga_props ga_props;
364
365 save_args(ac, av);
366
367 (void) setlocale(LC_ALL, "");
368
369 #if defined(USE_NLS)
370 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
371 #define TEXT_DOMAIN "hdump" /* Use this only if it weren't */
372 #endif
373 dir = searchfileinpath("share/locale", F_OK,
374 SIP_ANY_FILE|SIP_NO_PATH, NULL);
375 if (dir)
376 (void) bindtextdomain(TEXT_DOMAIN, dir);
377 else
378 #ifdef PROTOTYPES
379 (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
380 #else
381 (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
382 #endif
383 (void) textdomain(TEXT_DOMAIN);
384 #endif
385
386 /*
387 * First set defaults related to the current CLI variant.
388 */
389 if (streql(filename(av[0]), "od")) { /* "od" interface? */
390 const char *exname;
391
392 is_od = TRUE; /* "od" behavior */
393 lradix = 8; /* "od" def is octal */
394 #ifdef HAVE_GETEXECNAME
395 exname = getexecname();
396 #else
397 exname = getexecpath();
398 #endif
399 if (exname &&
400 strstr(exname, "/xpg4")) { /* X-Open interface? */
401 /*
402 * This makes the behavior for the -c option depend
403 * on the current locale instead of using single byte
404 * characters as with the AT&T "od".
405 *
406 * It also disables to use "-" as a synonym for stdin
407 * and it modifies the way the "offset" argument past
408 * a single file argument is parsed.
409 */
410 is_xpg4 = TRUE;
411 }
412 }
413
414 cac = --ac;
415 cav = ++av;
416
417 /*
418 * POSIX doesn't permit +opt and requires support for combined
419 * single char options with the one having an argument. If we did
420 * use the macro GAF_POSIX instead, we would include GAF_NO_EQUAL.
421 */
422 getarginit(&ga_props, GAF_NO_PLUS|GAF_SINGLEARG);
423 if (getlargs(&cac, &cav, &ga_props, options,
424 &Aflag,
425 getllnum, &skip, /* -j skip */
426 getllnum, &nbytes, /* -N bytes */
427 gettype, NULL, /* -t type */
428 add_out, &d_ascii, /* -a */
429 opt_b, NULL, /* -b */
430 opt_c, NULL, /* -c */
431 add_out, &d_mbch, /* -C */
432 opt_d, NULL, /* -d */
433 add_fmt, "u4", /* -D */
434 add_fmt, "f4", /* -f */
435 add_fmt, "f8", /* -F */
436 opt_l, NULL, /* -l (hdump) */
437 opt_o, NULL, /* -o */
438 add_fmt, "o4", /* -O */
439 add_fmt, "d2", /* -s */
440 add_fmt, "d4", /* -S */
441 opt_u, NULL, /* -u (hdump) */
442 &vflag, /* -v */
443 add_fmt, "x2", /* -x */
444 add_fmt, "x4", /* -X */
445 &help, &prversion) < 0) {
446 error(_("Bad flag: '%s'.\n"), cav[0]);
447 usage(1);
448 }
449 if (help)
450 usage(0);
451 if (prversion) {
452 printf(
453 _("%s release %s %s (%s-%s-%s) Copyright (C) 1986-2021 %s\n"),
454 is_od ? "Od":"Hdump",
455 "1.46", "2021/02/07",
456 HOST_CPU, HOST_VENDOR, HOST_OS,
457 _("Joerg Schilling"));
458 exit(0);
459 }
460 is_pipe = out_ispipe(); /* Flush output if we write to a pipe */
461
462 if (skip < 0)
463 comerrno(EX_BAD, _("Invalid offset %lld.\n"), skip);
464 if (skip > 0) {
465 is_posix = TRUE; /* Using -j skip switches to POSIX */
466 pos = skip;
467 if (pos != skip) {
468 comerrno(EX_BAD,
469 _("Offset %lld is too large for type 'off_t'.\n"),
470 skip);
471 }
472 }
473 if (nbytes < 0)
474 comerrno(EX_BAD, _("Invalid number of bytes.\n"));
475 if (nbytes > 0) {
476 is_posix = TRUE; /* Using -N bytes switches to POSIX */
477 lenflag = TRUE;
478 len = nbytes;
479 if (len != nbytes) {
480 comerrno(EX_BAD,
481 _("Number of bytes %lld is too large for type 'off_t'.\n"),
482 nbytes);
483 }
484 }
485 if (Aflag || tflag)
486 is_posix = TRUE; /* Using -A/-t switches to POSIX */
487
488 cac = ac;
489 cav = av;
490 dst.excode = 0;
491 dst.inname = NULL;
492 dst.f = (FILE *)NULL;
493 if (getlfiles(&cac, &cav, &ga_props, options) <= 0) { /* Skip opts */
494 dst.argc = -2;
495 dst.argv = cav;
496 } else {
497 if (cac == 1 && cav[0][0] == '+') /* If called od +off */
498 dst.argc = -2; /* mark to use stdin */
499 else
500 dst.argc = cac;
501 dst.argv = cav;
502 }
503 open_next(&dst); /* Open first file */
504 if (dst.f == (FILE *)NULL)
505 return (dst.excode);
506
507 /*
508 * Permit to call "od +offset" (use old skip syntax and dump stdin).
509 */
510 if (!(cac == 1 && cav[0][0] == '+')) {
511 cac--, cav++;
512 }
513 /*
514 * Only when not in POSIX CLI mode, use the historical offset arg.
515 * POSIX CLI mode is not related to the POSIX binary path, but used
516 * when the POSIX options -A/-j/-N/-t are part of the current
517 * command line.
518 */
519 if (!is_posix && ((is_od && cac == 1) || (!is_od && cac > 0))) {
520 char *arg = cav[0];
521
522 if ((is_xpg4 && /* This is for /usr/xpg4/bin/od */
523 strchr("+0123456789", *arg)) ||
524 (!is_xpg4 && /* This is for /usr/bin/od and hdump */
525 (strchr("+0123456789", *arg) ||
526 (arg[0] == 'x' && arg[1] == '\0') ||
527 (arg[0] == 'x' && strchr("0123456789abcdef", arg[1])) ||
528 (arg[0] == '.' && arg[1] == '\0')))) {
529 if (*arg == '+')
530 arg++;
531 pos = (off_t)myatoll(arg);
532 if (!is_od)
533 pos &= ~((off_t)1);
534 lradix = curradix;
535 didoffset = TRUE;
536 cac--, cav++;
537 dst.argc--;
538 }
539 }
540 if (!is_od && didoffset && cac > 0) {
541 /*
542 * Hdump supports an additional "count" argument when
543 * only a single file has been specified.
544 */
545 len = (off_t)myatoll(cav[0]);
546 lenflag = TRUE;
547 cac--; cav++;
548 dst.argc--;
549
550 if (cac > 0) {
551 errmsgno(EX_BAD,
552 _("Unexpected argument '%s'.\n"), cav[0]);
553 usage(1);
554 }
555 }
556
557 setaddrfmt(Aflag, lradix); /* Set format for address labels */
558
559 if (pos > 0) {
560 off_t newpos = advance(&dst, pos);
561
562 if (newpos > 0)
563 comerrno(-2, _("Cannot skip past EOF.\n"));
564 /*
565 * In case of a POSIX -j offset spec, start with address
566 * label 0, otherwise use the address label that matches pos.
567 */
568 if (skip > 0)
569 pos = 0;
570 }
571 if (pr_root == NULL) { /* No pr format yet? */
572 if (is_od) {
573 add_dout(&d_s_o); /* od default: -toS */
574 } else {
575 if (lflag)
576 add_dout(&d_long);
577 else
578 add_dout(&d_short);
579 }
580 }
581 checkfill(&dst);
582 dump(len, &dst);
583 return (dst.excode);
584 }
585
586 /*
587 * Check how many fill characters are needed for each format in order to
588 * align the output according to the POSIX standard.
589 */
590 LOCAL void
checkfill(dstp)591 checkfill(dstp)
592 dst_t *dstp;
593 {
594 pr_t *dp;
595 int kgv = 1;
596 int n;
597
598 for (dp = pr_root; dp != NULL; dp = dp->pr_next) {
599 if (kgv % dp->pr_size) {
600 n = kgv;
601 while (n % dp->pr_size)
602 n += kgv;
603 kgv = n;
604 }
605 }
606 while (kgv < 12)
607 kgv *= 2;
608 dstp->blocksize = kgv;
609
610 for (dp = pr_root, n = 0; dp != NULL; dp = dp->pr_next) {
611 int lmax;
612 int nmax;
613
614 lmax = dstp->blocksize / dp->pr_size * dp->pr_fieldw;
615 if (lmax > maxline)
616 maxline = lmax;
617 nmax = dstp->blocksize / dp->pr_size;
618 if (nmax > n)
619 n = nmax;
620 }
621 /*
622 * Round up to the next value that is dividable by the highest
623 * number of objects per line.
624 */
625 while (maxline > (maxline / n * n))
626 maxline++;
627 for (dp = pr_root; dp != NULL; dp = dp->pr_next) {
628 dp->pr_fill =
629 maxline/(dstp->blocksize/dp->pr_size)-dp->pr_fieldw;
630 }
631 }
632
633 /*
634 * Get the type for the -t type option.
635 * Mark that we did call the type parser along with -t.
636 */
637 /* ARGSUSED */
638 LOCAL int
gettype(arg,valp)639 gettype(arg, valp)
640 const char *arg;
641 void *valp;
642 {
643 tflag = TRUE;
644 return (ptype(arg));
645 }
646
647 /*
648 * Append an output definition to our current list.
649 */
650 LOCAL void
add_dout(this)651 add_dout(this)
652 pr_t *this;
653 {
654 pr_t *new = malloc(sizeof (*new));
655
656 if (new == NULL)
657 comerr(_("No memory.\n"));
658
659 *new = *this;
660 new->pr_next = (pr_t *)0;
661 *pr_tail = new;
662 pr_tail = &new->pr_next;
663 }
664
665 /*
666 * Append an output definition to our current list.
667 * This variant is called as getargs() callback.
668 */
669 /* ARGSUSED */
670 LOCAL int
add_out(arg,valp)671 add_out(arg, valp)
672 const char *arg;
673 long *valp;
674 {
675 add_dout((pr_t *)valp);
676 return (1);
677 }
678
679 /*
680 * Append an output definition from type string.
681 * This variant is called as getargs() callback.
682 */
683 /* ARGSUSED */
684 LOCAL int
add_fmt(arg,valp)685 add_fmt(arg, valp)
686 const char *arg;
687 long *valp;
688 {
689 return (ptype((char *)valp));
690 }
691
692 /*
693 * getargs() callback to implement -b for bin/hdump, bin/od and xpg4/bin/od.
694 */
695 /* ARGSUSED */
696 LOCAL int
opt_b(arg,valp)697 opt_b(arg, valp)
698 const char *arg;
699 long *valp;
700 {
701 if (is_od || tflag)
702 return (ptype("o1"));
703 add_dout(&d_bbytes);
704 return (1);
705 }
706
707 /*
708 * getargs() callback to implement -c for bin/hdump, bin/od and xpg4/bin/od.
709 */
710 /* ARGSUSED */
711 LOCAL int
opt_c(arg,valp)712 opt_c(arg, valp)
713 const char *arg;
714 long *valp;
715 {
716 if (is_od || tflag) {
717 if (is_xpg4)
718 add_dout(&d_mbch);
719 else
720 add_dout(&d_ch);
721 return (1);
722 }
723 add_dout(&d_cbytes);
724 return (1);
725 }
726
727 /*
728 * getargs() callback to implement -d for bin/hdump, bin/od and xpg4/bin/od.
729 */
730 /* ARGSUSED */
731 LOCAL int
opt_d(arg,valp)732 opt_d(arg, valp)
733 const char *arg;
734 long *valp;
735 {
736 if (is_od || tflag)
737 return (ptype("u2"));
738 dflag = TRUE;
739 return (1);
740 }
741
742 /*
743 * getargs() callback to implement -l for bin/hdump, bin/od and xpg4/bin/od.
744 */
745 /* ARGSUSED */
746 LOCAL int
opt_l(arg,valp)747 opt_l(arg, valp)
748 const char *arg;
749 long *valp;
750 {
751 if (is_od)
752 return (-1); /* -l is illegal for od(1) */
753 lflag = TRUE;
754 return (1);
755 }
756
757 /*
758 * getargs() callback to implement -o for bin/hdump, bin/od and xpg4/bin/od.
759 */
760 /* ARGSUSED */
761 LOCAL int
opt_o(arg,valp)762 opt_o(arg, valp)
763 const char *arg;
764 long *valp;
765 {
766 if (is_od || tflag)
767 return (ptype("o2"));
768 oflag = TRUE;
769 return (1);
770 }
771
772 /*
773 * getargs() callback to implement -u for bin/hdump, bin/od and xpg4/bin/od.
774 */
775 /* ARGSUSED */
776 LOCAL int
opt_u(arg,valp)777 opt_u(arg, valp)
778 const char *arg;
779 long *valp;
780 {
781 if (is_od)
782 return (-1); /* -u is illegal for od(1) */
783 uflag = TRUE;
784 return (1);
785 }
786
787 LOCAL void
dump(len,dstp)788 dump(len, dstp)
789 register off_t len;
790 dst_t *dstp;
791 {
792 char obuf[4 * 24]; /* 1x align 2x main buffer 1x ahead */
793 register char *buf;
794 register char *oldbuf;
795 register char *temp;
796 register int cnt;
797
798 /*
799 * Align for the worst case (This is a long double in LP64 mode)
800 */
801 buf = xalign((obuf), 16, 15);
802 oldbuf = buf + dstp->blocksize;
803
804 dstp->imcnt = 0;
805 dstp->rest = 0;
806 dstp->printable = FALSE;
807
808 do {
809 if (lenflag) {
810 if (len <= 0)
811 break;
812 cnt = len > dstp->blocksize ? dstp->blocksize:(int)len;
813 } else {
814 cnt = dstp->blocksize;
815 }
816
817 if (dstp->imcnt > 0) {
818 movebytes(oldbuf+dstp->blocksize, buf, dstp->imcnt);
819 cnt = cnt < dstp->imcnt ? cnt:dstp->imcnt;
820 dstp->imcnt = 0;
821 } else {
822 if ((cnt = read_input(dstp, buf, cnt)) == 0)
823 break;
824 }
825 if (vflag ||
826 !bufeql((long *)buf, (long *)oldbuf, dstp->blocksize)) {
827 if (cnt < dstp->blocksize)
828 fillbytes(buf+cnt, dstp->blocksize-cnt, '\0');
829 prbuf(cnt, buf, dstp);
830 }
831 pos += cnt;
832 len -= cnt;
833
834 temp = oldbuf;
835 oldbuf = buf;
836 buf = temp;
837 } while (!feof(dstp->f));
838 if (*addrfmt != '\t')
839 printf(addrfmt, pos);
840 printf("\n");
841 }
842
843 LOCAL void
prbuf(cnt,obuf,dstp)844 prbuf(cnt, obuf, dstp)
845 int cnt;
846 register char *obuf;
847 dst_t *dstp;
848 {
849 register pr_t *dp;
850
851 /*
852 * cnt > 0 is granted by dump()
853 */
854 printf(addrfmt, pos);
855
856 for (dp = pr_root; dp; dp = dp->pr_next) {
857 if (dp->pr_block) {
858 (*dp->pr_block)(cnt, obuf, dstp);
859 } else {
860 register int i;
861 register char *cp = obuf;
862
863 for (i = 0; i < cnt; ) {
864 register int k = dp->pr_fill;
865
866 while (--k >= 0)
867 (void) putchar(' ');
868
869 (*dp->pr_out)(dp->pr_fmt, cp);
870 i += dp->pr_size;
871 cp += dp->pr_size;
872 }
873 }
874 if (dp->pr_next)
875 printf("\n ");
876 else
877 printf("\n");
878 }
879 }
880
881 /*
882 * POSIX names for -ta (named characters).
883 */
884 LOCAL char *ascii_names[] = {
885 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
886 " bs", " ht", " lf", " vt", " ff", " cr", " so", " si",
887 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
888 "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
889 " sp", " !", " \"", " #", " $", " %", " &", " '",
890 " (", " )", " *", " +", " ,", " -", " .", " /",
891 " 0", " 1", " 2", " 3", " 4", " 5", " 6", " 7",
892 " 8", " 9", " :", " ;", " <", " =", " >", " ?",
893 " @", " A", " B", " C", " D", " E", " F", " G",
894 " H", " I", " J", " K", " L", " M", " N", " O",
895 " P", " Q", " R", " S", " T", " U", " V", " W",
896 " X", " Y", " Z", " [", " \\", " ]", " ^", " _",
897 " `", " a", " b", " c", " d", " e", " f", " g",
898 " h", " i", " j", " k", " l", " m", " n", " o",
899 " p", " q", " r", " s", " t", " u", " v", " w",
900 " x", " y", " z", " {", " |", " }", " ~", "del"
901 };
902
903 /*
904 * Print named 7-bit ASCII characters
905 */
906 /* ARGSUSED */
907 LOCAL int
prasc(cnt,buf,dstp)908 prasc(cnt, buf, dstp)
909 register int cnt;
910 register char *buf;
911 dst_t *dstp;
912 {
913 register short i;
914
915 for (i = 0; i < cnt; i++) {
916 (void) putchar(' ');
917 (void) fputs(ascii_names[buf[i]&0177], stdout);
918 }
919 return (0);
920 }
921
922 /*
923 * Print single byte characters, quote non-printable chars.
924 */
925 /* ARGSUSED */
926 LOCAL int
prch(cnt,buf,dstp)927 prch(cnt, buf, dstp)
928 register int cnt;
929 register char *buf;
930 dst_t *dstp;
931 {
932 register short i;
933 register Uchar c;
934
935 for (i = 0; i < cnt; i++) {
936 c = buf[i];
937 if (isprint(c))
938 printf(" %3c", c);
939 else switch (c) {
940
941 case '\0': printf(" \\0"); break;
942 case ALERT: printf(" \\a"); break;
943 case '\b': printf(" \\b"); break;
944 case '\f': printf(" \\f"); break;
945 case '\n': printf(" \\n"); break;
946 case '\r': printf(" \\r"); break;
947 case '\t': printf(" \\t"); break;
948 case '\v': printf(" \\v"); break;
949 default:
950 printf(" %3.3hho", c);
951 }
952 }
953 return (0);
954 }
955
956 /*
957 * Print single byte or multi-byte characters, quote non-printable chars.
958 * The character type is selected from LC_CTYPE.
959 */
960 LOCAL int
prmbch(cnt,buf,dstp)961 prmbch(cnt, buf, dstp)
962 register int cnt;
963 register char *buf;
964 dst_t *dstp;
965 {
966 register short i = 0;
967 register int n;
968 wchar_t wc = 0;
969
970 n = dstp->rest;
971 dstp->rest = 0;
972
973 while (--n >= 0 && i < cnt) {
974 if (dstp->printable)
975 printf(" **");
976 else
977 printf(" %3.3hho", buf[i]);
978 i++;
979 }
980
981 for (; i < cnt; i++) {
982 again:
983 n = mbtowc(&wc, &buf[i], cnt - i + dstp->imcnt);
984 if (n < 0) {
985 (void) mbtowc(NULL, NULL, 0);
986 /*
987 * Be careful here: Solaris is buggy and sets
988 * MB_CUR_MAX to 3 for UTF-8 although mbtowc() may
989 * return larger numbers.
990 */
991 if (dstp->imcnt == 0 && (cnt - i) < MB_LEN_MAX) {
992 dstp->imcnt = read_input(dstp,
993 buf+dstp->blocksize,
994 dstp->blocksize);
995 if (dstp->imcnt > 0)
996 goto again; /* Don't increment i */
997 }
998 }
999 if (n > 0 && iswprint(wc)) {
1000 printf("%*c%.*s", 4-wcwidth(wc), ' ', n, &buf[i]);
1001 while (--n > 0 && ++i < cnt)
1002 printf(" **");
1003 dstp->printable = TRUE;
1004 } else {
1005 dstp->printable = FALSE;
1006 n--;
1007 switch (wc) {
1008
1009 case '\0': printf(" \\0"); break;
1010 case ALERT: printf(" \\a"); break;
1011 case '\b': printf(" \\b"); break;
1012 case '\f': printf(" \\f"); break;
1013 case '\n': printf(" \\n"); break;
1014 case '\r': printf(" \\r"); break;
1015 case '\t': printf(" \\t"); break;
1016 case '\v': printf(" \\v"); break;
1017 default:
1018 do {
1019 printf(" %3.3hho", buf[i]);
1020 if (++i >= cnt)
1021 break;
1022 } while (--n >= 0);
1023 i--;
1024 }
1025 }
1026 }
1027 dstp->rest = n;
1028 return (0);
1029 }
1030
1031 /*
1032 * Implement hdump -c output.
1033 */
1034 /* ARGSUSED */
1035 LOCAL int
prcbytes(cnt,buf,dstp)1036 prcbytes(cnt, buf, dstp)
1037 register int cnt;
1038 register char *buf;
1039 dst_t *dstp;
1040 {
1041 register short i;
1042
1043 for (i = 0; i < cnt; i++) {
1044 if (buf[i] < ' ' || buf[i] >= '\177')
1045 printf(" \\%02X", 0377&buf[i]);
1046 else
1047 printf(" %c", buf[i]);
1048 if (i == 7 && cnt > 8)
1049 printf("\n ");
1050 }
1051 return (0);
1052 }
1053
1054 /*
1055 * Implement hdump -b output.
1056 */
1057 /* ARGSUSED */
1058 LOCAL int
prbbytes(cnt,buf,dstp)1059 prbbytes(cnt, buf, dstp)
1060 register int cnt;
1061 register char *buf;
1062 dst_t *dstp;
1063 {
1064 register short i;
1065
1066 for (i = 0; i < cnt; i++) {
1067 if (dflag) {
1068 if (uflag)
1069 printf(" %4d", 0377&buf[i]);
1070 else
1071 printf(" %4d", buf[i]);
1072 } else if (oflag) {
1073 printf(" %04o", 0377&buf[i]);
1074 } else {
1075 printf(" %02X", 0377&buf[i]);
1076 }
1077 if (i == 7 && cnt > 8)
1078 printf("\n ");
1079 }
1080 return (0);
1081 }
1082
1083 /*
1084 * Implement hdump -a output.
1085 */
1086 /* ARGSUSED */
1087 LOCAL int
prascii(cnt,buf,dstp)1088 prascii(cnt, buf, dstp)
1089 register int cnt;
1090 register char *buf;
1091 dst_t *dstp;
1092 {
1093 register short i;
1094 register short n = dstp->blocksize;
1095 register char c;
1096
1097 for (i = 0; i < n; i++) {
1098 if (i >= cnt)
1099 printf(" ");
1100 else if (dflag) {
1101 if (uflag)
1102 printf("%4u", 0377&buf[i]);
1103 else
1104 printf("%4d", buf[i]);
1105 } else if (oflag) {
1106 printf(" %03o", 0377&buf[i]);
1107 } else {
1108 printf(" %02X", 0377&buf[i]);
1109 }
1110 if (i == 7)
1111 printf(" ");
1112 }
1113 if (dflag || oflag)
1114 printf("\n ");
1115 else
1116 printf(" ");
1117 for (i = 0; i < cnt; i++) {
1118 c = buf[i];
1119 (void) putchar(c < ' ' || c >= 0177 ? '.' : c);
1120 }
1121 return (0);
1122 }
1123
1124 /*
1125 * Implement hdump -l output.
1126 */
1127 /* ARGSUSED */
1128 LOCAL int
prlong(cnt,buf,dstp)1129 prlong(cnt, buf, dstp)
1130 int cnt;
1131 char *buf;
1132 dst_t *dstp;
1133 {
1134 /* LINTED */
1135 register long *obuf = (long *)buf;
1136 register short i;
1137 register int n = cnt;
1138
1139 n /= sizeof (long);
1140 for (i = 0; i < n; i++) {
1141 last:
1142 if (dflag) {
1143 if (uflag)
1144 printf("%12lu", obuf[i]);
1145 else
1146 printf("%12ld", obuf[i]);
1147 } else if (oflag) {
1148 printf(" %012lo", obuf[i]);
1149 } else {
1150 printf(" %08lX", obuf[i]);
1151 }
1152 }
1153 if ((i = (cnt % sizeof (long))) != 0) {
1154 fillbytes(&((char *)obuf)[cnt], sizeof (long)-i, '\0');
1155 cnt -= i;
1156 i = cnt / sizeof (long);
1157 goto last;
1158 }
1159 return (0);
1160 }
1161
1162 /*
1163 * Implement hdump default size output.
1164 */
1165 /* ARGSUSED */
1166 LOCAL int
prshort(cnt,buf,dstp)1167 prshort(cnt, buf, dstp)
1168 int cnt;
1169 char *buf;
1170 dst_t *dstp;
1171 {
1172 /* LINTED */
1173 register short *obuf = (short *)buf;
1174 register short i;
1175 register int n = cnt;
1176
1177 n /= sizeof (short);
1178 for (i = 0; i < n; i++) {
1179 last:
1180 if (dflag) {
1181 if (uflag)
1182 printf("%7hu", obuf[i]);
1183 else
1184 printf("%7hd", obuf[i]);
1185 } else if (oflag) {
1186 printf(" %06ho", obuf[i]);
1187 } else {
1188 printf(" %04hX", obuf[i]);
1189 }
1190 }
1191 if ((i = (cnt % sizeof (short))) != 0) {
1192 fillbytes(&((char *)obuf)[cnt], sizeof (short)-i, '\0');
1193 cnt -= i;
1194 i = cnt / sizeof (short);
1195 goto last;
1196 }
1197 return (0);
1198 }
1199
1200 LOCAL BOOL
bufeql(b1,b2,cnt)1201 bufeql(b1, b2, cnt)
1202 register long *b1;
1203 register long *b2;
1204 int cnt;
1205 {
1206 register int i;
1207 static int dont_print = -1;
1208
1209 if (dont_print < 0)
1210 return (dont_print = FALSE);
1211 for (i = cnt / sizeof (long); --i >= 0; )
1212 if (*b1++ != *b2++)
1213 return (dont_print = FALSE);
1214 if (!dont_print) {
1215 printf("%s", samefmt);
1216 if (is_pipe) /* Make it immediately visible in $PAGER */
1217 (void) fflush(stdout);
1218 }
1219 return (dont_print = TRUE);
1220 }
1221
1222 LOCAL Llong
myatoll(s)1223 myatoll(s)
1224 char *s;
1225 {
1226 char *p;
1227 Llong val = 0;
1228
1229 if (s[0] == 'x' && s[1] == '\0') { /* "x" -> "0x0" */
1230 curradix = 16;
1231 return (val);
1232 } else if (s[0] == 'x' &&
1233 strchr("0123456789abcdefABCDEF", s[1])) {
1234 curradix = 16;
1235 s++;
1236 } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
1237 curradix = 16;
1238 s += 2;
1239 } else if (s[0] == '0' && !streql("0", s)) {
1240 curradix = 8;
1241 } else if (((p = strchr(s, '.')) != NULL) &&
1242 (p[1] == '\0' ||
1243 ((p[1] == 'b' || p[1] == 'B') && p[2] == '\0'))) {
1244 curradix = 10;
1245 } else { /* No prefix -> default */
1246 if (is_od)
1247 curradix = 8;
1248 /*
1249 * In hdump mode, leave curradix at 0.
1250 */
1251 }
1252
1253 p = astollb(s, &val, curradix);
1254
1255 if (*p != '\0') {
1256 if (*p == '.') {
1257 p++;
1258 curradix = 10;
1259 }
1260 if (*p && (streql(p, "b") || streql(p, "B"))) {
1261 if (*p == 'b') val *= 512;
1262 if (*p == 'B') val *= 512;
1263 } else if (*p)
1264 comerrno(EX_BAD, _("Bad numeric argument '%s'.\n"), s);
1265 }
1266
1267 return (val);
1268 }
1269
1270 LOCAL int
read_input(dstp,bp,cnt)1271 read_input(dstp, bp, cnt)
1272 register dst_t *dstp;
1273 register char *bp;
1274 register int cnt;
1275 {
1276 register int amt;
1277 register int total = 0;
1278
1279 while (cnt > 0) {
1280 amt = fileread(dstp->f, bp, cnt);
1281 if (amt <= 0) {
1282 if (amt < 0) {
1283 errmsg(_("Error reading '%s'.\n"),
1284 dstp->inname);
1285 }
1286 if (!open_next(dstp))
1287 return (total);
1288 continue;
1289 }
1290 if (feof(dstp->f) && !open_next(dstp))
1291 return (total+amt);
1292
1293 total += amt;
1294 cnt -= amt;
1295 bp += amt;
1296 };
1297 return (total);
1298 }
1299
1300 LOCAL BOOL
open_next(dstp)1301 open_next(dstp)
1302 dst_t *dstp;
1303 {
1304 FILE *f;
1305 char *inname;
1306 BOOL stdinflag;
1307
1308 do {
1309 stdinflag = FALSE;
1310 if (dstp->argc == -2) { /* Once only decrement later */
1311 inname = "/dev/stdin";
1312 dstp->inname = "stdin";
1313 stdinflag = TRUE;
1314 } else if (dstp->argc <= 0) {
1315 return (FALSE);
1316 } else {
1317 dstp->inname = inname = dstp->argv[0];
1318 dstp->argv++;
1319 }
1320 /*
1321 * POSIX.1-2008 optionally permits the notation "-" for stdin
1322 * but /usr/xpg4/bin/od on Solaris does not. We currently
1323 * follow /usr/xpg4/bin/od.
1324 */
1325 if (!is_xpg4 && inname[0] == '-' && inname[1] == '\0') {
1326 inname = "/dev/stdin";
1327 dstp->inname = "stdin";
1328 stdinflag = TRUE;
1329 }
1330 #ifndef HAVE__DEV_STDIN
1331 if (stdinflag) {
1332 if (dstp->f != (FILE *)NULL) {
1333 fclose(dstp->f);
1334 dstp->f = (FILE *)NULL;
1335 }
1336 f = fileluopen(dup(STDIN_FILENO), "rb");
1337 } else
1338 #endif
1339 if (dstp->f == (FILE *)NULL) {
1340 f = fileopen(inname, "rb");
1341 } else {
1342 f = filereopen(inname, "rb", dstp->f);
1343 }
1344 /* LINTED */
1345 if (stdinflag && f != (FILE *)NULL)
1346 setmode(fileno(f), O_BINARY);
1347 if (f == (FILE *)NULL) {
1348 errmsg(_("Can't open '%s'.\n"), dstp->inname);
1349 dstp->excode = geterrno();
1350 }
1351 dstp->argc--;
1352 } while (f == (FILE *)NULL);
1353
1354 if (f == (FILE *)NULL)
1355 return (FALSE);
1356
1357 dstp->f = f;
1358 file_raise(dstp->f, FALSE);
1359 #ifdef _FASCII /* Mark Williams C */
1360 dsp->f->_ff &= ~_FASCII;
1361 #endif
1362 return (TRUE);
1363 }
1364
1365 /*
1366 * Seek/skip bytes and return the number of unskipped bytes
1367 */
1368 LOCAL off_t
advance(dstp,xpos)1369 advance(dstp, xpos)
1370 dst_t *dstp;
1371 off_t xpos;
1372 {
1373 off_t newpos = xpos;
1374
1375 do {
1376 newpos = doadvance(dstp->f, newpos, dstp->argc <= 0);
1377 } while (newpos > 0 && open_next(dstp));
1378 return (newpos);
1379 }
1380
1381 #include <schily/stat.h>
1382
1383 /*
1384 * Seek/skip bytes and return the number of unskipped bytes
1385 */
1386 LOCAL off_t
doadvance(f,xpos,is_last)1387 doadvance(f, xpos, is_last)
1388 FILE *f;
1389 off_t xpos;
1390 BOOL is_last;
1391 {
1392 struct stat sb;
1393
1394 if (fstat(fdown(f), &sb) < 0)
1395 return (doskip(f, xpos));
1396 if (isatty(fdown(f)))
1397 return (doskip(f, xpos));
1398 /*
1399 * Skip fast in case this is a plain file smaller than the skip value.
1400 */
1401 if (S_ISREG(sb.st_mode) && sb.st_size < xpos)
1402 return (xpos - sb.st_size);
1403 /*
1404 * Seekable is any plain file
1405 * and the last block or character device in the file name list.
1406 */
1407 if (S_ISREG(sb.st_mode) ||
1408 (is_last &&
1409 (S_ISBLK(sb.st_mode) ||
1410 S_ISCHR(sb.st_mode)))) {
1411 off_t newpos = xpos;
1412
1413 /*
1414 * On raw devices, we need to be aware of the max. sector size.
1415 * Make sure that we still need to read something to be able to
1416 * verify our position in case we are on a device.
1417 */
1418 if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
1419 newpos = xpos / 4096 * 4096;
1420 if (newpos == xpos && newpos > 0)
1421 newpos -= 4096;
1422 }
1423 (void) fileseek(f, newpos);
1424 newpos = filepos(f);
1425 if (newpos > 0)
1426 xpos -= newpos;
1427 }
1428 return (doskip(f, xpos));
1429 }
1430
1431 /*
1432 * Skip bytes and return the number of unskipped bytes
1433 */
1434 LOCAL off_t
doskip(f,xpos)1435 doskip(f, xpos)
1436 FILE *f;
1437 off_t xpos;
1438 {
1439 char sbuf[BUFSIZ];
1440 int amt;
1441
1442 while (xpos > 0) {
1443 amt = sizeof (sbuf);
1444 if (xpos < amt)
1445 amt = (int)xpos;
1446 amt = fileread(f, sbuf, amt);
1447 if (amt <= 0)
1448 break;
1449 xpos -= amt;
1450 }
1451 return (xpos);
1452 }
1453
1454 LOCAL BOOL
out_ispipe()1455 out_ispipe()
1456 {
1457 struct stat sb;
1458
1459 if (fstat(fdown(stdout), &sb) < 0)
1460 return (TRUE);
1461 return (S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode));
1462 }
1463
1464 /*
1465 * Fill POSIX size description strings for -t type according to the parameters
1466 * of the current platform.
1467 *
1468 * The typical ILP32 and LP64 implementations do not cause problems as all
1469 * sizes 1 2 4 8 are present as basic types. Tru64 and older Linux versions for
1470 * DEC Alpha are implemented as ILP64 and cause a problem from missing an
1471 * official basic type with 32 bits. There is only __int32.
1472 */
1473 LOCAL char chartype[3] = { 'C', sizeof (char) + '0', '\0' };
1474 LOCAL char shorttype[3] = { 'S', sizeof (short) + '0', '\0' };
1475 LOCAL char inttype[3] = { 'I', sizeof (int) + '0', '\0' };
1476 LOCAL char longtype[3] = { 'L', sizeof (long) + '0', '\0' };
1477 #if SIZEOF_LONG_LONG > SIZEOF_LONG_INT
1478 LOCAL char longlongtype[3] = { sizeof (Llong) + '0', '\0' };
1479 #endif
1480 LOCAL char floattype[3] = { 'F', sizeof (float) + '0', '\0' };
1481 LOCAL char doubletype[3] = { 'D', sizeof (double) + '0', '\0' };
1482 #ifdef HAVE_LONGDOUBLE
1483 LOCAL char ldoubletype[3] = { 'L', '\0' };
1484 #endif
1485
1486 /*
1487 * POSIX type string to output conversion.
1488 */
1489 LOCAL int
ptype(arg)1490 ptype(arg)
1491 const char *arg;
1492 {
1493 int type;
1494 int size;
1495
1496 #define error(a)
1497
1498 while ((type = *arg++) != '\0') {
1499
1500 switch (type) {
1501
1502 case 'a':
1503 error("CHAR Named character\n");
1504 add_dout(&d_asc);
1505 break;
1506 case 'c':
1507 error("CHAR Character\n");
1508 add_dout(&d_mbch);
1509 break;
1510
1511 /* Int size */
1512 case 'd': /* C S I L 1 2 4 8 */
1513 size = *arg++;
1514
1515 if (size == '\0') {
1516 error("INT Dezimal\n");
1517 add_dout(&d_i_d);
1518 arg--;
1519 } else if (strchr(chartype, size)) {
1520 error("CHAR Dezimal\n");
1521 add_dout(&d_c_d);
1522 } else if (strchr(shorttype, size)) {
1523 error("SHORT Dezimal\n");
1524 add_dout(&d_s_d);
1525 } else if (strchr(inttype, size)) {
1526 error("INT Dezimal\n");
1527 add_dout(&d_i_d);
1528 } else if (strchr(longtype, size)) {
1529 error("LONG Dezimal\n");
1530 add_dout(&d_l_d);
1531 #if SIZEOF_LONG_LONG > SIZEOF_LONG_INT
1532 } else if (strchr(longlongtype, size)) {
1533 error("LONG LONG Dezimal\n");
1534 add_dout(&d_ll_d);
1535 #endif
1536 } else {
1537 if (isupper(size) || isdigit(size))
1538 return (illsize(size));
1539 error("INT Dezimal\n");
1540 add_dout(&d_i_d);
1541 arg--;
1542 }
1543 break;
1544
1545 #ifndef NO_FLOATINGPOINT
1546 case 'f': /* F D L 4 8 */
1547 size = *arg++;
1548
1549 if (size == '\0') {
1550 error("DOUBLE\n");
1551 add_dout(&d_d_f);
1552 arg--;
1553 } else if (strchr(floattype, size)) {
1554 error("FLOAT\n");
1555 add_dout(&d_f_f);
1556 } else if (strchr(doubletype, size)) {
1557 error("DOUBLE\n");
1558 add_dout(&d_d_f);
1559 #ifdef HAVE_LONGDOUBLE
1560 } else if (strchr(ldoubletype, size)) {
1561 error("LONG DOUBLE\n");
1562 add_dout(&d_ld_f);
1563 #endif
1564 } else {
1565 if (isupper(size) || isdigit(size))
1566 return (illfsize(size));
1567 error("DOUBLE\n");
1568 add_dout(&d_d_f);
1569 arg--;
1570 }
1571 break;
1572 #endif
1573
1574 case 'o': /* C S I L 1 2 4 8 */
1575 size = *arg++;
1576
1577 if (size == '\0') {
1578 error("INT Octal\n");
1579 add_dout(&d_i_o);
1580 arg--;
1581 } else if (strchr(chartype, size)) {
1582 error("CHAR Octal\n");
1583 add_dout(&d_c_o);
1584 } else if (strchr(shorttype, size)) {
1585 error("SHORT Octal\n");
1586 add_dout(&d_s_o);
1587 } else if (strchr(inttype, size)) {
1588 error("INT Octal\n");
1589 add_dout(&d_i_o);
1590 } else if (strchr(longtype, size)) {
1591 error("LONG Octal\n");
1592 add_dout(&d_l_o);
1593 #if SIZEOF_LONG_LONG > SIZEOF_LONG_INT
1594 } else if (strchr(longlongtype, size)) {
1595 error("LONG LONG Octal\n");
1596 add_dout(&d_ll_o);
1597 #endif
1598 } else {
1599 if (isupper(size) || isdigit(size))
1600 return (illsize(size));
1601 error("INT Octal\n");
1602 add_dout(&d_i_o);
1603 arg--;
1604 }
1605 break;
1606
1607 case 'u': /* C S I L 1 2 4 8 */
1608 size = *arg++;
1609
1610 if (size == '\0') {
1611 error("INT Unsigned\n");
1612 add_dout(&d_i_u);
1613 arg--;
1614 } else if (strchr(chartype, size)) {
1615 error("CHAR Unsigned\n");
1616 add_dout(&d_c_u);
1617 } else if (strchr(shorttype, size)) {
1618 error("SHORT Unsigned\n");
1619 add_dout(&d_s_u);
1620 } else if (strchr(inttype, size)) {
1621 error("INT Unsigned\n");
1622 add_dout(&d_i_u);
1623 } else if (strchr(longtype, size)) {
1624 error("LONG Unsigned\n");
1625 add_dout(&d_l_u);
1626 #if SIZEOF_LONG_LONG > SIZEOF_LONG_INT
1627 } else if (strchr(longlongtype, size)) {
1628 error("LONG LONG Unsigned\n");
1629 add_dout(&d_ll_u);
1630 #endif
1631 } else {
1632 if (isupper(size) || isdigit(size))
1633 return (illsize(size));
1634 error("INT Unsigned\n");
1635 add_dout(&d_i_u);
1636 arg--;
1637 }
1638 break;
1639
1640 case 'x': /* C S I L 1 2 4 8 */
1641 size = *arg++;
1642
1643 if (size == '\0') {
1644 error("INT Hex\n");
1645 add_dout(&d_i_x);
1646 arg--;
1647 } else if (strchr(chartype, size)) {
1648 error("CHAR Hex\n");
1649 add_dout(&d_c_x);
1650 } else if (strchr(shorttype, size)) {
1651 error("SHORT Hex\n");
1652 add_dout(&d_s_x);
1653 } else if (strchr(inttype, size)) {
1654 error("INT Hex\n");
1655 add_dout(&d_i_x);
1656 } else if (strchr(longtype, size)) {
1657 error("LONG Hex\n");
1658 add_dout(&d_l_x);
1659 #if SIZEOF_LONG_LONG > SIZEOF_LONG_INT
1660 } else if (strchr(longlongtype, size)) {
1661 error("LONG LONG Hex\n");
1662 add_dout(&d_ll_x);
1663 #endif
1664 } else {
1665 if (isupper(size) || isdigit(size))
1666 return (illsize(size));
1667 error("INT hex\n");
1668 add_dout(&d_i_x);
1669 arg--;
1670 }
1671 break;
1672
1673 default:
1674 return (illtype(type));
1675 }
1676 }
1677 return (1);
1678 }
1679
1680 LOCAL int
illsize(size)1681 illsize(size)
1682 int size;
1683 {
1684 errmsgno(EX_BAD,
1685 _("Illegal size '%c', use C, S, I, L, 1, 2, 4 or 8.\n"),
1686 size);
1687 return (-1);
1688 }
1689
1690 LOCAL int
illfsize(size)1691 illfsize(size)
1692 int size;
1693 {
1694 errmsgno(EX_BAD,
1695 _("Illegal size '%c', use F, D L, 4 or 8.\n"),
1696 size);
1697 return (-1);
1698 }
1699
1700 LOCAL int
illtype(type)1701 illtype(type)
1702 int type;
1703 {
1704 errmsgno(EX_BAD,
1705 #ifndef NO_FLOATINGPOINT
1706 _("Illegal type '%c', use 'a', 'c', 'd', 'f', 'o', 'u' or 'x'.\n"),
1707 #else
1708 _("Illegal type '%c', use 'a', 'c', 'd', 'o', 'u' or 'x'.\n"),
1709 #endif
1710 type);
1711 return (-1);
1712 }
1713
1714 LOCAL void
setaddrfmt(Aflag,lradix)1715 setaddrfmt(Aflag, lradix)
1716 int Aflag;
1717 int lradix;
1718 {
1719 char *llfmt; /* Address format off_t -> Llong */
1720 char *lfmt; /* Address format off_t -> long */
1721
1722 if (is_od)
1723 samefmt = "*\n";
1724 else
1725 samefmt = " *\n";
1726
1727 switch (Aflag) {
1728
1729 case 'x':
1730 if (is_od) {
1731 lfmt = "%7.7lx";
1732 llfmt = "%7.7llx";
1733 } else {
1734 lfmt = "%6lx: ";
1735 llfmt = "%6llx: ";
1736 }
1737 break;
1738
1739 case 'd':
1740 if (is_od) {
1741 lfmt = "%7.7ld";
1742 llfmt = "%7.7lld";
1743 } else {
1744 lfmt = "%6ld: ";
1745 llfmt = "%6lld: ";
1746 }
1747 break;
1748
1749 case 'o':
1750 if (is_od) {
1751 lfmt = "%7.7lo";
1752 llfmt = "%7.7llo";
1753 } else {
1754 lfmt = "%6.6lo: ";
1755 llfmt = "%6.6llo: ";
1756 }
1757 break;
1758
1759 case 'n':
1760 if (is_od) {
1761 llfmt = lfmt = "\t";
1762 } else {
1763 llfmt = lfmt = " ";
1764 }
1765 samefmt = "*\n";
1766 break;
1767
1768 case 0: /* No -Ac format specified */
1769 if (is_od) {
1770 llfmt = lradix == 16 ? "%07.7llx" :
1771 (lradix == 10 ? "%7.7lld" : "%7.7llo");
1772 lfmt = lradix == 16 ? "%07.7lx" :
1773 (lradix == 10 ? "%7.7ld" : "%7.7lo");
1774 } else {
1775 llfmt = lradix == 8 ? "%06llo:" :
1776 (lradix == 10 ? "%6lld:" : "%6llx:");
1777 lfmt = lradix == 8 ? "%06lo:" :
1778 (lradix == 10 ? "%6ld:" : "%6lx:");
1779 }
1780 break;
1781 default:
1782 llfmt = lfmt = ""; /* Make GCC and lint happy */
1783
1784 /* NOTREACHED */
1785 comerrno(EX_BAD,
1786 _("-A option only accepts the following: d, o, n, and x.\n"));
1787 }
1788 if (sizeof (pos) > sizeof (long))
1789 addrfmt = llfmt;
1790 else
1791 addrfmt = lfmt;
1792 }
1793