xref: /freebsd/usr.bin/hexdump/conv.c (revision fbf96e52bbd90bbbb9c9e2ae6fbc101fa6ebd080)
1 /*
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static const char sccsid[] = "@(#)conv.c	8.1 (Berkeley) 6/6/93";
36 #endif /* not lint */
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39 
40 #include <sys/types.h>
41 
42 #include <assert.h>
43 #include <stdio.h>
44 #include <ctype.h>
45 #include <limits.h>
46 #include <stdlib.h>
47 #include <wchar.h>
48 #include <wctype.h>
49 #include "hexdump.h"
50 
51 void
52 conv_c(PR *pr, u_char *p, size_t bufsize)
53 {
54 	char buf[10];
55 	char const *str;
56 	wchar_t wc;
57 	size_t clen, oclen;
58 	int converr, pad, width;
59 	char peekbuf[MB_LEN_MAX];
60 
61 	if (pr->mbleft > 0) {
62 		str = "**";
63 		pr->mbleft--;
64 		goto strpr;
65 	}
66 
67 	switch(*p) {
68 	case '\0':
69 		str = "\\0";
70 		goto strpr;
71 	/* case '\a': */
72 	case '\007':
73 		str = "\\a";
74 		goto strpr;
75 	case '\b':
76 		str = "\\b";
77 		goto strpr;
78 	case '\f':
79 		str = "\\f";
80 		goto strpr;
81 	case '\n':
82 		str = "\\n";
83 		goto strpr;
84 	case '\r':
85 		str = "\\r";
86 		goto strpr;
87 	case '\t':
88 		str = "\\t";
89 		goto strpr;
90 	case '\v':
91 		str = "\\v";
92 		goto strpr;
93 	default:
94 		break;
95 	}
96 	/*
97 	 * Multibyte characters are disabled for hexdump(1) for backwards
98 	 * compatibility and consistency (none of its other output formats
99 	 * recognize them correctly).
100 	 */
101 	converr = 0;
102 	if (odmode && MB_CUR_MAX > 1) {
103 		oclen = 0;
104 retry:
105 		clen = mbrtowc(&wc, p, bufsize, &pr->mbstate);
106 		if (clen == 0)
107 			clen = 1;
108 		else if (clen == (size_t)-1 || (clen == (size_t)-2 &&
109 		    buf == peekbuf)) {
110 			memset(&pr->mbstate, 0, sizeof(pr->mbstate));
111 			wc = *p;
112 			clen = 1;
113 			converr = 1;
114 		} else if (clen == (size_t)-2) {
115 			/*
116 			 * Incomplete character; peek ahead and see if we
117 			 * can complete it.
118 			 */
119 			oclen = bufsize;
120 			bufsize = peek(p = peekbuf, MB_CUR_MAX);
121 			goto retry;
122 		}
123 		clen += oclen;
124 	} else {
125 		wc = *p;
126 		clen = 1;
127 	}
128 	if (!converr && iswprint(wc)) {
129 		if (!odmode) {
130 			*pr->cchar = 'c';
131 			(void)printf(pr->fmt, (int)wc);
132 		} else {
133 			*pr->cchar = 'C';
134 			assert(strcmp(pr->fmt, "%3C") == 0);
135 			width = wcwidth(wc);
136 			assert(width > 0);
137 			pad = 3 - width;
138 			if (pad < 0)
139 				pad = 0;
140 			(void)printf("%*s%C", pad, "", wc);
141 			pr->mbleft = clen - 1;
142 		}
143 	} else {
144 		(void)sprintf(buf, "%03o", (int)*p);
145 		str = buf;
146 strpr:		*pr->cchar = 's';
147 		(void)printf(pr->fmt, str);
148 	}
149 }
150 
151 void
152 conv_u(PR *pr, u_char *p)
153 {
154 	static char const * list[] = {
155 		"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
156 		 "bs",  "ht",  "lf",  "vt",  "ff",  "cr",  "so",  "si",
157 		"dle", "dcl", "dc2", "dc3", "dc4", "nak", "syn", "etb",
158 		"can",  "em", "sub", "esc",  "fs",  "gs",  "rs",  "us",
159 	};
160 
161 						/* od used nl, not lf */
162 	if (*p <= 0x1f) {
163 		*pr->cchar = 's';
164 		if (odmode && *p == 0x0a)
165 			(void)printf(pr->fmt, "nl");
166 		else
167 			(void)printf(pr->fmt, list[*p]);
168 	} else if (*p == 0x7f) {
169 		*pr->cchar = 's';
170 		(void)printf(pr->fmt, "del");
171 	} else if (odmode && *p == 0x20) {	/* od replaced space with sp */
172 		*pr->cchar = 's';
173 		(void)printf(pr->fmt, " sp");
174 	} else if (isprint(*p)) {
175 		*pr->cchar = 'c';
176 		(void)printf(pr->fmt, *p);
177 	} else {
178 		*pr->cchar = 'x';
179 		(void)printf(pr->fmt, (int)*p);
180 	}
181 }
182