xref: /freebsd/bin/ls/util.c (revision 8b92977857f8acaa539c21800b024edea9eee8b4)
19ddb49cbSWarner Losh /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
44b88c807SRodney W. Grimes  * Copyright (c) 1989, 1993, 1994
54b88c807SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
64b88c807SRodney W. Grimes  *
74b88c807SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
84b88c807SRodney W. Grimes  * Michael Fischbein.
94b88c807SRodney W. Grimes  *
104b88c807SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
114b88c807SRodney W. Grimes  * modification, are permitted provided that the following conditions
124b88c807SRodney W. Grimes  * are met:
134b88c807SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
144b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
154b88c807SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
164b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
174b88c807SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
194b88c807SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
204b88c807SRodney W. Grimes  *    without specific prior written permission.
214b88c807SRodney W. Grimes  *
224b88c807SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
234b88c807SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
244b88c807SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
254b88c807SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
264b88c807SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
274b88c807SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
284b88c807SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
294b88c807SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
304b88c807SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
314b88c807SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
324b88c807SRodney W. Grimes  * SUCH DAMAGE.
334b88c807SRodney W. Grimes  */
344b88c807SRodney W. Grimes 
354b88c807SRodney W. Grimes #include <sys/types.h>
364b88c807SRodney W. Grimes #include <sys/stat.h>
374b88c807SRodney W. Grimes 
384b88c807SRodney W. Grimes #include <ctype.h>
397ea30648SDag-Erling Smørgrav #include <err.h>
404b88c807SRodney W. Grimes #include <fts.h>
41107409f4STim J. Robbins #include <limits.h>
424b88c807SRodney W. Grimes #include <stdio.h>
434b88c807SRodney W. Grimes #include <stdlib.h>
444b88c807SRodney W. Grimes #include <string.h>
45107409f4STim J. Robbins #include <wchar.h>
46107409f4STim J. Robbins #include <wctype.h>
474b88c807SRodney W. Grimes 
484b88c807SRodney W. Grimes #include "ls.h"
494b88c807SRodney W. Grimes #include "extern.h"
504b88c807SRodney W. Grimes 
51ee579ffbSAssar Westerlund int
520fdf7fa8SConrad Meyer prn_normal(const char *s)
53107409f4STim J. Robbins {
54107409f4STim J. Robbins 	mbstate_t mbs;
55107409f4STim J. Robbins 	wchar_t wc;
56107409f4STim J. Robbins 	int i, n;
57107409f4STim J. Robbins 	size_t clen;
58107409f4STim J. Robbins 
59107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
60107409f4STim J. Robbins 	n = 0;
61107409f4STim J. Robbins 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
62107409f4STim J. Robbins 		if (clen == (size_t)-2) {
63107409f4STim J. Robbins 			n += printf("%s", s);
64107409f4STim J. Robbins 			break;
65107409f4STim J. Robbins 		}
66107409f4STim J. Robbins 		if (clen == (size_t)-1) {
67107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
68107409f4STim J. Robbins 			putchar((unsigned char)*s);
69107409f4STim J. Robbins 			s++;
70107409f4STim J. Robbins 			n++;
71107409f4STim J. Robbins 			continue;
72107409f4STim J. Robbins 		}
73107409f4STim J. Robbins 		for (i = 0; i < (int)clen; i++)
74107409f4STim J. Robbins 			putchar((unsigned char)s[i]);
75107409f4STim J. Robbins 		s += clen;
766449b88bSTim J. Robbins 		if (iswprint(wc))
77107409f4STim J. Robbins 			n += wcwidth(wc);
78107409f4STim J. Robbins 	}
79107409f4STim J. Robbins 	return (n);
80107409f4STim J. Robbins }
81107409f4STim J. Robbins 
820fdf7fa8SConrad Meyer int
830fdf7fa8SConrad Meyer prn_printable(const char *s)
844b88c807SRodney W. Grimes {
85107409f4STim J. Robbins 	mbstate_t mbs;
86107409f4STim J. Robbins 	wchar_t wc;
87107409f4STim J. Robbins 	int i, n;
88107409f4STim J. Robbins 	size_t clen;
894b88c807SRodney W. Grimes 
90107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
91107409f4STim J. Robbins 	n = 0;
92107409f4STim J. Robbins 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
93107409f4STim J. Robbins 		if (clen == (size_t)-1) {
940fdf7fa8SConrad Meyer 			putchar('?');
95107409f4STim J. Robbins 			s++;
96107409f4STim J. Robbins 			n++;
97107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
98107409f4STim J. Robbins 			continue;
99107409f4STim J. Robbins 		}
100107409f4STim J. Robbins 		if (clen == (size_t)-2) {
1010fdf7fa8SConrad Meyer 			putchar('?');
102107409f4STim J. Robbins 			n++;
103107409f4STim J. Robbins 			break;
104107409f4STim J. Robbins 		}
105107409f4STim J. Robbins 		if (!iswprint(wc)) {
1060fdf7fa8SConrad Meyer 			putchar('?');
107107409f4STim J. Robbins 			s += clen;
108107409f4STim J. Robbins 			n++;
109107409f4STim J. Robbins 			continue;
110107409f4STim J. Robbins 		}
111107409f4STim J. Robbins 		for (i = 0; i < (int)clen; i++)
1120fdf7fa8SConrad Meyer 			putchar((unsigned char)s[i]);
113107409f4STim J. Robbins 		s += clen;
114107409f4STim J. Robbins 		n += wcwidth(wc);
115107409f4STim J. Robbins 	}
1160fdf7fa8SConrad Meyer 	return (n);
1174b88c807SRodney W. Grimes }
1184b88c807SRodney W. Grimes 
1197ea30648SDag-Erling Smørgrav /*
1207ea30648SDag-Erling Smørgrav  * The fts system makes it difficult to replace fts_name with a different-
1217ea30648SDag-Erling Smørgrav  * sized string, so we just calculate the real length here and do the
1227ea30648SDag-Erling Smørgrav  * conversion in prn_octal()
1230d86878cSDag-Erling Smørgrav  *
1240d86878cSDag-Erling Smørgrav  * XXX when using f_octal_escape (-b) rather than f_octal (-B), the
1250d86878cSDag-Erling Smørgrav  * length computed by len_octal may be too big. I just can't be buggered
1260d86878cSDag-Erling Smørgrav  * to fix this as an efficient fix would involve a lookup table. Same goes
1270d86878cSDag-Erling Smørgrav  * for the rather inelegant code in prn_octal.
1280d86878cSDag-Erling Smørgrav  *
1290d86878cSDag-Erling Smørgrav  *						DES 1998/04/23
1307ea30648SDag-Erling Smørgrav  */
1310d86878cSDag-Erling Smørgrav 
1329052855aSMark Murray size_t
13346251ddeSWarner Losh len_octal(const char *s, int len)
1347ea30648SDag-Erling Smørgrav {
135107409f4STim J. Robbins 	mbstate_t mbs;
136107409f4STim J. Robbins 	wchar_t wc;
137107409f4STim J. Robbins 	size_t clen, r;
1387ea30648SDag-Erling Smørgrav 
139107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
140107409f4STim J. Robbins 	r = 0;
141107409f4STim J. Robbins 	while (len != 0 && (clen = mbrtowc(&wc, s, len, &mbs)) != 0) {
142107409f4STim J. Robbins 		if (clen == (size_t)-1) {
143107409f4STim J. Robbins 			r += 4;
144107409f4STim J. Robbins 			s++;
145107409f4STim J. Robbins 			len--;
146107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
147107409f4STim J. Robbins 			continue;
148107409f4STim J. Robbins 		}
149107409f4STim J. Robbins 		if (clen == (size_t)-2) {
150107409f4STim J. Robbins 			r += 4 * len;
151107409f4STim J. Robbins 			break;
152107409f4STim J. Robbins 		}
153107409f4STim J. Robbins 		if (iswprint(wc))
154107409f4STim J. Robbins 			r++;
155107409f4STim J. Robbins 		else
156107409f4STim J. Robbins 			r += 4 * clen;
157107409f4STim J. Robbins 		s += clen;
158107409f4STim J. Robbins 	}
159107409f4STim J. Robbins 	return (r);
1607ea30648SDag-Erling Smørgrav }
1617ea30648SDag-Erling Smørgrav 
1620fdf7fa8SConrad Meyer int
1630fdf7fa8SConrad Meyer prn_octal(const char *s)
1647ea30648SDag-Erling Smørgrav {
165107409f4STim J. Robbins 	static const char esc[] = "\\\\\"\"\aa\bb\ff\nn\rr\tt\vv";
166107409f4STim J. Robbins 	const char *p;
167107409f4STim J. Robbins 	mbstate_t mbs;
168107409f4STim J. Robbins 	wchar_t wc;
169107409f4STim J. Robbins 	size_t clen;
1707ea30648SDag-Erling Smørgrav 	unsigned char ch;
171107409f4STim J. Robbins 	int goodchar, i, len, prtlen;
1727ea30648SDag-Erling Smørgrav 
173107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
174107409f4STim J. Robbins 	len = 0;
175107409f4STim J. Robbins 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
176107409f4STim J. Robbins 		goodchar = clen != (size_t)-1 && clen != (size_t)-2;
177107409f4STim J. Robbins 		if (goodchar && iswprint(wc) && wc != L'\"' && wc != L'\\') {
178107409f4STim J. Robbins 			for (i = 0; i < (int)clen; i++)
1790fdf7fa8SConrad Meyer 				putchar((unsigned char)s[i]);
180107409f4STim J. Robbins 			len += wcwidth(wc);
1813c96f482SAndrew Turner 		} else if (goodchar && f_octal_escape &&
1823c96f482SAndrew Turner #if WCHAR_MIN < 0
1833c96f482SAndrew Turner                     wc >= 0 &&
1843c96f482SAndrew Turner #endif
185107409f4STim J. Robbins 		    wc <= (wchar_t)UCHAR_MAX &&
186107409f4STim J. Robbins 		    (p = strchr(esc, (char)wc)) != NULL) {
1870fdf7fa8SConrad Meyer 			putchar('\\');
1880fdf7fa8SConrad Meyer 			putchar(p[1]);
1890d86878cSDag-Erling Smørgrav 			len += 2;
190107409f4STim J. Robbins 		} else {
191107409f4STim J. Robbins 			if (goodchar)
192107409f4STim J. Robbins 				prtlen = clen;
193107409f4STim J. Robbins 			else if (clen == (size_t)-1)
194107409f4STim J. Robbins 				prtlen = 1;
195107409f4STim J. Robbins 			else
196107409f4STim J. Robbins 				prtlen = strlen(s);
197107409f4STim J. Robbins 			for (i = 0; i < prtlen; i++) {
198107409f4STim J. Robbins 				ch = (unsigned char)s[i];
1990fdf7fa8SConrad Meyer 				putchar('\\');
2000fdf7fa8SConrad Meyer 				putchar('0' + (ch >> 6));
2010fdf7fa8SConrad Meyer 				putchar('0' + ((ch >> 3) & 7));
2020fdf7fa8SConrad Meyer 				putchar('0' + (ch & 7));
2037ea30648SDag-Erling Smørgrav 				len += 4;
2047ea30648SDag-Erling Smørgrav 			}
2057ea30648SDag-Erling Smørgrav 		}
206107409f4STim J. Robbins 		if (clen == (size_t)-2)
207107409f4STim J. Robbins 			break;
208107409f4STim J. Robbins 		if (clen == (size_t)-1) {
209107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
210107409f4STim J. Robbins 			s++;
211107409f4STim J. Robbins 		} else
212107409f4STim J. Robbins 			s += clen;
213107409f4STim J. Robbins 	}
2140fdf7fa8SConrad Meyer 	return (len);
2157ea30648SDag-Erling Smørgrav }
2167ea30648SDag-Erling Smørgrav 
2174b88c807SRodney W. Grimes void
21846251ddeSWarner Losh usage(void)
2194b88c807SRodney W. Grimes {
2200fdf7fa8SConrad Meyer 	(void)fprintf(stderr,
221a04eaf5bSAndrey A. Chernov #ifdef COLORLS
222*8b929778SPiotr Pawel Stefaniak 	"usage: ls [-ABCFGHILPRSTUWZabcdfghiklmnopqrstuvwxy1,] [--color=when] [-D format] [--group-directories=]"
223a04eaf5bSAndrey A. Chernov #else
224*8b929778SPiotr Pawel Stefaniak 	"usage: ls [-ABCFHILPRSTUWZabcdfghiklmnopqrstuvwxy1,] [-D format] [--group-directories=]"
225a04eaf5bSAndrey A. Chernov #endif
2263a34dbf7SDag-Erling Smørgrav 		      " [file ...]\n");
2274b88c807SRodney W. Grimes 	exit(1);
2284b88c807SRodney W. Grimes }
229