xref: /freebsd/bin/ls/util.c (revision bdcbfde31e8e9b343f113a1956384bdf30d1ed62)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1989, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Michael Fischbein.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #if 0
36 #endif
37 #include <sys/cdefs.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 
41 #include <ctype.h>
42 #include <err.h>
43 #include <fts.h>
44 #include <limits.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <wchar.h>
49 #include <wctype.h>
50 
51 #include "ls.h"
52 #include "extern.h"
53 
54 int
55 prn_normal(const char *s)
56 {
57 	mbstate_t mbs;
58 	wchar_t wc;
59 	int i, n;
60 	size_t clen;
61 
62 	memset(&mbs, 0, sizeof(mbs));
63 	n = 0;
64 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
65 		if (clen == (size_t)-2) {
66 			n += printf("%s", s);
67 			break;
68 		}
69 		if (clen == (size_t)-1) {
70 			memset(&mbs, 0, sizeof(mbs));
71 			putchar((unsigned char)*s);
72 			s++;
73 			n++;
74 			continue;
75 		}
76 		for (i = 0; i < (int)clen; i++)
77 			putchar((unsigned char)s[i]);
78 		s += clen;
79 		if (iswprint(wc))
80 			n += wcwidth(wc);
81 	}
82 	return (n);
83 }
84 
85 int
86 prn_printable(const char *s)
87 {
88 	mbstate_t mbs;
89 	wchar_t wc;
90 	int i, n;
91 	size_t clen;
92 
93 	memset(&mbs, 0, sizeof(mbs));
94 	n = 0;
95 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
96 		if (clen == (size_t)-1) {
97 			putchar('?');
98 			s++;
99 			n++;
100 			memset(&mbs, 0, sizeof(mbs));
101 			continue;
102 		}
103 		if (clen == (size_t)-2) {
104 			putchar('?');
105 			n++;
106 			break;
107 		}
108 		if (!iswprint(wc)) {
109 			putchar('?');
110 			s += clen;
111 			n++;
112 			continue;
113 		}
114 		for (i = 0; i < (int)clen; i++)
115 			putchar((unsigned char)s[i]);
116 		s += clen;
117 		n += wcwidth(wc);
118 	}
119 	return (n);
120 }
121 
122 /*
123  * The fts system makes it difficult to replace fts_name with a different-
124  * sized string, so we just calculate the real length here and do the
125  * conversion in prn_octal()
126  *
127  * XXX when using f_octal_escape (-b) rather than f_octal (-B), the
128  * length computed by len_octal may be too big. I just can't be buggered
129  * to fix this as an efficient fix would involve a lookup table. Same goes
130  * for the rather inelegant code in prn_octal.
131  *
132  *						DES 1998/04/23
133  */
134 
135 size_t
136 len_octal(const char *s, int len)
137 {
138 	mbstate_t mbs;
139 	wchar_t wc;
140 	size_t clen, r;
141 
142 	memset(&mbs, 0, sizeof(mbs));
143 	r = 0;
144 	while (len != 0 && (clen = mbrtowc(&wc, s, len, &mbs)) != 0) {
145 		if (clen == (size_t)-1) {
146 			r += 4;
147 			s++;
148 			len--;
149 			memset(&mbs, 0, sizeof(mbs));
150 			continue;
151 		}
152 		if (clen == (size_t)-2) {
153 			r += 4 * len;
154 			break;
155 		}
156 		if (iswprint(wc))
157 			r++;
158 		else
159 			r += 4 * clen;
160 		s += clen;
161 	}
162 	return (r);
163 }
164 
165 int
166 prn_octal(const char *s)
167 {
168 	static const char esc[] = "\\\\\"\"\aa\bb\ff\nn\rr\tt\vv";
169 	const char *p;
170 	mbstate_t mbs;
171 	wchar_t wc;
172 	size_t clen;
173 	unsigned char ch;
174 	int goodchar, i, len, prtlen;
175 
176 	memset(&mbs, 0, sizeof(mbs));
177 	len = 0;
178 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
179 		goodchar = clen != (size_t)-1 && clen != (size_t)-2;
180 		if (goodchar && iswprint(wc) && wc != L'\"' && wc != L'\\') {
181 			for (i = 0; i < (int)clen; i++)
182 				putchar((unsigned char)s[i]);
183 			len += wcwidth(wc);
184 		} else if (goodchar && f_octal_escape &&
185 #if WCHAR_MIN < 0
186                     wc >= 0 &&
187 #endif
188 		    wc <= (wchar_t)UCHAR_MAX &&
189 		    (p = strchr(esc, (char)wc)) != NULL) {
190 			putchar('\\');
191 			putchar(p[1]);
192 			len += 2;
193 		} else {
194 			if (goodchar)
195 				prtlen = clen;
196 			else if (clen == (size_t)-1)
197 				prtlen = 1;
198 			else
199 				prtlen = strlen(s);
200 			for (i = 0; i < prtlen; i++) {
201 				ch = (unsigned char)s[i];
202 				putchar('\\');
203 				putchar('0' + (ch >> 6));
204 				putchar('0' + ((ch >> 3) & 7));
205 				putchar('0' + (ch & 7));
206 				len += 4;
207 			}
208 		}
209 		if (clen == (size_t)-2)
210 			break;
211 		if (clen == (size_t)-1) {
212 			memset(&mbs, 0, sizeof(mbs));
213 			s++;
214 		} else
215 			s += clen;
216 	}
217 	return (len);
218 }
219 
220 void
221 usage(void)
222 {
223 	(void)fprintf(stderr,
224 #ifdef COLORLS
225 	"usage: ls [-ABCFGHILPRSTUWZabcdfghiklmnopqrstuvwxy1,] [--color=when] [-D format]"
226 #else
227 	"usage: ls [-ABCFHILPRSTUWZabcdfghiklmnopqrstuvwxy1,] [-D format]"
228 #endif
229 		      " [file ...]\n");
230 	exit(1);
231 }
232