hbase

heirloom base
git clone git://git.2f30.org/hbase
Log | Files | Refs | README

od.c (21036B)


      1 /*
      2  * od - octal dump
      3  *
      4  * Gunnar Ritter, Freiburg i. Br., Germany, December 2002.
      5  */
      6 /*
      7  * Copyright (c) 2003 Gunnar Ritter
      8  *
      9  * This software is provided 'as-is', without any express or implied
     10  * warranty. In no event will the authors be held liable for any damages
     11  * arising from the use of this software.
     12  *
     13  * Permission is granted to anyone to use this software for any purpose,
     14  * including commercial applications, and to alter it and redistribute
     15  * it freely, subject to the following restrictions:
     16  *
     17  * 1. The origin of this software must not be misrepresented; you must not
     18  *    claim that you wrote the original software. If you use this software
     19  *    in a product, an acknowledgment in the product documentation would be
     20  *    appreciated but is not required.
     21  *
     22  * 2. Altered source versions must be plainly marked as such, and must not be
     23  *    misrepresented as being the original software.
     24  *
     25  * 3. This notice may not be removed or altered from any source distribution.
     26  */
     27 
     28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
     29 #define	USED	__attribute__ ((used))
     30 #elif defined __GNUC__
     31 #define	USED	__attribute__ ((unused))
     32 #else
     33 #define	USED
     34 #endif
     35 #if defined (SUS)
     36 static const char sccsid[] USED = "@(#)od_sus.sl	1.26 (gritter) 5/29/05";
     37 #else
     38 static const char sccsid[] USED = "@(#)od.sl	1.26 (gritter) 5/29/05";
     39 #endif
     40 
     41 #include	<unistd.h>
     42 #include	<stdio.h>
     43 #include	<string.h>
     44 #include	<stdlib.h>
     45 #include	<errno.h>
     46 #include	<libgen.h>
     47 #include	<inttypes.h>
     48 #include	<locale.h>
     49 #include	<ctype.h>
     50 #include	<wctype.h>
     51 #include	<wchar.h>
     52 #include	<limits.h>
     53 #include	"asciitype.h"
     54 #include	"atoll.h"
     55 
     56 #ifdef	__GLIBC__
     57 #ifdef	_IO_getc_unlocked
     58 #undef	getc
     59 #define	getc(f)		_IO_getc_unlocked(f)
     60 #endif	/* _IO_getc_unlocked */
     61 #ifdef	_IO_putc_unlocked
     62 #undef	putc
     63 #define	putc(c, f)	_IO_putc_unlocked(c, f)
     64 #endif	/* _IO_putc_unlocked */
     65 #endif	/* __GLIBC__ */
     66 
     67 enum	{
     68 	BLOCK = 16
     69 };
     70 
     71 /*
     72  * An input block.
     73  */
     74 union	block {
     75 	char		b_c[BLOCK];
     76 	int16_t		b_16[8];
     77 	int32_t		b_32[4];
     78 	int64_t		b_64[2];
     79 	float		b_f[4];
     80 	double		b_d[2];
     81 };
     82 
     83 /*
     84  * Format type as given with the -t option.
     85  */
     86 struct	type {
     87 	struct type	*t_nxt;		/* next type */
     88 	const char	*t_prf;		/* format string */
     89 	int		t_rst;		/* rest of multibyte character */
     90 	char		t_cnt;		/* word size */
     91 	char		t_fmt;		/* format character */
     92 	char		t_pad;		/* space padding length */
     93 	char		t_000;		/* currently unused */
     94 };
     95 
     96 /*
     97  * An input buffer.
     98  */
     99 struct	buffer {
    100 	union block	bu_blk;		/* input data */
    101 	int		bu_cnt;		/* valid bytes in input data */
    102 };
    103 
    104 /*
    105  * Maps -t format to printf strings.
    106  */
    107 static const struct	{
    108 	char		p_cnt;
    109 	char		p_fmt;
    110 	char		p_pad;
    111 	char		p_000;
    112 	const char	*p_prf;
    113 } prf[] = {
    114 	{	4,	'f',	1,	0,	" %14.7e"	},
    115 	{	8,	'f',	10,	0,	" %21.14le"	},
    116 	{	1,	'd',	0,	0,	" %3d",		},
    117 	{	2,	'd',	0,	0,	"\205\212",	},
    118 	{	4,	'd',	4,	0,	"\12\212",	},
    119 	{	8,	'd',	10,	0,	"\24\212",	},
    120 	{	1,	'o',	0,	0,	"\3\10"		},
    121 	{	2,	'o',	1,	0,	"\6\10"		},
    122 	{	4,	'o',	4,	0,	"\13\10"	},
    123 	{	8,	'o',	9,	0,	"\26\10"	},
    124 	{	1,	'u',	0,	0,	"\3\12"		},
    125 	{	2,	'u',	2,	0,	"\5\12"		},
    126 	{	4,	'u',	5,	0,	"\12\12"	},
    127 	{	8,	'u',	11,	0,	"\24\12"	},
    128 	{	1,	'x',	1,	0,	"\2\20"		},
    129 	{	2,	'x',	3,	0,	"\4\20"		},
    130 	{	4,	'x',	7,	0,	"\10\20"	},
    131 	{	8,	'x',	15,	0,	"\20\20"	},
    132 	{	1,	'a',	0,	0,	""		},
    133 	{	1,	'c',	0,	0,	""		},
    134 	{	1,	'\0',	0,	0,	""		},
    135 	{	0,	0,	0,	0,	NULL		}
    136 };
    137 
    138 static unsigned		errcnt;		/* count of errors */
    139 static char		*progname;	/* argv[0] to main() */
    140 static int		offset_base = 8;/* base of offset to be printed */
    141 static int		offset_oflo = 07777777;	/* max offs. in regular width */
    142 static long long	skip;		/* skip bytes of input */
    143 static long long	limit = -1;	/* print no more bytes than limit */
    144 static long long	total;		/* total bytes of input */
    145 static long long	offset;		/* offset to print */
    146 static int		vflag;		/* print all lines */
    147 static int		Cflag;		/* Cray -C option */
    148 static char		**files;	/* files to read */
    149 static const char	*skipstr;	/* skip format string for error msg */
    150 static FILE		*curfile;	/* current file */
    151 static struct type	*types;		/* output formats */
    152 static int		mb_cur_max;	/* MB_CUR_MAX */
    153 static int		hadinput;	/* did actually read from a file */
    154 static int		stretch;	/* stretch output columns */
    155 static int		expensive;	/* need to compare output lines */
    156 
    157 /*
    158  * For -t a.
    159  */
    160 static const char	*const ctab_a[] = {
    161 	"nul",	"soh",	"stx",	"etx",	"eot",	"enq",	"ack",	"bel",
    162 	" bs",	" ht",	" nl",	" vt",	" ff",	" cr",	" so",	" si",
    163 	"dle",	"dc1",	"dc2",	"dc3",	"dc4",	"nak",	"syn",	"etb",
    164 	"can",	" em",	"sub",	"esc",	" fs",	" gs",	" rs",	" us",
    165 	" sp"
    166 };
    167 
    168 /*
    169  * For -c.
    170  */
    171 static const char	*const ctab_0[] = {
    172 	" \\0",	"001",	"002",	"003",	"004",	"005",	"006",	"007",
    173 	" \\b",	" \\t",	" \\n",	"013",	" \\f",	" \\r",	"016",	"017",
    174 	"020",	"021",	"022",	"023",	"024",	"025",	"026",	"027",
    175 	"030",	"031",	"032",	"033",	"034",	"035",	"036",	"037",
    176 	"   "
    177 };
    178 
    179 /*
    180  * For -t c.
    181  */
    182 static const char	*const ctab_c[] = {
    183 	" \\0",	"001",	"002",	"003",	"004",	"005",	"006",	" \\a",
    184 	" \\b",	" \\t",	" \\n",	" \\v",	" \\f",	" \\r",	"016",	"017",
    185 	"020",	"021",	"022",	"023",	"024",	"025",	"026",	"027",
    186 	"030",	"031",	"032",	"033",	"034",	"035",	"036",	"037",
    187 	"   "
    188 };
    189 
    190 /******************************* HELPERS ********************************/
    191 static void *
    192 scalloc(size_t nmemb, size_t size)
    193 {
    194 	void	*p;
    195 
    196 	if ((p = calloc(nmemb, size)) == NULL) {
    197 		write(2, "No storage\n", 11);
    198 		exit(077);
    199 	}
    200 	return p;
    201 }
    202 
    203 static void *
    204 srealloc(void *vp, size_t nbytes)
    205 {
    206 	void	*p;
    207 
    208 	if ((p = realloc(vp, nbytes)) == NULL) {
    209 		write(2, "No storage\n", 11);
    210 		exit(077);
    211 	}
    212 	return p;
    213 }
    214 
    215 /*static void *
    216 smalloc(size_t nbytes)
    217 {
    218 	return srealloc(NULL, nbytes);
    219 }*/
    220 
    221 /******************************* EXECUTION ********************************/
    222 /*
    223  * Return the next file in the argument list, or NULL if there are
    224  * no further files.
    225  */
    226 static FILE *
    227 nextfile(void)
    228 {
    229 	FILE	*fp;
    230 
    231 	if (curfile && curfile != stdin)
    232 		fclose(curfile);
    233 	do {
    234 		if (files == NULL || files[0] == NULL)
    235 			return NULL;
    236 		if (files[0][0] == '-' && files[0][1] == '\0') {
    237 			fp = stdin;
    238 			if (limit >= 0)
    239 				setvbuf(stdin, NULL, _IONBF, 0);
    240 		} else {
    241 			if ((fp = fopen(files[0], "r")) == NULL) {
    242 				fprintf(stderr, "%s: cannot open %s\n",
    243 						progname, files[0]);
    244 				errcnt |= 1;
    245 			}
    246 		}
    247 		files++;
    248 	} while (fp == NULL);
    249 	if (hadinput == 0 && fp != NULL)
    250 		hadinput++;
    251 	return fp;
    252 }
    253 
    254 /*
    255  * Skip bytes of input.
    256  */
    257 static void
    258 doskip(void)
    259 {
    260 	while (skip > 0) {
    261 		if (curfile == NULL || getc(curfile) == EOF) {
    262 			if ((curfile = nextfile()) == NULL) {
    263 				fprintf(stderr, "%s: %s is too large.\n",
    264 						progname, skipstr);
    265 				exit(2);
    266 			}
    267 			continue;
    268 		}
    269 		total++;
    270 		skip--;
    271 	}
    272 	if (limit >= 0)
    273 		limit += total;
    274 }
    275 
    276 /*
    277  * Fill an input buffer.
    278  */
    279 static int
    280 fill(struct buffer *bp)
    281 {
    282 	int	c, i;
    283 
    284 	i = 0;
    285 	while (i < sizeof bp->bu_blk && (limit <= 0 || total < limit)) {
    286 		if (curfile == NULL || (c = getc(curfile)) == EOF) {
    287 			if ((curfile = nextfile()) == NULL)
    288 				break;
    289 			continue;
    290 		}
    291 		bp->bu_blk.b_c[i++] = (char)c;
    292 		total++;
    293 	}
    294 	bp->bu_cnt = i;
    295 	while (i < sizeof bp->bu_blk)
    296 		bp->bu_blk.b_c[i++] = '\0';
    297 	return bp->bu_cnt;
    298 }
    299 
    300 /*
    301  * Print a value to the passed buffer. As 64-bit arithmethics requires
    302  * more than twice the time of 32-bit arithmetics on 32-bit platforms,
    303  * generate different function sets for int, long, and long long.
    304  */
    305 #define	digit(T, type)	static size_t \
    306 T ## digit(char *buf, int size, int base, unsigned type n) \
    307 { \
    308 	char	*cp; \
    309 	int	d; \
    310 \
    311 	if (size == 0) \
    312 		return 0; \
    313 	cp = buf + T ## digit(buf, size - 1, base, n / base); \
    314 	*cp = (d = n % base) > 9 ? d - 10 + 'a' : d + '0'; \
    315 	return cp - buf + 1; \
    316 }
    317 
    318 #define	number(T, type)	static size_t \
    319 T ## number(char *buf, const char *fmt, unsigned type n) \
    320 { \
    321 	int	size = fmt[0] & 0377, base = fmt[1] & 0377; \
    322 	int	add = 1; \
    323 \
    324 	buf[0] = ' '; \
    325 	if (size & 0200) { \
    326 		size &= 0177; \
    327 		buf[add++] = ' '; \
    328 	} \
    329 	if (base & 0200) { \
    330 		base &= 0177; \
    331 		if ((type)n < 0) { \
    332 			buf[add] = '-'; \
    333 			n = 0 - (type)n; \
    334 		} else \
    335 			buf[add] = ' '; \
    336 		add++; \
    337 	} \
    338 	return T ## digit(&buf[add], size, base, n) + add; \
    339 }
    340 
    341 #define	mkfuncs(T, type)	digit(T, type) number(T, type)
    342 
    343 mkfuncs(i, int)
    344 mkfuncs(l, long)
    345 mkfuncs(ll, long long)
    346 
    347 /*
    348  * Print the offset at the start of each row.
    349  */
    350 static void
    351 prna(long long addr, int c)
    352 {
    353 	unsigned long long	a;
    354 	char	buf[30];
    355 	int	m, n, s;
    356 
    357 	if (offset_base != 0) {
    358 		if (addr <= offset_oflo) {
    359 			/*
    360 			 * Address fits in 7 characters and is preceded
    361 			 * by '0' characters.
    362 			 */
    363 			if (addr > UINT_MAX)
    364 				n = lldigit(buf, 7, offset_base, addr);
    365 			else
    366 				n = idigit(buf, 7, offset_base, addr);
    367 			for (m = 0; m < n; m++)
    368 				putc(buf[m], stdout);
    369 		} else {
    370 			/*
    371 			 * Precompute the length of the address in
    372 			 * characters if possible (speed improvement).
    373 			 */
    374 			switch (offset_base) {
    375 			case 8:
    376 				a = addr;
    377 				for (s = 0; a != 0; s++)
    378 					a >>= 3;
    379 				break;
    380 			case 16:
    381 				a = addr;
    382 				for (s = 0; a != 0; s++)
    383 					a >>= 4;
    384 				break;
    385 			default:
    386 				s = sizeof buf;
    387 			}
    388 			if (addr > UINT_MAX)
    389 				n = lldigit(buf, s, offset_base, addr);
    390 			else
    391 				n = idigit(buf, s, offset_base, addr);
    392 			for (m = 0; buf[m] == '0'; m++);
    393 			while (m < n) {
    394 				putc(buf[m], stdout);
    395 				m++;
    396 			}
    397 		}
    398 	}
    399 	if (c != '\0')
    400 		putc(c, stdout);
    401 }
    402 
    403 /*
    404  * Print a number of output lines, each preceded by the offset column.
    405  */
    406 static void
    407 prnt(long long addr, const char *s)
    408 {
    409 	int	lc = 0;
    410 
    411 	do {
    412 		if (lc++ == 0)
    413 			prna(addr, '\0');
    414 		else
    415 			fputs("       ", stdout);
    416 		do
    417 			putc(*s, stdout);
    418 		while (*s++ != '\n');
    419 	} while (*s != '\0');
    420 }
    421 
    422 /*
    423  * Append a string to a group of output lines, or flush if s == NULL.
    424  */
    425 static void
    426 put(const char *s)
    427 {
    428 	static char	*ob, *Ob;
    429 	static size_t	os, Os, ol;
    430 	static int	eq;
    431 
    432 	if (s == NULL) {
    433 		if (Ob && !vflag && expensive && strcmp(ob, Ob) == 0) {
    434 			if (eq++ == 0)
    435 				printf("*\n");
    436 		} else {
    437 			prnt(offset, ob);
    438 			if (ol + 1 > Os)
    439 				Ob = srealloc(Ob, Os = ol + 1);
    440 			strcpy(Ob, ob);
    441 			eq = 0;
    442 		}
    443 		ol = 0;
    444 	} else {
    445 		size_t	l = strlen(s);
    446 
    447 		if (ol + l + 1 >= os)
    448 			ob = srealloc(ob, os = ol + l + 1);
    449 		strcpy(&ob[ol], s);
    450 		ol += l;
    451 	}
    452 }
    453 
    454 /*
    455  * Format the data within the buffers according to tp.
    456  */
    457 static void
    458 format(struct type *tp, struct buffer *b1, struct buffer *b2)
    459 {
    460 	char	buf[200];
    461 	int	i, j, n, l = 0;
    462 
    463 	switch (tp->t_fmt) {
    464 	case 'a':
    465 	case '\0':
    466 	case 'c':
    467 		for (i = 0; i < b1->bu_cnt; i++) {
    468 			int	c = b1->bu_blk.b_c[i] & 0377;
    469 
    470 			if (tp->t_fmt == 'a')
    471 				c &= 0177;
    472 			if (tp->t_rst) {
    473 				strcpy(&buf[l], "  **");
    474 				tp->t_rst--;
    475 				l += 4;
    476 			} else if (tp->t_fmt != 'a' && c > 040 &&
    477 					mb_cur_max > 1) {
    478 				char	mb[MB_LEN_MAX];
    479 				struct buffer	*bp;
    480 				int	m, n;
    481 				wchar_t	wc;
    482 
    483 				m = i;
    484 				bp = b1;
    485 				for (n = 0; n < mb_cur_max; n++) {
    486 					mb[n] = bp->bu_blk.b_c[m++];
    487 					if (m >= bp->bu_cnt) {
    488 						if (bp == b1) {
    489 							bp = b2;
    490 							m = 0;
    491 						} else
    492 							break;
    493 					}
    494 				}
    495 				mb[n] = '\0';
    496 				if ((n = mbtowc(&wc, mb, mb_cur_max)) <= 0
    497 						|| !iswprint(wc))
    498 					goto spec;
    499 				m = wcwidth(wc);
    500 				do
    501 					buf[l++] = ' ';
    502 				while (++m < 4);
    503 				for (m = 0; m < n; m++)
    504 					buf[l++] = mb[m];
    505 				if (n > 1)
    506 					tp->t_rst = n - 1;
    507 			} else if (c > 040 && isprint(c)) {
    508 				buf[l++] = ' ';
    509 				buf[l++] = ' ';
    510 				buf[l++] = ' ';
    511 				buf[l++] = c;
    512 			} else {
    513 			spec:	if (c <= 040) {
    514 					buf[l] = ' ';
    515 					switch (tp->t_fmt) {
    516 					case 'a':
    517 						strcpy(&buf[l+1], ctab_a[c]);
    518 						break;
    519 					case '\0':
    520 						strcpy(&buf[l+1], ctab_0[c]);
    521 						break;
    522 					case 'c':
    523 						strcpy(&buf[l+1], ctab_c[c]);
    524 						break;
    525 					}
    526 					l += 4;
    527 				} else if (tp->t_fmt == 'a' && c == '\177') {
    528 					strcpy(&buf[l], " del");
    529 					l += 4;
    530 				} else
    531 					l += inumber(&buf[l], "\3\10", c);
    532 			}
    533 		}
    534 		break;
    535 	case 'f':
    536 	case 'd':
    537 	case 'o':
    538 	case 'u':
    539 	case 'x':
    540 		for (i = 0, n = 0;
    541 				i < BLOCK / tp->t_cnt && n < b1->bu_cnt;
    542 				i++, n += tp->t_cnt) {
    543 			if (stretch) {
    544 				for (j = 0; j < tp->t_pad + stretch - 1; j++)
    545 					buf[l++] = ' ';
    546 			}
    547 			if (tp->t_fmt == 'f') {
    548 				switch (tp->t_cnt) {
    549 				case 4:
    550 					l += sprintf(&buf[l], tp->t_prf,
    551 						b1->bu_blk.b_f[i]);
    552 					break;
    553 				case 8:
    554 					l += sprintf(&buf[l], tp->t_prf,
    555 						b1->bu_blk.b_d[i]);
    556 					break;
    557 				}
    558 			} else {
    559 				switch (tp->t_cnt) {
    560 				case 1:
    561 					if (tp->t_fmt == 'd')
    562 						l += sprintf(&buf[l], tp->t_prf,
    563 							b1->bu_blk.b_c[i]);
    564 					else
    565 						l += inumber(&buf[l], tp->t_prf,
    566 							b1->bu_blk.b_c[i]&0377);
    567 					break;
    568 				case 2:
    569 					if (tp->t_fmt == 'd')
    570 						l += inumber(&buf[l], tp->t_prf,
    571 							b1->bu_blk.b_16[i]);
    572 					else
    573 						l += inumber(&buf[l], tp->t_prf,
    574 						b1->bu_blk.b_16[i] & 0177777U);
    575 					break;
    576 				case 4:
    577 					if (tp->t_fmt == 'd')
    578 						l += lnumber(&buf[l], tp->t_prf,
    579 							b1->bu_blk.b_32[i]);
    580 					else
    581 						l += lnumber(&buf[l], tp->t_prf,
    582 							b1->bu_blk.b_32[i] &
    583 							037777777777UL);
    584 					break;
    585 				case 8:
    586 					if (tp->t_fmt == 'd')
    587 						l+= llnumber(&buf[l], tp->t_prf,
    588 							b1->bu_blk.b_64[i]);
    589 					else
    590 						l+= llnumber(&buf[l], tp->t_prf,
    591 							b1->bu_blk.b_64[i] &
    592 						01777777777777777777777ULL);
    593 					break;
    594 				}
    595 			}
    596 		}
    597 	}
    598 	if (Cflag && b1->bu_cnt > 0) {
    599 		static int	max;
    600 		int	c;
    601 		if (max == 0)
    602 			max = l * (BLOCK/tp->t_cnt) /
    603 				((b1->bu_cnt+tp->t_cnt-1) / tp->t_cnt);
    604 		while (l < max)
    605 			buf[l++] = ' ';
    606 		buf[l++] = ' ';
    607 		for (i = 0; i < b1->bu_cnt || i % 8; i++) {
    608 			c = i < b1->bu_cnt ? b1->bu_blk.b_c[i] & 0377 : '.';
    609 			buf[l++] = isprint(c) ? c : '.';
    610 		}
    611 	}
    612 	buf[l++] = '\n';
    613 	buf[l] = '\0';
    614 	put(buf);
    615 }
    616 
    617 /*
    618  * Main execution loop. Two input buffers are necessary because multibyte
    619  * characters for the -c option do not always end at a buffer boundary.
    620  */
    621 static void
    622 od(void)
    623 {
    624 	struct buffer	b1, b2, *bp, *bq;
    625 	struct type	*tp;
    626 	int	star = 0;
    627 
    628 	offset = total;
    629 	fill(bp = &b1);
    630 	fill(bq = &b2);
    631 	if (hadinput == 0)
    632 		return;
    633 	do {
    634 		if (star == 0) {
    635 			for (tp = types; tp; tp = tp->t_nxt)
    636 				format(tp, bp, bq);
    637 			put(NULL);
    638 		}
    639 		offset += bp->bu_cnt;
    640 		bp = (bp == &b1 ? &b2 : &b1);
    641 		bq = (bq == &b1 ? &b2 : &b1);
    642 		/*
    643 		 * If no multibyte characters are to be printed, identical
    644 		 * input blocks always lead to identical output lines. It
    645 		 * is thus not necessary to format them for comparison;
    646 		 * comparing at this point saves a lot of time for files
    647 		 * that contain many identical lines.
    648 		 */
    649 		if (!vflag && !expensive && bp->bu_cnt &&
    650 				bp->bu_cnt == bq->bu_cnt &&
    651 				memcmp(bp->bu_blk.b_c, bq->bu_blk.b_c,
    652 					bp->bu_cnt) == 0) {
    653 			if (star == 0)
    654 				printf("*\n");
    655 			star = 1;
    656 		} else
    657 			star = 0;
    658 	} while (fill(bq) > 0 || bp->bu_cnt > 0);
    659 	if (total > 0)
    660 		prna(total, '\n');
    661 }
    662 
    663 /*************************** OPTION SCANNING *****************************/
    664 static void
    665 usage(void)
    666 {
    667 	fprintf(stderr, "usage: %s [-bcdDfFoOsSvxX] [file] [[+]offset[.][b]]\n",
    668                progname);
    669 	exit(2);
    670 }
    671 
    672 static void
    673 setfiles(char **av)
    674 {
    675 	if (*av)
    676 		files = av;
    677 	else {
    678 		curfile = stdin;
    679 		hadinput = 1;
    680 		if (limit >= 0)
    681 			setvbuf(stdin, NULL, _IONBF, 0);
    682 	}
    683 }
    684 
    685 static void
    686 invarg(int c)
    687 {
    688 	fprintf(stderr, "%s: invalid argument to option -%c\n", progname, c);
    689 	usage();
    690 }
    691 
    692 /*
    693  * Compute output column alignment.
    694  */
    695 static void
    696 align(void)
    697 {
    698 	struct type	*tp, *tq;
    699 
    700 	for (tp = types; tp && tp->t_nxt; tp = tp->t_nxt) {
    701 		tq = tp->t_nxt;
    702 
    703 		if (tp->t_pad != tq->t_pad) {
    704 			stretch = 1;
    705 			break;
    706 		}
    707 	}
    708 }
    709 
    710 /*
    711  * Add an element to the list of types.
    712  */
    713 static void
    714 addtype(char fmt, char cnt)
    715 {
    716 	struct type	*tp, *tq;
    717 	int	i;
    718 
    719 	tp = scalloc(1, sizeof *tp);
    720 	tp->t_fmt = fmt;
    721 	tp->t_cnt = cnt;
    722 	for (i = 0; prf[i].p_prf; i++) {
    723 		if (prf[i].p_cnt == cnt && prf[i].p_fmt == fmt) {
    724 			tp->t_prf = prf[i].p_prf;
    725 			tp->t_pad = prf[i].p_pad;
    726 			tp->t_000 = prf[i].p_000;
    727 			break;
    728 		}
    729 	}
    730 	if (types) {
    731 		for (tq = types; tq->t_nxt; tq = tq->t_nxt);
    732 		tq->t_nxt = tp;
    733 	} else
    734 		types = tp;
    735 }
    736 
    737 /*
    738  * Handle the argument to -t.
    739  */
    740 static int
    741 settype(const char *s)
    742 {
    743 	char	fmt, cnt;
    744 
    745 	if (s == NULL) {
    746 		expensive = mb_cur_max > 1;
    747 		addtype('\0', 1);
    748 		return 0;
    749 	}
    750 	while (*s) {
    751 		switch (fmt = *s++) {
    752 		case 'c':
    753 			expensive = mb_cur_max > 1;
    754 			/*FALLTHRU*/
    755 		case 'a':
    756 			addtype(fmt, 1);
    757 			break;
    758 		case 'f':
    759 			switch (*s) {
    760 			case 'F':
    761 			case '4':
    762 				cnt = 4;
    763 				s++;
    764 				break;
    765 			case 'D':
    766 			case 'L':
    767 			case '8':
    768 				cnt = 8;
    769 				s++;
    770 				break;
    771 			default:
    772 				cnt = 8;
    773 			}
    774 			addtype(fmt, cnt);
    775 			break;
    776 		case 'd':
    777 		case 'o':
    778 		case 'u':
    779 		case 'x':
    780 			switch (*s) {
    781 			case '1':
    782 				cnt = 1;
    783 				s++;
    784 				break;
    785 			case 'C':
    786 				cnt = sizeof (char);
    787 				s++;
    788 				break;
    789 			case '2':
    790 				cnt = 2;
    791 				s++;
    792 				break;
    793 			case 'S':
    794 				cnt = sizeof (short);
    795 				s++;
    796 				break;
    797 			case '4':
    798 				cnt = 4;
    799 				s++;
    800 				break;
    801 			case 'I':
    802 				cnt = sizeof (int);
    803 				s++;
    804 				break;
    805 			case '8':
    806 				cnt = 8;
    807 				s++;
    808 				break;
    809 			case 'L':
    810 				cnt = sizeof (long);
    811 				s++;
    812 				break;
    813 			default:
    814 				cnt = sizeof (int);
    815 			}
    816 			addtype(fmt, cnt);
    817 			break;
    818 		default:
    819 			return -1;
    820 		}
    821 	}
    822 	return 0;
    823 }
    824 
    825 /*
    826  * Handle a traditional offset argument.
    827  */
    828 static int
    829 setoffset(const char *s)
    830 {
    831 	long long	o;
    832 	const char	*sp;
    833 	int	base = 8;
    834 	int	mult = 1;
    835 
    836 	skipstr = s;
    837 	if (*s == '+')
    838 		s++;
    839 	for (sp = s; digitchar(*sp & 0377); sp++);
    840 	if (sp > s) {
    841 		if (*sp == '.') {
    842 			base = 10;
    843 			sp++;
    844 		}
    845 		if (*sp == 'b' || *sp == 'B') {
    846 			mult = 512;
    847 			sp++;
    848 		}
    849 		if (*sp != '\0')
    850 			return -1;
    851 	} else
    852 		return -1;
    853 	o = strtoll(s, NULL, base);
    854 	skip = o * mult;
    855 	return 0;
    856 }
    857 
    858 /*
    859  * Handle the argument to -j.
    860  */
    861 static int
    862 setskip(const char *s)
    863 {
    864 	const char	*sp = NULL;
    865 	long long	o;
    866 	int	base = 10;
    867 	int	mult = 1;
    868 
    869 	skipstr = s;
    870 	if (s[0] == '0' && s[1]) {
    871 		s++;
    872 		if (*s == 'x' || *s == 'X') {
    873 			s++;
    874 			base = 16;
    875 		} else
    876 			base = 8;
    877 	}
    878 	switch (base) {
    879 	case 8:
    880 		for (sp = s; octalchar(*sp & 0377); sp++);
    881 		break;
    882 	case 10:
    883 		for (sp = s; digitchar(*sp & 0377); sp++);
    884 		break;
    885 	case 16:
    886 		for (sp = s; digitchar(*sp & 0377) ||
    887 				*sp == 'a' || *sp == 'A' ||
    888 				*sp == 'b' || *sp == 'B' ||
    889 				*sp == 'c' || *sp == 'C' ||
    890 				*sp == 'd' || *sp == 'D' ||
    891 				*sp == 'e' || *sp == 'E' ||
    892 				*sp == 'f' || *sp == 'F';
    893 			sp++);
    894 		break;
    895 	}
    896 	if (sp > s) {
    897 		switch (*sp) {
    898 		case 'b':
    899 			mult = 512;
    900 			sp++;
    901 			break;
    902 		case 'k':
    903 			mult = 1024;
    904 			sp++;
    905 			break;
    906 		case 'm':
    907 			mult = 1048576;
    908 			sp++;
    909 			break;
    910 		case '\0':
    911 			break;
    912 		default:
    913 			return -1;
    914 		}
    915 		if (*sp != '\0')
    916 			return -1;
    917 	} else
    918 		return -1;
    919 	o = strtoull(s, NULL, base);
    920 	skip = o * mult;
    921 	return 0;
    922 }
    923 
    924 /*
    925  * Handle the argument to -N.
    926  */
    927 static int
    928 setlimit(const char *s)
    929 {
    930 	long long	o;
    931 	char	*x;
    932 	int	base = 10;
    933 
    934 	if (*s == '0') {
    935 		s++;
    936 		if (*s == 'x' || *s == 'X') {
    937 			s++;
    938 			base = 16;
    939 		} else
    940 			base = 8;
    941 	}
    942 	o = strtoll(s, &x, base);
    943 	if (*x != '\0')
    944 		return -1;
    945 	limit = o;
    946 	return 0;
    947 }
    948 
    949 int
    950 main(int argc, char **argv)
    951 {
    952 	const char	optstring[] = ":A:bcCdDfFj:N:oOsSt:vxX";
    953 	int	i, newopt = 0;;
    954 
    955 	setlocale(LC_CTYPE, "");
    956 	mb_cur_max = MB_CUR_MAX;
    957 	if (sizeof (union block) != BLOCK || mb_cur_max > BLOCK)
    958 		abort();
    959 	progname = basename(argv[0]);
    960 #ifdef	__GLIBC__
    961 	putenv("POSIXLY_CORRECT=1");
    962 #endif
    963 	while ((i = getopt(argc, argv, optstring)) != EOF) {
    964 		switch (i) {
    965 		case 'A':
    966 			switch (optarg[0]) {
    967 			case 'd':
    968 				offset_base = 10;
    969 				offset_oflo = 9999999;
    970 				break;
    971 			case 'o':
    972 				offset_base = 8;
    973 				offset_oflo = 07777777;
    974 				break;
    975 			case 'x':
    976 				offset_base = 16;
    977 				offset_oflo = 0xfffffff;
    978 				break;
    979 			case 'n':
    980 				offset_base = 0;
    981 				break;
    982 			default:
    983 				invarg(i);
    984 			}
    985 			if (optarg[1] != '\0')
    986 				invarg(i);
    987 			newopt = 1;
    988 			break;
    989 		case 'b':
    990 			settype("o1");
    991 			break;
    992 		case 'c':
    993 			settype(NULL);
    994 			break;
    995 		case 'd':
    996 			settype("u2");
    997 			break;
    998 		case 'D':
    999 			settype("u4");
   1000 			break;
   1001 		case 'f':
   1002 			settype("fF");
   1003 			break;
   1004 		case 'F':
   1005 			settype("fD");
   1006 			break;
   1007 		case 'j':
   1008 			if (setskip(optarg) < 0)
   1009 				invarg(i);
   1010 			newopt = 1;
   1011 			break;
   1012 		case 'N':
   1013 			if (setlimit(optarg) < 0)
   1014 				invarg(i);
   1015 			newopt = 1;
   1016 			break;
   1017 		case 'o':
   1018 			settype("o2");
   1019 			break;
   1020 		case 'O':
   1021 			settype("o4");
   1022 			break;
   1023 		case 's':
   1024 			settype("d2");
   1025 			break;
   1026 		case 'S':
   1027 			settype("d4");
   1028 			break;
   1029 		case 't':
   1030 			if (settype(optarg) < 0)
   1031 				invarg('t');
   1032 			newopt = 1;
   1033 			break;
   1034 		case 'v':
   1035 			vflag = 1;
   1036 			break;
   1037 		case 'x':
   1038 			settype("x2");
   1039 			break;
   1040 		case 'X':
   1041 			settype("x4");
   1042 			break;
   1043 		case ':':
   1044 			fprintf(stderr,
   1045 				"%s: option requires an argument -- %c\n",
   1046 				progname, optopt);
   1047 			usage();
   1048 		case 'C':
   1049 			Cflag = 1;
   1050 			break;
   1051 		case '?':
   1052 			fprintf(stderr, "%s: bad flag -%c\n",
   1053 					progname, optopt);
   1054 			/*FALLTHRU*/
   1055 		default:
   1056 			usage();
   1057 		}
   1058 	}
   1059 	if (newopt == 0 && ((optind>=argc-2 && argc &&argv[argc-1][0] == '+') ||
   1060 #ifndef	SUS
   1061 				(optind>=argc-2 && argc &&
   1062 #else	/* SUS */
   1063 				(optind == argc-1 &&
   1064 #endif	/* SUS */
   1065 				digitchar(argv[argc-1][0] & 0377))) &&
   1066 			setoffset(argv[argc-1]) >= 0) {
   1067 		argc--;
   1068 		argv[argc] = NULL;
   1069 	}
   1070 	setfiles(argc ? &argv[optind] : &argv[0]);
   1071 	if (types == NULL)
   1072 		settype("oS");
   1073 	align();
   1074 	if (skip > 0)
   1075 		doskip();
   1076 	od();
   1077 	return errcnt;
   1078 }