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
35 static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/2/94";
36 #endif /* not lint */
37 #endif
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
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
58 int
prn_normal(const char * field,const char * s)59 prn_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
95 char *
get_printable(const char * s)96 get_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
148 size_t
len_octal(const char * s,int len)149 len_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
178 char *
get_octal(const char * s)179 get_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
237 void
usage(void)238 usage(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