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