xref: /freebsd/bin/ls/util.c (revision 9ddb49cbe45441fa3f3a10f6dd355e9956480b5f)
19ddb49cbSWarner Losh /*-
24b88c807SRodney W. Grimes  * Copyright (c) 1989, 1993, 1994
34b88c807SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
44b88c807SRodney W. Grimes  *
54b88c807SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
64b88c807SRodney W. Grimes  * Michael Fischbein.
74b88c807SRodney W. Grimes  *
84b88c807SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
94b88c807SRodney W. Grimes  * modification, are permitted provided that the following conditions
104b88c807SRodney W. Grimes  * are met:
114b88c807SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
124b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
134b88c807SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
144b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
154b88c807SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
164b88c807SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
174b88c807SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
184b88c807SRodney W. Grimes  *    without specific prior written permission.
194b88c807SRodney W. Grimes  *
204b88c807SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
214b88c807SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224b88c807SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234b88c807SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
244b88c807SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254b88c807SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264b88c807SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274b88c807SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284b88c807SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294b88c807SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304b88c807SRodney W. Grimes  * SUCH DAMAGE.
314b88c807SRodney W. Grimes  */
324b88c807SRodney W. Grimes 
33febad2fcSSteve Price #if 0
34c73d77ceSMark Murray #ifndef lint
35febad2fcSSteve Price static char sccsid[] = "@(#)util.c	8.3 (Berkeley) 4/2/94";
364b88c807SRodney W. Grimes #endif /* not lint */
37c73d77ceSMark Murray #endif
3840feca3aSMark Murray #include <sys/cdefs.h>
395eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$");
404b88c807SRodney W. Grimes 
414b88c807SRodney W. Grimes #include <sys/types.h>
424b88c807SRodney W. Grimes #include <sys/stat.h>
434b88c807SRodney W. Grimes 
444b88c807SRodney W. Grimes #include <ctype.h>
457ea30648SDag-Erling Smørgrav #include <err.h>
464b88c807SRodney W. Grimes #include <fts.h>
47107409f4STim J. Robbins #include <limits.h>
484b88c807SRodney W. Grimes #include <stdio.h>
494b88c807SRodney W. Grimes #include <stdlib.h>
504b88c807SRodney W. Grimes #include <string.h>
51107409f4STim J. Robbins #include <wchar.h>
52107409f4STim J. Robbins #include <wctype.h>
534b88c807SRodney W. Grimes 
544b88c807SRodney W. Grimes #include "ls.h"
554b88c807SRodney W. Grimes #include "extern.h"
564b88c807SRodney W. Grimes 
57ee579ffbSAssar Westerlund int
58107409f4STim J. Robbins prn_normal(const char *s)
59107409f4STim J. Robbins {
60107409f4STim J. Robbins 	mbstate_t mbs;
61107409f4STim J. Robbins 	wchar_t wc;
62107409f4STim J. Robbins 	int i, n;
63107409f4STim J. Robbins 	size_t clen;
64107409f4STim J. Robbins 
65107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
66107409f4STim J. Robbins 	n = 0;
67107409f4STim J. Robbins 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
68107409f4STim J. Robbins 		if (clen == (size_t)-2) {
69107409f4STim J. Robbins 			n += printf("%s", s);
70107409f4STim J. Robbins 			break;
71107409f4STim J. Robbins 		}
72107409f4STim J. Robbins 		if (clen == (size_t)-1) {
73107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
74107409f4STim J. Robbins 			putchar((unsigned char)*s);
75107409f4STim J. Robbins 			s++;
76107409f4STim J. Robbins 			n++;
77107409f4STim J. Robbins 			continue;
78107409f4STim J. Robbins 		}
79107409f4STim J. Robbins 		for (i = 0; i < (int)clen; i++)
80107409f4STim J. Robbins 			putchar((unsigned char)s[i]);
81107409f4STim J. Robbins 		s += clen;
826449b88bSTim J. Robbins 		if (iswprint(wc))
83107409f4STim J. Robbins 			n += wcwidth(wc);
84107409f4STim J. Robbins 	}
85107409f4STim J. Robbins 	return (n);
86107409f4STim J. Robbins }
87107409f4STim J. Robbins 
88107409f4STim J. Robbins int
8946251ddeSWarner Losh prn_printable(const char *s)
904b88c807SRodney W. Grimes {
91107409f4STim J. Robbins 	mbstate_t mbs;
92107409f4STim J. Robbins 	wchar_t wc;
93107409f4STim J. Robbins 	int i, n;
94107409f4STim J. Robbins 	size_t clen;
954b88c807SRodney W. Grimes 
96107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
97107409f4STim J. Robbins 	n = 0;
98107409f4STim J. Robbins 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
99107409f4STim J. Robbins 		if (clen == (size_t)-1) {
100ee579ffbSAssar Westerlund 			putchar('?');
101107409f4STim J. Robbins 			s++;
102107409f4STim J. Robbins 			n++;
103107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
104107409f4STim J. Robbins 			continue;
105107409f4STim J. Robbins 		}
106107409f4STim J. Robbins 		if (clen == (size_t)-2) {
107107409f4STim J. Robbins 			putchar('?');
108107409f4STim J. Robbins 			n++;
109107409f4STim J. Robbins 			break;
110107409f4STim J. Robbins 		}
111107409f4STim J. Robbins 		if (!iswprint(wc)) {
112107409f4STim J. Robbins 			putchar('?');
113107409f4STim J. Robbins 			s += clen;
114107409f4STim J. Robbins 			n++;
115107409f4STim J. Robbins 			continue;
116107409f4STim J. Robbins 		}
117107409f4STim J. Robbins 		for (i = 0; i < (int)clen; i++)
118107409f4STim J. Robbins 			putchar((unsigned char)s[i]);
119107409f4STim J. Robbins 		s += clen;
120107409f4STim J. Robbins 		n += wcwidth(wc);
121107409f4STim J. Robbins 	}
122107409f4STim J. Robbins 	return (n);
1234b88c807SRodney W. Grimes }
1244b88c807SRodney W. Grimes 
1257ea30648SDag-Erling Smørgrav /*
1267ea30648SDag-Erling Smørgrav  * The fts system makes it difficult to replace fts_name with a different-
1277ea30648SDag-Erling Smørgrav  * sized string, so we just calculate the real length here and do the
1287ea30648SDag-Erling Smørgrav  * conversion in prn_octal()
1290d86878cSDag-Erling Smørgrav  *
1300d86878cSDag-Erling Smørgrav  * XXX when using f_octal_escape (-b) rather than f_octal (-B), the
1310d86878cSDag-Erling Smørgrav  * length computed by len_octal may be too big. I just can't be buggered
1320d86878cSDag-Erling Smørgrav  * to fix this as an efficient fix would involve a lookup table. Same goes
1330d86878cSDag-Erling Smørgrav  * for the rather inelegant code in prn_octal.
1340d86878cSDag-Erling Smørgrav  *
1350d86878cSDag-Erling Smørgrav  *                                              DES 1998/04/23
1367ea30648SDag-Erling Smørgrav  */
1370d86878cSDag-Erling Smørgrav 
1389052855aSMark Murray size_t
13946251ddeSWarner Losh len_octal(const char *s, int len)
1407ea30648SDag-Erling Smørgrav {
141107409f4STim J. Robbins 	mbstate_t mbs;
142107409f4STim J. Robbins 	wchar_t wc;
143107409f4STim J. Robbins 	size_t clen, r;
1447ea30648SDag-Erling Smørgrav 
145107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
146107409f4STim J. Robbins 	r = 0;
147107409f4STim J. Robbins 	while (len != 0 && (clen = mbrtowc(&wc, s, len, &mbs)) != 0) {
148107409f4STim J. Robbins 		if (clen == (size_t)-1) {
149107409f4STim J. Robbins 			r += 4;
150107409f4STim J. Robbins 			s++;
151107409f4STim J. Robbins 			len--;
152107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
153107409f4STim J. Robbins 			continue;
154107409f4STim J. Robbins 		}
155107409f4STim J. Robbins 		if (clen == (size_t)-2) {
156107409f4STim J. Robbins 			r += 4 * len;
157107409f4STim J. Robbins 			break;
158107409f4STim J. Robbins 		}
159107409f4STim J. Robbins 		if (iswprint(wc))
160107409f4STim J. Robbins 			r++;
161107409f4STim J. Robbins 		else
162107409f4STim J. Robbins 			r += 4 * clen;
163107409f4STim J. Robbins 		s += clen;
164107409f4STim J. Robbins 	}
165107409f4STim J. Robbins 	return (r);
1667ea30648SDag-Erling Smørgrav }
1677ea30648SDag-Erling Smørgrav 
1687ea30648SDag-Erling Smørgrav int
16946251ddeSWarner Losh prn_octal(const char *s)
1707ea30648SDag-Erling Smørgrav {
171107409f4STim J. Robbins 	static const char esc[] = "\\\\\"\"\aa\bb\ff\nn\rr\tt\vv";
172107409f4STim J. Robbins 	const char *p;
173107409f4STim J. Robbins 	mbstate_t mbs;
174107409f4STim J. Robbins 	wchar_t wc;
175107409f4STim J. Robbins 	size_t clen;
1767ea30648SDag-Erling Smørgrav 	unsigned char ch;
177107409f4STim J. Robbins 	int goodchar, i, len, prtlen;
1787ea30648SDag-Erling Smørgrav 
179107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
180107409f4STim J. Robbins 	len = 0;
181107409f4STim J. Robbins 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
182107409f4STim J. Robbins 		goodchar = clen != (size_t)-1 && clen != (size_t)-2;
183107409f4STim J. Robbins 		if (goodchar && iswprint(wc) && wc != L'\"' && wc != L'\\') {
184107409f4STim J. Robbins 			for (i = 0; i < (int)clen; i++)
185107409f4STim J. Robbins 				putchar((unsigned char)s[i]);
186107409f4STim J. Robbins 			len += wcwidth(wc);
187107409f4STim J. Robbins 		} else if (goodchar && f_octal_escape && wc >= 0 &&
188107409f4STim J. Robbins 		    wc <= (wchar_t)UCHAR_MAX &&
189107409f4STim J. Robbins 		    (p = strchr(esc, (char)wc)) != NULL) {
1900d86878cSDag-Erling Smørgrav 			putchar('\\');
191107409f4STim J. Robbins 			putchar(p[1]);
1920d86878cSDag-Erling Smørgrav 			len += 2;
193107409f4STim J. Robbins 		} else {
194107409f4STim J. Robbins 			if (goodchar)
195107409f4STim J. Robbins 				prtlen = clen;
196107409f4STim J. Robbins 			else if (clen == (size_t)-1)
197107409f4STim J. Robbins 				prtlen = 1;
198107409f4STim J. Robbins 			else
199107409f4STim J. Robbins 				prtlen = strlen(s);
200107409f4STim J. Robbins 			for (i = 0; i < prtlen; i++) {
201107409f4STim J. Robbins 				ch = (unsigned char)s[i];
2027ea30648SDag-Erling Smørgrav 				putchar('\\');
2037ea30648SDag-Erling Smørgrav 		                putchar('0' + (ch >> 6));
2040ffc35a4SDag-Erling Smørgrav 		                putchar('0' + ((ch >> 3) & 7));
2050ffc35a4SDag-Erling Smørgrav 		                putchar('0' + (ch & 7));
2067ea30648SDag-Erling Smørgrav 				len += 4;
2077ea30648SDag-Erling Smørgrav 			}
2087ea30648SDag-Erling Smørgrav 		}
209107409f4STim J. Robbins 		if (clen == (size_t)-2)
210107409f4STim J. Robbins 			break;
211107409f4STim J. Robbins 		if (clen == (size_t)-1) {
212107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
213107409f4STim J. Robbins 			s++;
214107409f4STim J. Robbins 		} else
215107409f4STim J. Robbins 			s += clen;
216107409f4STim J. Robbins 	}
217107409f4STim J. Robbins 	return (len);
2187ea30648SDag-Erling Smørgrav }
2197ea30648SDag-Erling Smørgrav 
2204b88c807SRodney W. Grimes void
22146251ddeSWarner Losh usage(void)
2224b88c807SRodney W. Grimes {
223a04eaf5bSAndrey A. Chernov 	(void)fprintf(stderr,
224a04eaf5bSAndrey A. Chernov #ifdef COLORLS
225bc458f66STim J. Robbins 	"usage: ls [-ABCFGHLPRTWZabcdfghiklmnoqrstuwx1]"
226a04eaf5bSAndrey A. Chernov #else
227bc458f66STim J. Robbins 	"usage: ls [-ABCFHLPRTWZabcdfghiklmnoqrstuwx1]"
228a04eaf5bSAndrey A. Chernov #endif
2293a34dbf7SDag-Erling Smørgrav 		      " [file ...]\n");
2304b88c807SRodney W. Grimes 	exit(1);
2314b88c807SRodney W. Grimes }
232