xref: /freebsd/usr.bin/hexdump/conv.c (revision 5e3934b15a2741b2de6b217e77dc9d798d740804)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
49b50d902SRodney W. Grimes  * Copyright (c) 1989, 1993
59b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
69b50d902SRodney W. Grimes  *
79b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes  * are met:
109b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes  *    without specific prior written permission.
189b50d902SRodney W. Grimes  *
199b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes  * SUCH DAMAGE.
309b50d902SRodney W. Grimes  */
319b50d902SRodney W. Grimes 
329b50d902SRodney W. Grimes #include <sys/types.h>
339b50d902SRodney W. Grimes 
3440ccfb31STim J. Robbins #include <assert.h>
359b50d902SRodney W. Grimes #include <ctype.h>
3640ccfb31STim J. Robbins #include <limits.h>
377eaedc0cSJohan Karlsson #include <stdio.h>
3840ccfb31STim J. Robbins #include <stdlib.h>
397eaedc0cSJohan Karlsson #include <string.h>
4040ccfb31STim J. Robbins #include <wchar.h>
4140ccfb31STim J. Robbins #include <wctype.h>
429b50d902SRodney W. Grimes #include "hexdump.h"
439b50d902SRodney W. Grimes 
449b50d902SRodney W. Grimes void
conv_c(PR * pr,u_char * p,size_t bufsize)4540ccfb31STim J. Robbins conv_c(PR *pr, u_char *p, size_t bufsize)
469b50d902SRodney W. Grimes {
4795e5dc04SDavid E. O'Brien 	char buf[10];
4895e5dc04SDavid E. O'Brien 	char const *str;
4940ccfb31STim J. Robbins 	wchar_t wc;
5040ccfb31STim J. Robbins 	size_t clen, oclen;
5140ccfb31STim J. Robbins 	int converr, pad, width;
527818f8dfSDimitry Andric 	u_char peekbuf[MB_LEN_MAX];
536bb76493SKyle Evans 	u_char *op;
5440ccfb31STim J. Robbins 
55*08c80489SLi-Wen Hsu 	op = NULL;
56*08c80489SLi-Wen Hsu 
5740ccfb31STim J. Robbins 	if (pr->mbleft > 0) {
5840ccfb31STim J. Robbins 		str = "**";
5940ccfb31STim J. Robbins 		pr->mbleft--;
6040ccfb31STim J. Robbins 		goto strpr;
6140ccfb31STim J. Robbins 	}
629b50d902SRodney W. Grimes 
639b50d902SRodney W. Grimes 	switch(*p) {
649b50d902SRodney W. Grimes 	case '\0':
6595e5dc04SDavid E. O'Brien 		str = "\\0";
669b50d902SRodney W. Grimes 		goto strpr;
679b50d902SRodney W. Grimes 	/* case '\a': */
689b50d902SRodney W. Grimes 	case '\007':
6995e5dc04SDavid E. O'Brien 		str = "\\a";
709b50d902SRodney W. Grimes 		goto strpr;
719b50d902SRodney W. Grimes 	case '\b':
7295e5dc04SDavid E. O'Brien 		str = "\\b";
739b50d902SRodney W. Grimes 		goto strpr;
749b50d902SRodney W. Grimes 	case '\f':
7595e5dc04SDavid E. O'Brien 		str = "\\f";
769b50d902SRodney W. Grimes 		goto strpr;
779b50d902SRodney W. Grimes 	case '\n':
7895e5dc04SDavid E. O'Brien 		str = "\\n";
799b50d902SRodney W. Grimes 		goto strpr;
809b50d902SRodney W. Grimes 	case '\r':
8195e5dc04SDavid E. O'Brien 		str = "\\r";
829b50d902SRodney W. Grimes 		goto strpr;
839b50d902SRodney W. Grimes 	case '\t':
8495e5dc04SDavid E. O'Brien 		str = "\\t";
859b50d902SRodney W. Grimes 		goto strpr;
869b50d902SRodney W. Grimes 	case '\v':
8795e5dc04SDavid E. O'Brien 		str = "\\v";
889b50d902SRodney W. Grimes 		goto strpr;
899b50d902SRodney W. Grimes 	default:
909b50d902SRodney W. Grimes 		break;
919b50d902SRodney W. Grimes 	}
9240ccfb31STim J. Robbins 	/*
9340ccfb31STim J. Robbins 	 * Multibyte characters are disabled for hexdump(1) for backwards
9440ccfb31STim J. Robbins 	 * compatibility and consistency (none of its other output formats
9540ccfb31STim J. Robbins 	 * recognize them correctly).
9640ccfb31STim J. Robbins 	 */
9740ccfb31STim J. Robbins 	converr = 0;
9840ccfb31STim J. Robbins 	if (odmode && MB_CUR_MAX > 1) {
9940ccfb31STim J. Robbins 		oclen = 0;
10040ccfb31STim J. Robbins retry:
10140ccfb31STim J. Robbins 		clen = mbrtowc(&wc, p, bufsize, &pr->mbstate);
10240ccfb31STim J. Robbins 		if (clen == 0)
10340ccfb31STim J. Robbins 			clen = 1;
10440ccfb31STim J. Robbins 		else if (clen == (size_t)-1 || (clen == (size_t)-2 &&
1057818f8dfSDimitry Andric 		    p == peekbuf)) {
10640ccfb31STim J. Robbins 			memset(&pr->mbstate, 0, sizeof(pr->mbstate));
1076bb76493SKyle Evans 			if (p == peekbuf) {
1086bb76493SKyle Evans 				/*
1096bb76493SKyle Evans 				 * We peeked ahead, but that didn't help --
1106bb76493SKyle Evans 				 * we either got an illegal sequence or still
1116bb76493SKyle Evans 				 * can't complete; restore original character.
1126bb76493SKyle Evans 				 */
1136bb76493SKyle Evans 				oclen = 0;
1146bb76493SKyle Evans 				p = op;
1156bb76493SKyle Evans 			}
11640ccfb31STim J. Robbins 			wc = *p;
11740ccfb31STim J. Robbins 			clen = 1;
11840ccfb31STim J. Robbins 			converr = 1;
11940ccfb31STim J. Robbins 		} else if (clen == (size_t)-2) {
12040ccfb31STim J. Robbins 			/*
12140ccfb31STim J. Robbins 			 * Incomplete character; peek ahead and see if we
12240ccfb31STim J. Robbins 			 * can complete it.
12340ccfb31STim J. Robbins 			 */
12440ccfb31STim J. Robbins 			oclen = bufsize;
1256bb76493SKyle Evans 			op = p;
12640ccfb31STim J. Robbins 			bufsize = peek(p = peekbuf, MB_CUR_MAX);
12740ccfb31STim J. Robbins 			goto retry;
12840ccfb31STim J. Robbins 		}
12940ccfb31STim J. Robbins 		clen += oclen;
13040ccfb31STim J. Robbins 	} else {
13140ccfb31STim J. Robbins 		wc = *p;
13240ccfb31STim J. Robbins 		clen = 1;
13340ccfb31STim J. Robbins 	}
13440ccfb31STim J. Robbins 	if (!converr && iswprint(wc)) {
13540ccfb31STim J. Robbins 		if (!odmode) {
1369b50d902SRodney W. Grimes 			*pr->cchar = 'c';
13740ccfb31STim J. Robbins 			(void)printf(pr->fmt, (int)wc);
13840ccfb31STim J. Robbins 		} else {
13940ccfb31STim J. Robbins 			*pr->cchar = 'C';
14040ccfb31STim J. Robbins 			assert(strcmp(pr->fmt, "%3C") == 0);
14140ccfb31STim J. Robbins 			width = wcwidth(wc);
1421ae99265SJoseph Koshy 			assert(width >= 0);
14340ccfb31STim J. Robbins 			pad = 3 - width;
14440ccfb31STim J. Robbins 			if (pad < 0)
14540ccfb31STim J. Robbins 				pad = 0;
14640ccfb31STim J. Robbins 			(void)printf("%*s%C", pad, "", wc);
14740ccfb31STim J. Robbins 			pr->mbleft = clen - 1;
14840ccfb31STim J. Robbins 		}
1499b50d902SRodney W. Grimes 	} else {
15095e5dc04SDavid E. O'Brien 		(void)sprintf(buf, "%03o", (int)*p);
15195e5dc04SDavid E. O'Brien 		str = buf;
1529b50d902SRodney W. Grimes strpr:		*pr->cchar = 's';
1539b50d902SRodney W. Grimes 		(void)printf(pr->fmt, str);
1549b50d902SRodney W. Grimes 	}
1559b50d902SRodney W. Grimes }
1569b50d902SRodney W. Grimes 
1579b50d902SRodney W. Grimes void
conv_u(PR * pr,u_char * p)158f4ac32deSDavid Malone conv_u(PR *pr, u_char *p)
1599b50d902SRodney W. Grimes {
16095e5dc04SDavid E. O'Brien 	static char const * list[] = {
1619b50d902SRodney W. Grimes 		"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
1629b50d902SRodney W. Grimes 		 "bs",  "ht",  "lf",  "vt",  "ff",  "cr",  "so",  "si",
16324029986SEitan Adler 		"dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
1649b50d902SRodney W. Grimes 		"can",  "em", "sub", "esc",  "fs",  "gs",  "rs",  "us",
1659b50d902SRodney W. Grimes 	};
1669b50d902SRodney W. Grimes 
1679b50d902SRodney W. Grimes 						/* od used nl, not lf */
1689b50d902SRodney W. Grimes 	if (*p <= 0x1f) {
1699b50d902SRodney W. Grimes 		*pr->cchar = 's';
170ca9cbcecSTim J. Robbins 		if (odmode && *p == 0x0a)
1719b50d902SRodney W. Grimes 			(void)printf(pr->fmt, "nl");
1729b50d902SRodney W. Grimes 		else
1739b50d902SRodney W. Grimes 			(void)printf(pr->fmt, list[*p]);
1749b50d902SRodney W. Grimes 	} else if (*p == 0x7f) {
1759b50d902SRodney W. Grimes 		*pr->cchar = 's';
1769b50d902SRodney W. Grimes 		(void)printf(pr->fmt, "del");
177ca9cbcecSTim J. Robbins 	} else if (odmode && *p == 0x20) {	/* od replaced space with sp */
1789b50d902SRodney W. Grimes 		*pr->cchar = 's';
1799b50d902SRodney W. Grimes 		(void)printf(pr->fmt, " sp");
1809b50d902SRodney W. Grimes 	} else if (isprint(*p)) {
1819b50d902SRodney W. Grimes 		*pr->cchar = 'c';
1829b50d902SRodney W. Grimes 		(void)printf(pr->fmt, *p);
1839b50d902SRodney W. Grimes 	} else {
1849b50d902SRodney W. Grimes 		*pr->cchar = 'x';
1859b50d902SRodney W. Grimes 		(void)printf(pr->fmt, (int)*p);
1869b50d902SRodney W. Grimes 	}
1879b50d902SRodney W. Grimes }
188