Remove not needed void casts.
[dragonfly.git] / bin / ls / print.c
CommitLineData
984263bc
MD
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 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
1de703da
MD
35 *
36 * @(#)print.c 8.4 (Berkeley) 4/17/94
37 * $FreeBSD: src/bin/ls/print.c,v 1.19.2.7 2002/11/17 10:27:34 tjr Exp $
57fed2af 38 * $DragonFly: src/bin/ls/print.c,v 1.7 2004/11/07 20:54:51 eirikn Exp $
984263bc
MD
39 */
40
984263bc
MD
41#include <sys/param.h>
42#include <sys/stat.h>
43
44#include <err.h>
45#include <errno.h>
46#include <fts.h>
47#include <math.h>
48#include <langinfo.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <time.h>
53#include <unistd.h>
54#ifdef COLORLS
55#include <ctype.h>
56#include <termcap.h>
57#include <signal.h>
58#endif
59
60#include "ls.h"
61#include "extern.h"
62
63static int printaname(FTSENT *, u_long, u_long);
64static void printlink(FTSENT *);
65static void printtime(time_t);
66static int printtype(u_int);
67static void printsize(size_t, off_t);
68#ifdef COLORLS
69static void endcolor(int);
70static int colortype(mode_t);
71#endif
72
73#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT)
74
75#define KILO_SZ(n) (n)
76#define MEGA_SZ(n) ((n) * (n))
77#define GIGA_SZ(n) ((n) * (n) * (n))
78#define TERA_SZ(n) ((n) * (n) * (n) * (n))
79#define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n))
80
81#define KILO_2_SZ (KILO_SZ(1024ULL))
82#define MEGA_2_SZ (MEGA_SZ(1024ULL))
83#define GIGA_2_SZ (GIGA_SZ(1024ULL))
84#define TERA_2_SZ (TERA_SZ(1024ULL))
85#define PETA_2_SZ (PETA_SZ(1024ULL))
86
87static unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ};
88
89typedef enum {
90 NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX
91} unit_t;
92static unit_t unit_adjust(off_t *);
93
94static int unitp[] = {NONE, KILO, MEGA, GIGA, TERA, PETA};
95
96#ifdef COLORLS
97/* Most of these are taken from <sys/stat.h> */
98typedef enum Colors {
99 C_DIR, /* directory */
100 C_LNK, /* symbolic link */
101 C_SOCK, /* socket */
102 C_FIFO, /* pipe */
103 C_EXEC, /* executable */
104 C_BLK, /* block special */
105 C_CHR, /* character special */
106 C_SUID, /* setuid executable */
107 C_SGID, /* setgid executable */
108 C_WSDIR, /* directory writeble to others, with sticky
109 * bit */
110 C_WDIR, /* directory writeble to others, without
111 * sticky bit */
112 C_NUMCOLORS /* just a place-holder */
113} Colors;
114
115static const char *defcolors = "exfxcxdxbxegedabagacad";
116
117/* colors for file types */
118static struct {
119 int num[2];
120 int bold;
121} colors[C_NUMCOLORS];
122#endif
123
124void
125printscol(DISPLAY *dp)
126{
127 FTSENT *p;
128
129 for (p = dp->list; p; p = p->fts_link) {
130 if (IS_NOPRINT(p))
131 continue;
57fed2af
EN
132 printaname(p, dp->s_inode, dp->s_block);
133 putchar('\n');
984263bc
MD
134 }
135}
136
137/*
138 * print name in current style
139 */
140int
141printname(const char *name)
142{
143 if (f_octal || f_octal_escape)
144 return prn_octal(name);
145 else if (f_nonprint)
146 return prn_printable(name);
147 else
148 return printf("%s", name);
149}
150
151void
152printlong(DISPLAY *dp)
153{
154 struct stat *sp;
155 FTSENT *p;
156 NAMES *np;
157 char buf[20];
158#ifdef COLORLS
159 int color_printed = 0;
160#endif
161
162 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
57fed2af 163 printf("total %lu\n", howmany(dp->btotal, blocksize));
984263bc
MD
164
165 for (p = dp->list; p; p = p->fts_link) {
166 if (IS_NOPRINT(p))
167 continue;
168 sp = p->fts_statp;
169 if (f_inode)
57fed2af 170 printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
984263bc 171 if (f_size)
57fed2af 172 printf("%*lld ",
984263bc
MD
173 dp->s_block, howmany(sp->st_blocks, blocksize));
174 strmode(sp->st_mode, buf);
175 np = p->fts_pointer;
57fed2af 176 printf("%s %*u %-*s %-*s ", buf, dp->s_nlink,
984263bc
MD
177 sp->st_nlink, dp->s_user, np->user, dp->s_group,
178 np->group);
179 if (f_flags)
57fed2af 180 printf("%-*s ", dp->s_flags, np->flags);
984263bc
MD
181 if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
182 if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
57fed2af 183 printf("%3d, 0x%08x ",
984263bc
MD
184 major(sp->st_rdev),
185 (u_int)minor(sp->st_rdev));
186 else
57fed2af 187 printf("%3d, %3d ",
984263bc
MD
188 major(sp->st_rdev), minor(sp->st_rdev));
189 else if (dp->bcfile)
57fed2af 190 printf("%*s%*lld ",
984263bc
MD
191 8 - dp->s_size, "", dp->s_size, sp->st_size);
192 else
193 printsize(dp->s_size, sp->st_size);
194 if (f_accesstime)
195 printtime(sp->st_atime);
196 else if (f_statustime)
197 printtime(sp->st_ctime);
198 else
199 printtime(sp->st_mtime);
200#ifdef COLORLS
201 if (f_color)
202 color_printed = colortype(sp->st_mode);
203#endif
57fed2af 204 printname(p->fts_name);
984263bc
MD
205#ifdef COLORLS
206 if (f_color && color_printed)
207 endcolor(0);
208#endif
209 if (f_type)
57fed2af 210 printtype(sp->st_mode);
984263bc
MD
211 if (S_ISLNK(sp->st_mode))
212 printlink(p);
57fed2af 213 putchar('\n');
984263bc
MD
214 }
215}
216
217void
218printstream(DISPLAY *dp)
219{
220 FTSENT *p;
984263bc
MD
221 int chcnt;
222
223 for (p = dp->list, chcnt = 0; p; p = p->fts_link) {
224 if (p->fts_number == NO_PRINT)
225 continue;
226 if (strlen(p->fts_name) + chcnt +
227 (p->fts_link ? 2 : 0) >= (unsigned)termwidth) {
228 putchar('\n');
229 chcnt = 0;
230 }
231 chcnt += printaname(p, dp->s_inode, dp->s_block);
232 if (p->fts_link) {
233 printf(", ");
234 chcnt += 2;
235 }
236 }
237 if (chcnt)
238 putchar('\n');
239}
240
241void
242printcol(DISPLAY *dp)
243{
984263bc
MD
244 static FTSENT **array;
245 static int lastentries = -1;
246 FTSENT *p;
68918172 247 FTSENT **narray;
984263bc
MD
248 int base;
249 int chcnt;
250 int cnt;
251 int col;
252 int colwidth;
253 int endcol;
254 int num;
255 int numcols;
256 int numrows;
257 int row;
258 int tabwidth;
259
260 if (f_notabs)
261 tabwidth = 1;
262 else
263 tabwidth = 8;
264
265 /*
266 * Have to do random access in the linked list -- build a table
267 * of pointers.
268 */
269 if (dp->entries > lastentries) {
270 lastentries = dp->entries;
68918172 271 if ((narray =
984263bc
MD
272 realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
273 warn(NULL);
274 printscol(dp);
68918172 275 return;
984263bc 276 }
68918172
DR
277 lastentries = dp->entries;
278 array = narray;
984263bc
MD
279 }
280 for (p = dp->list, num = 0; p; p = p->fts_link)
281 if (p->fts_number != NO_PRINT)
282 array[num++] = p;
283
284 colwidth = dp->maxlen;
285 if (f_inode)
286 colwidth += dp->s_inode + 1;
287 if (f_size)
288 colwidth += dp->s_block + 1;
289 if (f_type)
290 colwidth += 1;
291
292 colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
293 if (termwidth < 2 * colwidth) {
294 printscol(dp);
295 return;
296 }
297 numcols = termwidth / colwidth;
298 numrows = num / numcols;
299 if (num % numcols)
300 ++numrows;
301
302 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
57fed2af 303 printf("total %lu\n", howmany(dp->btotal, blocksize));
984263bc 304
00a63dd3
MD
305 /* counter if f_sortacross, else case-by-case */
306 base = 0;
307
984263bc
MD
308 for (row = 0; row < numrows; ++row) {
309 endcol = colwidth;
310 if (!f_sortacross)
311 base = row;
312 for (col = 0, chcnt = 0; col < numcols; ++col) {
313 chcnt += printaname(array[base], dp->s_inode,
314 dp->s_block);
315 if (f_sortacross)
316 base++;
317 else
318 base += numrows;
319 if (base >= num)
320 break;
321 while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
322 <= endcol) {
323 if (f_sortacross && col + 1 >= numcols)
324 break;
57fed2af 325 putchar(f_notabs ? ' ' : '\t');
984263bc
MD
326 chcnt = cnt;
327 }
328 endcol += colwidth;
329 }
57fed2af 330 putchar('\n');
984263bc
MD
331 }
332}
333
334/*
335 * print [inode] [size] name
336 * return # of characters printed, no trailing characters.
337 */
338static int
339printaname(FTSENT *p, u_long inodefield, u_long sizefield)
340{
341 struct stat *sp;
342 int chcnt;
343#ifdef COLORLS
344 int color_printed = 0;
345#endif
346
347 sp = p->fts_statp;
348 chcnt = 0;
349 if (f_inode)
350 chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
351 if (f_size)
352 chcnt += printf("%*lld ",
353 (int)sizefield, howmany(sp->st_blocks, blocksize));
354#ifdef COLORLS
355 if (f_color)
356 color_printed = colortype(sp->st_mode);
357#endif
358 chcnt += printname(p->fts_name);
359#ifdef COLORLS
360 if (f_color && color_printed)
361 endcolor(0);
362#endif
363 if (f_type)
364 chcnt += printtype(sp->st_mode);
365 return (chcnt);
366}
367
368static void
369printtime(time_t ftime)
370{
371 char longstring[80];
372 static time_t now;
373 const char *format;
374 static int d_first = -1;
375
376 if (d_first < 0)
377 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
378 if (now == 0)
379 now = time(NULL);
380
381#define SIXMONTHS ((365 / 2) * 86400)
382 if (f_sectime)
383 /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
384 format = d_first ? "%e %b %T %Y " : "%b %e %T %Y ";
385 else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
386 /* mmm dd hh:mm || dd mmm hh:mm */
387 format = d_first ? "%e %b %R " : "%b %e %R ";
388 else
389 /* mmm dd yyyy || dd mmm yyyy */
390 format = d_first ? "%e %b %Y " : "%b %e %Y ";
391 strftime(longstring, sizeof(longstring), format, localtime(&ftime));
392 fputs(longstring, stdout);
393}
394
395static int
396printtype(u_int mode)
397{
398
399 if (f_slash) {
400 if ((mode & S_IFMT) == S_IFDIR) {
57fed2af 401 putchar('/');
984263bc
MD
402 return (1);
403 }
404 return (0);
405 }
406
407 switch (mode & S_IFMT) {
408 case S_IFDIR:
57fed2af 409 putchar('/');
984263bc
MD
410 return (1);
411 case S_IFIFO:
57fed2af 412 putchar('|');
984263bc
MD
413 return (1);
414 case S_IFLNK:
57fed2af 415 putchar('@');
984263bc
MD
416 return (1);
417 case S_IFSOCK:
57fed2af 418 putchar('=');
984263bc
MD
419 return (1);
420 case S_IFWHT:
57fed2af 421 putchar('%');
984263bc
MD
422 return (1);
423 default:
424 break;
425 }
426 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
57fed2af 427 putchar('*');
984263bc
MD
428 return (1);
429 }
430 return (0);
431}
432
433#ifdef COLORLS
434static int
435putch(int c)
436{
57fed2af 437 putchar(c);
984263bc
MD
438 return 0;
439}
440
441static int
442writech(int c)
443{
444 char tmp = c;
445
57fed2af 446 write(STDOUT_FILENO, &tmp, 1);
984263bc
MD
447 return 0;
448}
449
450static void
451printcolor(Colors c)
452{
453 char *ansiseq;
454
455 if (colors[c].bold)
456 tputs(enter_bold, 1, putch);
457
458 if (colors[c].num[0] != -1) {
459 ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
460 if (ansiseq)
461 tputs(ansiseq, 1, putch);
462 }
463 if (colors[c].num[1] != -1) {
464 ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
465 if (ansiseq)
466 tputs(ansiseq, 1, putch);
467 }
468}
469
470static void
471endcolor(int sig)
472{
473 tputs(ansi_coloff, 1, sig ? writech : putch);
474 tputs(attrs_off, 1, sig ? writech : putch);
475}
476
477static int
478colortype(mode_t mode)
479{
480 switch (mode & S_IFMT) {
481 case S_IFDIR:
482 if (mode & S_IWOTH)
483 if (mode & S_ISTXT)
484 printcolor(C_WSDIR);
485 else
486 printcolor(C_WDIR);
487 else
488 printcolor(C_DIR);
489 return (1);
490 case S_IFLNK:
491 printcolor(C_LNK);
492 return (1);
493 case S_IFSOCK:
494 printcolor(C_SOCK);
495 return (1);
496 case S_IFIFO:
497 printcolor(C_FIFO);
498 return (1);
499 case S_IFBLK:
500 printcolor(C_BLK);
501 return (1);
502 case S_IFCHR:
503 printcolor(C_CHR);
504 return (1);
505 }
506 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
507 if (mode & S_ISUID)
508 printcolor(C_SUID);
509 else if (mode & S_ISGID)
510 printcolor(C_SGID);
511 else
512 printcolor(C_EXEC);
513 return (1);
514 }
515 return (0);
516}
517
518void
519parsecolors(const char *cs)
520{
521 int i;
522 int j;
523 int len;
524 char c[2];
525 short legacy_warn = 0;
526
527 if (cs == NULL)
528 cs = ""; /* LSCOLORS not set */
529 len = strlen(cs);
530 for (i = 0; i < C_NUMCOLORS; i++) {
531 colors[i].bold = 0;
532
533 if (len <= 2 * i) {
534 c[0] = defcolors[2 * i];
535 c[1] = defcolors[2 * i + 1];
536 } else {
537 c[0] = cs[2 * i];
538 c[1] = cs[2 * i + 1];
539 }
540 for (j = 0; j < 2; j++) {
541 /* Legacy colours used 0-7 */
542 if (c[j] >= '0' && c[j] <= '7') {
543 colors[i].num[j] = c[j] - '0';
544 if (!legacy_warn) {
545 fprintf(stderr,
546 "warn: LSCOLORS should use "
547 "characters a-h instead of 0-9 ("
548 "see the manual page)\n");
549 }
550 legacy_warn = 1;
551 } else if (c[j] >= 'a' && c[j] <= 'h')
552 colors[i].num[j] = c[j] - 'a';
553 else if (c[j] >= 'A' && c[j] <= 'H') {
554 colors[i].num[j] = c[j] - 'A';
555 colors[i].bold = 1;
556 } else if (tolower((unsigned char)c[j] == 'x'))
557 colors[i].num[j] = -1;
558 else {
559 fprintf(stderr,
560 "error: invalid character '%c' in LSCOLORS"
561 " env var\n", c[j]);
562 colors[i].num[j] = -1;
563 }
564 }
565 }
566}
567
568void
569colorquit(int sig)
570{
571 endcolor(sig);
572
57fed2af
EN
573 signal(sig, SIG_DFL);
574 kill(getpid(), sig);
984263bc
MD
575}
576
577#endif /* COLORLS */
578
579static void
580printlink(FTSENT *p)
581{
582 int lnklen;
583 char name[MAXPATHLEN + 1];
584 char path[MAXPATHLEN + 1];
585
586 if (p->fts_level == FTS_ROOTLEVEL)
57fed2af 587 snprintf(name, sizeof(name), "%s", p->fts_name);
984263bc 588 else
57fed2af 589 snprintf(name, sizeof(name),
984263bc
MD
590 "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
591 if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
57fed2af 592 fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
984263bc
MD
593 return;
594 }
595 path[lnklen] = '\0';
57fed2af
EN
596 printf(" -> ");
597 printname(path);
984263bc
MD
598}
599
600static void
601printsize(size_t width, off_t bytes)
602{
603 unit_t unit;
604
605 if (f_humanval) {
606 unit = unit_adjust(&bytes);
607
608 if (bytes == 0)
57fed2af 609 printf("%*s ", width, "0B");
984263bc 610 else
57fed2af 611 printf("%*lld%c ", width - 1, bytes,
984263bc
MD
612 "BKMGTPE"[unit]);
613 } else
57fed2af 614 printf("%*lld ", width, bytes);
984263bc
MD
615}
616
617/*
618 * Output in "human-readable" format. Uses 3 digits max and puts
619 * unit suffixes at the end. Makes output compact and easy to read,
620 * especially on huge disks.
621 *
622 */
862efa0c 623static unit_t
984263bc
MD
624unit_adjust(off_t *val)
625{
626 double abval;
627 unit_t unit;
628 unsigned int unit_sz;
629
630 abval = fabs((double)*val);
631
632 unit_sz = abval ? ilogb(abval) / 10 : 0;
633
634 if (unit_sz >= UNIT_MAX) {
635 unit = NONE;
636 } else {
637 unit = unitp[unit_sz];
638 *val /= (double)vals_base2[unit_sz];
639 }
640
641 return (unit);
642}