xref: /freebsd/bin/ls/util.c (revision fbbd9655e5107c68e4e0146ff22b73d7350475bc)
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.
16*fbbd9655SWarner Losh  * 3. 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>
5352e4a08cSMarcel Moolenaar #include <libxo/xo.h>
544b88c807SRodney W. Grimes 
554b88c807SRodney W. Grimes #include "ls.h"
564b88c807SRodney W. Grimes #include "extern.h"
574b88c807SRodney W. Grimes 
58ee579ffbSAssar Westerlund int
5952e4a08cSMarcel Moolenaar prn_normal(const char *field, const char *s)
60107409f4STim J. Robbins {
6152e4a08cSMarcel Moolenaar 	char fmt[_POSIX2_LINE_MAX];
6252e4a08cSMarcel Moolenaar 
6352e4a08cSMarcel Moolenaar 	snprintf(fmt, sizeof(fmt), "{:%s/%%hs}", field);
6452e4a08cSMarcel Moolenaar 	return xo_emit(fmt, s);
6552e4a08cSMarcel Moolenaar #if 0
66107409f4STim J. Robbins 	mbstate_t mbs;
67107409f4STim J. Robbins 	wchar_t wc;
68107409f4STim J. Robbins 	int i, n;
69107409f4STim J. Robbins 	size_t clen;
70107409f4STim J. Robbins 
71107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
72107409f4STim J. Robbins 	n = 0;
73107409f4STim J. Robbins 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
74107409f4STim J. Robbins 		if (clen == (size_t)-2) {
75107409f4STim J. Robbins 			n += printf("%s", s);
76107409f4STim J. Robbins 			break;
77107409f4STim J. Robbins 		}
78107409f4STim J. Robbins 		if (clen == (size_t)-1) {
79107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
80107409f4STim J. Robbins 			putchar((unsigned char)*s);
81107409f4STim J. Robbins 			s++;
82107409f4STim J. Robbins 			n++;
83107409f4STim J. Robbins 			continue;
84107409f4STim J. Robbins 		}
85107409f4STim J. Robbins 		for (i = 0; i < (int)clen; i++)
86107409f4STim J. Robbins 			putchar((unsigned char)s[i]);
87107409f4STim J. Robbins 		s += clen;
886449b88bSTim J. Robbins 		if (iswprint(wc))
89107409f4STim J. Robbins 			n += wcwidth(wc);
90107409f4STim J. Robbins 	}
91107409f4STim J. Robbins 	return (n);
9252e4a08cSMarcel Moolenaar #endif
93107409f4STim J. Robbins }
94107409f4STim J. Robbins 
9552e4a08cSMarcel Moolenaar char *
9652e4a08cSMarcel Moolenaar get_printable(const char *s)
974b88c807SRodney W. Grimes {
98107409f4STim J. Robbins 	mbstate_t mbs;
99107409f4STim J. Robbins 	wchar_t wc;
100107409f4STim J. Robbins 	int i, n;
101107409f4STim J. Robbins 	size_t clen;
10252e4a08cSMarcel Moolenaar 	int slen = strlen(s);
10352e4a08cSMarcel Moolenaar 	char *buf = alloca(slen + 1), *bp = buf;
1044b88c807SRodney W. Grimes 
105107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
106107409f4STim J. Robbins 	n = 0;
107107409f4STim J. Robbins 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
108107409f4STim J. Robbins 		if (clen == (size_t)-1) {
10952e4a08cSMarcel Moolenaar 			*bp++ = '?';
110107409f4STim J. Robbins 			s++;
111107409f4STim J. Robbins 			n++;
112107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
113107409f4STim J. Robbins 			continue;
114107409f4STim J. Robbins 		}
115107409f4STim J. Robbins 		if (clen == (size_t)-2) {
11652e4a08cSMarcel Moolenaar 			*bp++ = '?';
117107409f4STim J. Robbins 			n++;
118107409f4STim J. Robbins 			break;
119107409f4STim J. Robbins 		}
120107409f4STim J. Robbins 		if (!iswprint(wc)) {
12152e4a08cSMarcel Moolenaar 			*bp++ = '?';
122107409f4STim J. Robbins 			s += clen;
123107409f4STim J. Robbins 			n++;
124107409f4STim J. Robbins 			continue;
125107409f4STim J. Robbins 		}
126107409f4STim J. Robbins 		for (i = 0; i < (int)clen; i++)
12752e4a08cSMarcel Moolenaar 			*bp++ = (unsigned char)s[i];
128107409f4STim J. Robbins 		s += clen;
129107409f4STim J. Robbins 		n += wcwidth(wc);
130107409f4STim J. Robbins 	}
13152e4a08cSMarcel Moolenaar 	*bp = '\0';
13252e4a08cSMarcel Moolenaar 	return strdup(buf);
1334b88c807SRodney W. Grimes }
1344b88c807SRodney W. Grimes 
1357ea30648SDag-Erling Smørgrav /*
1367ea30648SDag-Erling Smørgrav  * The fts system makes it difficult to replace fts_name with a different-
1377ea30648SDag-Erling Smørgrav  * sized string, so we just calculate the real length here and do the
1387ea30648SDag-Erling Smørgrav  * conversion in prn_octal()
1390d86878cSDag-Erling Smørgrav  *
1400d86878cSDag-Erling Smørgrav  * XXX when using f_octal_escape (-b) rather than f_octal (-B), the
1410d86878cSDag-Erling Smørgrav  * length computed by len_octal may be too big. I just can't be buggered
1420d86878cSDag-Erling Smørgrav  * to fix this as an efficient fix would involve a lookup table. Same goes
1430d86878cSDag-Erling Smørgrav  * for the rather inelegant code in prn_octal.
1440d86878cSDag-Erling Smørgrav  *
1450d86878cSDag-Erling Smørgrav  *						DES 1998/04/23
1467ea30648SDag-Erling Smørgrav  */
1470d86878cSDag-Erling Smørgrav 
1489052855aSMark Murray size_t
14946251ddeSWarner Losh len_octal(const char *s, int len)
1507ea30648SDag-Erling Smørgrav {
151107409f4STim J. Robbins 	mbstate_t mbs;
152107409f4STim J. Robbins 	wchar_t wc;
153107409f4STim J. Robbins 	size_t clen, r;
1547ea30648SDag-Erling Smørgrav 
155107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
156107409f4STim J. Robbins 	r = 0;
157107409f4STim J. Robbins 	while (len != 0 && (clen = mbrtowc(&wc, s, len, &mbs)) != 0) {
158107409f4STim J. Robbins 		if (clen == (size_t)-1) {
159107409f4STim J. Robbins 			r += 4;
160107409f4STim J. Robbins 			s++;
161107409f4STim J. Robbins 			len--;
162107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
163107409f4STim J. Robbins 			continue;
164107409f4STim J. Robbins 		}
165107409f4STim J. Robbins 		if (clen == (size_t)-2) {
166107409f4STim J. Robbins 			r += 4 * len;
167107409f4STim J. Robbins 			break;
168107409f4STim J. Robbins 		}
169107409f4STim J. Robbins 		if (iswprint(wc))
170107409f4STim J. Robbins 			r++;
171107409f4STim J. Robbins 		else
172107409f4STim J. Robbins 			r += 4 * clen;
173107409f4STim J. Robbins 		s += clen;
174107409f4STim J. Robbins 	}
175107409f4STim J. Robbins 	return (r);
1767ea30648SDag-Erling Smørgrav }
1777ea30648SDag-Erling Smørgrav 
17852e4a08cSMarcel Moolenaar char *
17952e4a08cSMarcel Moolenaar get_octal(const char *s)
1807ea30648SDag-Erling Smørgrav {
181107409f4STim J. Robbins 	static const char esc[] = "\\\\\"\"\aa\bb\ff\nn\rr\tt\vv";
182107409f4STim J. Robbins 	const char *p;
183107409f4STim J. Robbins 	mbstate_t mbs;
184107409f4STim J. Robbins 	wchar_t wc;
185107409f4STim J. Robbins 	size_t clen;
1867ea30648SDag-Erling Smørgrav 	unsigned char ch;
187107409f4STim J. Robbins 	int goodchar, i, len, prtlen;
18852e4a08cSMarcel Moolenaar 	int slen = strlen(s);
18952e4a08cSMarcel Moolenaar 	char *buf = alloca(slen * 4 + 1), *bp = buf;
1907ea30648SDag-Erling Smørgrav 
191107409f4STim J. Robbins 	memset(&mbs, 0, sizeof(mbs));
192107409f4STim J. Robbins 	len = 0;
193107409f4STim J. Robbins 	while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
194107409f4STim J. Robbins 		goodchar = clen != (size_t)-1 && clen != (size_t)-2;
195107409f4STim J. Robbins 		if (goodchar && iswprint(wc) && wc != L'\"' && wc != L'\\') {
196107409f4STim J. Robbins 			for (i = 0; i < (int)clen; i++)
19752e4a08cSMarcel Moolenaar 				*bp++ = (unsigned char)s[i];
198107409f4STim J. Robbins 			len += wcwidth(wc);
1993c96f482SAndrew Turner 		} else if (goodchar && f_octal_escape &&
2003c96f482SAndrew Turner #if WCHAR_MIN < 0
2013c96f482SAndrew Turner                     wc >= 0 &&
2023c96f482SAndrew Turner #endif
203107409f4STim J. Robbins 		    wc <= (wchar_t)UCHAR_MAX &&
204107409f4STim J. Robbins 		    (p = strchr(esc, (char)wc)) != NULL) {
20552e4a08cSMarcel Moolenaar 			*bp ++ = '\\';
20652e4a08cSMarcel Moolenaar 			*bp++ = p[1];
2070d86878cSDag-Erling Smørgrav 			len += 2;
208107409f4STim J. Robbins 		} else {
209107409f4STim J. Robbins 			if (goodchar)
210107409f4STim J. Robbins 				prtlen = clen;
211107409f4STim J. Robbins 			else if (clen == (size_t)-1)
212107409f4STim J. Robbins 				prtlen = 1;
213107409f4STim J. Robbins 			else
214107409f4STim J. Robbins 				prtlen = strlen(s);
215107409f4STim J. Robbins 			for (i = 0; i < prtlen; i++) {
216107409f4STim J. Robbins 				ch = (unsigned char)s[i];
21752e4a08cSMarcel Moolenaar 				*bp++ = '\\';
21852e4a08cSMarcel Moolenaar 				*bp++ = '0' + (ch >> 6);
21952e4a08cSMarcel Moolenaar 				*bp++ = '0' + ((ch >> 3) & 7);
22052e4a08cSMarcel Moolenaar 				*bp++ = '0' + (ch & 7);
2217ea30648SDag-Erling Smørgrav 				len += 4;
2227ea30648SDag-Erling Smørgrav 			}
2237ea30648SDag-Erling Smørgrav 		}
224107409f4STim J. Robbins 		if (clen == (size_t)-2)
225107409f4STim J. Robbins 			break;
226107409f4STim J. Robbins 		if (clen == (size_t)-1) {
227107409f4STim J. Robbins 			memset(&mbs, 0, sizeof(mbs));
228107409f4STim J. Robbins 			s++;
229107409f4STim J. Robbins 		} else
230107409f4STim J. Robbins 			s += clen;
231107409f4STim J. Robbins 	}
23252e4a08cSMarcel Moolenaar 
23352e4a08cSMarcel Moolenaar 	*bp = '\0';
23452e4a08cSMarcel Moolenaar 	return strdup(buf);
2357ea30648SDag-Erling Smørgrav }
2367ea30648SDag-Erling Smørgrav 
2374b88c807SRodney W. Grimes void
23846251ddeSWarner Losh usage(void)
2394b88c807SRodney W. Grimes {
24052e4a08cSMarcel Moolenaar 	xo_error(
241a04eaf5bSAndrey A. Chernov #ifdef COLORLS
2429aa68a3fSGreg Lehey 	"usage: ls [-ABCFGHILPRSTUWZabcdfghiklmnopqrstuwxy1,] [-D format]"
243a04eaf5bSAndrey A. Chernov #else
2449aa68a3fSGreg Lehey 	"usage: ls [-ABCFHILPRSTUWZabcdfghiklmnopqrstuwxy1,] [-D format]"
245a04eaf5bSAndrey A. Chernov #endif
2463a34dbf7SDag-Erling Smørgrav 		      " [file ...]\n");
2474b88c807SRodney W. Grimes 	exit(1);
2484b88c807SRodney W. Grimes }
249