1 /* $NetBSD: print.c,v 1.51 2012/06/29 12:51:38 yamt Exp $ */
4 * Copyright (c) 1989, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
38 static char sccsid
[] = "@(#)print.c 8.5 (Berkeley) 7/28/94";
40 __RCSID("$NetBSD: print.c,v 1.51 2012/06/29 12:51:38 yamt Exp $");
44 #include <sys/param.h>
65 static int printaname(FTSENT
*, int, int);
66 static void printlink(FTSENT
*);
67 static void printtime(time_t);
68 static void printtotal(DISPLAY
*dp
);
69 static int printtype(u_int
);
73 #define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT)
76 printscol(DISPLAY
*dp
)
80 for (p
= dp
->list
; p
; p
= p
->fts_link
) {
83 (void)printaname(p
, dp
->s_inode
, dp
->s_block
);
89 printlong(DISPLAY
*dp
)
94 char buf
[20], szbuf
[5];
98 printtotal(dp
); /* "total: %u\n" */
100 for (p
= dp
->list
; p
; p
= p
->fts_link
) {
105 (void)printf("%*lu ", dp
->s_inode
,
106 (unsigned long)sp
->st_ino
);
109 if ((humanize_number(szbuf
, sizeof(szbuf
),
110 sp
->st_blocks
* S_BLKSIZE
,
112 (HN_DECIMAL
| HN_B
| HN_NOSPACE
))) == -1)
113 err(1, "humanize_number");
114 (void)printf("%*s ", dp
->s_block
, szbuf
);
116 (void)printf(f_commas
? "%'*llu " : "%*llu ",
118 (unsigned long long)howmany(sp
->st_blocks
,
122 (void)strmode(sp
->st_mode
, buf
);
124 (void)printf("%s %*lu ", buf
, dp
->s_nlink
,
125 (unsigned long)sp
->st_nlink
);
127 (void)printf("%-*s ", dp
->s_user
, np
->user
);
128 (void)printf("%-*s ", dp
->s_group
, np
->group
);
130 (void)printf("%-*s ", dp
->s_flags
, np
->flags
);
131 if (S_ISCHR(sp
->st_mode
) || S_ISBLK(sp
->st_mode
))
132 (void)printf("%*lld, %*lld ",
133 dp
->s_major
, (long long)major(sp
->st_rdev
),
134 dp
->s_minor
, (long long)minor(sp
->st_rdev
));
137 if ((humanize_number(szbuf
, sizeof(szbuf
),
138 sp
->st_size
, "", HN_AUTOSCALE
,
139 (HN_DECIMAL
| HN_B
| HN_NOSPACE
))) == -1)
140 err(1, "humanize_number");
141 (void)printf("%*s ", dp
->s_size
, szbuf
);
143 (void)printf(f_commas
? "%'*llu " : "%*llu ",
144 dp
->s_size
, (unsigned long long)
148 printtime(sp
->st_atime
);
149 else if (f_statustime
)
150 printtime(sp
->st_ctime
);
152 printtime(sp
->st_mtime
);
153 if (f_octal
|| f_octal_escape
)
154 (void)safe_print(p
->fts_name
);
156 (void)printescaped(p
->fts_name
);
158 (void)printf("%s", p
->fts_name
);
160 if (f_type
|| (f_typedir
&& S_ISDIR(sp
->st_mode
)))
161 (void)printtype(sp
->st_mode
);
162 if (S_ISLNK(sp
->st_mode
))
169 printcol(DISPLAY
*dp
)
171 static FTSENT
**array
;
172 static int lastentries
= -1;
174 int base
, chcnt
, col
, colwidth
, num
;
175 int numcols
, numrows
, row
;
177 colwidth
= dp
->maxlen
;
179 colwidth
+= dp
->s_inode
+ 1;
182 colwidth
+= dp
->s_size
+ 1;
184 colwidth
+= dp
->s_block
+ 1;
186 if (f_type
|| f_typedir
)
191 if (termwidth
< 2 * colwidth
) {
197 * Have to do random access in the linked list -- build a table
200 if (dp
->entries
> lastentries
) {
203 newarray
= realloc(array
, dp
->entries
* sizeof(FTSENT
*));
204 if (newarray
== NULL
) {
209 lastentries
= dp
->entries
;
212 for (p
= dp
->list
, num
= 0; p
; p
= p
->fts_link
)
213 if (p
->fts_number
!= NO_PRINT
)
216 numcols
= termwidth
/ colwidth
;
217 colwidth
= termwidth
/ numcols
; /* spread out if possible */
218 numrows
= num
/ numcols
;
222 printtotal(dp
); /* "total: %u\n" */
224 for (row
= 0; row
< numrows
; ++row
) {
225 for (base
= row
, chcnt
= col
= 0; col
< numcols
; ++col
) {
226 chcnt
= printaname(array
[base
], dp
->s_inode
,
227 f_humanize
? dp
->s_size
: dp
->s_block
);
228 if ((base
+= numrows
) >= num
)
230 while (chcnt
++ < colwidth
)
238 printacol(DISPLAY
*dp
)
241 int chcnt
, col
, colwidth
;
244 colwidth
= dp
->maxlen
;
246 colwidth
+= dp
->s_inode
+ 1;
249 colwidth
+= dp
->s_size
+ 1;
251 colwidth
+= dp
->s_block
+ 1;
253 if (f_type
|| f_typedir
)
258 if (termwidth
< 2 * colwidth
) {
263 numcols
= termwidth
/ colwidth
;
264 colwidth
= termwidth
/ numcols
; /* spread out if possible */
266 printtotal(dp
); /* "total: %u\n" */
269 for (p
= dp
->list
; p
; p
= p
->fts_link
) {
272 if (col
>= numcols
) {
276 chcnt
= printaname(p
, dp
->s_inode
,
277 f_humanize
? dp
->s_size
: dp
->s_block
);
278 while (chcnt
++ < colwidth
)
286 printstream(DISPLAY
*dp
)
294 extwidth
+= dp
->s_inode
+ 1;
297 extwidth
+= dp
->s_size
+ 1;
299 extwidth
+= dp
->s_block
+ 1;
304 for (col
= 0, p
= dp
->list
; p
!= NULL
; p
= p
->fts_link
) {
308 (void)putchar(','), col
++;
309 if (col
+ 1 + extwidth
+ (int)p
->fts_namelen
>= termwidth
)
310 (void)putchar('\n'), col
= 0;
312 (void)putchar(' '), col
++;
314 col
+= printaname(p
, dp
->s_inode
,
315 f_humanize
? dp
->s_size
: dp
->s_block
);
321 * print [inode] [size] name
322 * return # of characters printed, no trailing characters.
325 printaname(FTSENT
*p
, int inodefield
, int sizefield
)
334 chcnt
+= printf("%*lu ", inodefield
, (unsigned long)sp
->st_ino
);
337 if ((humanize_number(szbuf
, sizeof(szbuf
), sp
->st_size
,
339 (HN_DECIMAL
| HN_B
| HN_NOSPACE
))) == -1)
340 err(1, "humanize_number");
341 chcnt
+= printf("%*s ", sizefield
, szbuf
);
343 chcnt
+= printf(f_commas
? "%'*llu " : "%*llu ",
344 sizefield
, (unsigned long long)
345 howmany(sp
->st_blocks
, blocksize
));
348 if (f_octal
|| f_octal_escape
)
349 chcnt
+= safe_print(p
->fts_name
);
351 chcnt
+= printescaped(p
->fts_name
);
353 chcnt
+= printf("%s", p
->fts_name
);
354 if (f_type
|| (f_typedir
&& S_ISDIR(sp
->st_mode
)))
355 chcnt
+= printtype(sp
->st_mode
);
360 printtime(time_t ftime
)
363 const char *longstring
;
365 if ((longstring
= ctime(&ftime
)) == NULL
) {
366 /* 012345678901234567890123 */
367 longstring
= "????????????????????????";
369 for (i
= 4; i
< 11; ++i
)
370 (void)putchar(longstring
[i
]);
372 #define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
374 for (i
= 11; i
< 24; i
++)
375 (void)putchar(longstring
[i
]);
376 else if (ftime
+ SIXMONTHS
> now
&& ftime
- SIXMONTHS
< now
)
377 for (i
= 11; i
< 16; ++i
)
378 (void)putchar(longstring
[i
]);
381 for (i
= 20; i
< 24; ++i
)
382 (void)putchar(longstring
[i
]);
388 * Display total used disk space in the form "total: %u\n".
389 * Note: POSIX (IEEE Std 1003.1-2001) says this should be always in 512 blocks,
390 * but we humanise it with -h, or separate it with commas with -M, and use 1024
394 printtotal(DISPLAY
*dp
)
398 if (dp
->list
->fts_level
!= FTS_ROOTLEVEL
&& (f_longform
|| f_size
)) {
400 if ((humanize_number(szbuf
, sizeof(szbuf
), (int64_t)dp
->stotal
,
402 (HN_DECIMAL
| HN_B
| HN_NOSPACE
))) == -1)
403 err(1, "humanize_number");
404 (void)printf("total %s\n", szbuf
);
406 (void)printf(f_commas
? "total %'llu\n" :
407 "total %llu\n", (unsigned long long)
408 howmany(dp
->btotal
, blocksize
));
414 printtype(u_int mode
)
416 switch (mode
& S_IFMT
) {
433 if (mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)) {
444 char name
[MAXPATHLEN
+ 1], path
[MAXPATHLEN
+ 1];
446 if (p
->fts_level
== FTS_ROOTLEVEL
)
447 (void)snprintf(name
, sizeof(name
), "%s", p
->fts_name
);
449 (void)snprintf(name
, sizeof(name
),
450 "%s/%s", p
->fts_parent
->fts_accpath
, p
->fts_name
);
451 if ((lnklen
= readlink(name
, path
, sizeof(path
) - 1)) == -1) {
452 (void)fprintf(stderr
, "\nls: %s: %s\n", name
, strerror(errno
));
456 (void)printf(" -> ");
457 if (f_octal
|| f_octal_escape
)
458 (void)safe_print(path
);
460 (void)printescaped(path
);
462 (void)printf("%s", path
);