print.c revision 90150
11556Srgrimes/*
21556Srgrimes * Copyright (c) 1989, 1993, 1994
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Michael Fischbein.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 3. All advertising materials mentioning features or use of this software
171556Srgrimes *    must display the following acknowledgement:
181556Srgrimes *	This product includes software developed by the University of
191556Srgrimes *	California, Berkeley and its contributors.
201556Srgrimes * 4. Neither the name of the University nor the names of its contributors
211556Srgrimes *    may be used to endorse or promote products derived from this software
221556Srgrimes *    without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341556Srgrimes * SUCH DAMAGE.
351556Srgrimes */
361556Srgrimes
371556Srgrimes#ifndef lint
3827967Ssteve#if 0
3927967Sstevestatic char sccsid[] = "@(#)print.c	8.4 (Berkeley) 4/17/94";
4027967Ssteve#else
4127958Sstevestatic const char rcsid[] =
4250471Speter  "$FreeBSD: head/bin/ls/print.c 90150 2002-02-03 19:11:32Z markm $";
4327967Ssteve#endif
441556Srgrimes#endif /* not lint */
451556Srgrimes
461556Srgrimes#include <sys/param.h>
471556Srgrimes#include <sys/stat.h>
481556Srgrimes
491556Srgrimes#include <err.h>
501556Srgrimes#include <errno.h>
511556Srgrimes#include <fts.h>
521556Srgrimes#include <grp.h>
5388591Sjoe#include <math.h>
5474566Sache#include <langinfo.h>
551556Srgrimes#include <pwd.h>
561556Srgrimes#include <stdio.h>
571556Srgrimes#include <stdlib.h>
581556Srgrimes#include <string.h>
591556Srgrimes#include <unistd.h>
6061294Sache#ifdef COLORLS
6161294Sache#include <ctype.h>
6261294Sache#include <termcap.h>
6361294Sache#include <signal.h>
6461294Sache#endif
651556Srgrimes
661556Srgrimes#include "ls.h"
671556Srgrimes#include "extern.h"
681556Srgrimes
6990110Simpstatic int	printaname(FTSENT *, u_long, u_long);
7090110Simpstatic void	printlink(FTSENT *);
7190110Simpstatic void	printtime(time_t);
7290110Simpstatic int	printtype(u_int);
7390110Simpstatic void	printsize(size_t, off_t);
7461321Sache#ifdef COLORLS
7590110Simpstatic void	endcolor(int);
7690110Simpstatic int	colortype(mode_t);
7761321Sache#endif
781556Srgrimes
791556Srgrimes#define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
801556Srgrimes
8188591Sjoe#define KILO_SZ(n) (n)
8288591Sjoe#define MEGA_SZ(n) ((n) * (n))
8388591Sjoe#define GIGA_SZ(n) ((n) * (n) * (n))
8488591Sjoe#define TERA_SZ(n) ((n) * (n) * (n) * (n))
8588591Sjoe#define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n))
8688591Sjoe
8788591Sjoe#define KILO_2_SZ (KILO_SZ(1024ULL))
8888591Sjoe#define MEGA_2_SZ (MEGA_SZ(1024ULL))
8988591Sjoe#define GIGA_2_SZ (GIGA_SZ(1024ULL))
9088591Sjoe#define TERA_2_SZ (TERA_SZ(1024ULL))
9188591Sjoe#define PETA_2_SZ (PETA_SZ(1024ULL))
9288591Sjoe
9390150Smarkmstatic unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ};
9488591Sjoe
9588602Sjoetypedef enum {
9688602Sjoe	NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX
9788602Sjoe} unit_t;
9890110Simpstatic unit_t unit_adjust(off_t *);
9988591Sjoe
10090150Smarkmstatic int unitp[] = {NONE, KILO, MEGA, GIGA, TERA, PETA};
10188591Sjoe
10261268Sjoe#ifdef COLORLS
10361178Sjoe/* Most of these are taken from <sys/stat.h> */
10461178Sjoetypedef enum Colors {
10588602Sjoe	C_DIR,			/* directory */
10688602Sjoe	C_LNK,			/* symbolic link */
10788602Sjoe	C_SOCK,			/* socket */
10888602Sjoe	C_FIFO,			/* pipe */
10988602Sjoe	C_EXEC,			/* executable */
11088602Sjoe	C_BLK,			/* block special */
11188602Sjoe	C_CHR,			/* character special */
11288602Sjoe	C_SUID,			/* setuid executable */
11388602Sjoe	C_SGID,			/* setgid executable */
11488602Sjoe	C_WSDIR,		/* directory writeble to others, with sticky
11588602Sjoe				 * bit */
11688602Sjoe	C_WDIR,			/* directory writeble to others, without
11788602Sjoe				 * sticky bit */
11888602Sjoe	C_NUMCOLORS		/* just a place-holder */
11988586Sjoe} Colors;
12061178Sjoe
12190150Smarkmstatic const char *defcolors = "exfxcxdxbxegedabagacad";
12261178Sjoe
12388583Sjoe/* colors for file types */
12488583Sjoestatic struct {
12588586Sjoe	int	num[2];
12688586Sjoe	int	bold;
12788583Sjoe} colors[C_NUMCOLORS];
12861268Sjoe#endif
12961178Sjoe
1301556Srgrimesvoid
13190110Simpprintscol(DISPLAY *dp)
1321556Srgrimes{
13388594Sjoe	FTSENT *p;
1341556Srgrimes
1351556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1361556Srgrimes		if (IS_NOPRINT(p))
1371556Srgrimes			continue;
1381556Srgrimes		(void)printaname(p, dp->s_inode, dp->s_block);
1391556Srgrimes		(void)putchar('\n');
1401556Srgrimes	}
1411556Srgrimes}
1421556Srgrimes
14362597Sassar/*
14462597Sassar * print name in current style
14562597Sassar */
14662597Sassarstatic int
14790110Simpprintname(const char *name)
14862597Sassar{
14962597Sassar	if (f_octal || f_octal_escape)
15062597Sassar		return prn_octal(name);
15162597Sassar	else if (f_nonprint)
15262597Sassar		return prn_printable(name);
15362597Sassar	else
15462597Sassar		return printf("%s", name);
15562597Sassar}
15662597Sassar
1571556Srgrimesvoid
15890110Simpprintlong(DISPLAY *dp)
1591556Srgrimes{
1601556Srgrimes	struct stat *sp;
16188594Sjoe	FTSENT *p;
16288594Sjoe	NAMES *np;
16388594Sjoe	char buf[20];
16461292Sache#ifdef COLORLS
16588594Sjoe	int color_printed = 0;
16661292Sache#endif
1671556Srgrimes
1681556Srgrimes	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
1691556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
1701556Srgrimes
1711556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1721556Srgrimes		if (IS_NOPRINT(p))
1731556Srgrimes			continue;
1741556Srgrimes		sp = p->fts_statp;
1751556Srgrimes		if (f_inode)
17620417Ssteve			(void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
1771556Srgrimes		if (f_size)
17890150Smarkm			(void)printf("%*lld ",
1791556Srgrimes			    dp->s_block, howmany(sp->st_blocks, blocksize));
18090150Smarkm		strmode(sp->st_mode, buf);
1811556Srgrimes		np = p->fts_pointer;
1821556Srgrimes		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
1831556Srgrimes		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
1841556Srgrimes		    np->group);
1851556Srgrimes		if (f_flags)
1861556Srgrimes			(void)printf("%-*s ", dp->s_flags, np->flags);
18786922Sgreen		if (f_lomac)
18886922Sgreen			(void)printf("%-*s ", dp->s_lattr, np->lattr);
1891556Srgrimes		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
19055514Sbde			if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
19113120Sjoerg				(void)printf("%3d, 0x%08x ",
19255514Sbde				    major(sp->st_rdev),
19355514Sbde				    (u_int)minor(sp->st_rdev));
19413120Sjoerg			else
19513120Sjoerg				(void)printf("%3d, %3d ",
19613120Sjoerg				    major(sp->st_rdev), minor(sp->st_rdev));
1971556Srgrimes		else if (dp->bcfile)
19890150Smarkm			(void)printf("%*s%*lld ",
1991556Srgrimes			    8 - dp->s_size, "", dp->s_size, sp->st_size);
2001556Srgrimes		else
20188591Sjoe			printsize(dp->s_size, sp->st_size);
2021556Srgrimes		if (f_accesstime)
2031556Srgrimes			printtime(sp->st_atime);
2041556Srgrimes		else if (f_statustime)
2051556Srgrimes			printtime(sp->st_ctime);
2061556Srgrimes		else
2071556Srgrimes			printtime(sp->st_mtime);
20861268Sjoe#ifdef COLORLS
20961178Sjoe		if (f_color)
21061291Sache			color_printed = colortype(sp->st_mode);
21161268Sjoe#endif
21262597Sassar		(void)printname(p->fts_name);
21361268Sjoe#ifdef COLORLS
21461291Sache		if (f_color && color_printed)
21561321Sache			endcolor(0);
21661268Sjoe#endif
2171556Srgrimes		if (f_type)
2181556Srgrimes			(void)printtype(sp->st_mode);
2191556Srgrimes		if (S_ISLNK(sp->st_mode))
2201556Srgrimes			printlink(p);
2211556Srgrimes		(void)putchar('\n');
2221556Srgrimes	}
2231556Srgrimes}
2241556Srgrimes
2251556Srgrimesvoid
22690110Simpprintcol(DISPLAY *dp)
2271556Srgrimes{
2281556Srgrimes	extern int termwidth;
2291556Srgrimes	static FTSENT **array;
2301556Srgrimes	static int lastentries = -1;
23188594Sjoe	FTSENT *p;
23288594Sjoe	int base;
23388594Sjoe	int chcnt;
23488594Sjoe	int cnt;
23588594Sjoe	int col;
23688594Sjoe	int colwidth;
23788594Sjoe	int endcol;
23888594Sjoe	int num;
23988594Sjoe	int numcols;
24088594Sjoe	int numrows;
24188594Sjoe	int row;
24288594Sjoe	int tabwidth;
2431556Srgrimes
24437932Shoek	if (f_notabs)
24537932Shoek		tabwidth = 1;
24637932Shoek	else
24737932Shoek		tabwidth = 8;
24837932Shoek
2491556Srgrimes	/*
2501556Srgrimes	 * Have to do random access in the linked list -- build a table
2511556Srgrimes	 * of pointers.
2521556Srgrimes	 */
2531556Srgrimes	if (dp->entries > lastentries) {
2541556Srgrimes		lastentries = dp->entries;
2551556Srgrimes		if ((array =
2561556Srgrimes		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
2571556Srgrimes			warn(NULL);
2581556Srgrimes			printscol(dp);
2591556Srgrimes		}
2601556Srgrimes	}
2611556Srgrimes	for (p = dp->list, num = 0; p; p = p->fts_link)
2621556Srgrimes		if (p->fts_number != NO_PRINT)
2631556Srgrimes			array[num++] = p;
2641556Srgrimes
2651556Srgrimes	colwidth = dp->maxlen;
2661556Srgrimes	if (f_inode)
2671556Srgrimes		colwidth += dp->s_inode + 1;
2681556Srgrimes	if (f_size)
2691556Srgrimes		colwidth += dp->s_block + 1;
2701556Srgrimes	if (f_type)
2711556Srgrimes		colwidth += 1;
2721556Srgrimes
27337932Shoek	colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
2741556Srgrimes	if (termwidth < 2 * colwidth) {
2751556Srgrimes		printscol(dp);
2761556Srgrimes		return;
2771556Srgrimes	}
2781556Srgrimes	numcols = termwidth / colwidth;
2791556Srgrimes	numrows = num / numcols;
2801556Srgrimes	if (num % numcols)
2811556Srgrimes		++numrows;
2821556Srgrimes
2831556Srgrimes	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
2841556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
2851556Srgrimes	for (row = 0; row < numrows; ++row) {
2861556Srgrimes		endcol = colwidth;
2871556Srgrimes		for (base = row, chcnt = col = 0; col < numcols; ++col) {
2881556Srgrimes			chcnt += printaname(array[base], dp->s_inode,
2891556Srgrimes			    dp->s_block);
2901556Srgrimes			if ((base += numrows) >= num)
2911556Srgrimes				break;
29237932Shoek			while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
29388595Sjoe			    <= endcol) {
29437932Shoek				(void)putchar(f_notabs ? ' ' : '\t');
2951556Srgrimes				chcnt = cnt;
2961556Srgrimes			}
2971556Srgrimes			endcol += colwidth;
2981556Srgrimes		}
2991556Srgrimes		(void)putchar('\n');
3001556Srgrimes	}
3011556Srgrimes}
3021556Srgrimes
3031556Srgrimes/*
3041556Srgrimes * print [inode] [size] name
3051556Srgrimes * return # of characters printed, no trailing characters.
3061556Srgrimes */
3071556Srgrimesstatic int
30890110Simpprintaname(FTSENT *p, u_long inodefield, u_long sizefield)
3091556Srgrimes{
3101556Srgrimes	struct stat *sp;
31188594Sjoe	int chcnt;
31261292Sache#ifdef COLORLS
31388594Sjoe	int color_printed = 0;
31461292Sache#endif
3151556Srgrimes
3161556Srgrimes	sp = p->fts_statp;
3171556Srgrimes	chcnt = 0;
3181556Srgrimes	if (f_inode)
31920417Ssteve		chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
3201556Srgrimes	if (f_size)
32190150Smarkm		chcnt += printf("%*lld ",
3221556Srgrimes		    (int)sizefield, howmany(sp->st_blocks, blocksize));
32361268Sjoe#ifdef COLORLS
32461178Sjoe	if (f_color)
32561291Sache		color_printed = colortype(sp->st_mode);
32661268Sjoe#endif
32762597Sassar	chcnt += printname(p->fts_name);
32861268Sjoe#ifdef COLORLS
32961291Sache	if (f_color && color_printed)
33061321Sache		endcolor(0);
33161268Sjoe#endif
3321556Srgrimes	if (f_type)
3331556Srgrimes		chcnt += printtype(sp->st_mode);
3341556Srgrimes	return (chcnt);
3351556Srgrimes}
3361556Srgrimes
3371556Srgrimesstatic void
33890110Simpprinttime(time_t ftime)
3391556Srgrimes{
34088594Sjoe	char longstring[80];
34188594Sjoe	static time_t now;
34288594Sjoe	const char *format;
34388594Sjoe	static int d_first = -1;
3441556Srgrimes
34574566Sache	if (d_first < 0)
34674566Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
34721545Smpp	if (now == 0)
34821545Smpp		now = time(NULL);
34921545Smpp
3509987Swollman#define	SIXMONTHS	((365 / 2) * 86400)
3511556Srgrimes	if (f_sectime)
35261920Sjoe		/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
35374566Sache		format = d_first ? "%e %b %T %Y " : "%b %e %T %Y ";
35421545Smpp	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
35561920Sjoe		/* mmm dd hh:mm || dd mmm hh:mm */
35674566Sache		format = d_first ? "%e %b %R " : "%b %e %R ";
35761814Sjoe	else
35861920Sjoe		/* mmm dd  yyyy || dd mmm  yyyy */
35974566Sache		format = d_first ? "%e %b  %Y " : "%b %e  %Y ";
36061814Sjoe	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
36161814Sjoe	fputs(longstring, stdout);
3621556Srgrimes}
3631556Srgrimes
3641556Srgrimesstatic int
36590110Simpprinttype(u_int mode)
3661556Srgrimes{
3671556Srgrimes	switch (mode & S_IFMT) {
3681556Srgrimes	case S_IFDIR:
3691556Srgrimes		(void)putchar('/');
3701556Srgrimes		return (1);
3711556Srgrimes	case S_IFIFO:
3721556Srgrimes		(void)putchar('|');
3731556Srgrimes		return (1);
3741556Srgrimes	case S_IFLNK:
3751556Srgrimes		(void)putchar('@');
3761556Srgrimes		return (1);
3771556Srgrimes	case S_IFSOCK:
3781556Srgrimes		(void)putchar('=');
3791556Srgrimes		return (1);
38020417Ssteve	case S_IFWHT:
38120417Ssteve		(void)putchar('%');
38220417Ssteve		return (1);
38390150Smarkm	default:
3841556Srgrimes	}
3851556Srgrimes	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
3861556Srgrimes		(void)putchar('*');
3871556Srgrimes		return (1);
3881556Srgrimes	}
3891556Srgrimes	return (0);
3901556Srgrimes}
3911556Srgrimes
39261268Sjoe#ifdef COLORLS
39361323Sachestatic int
39490110Simpputch(int c)
39561291Sache{
39688602Sjoe	(void)putchar(c);
39761321Sache	return 0;
39861291Sache}
39961291Sache
40061323Sachestatic int
40190110Simpwritech(int c)
40261321Sache{
40388594Sjoe	char tmp = c;
40461291Sache
40588602Sjoe	(void)write(STDOUT_FILENO, &tmp, 1);
40661321Sache	return 0;
40761321Sache}
40861321Sache
40961323Sachestatic void
41090110Simpprintcolor(Colors c)
41161178Sjoe{
41288594Sjoe	char *ansiseq;
41361268Sjoe
41488583Sjoe	if (colors[c].bold)
41588583Sjoe		tputs(enter_bold, 1, putch);
41688583Sjoe
41788583Sjoe	if (colors[c].num[0] != -1) {
41888583Sjoe		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
41961321Sache		if (ansiseq)
42061291Sache			tputs(ansiseq, 1, putch);
42161178Sjoe	}
42288583Sjoe	if (colors[c].num[1] != -1) {
42388583Sjoe		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
42461321Sache		if (ansiseq)
42561291Sache			tputs(ansiseq, 1, putch);
42661268Sjoe	}
42761178Sjoe}
42861178Sjoe
42961321Sachestatic void
43090110Simpendcolor(int sig)
43161268Sjoe{
43261321Sache	tputs(ansi_coloff, 1, sig ? writech : putch);
43388583Sjoe	tputs(attrs_off, 1, sig ? writech : putch);
43461268Sjoe}
43561268Sjoe
43661321Sachestatic int
43790110Simpcolortype(mode_t mode)
43861178Sjoe{
43988602Sjoe	switch (mode & S_IFMT) {
44088595Sjoe	case S_IFDIR:
44161178Sjoe		if (mode & S_IWOTH)
44288595Sjoe			if (mode & S_ISTXT)
44388595Sjoe				printcolor(C_WSDIR);
44488595Sjoe			else
44588595Sjoe				printcolor(C_WDIR);
44661178Sjoe		else
44788595Sjoe			printcolor(C_DIR);
44888602Sjoe		return (1);
44988595Sjoe	case S_IFLNK:
45061178Sjoe		printcolor(C_LNK);
45188602Sjoe		return (1);
45288595Sjoe	case S_IFSOCK:
45361178Sjoe		printcolor(C_SOCK);
45488602Sjoe		return (1);
45588595Sjoe	case S_IFIFO:
45661178Sjoe		printcolor(C_FIFO);
45788602Sjoe		return (1);
45888595Sjoe	case S_IFBLK:
45961178Sjoe		printcolor(C_BLK);
46088602Sjoe		return (1);
46188595Sjoe	case S_IFCHR:
46261178Sjoe		printcolor(C_CHR);
46388602Sjoe		return (1);
46461178Sjoe	}
46561178Sjoe	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
46661178Sjoe		if (mode & S_ISUID)
46788595Sjoe			printcolor(C_SUID);
46861178Sjoe		else if (mode & S_ISGID)
46988595Sjoe			printcolor(C_SGID);
47061178Sjoe		else
47188595Sjoe			printcolor(C_EXEC);
47288602Sjoe		return (1);
47361178Sjoe	}
47488602Sjoe	return (0);
47561178Sjoe}
47661178Sjoe
47761178Sjoevoid
47890110Simpparsecolors(const char *cs)
47961178Sjoe{
48088594Sjoe	int i;
48188594Sjoe	int j;
48288594Sjoe	int len;
48388594Sjoe	char c[2];
48488594Sjoe	short legacy_warn = 0;
48561321Sache
48688586Sjoe	if (cs == NULL)
48788602Sjoe		cs = "";	/* LSCOLORS not set */
48861178Sjoe	len = strlen(cs);
48988602Sjoe	for (i = 0; i < C_NUMCOLORS; i++) {
49088583Sjoe		colors[i].bold = 0;
49188583Sjoe
49288586Sjoe		if (len <= 2 * i) {
49388586Sjoe			c[0] = defcolors[2 * i];
49488586Sjoe			c[1] = defcolors[2 * i + 1];
49588602Sjoe		} else {
49688586Sjoe			c[0] = cs[2 * i];
49788586Sjoe			c[1] = cs[2 * i + 1];
49861178Sjoe		}
49988602Sjoe		for (j = 0; j < 2; j++) {
50088583Sjoe			/* Legacy colours used 0-7 */
50188583Sjoe			if (c[j] >= '0' && c[j] <= '7') {
50288583Sjoe				colors[i].num[j] = c[j] - '0';
50388583Sjoe				if (!legacy_warn) {
50488583Sjoe					fprintf(stderr,
50588668Sjoe					    "warn: LSCOLORS should use "
50688588Sjoe					    "characters a-h instead of 0-9 ("
50788588Sjoe					    "see the manual page)\n");
50888583Sjoe				}
50988583Sjoe				legacy_warn = 1;
51088583Sjoe			} else if (c[j] >= 'a' && c[j] <= 'h')
51188583Sjoe				colors[i].num[j] = c[j] - 'a';
51288583Sjoe			else if (c[j] >= 'A' && c[j] <= 'H') {
51388583Sjoe				colors[i].num[j] = c[j] - 'A';
51488583Sjoe				colors[i].bold = 1;
51588583Sjoe			} else if (tolower((unsigned char)c[j] == 'x'))
51688583Sjoe				colors[i].num[j] = -1;
51788583Sjoe			else {
51861178Sjoe				fprintf(stderr,
51988583Sjoe				    "error: invalid character '%c' in LSCOLORS"
52088583Sjoe				    " env var\n", c[j]);
52188584Sjoe				colors[i].num[j] = -1;
52261178Sjoe			}
52361178Sjoe		}
52461178Sjoe	}
52561178Sjoe}
52661291Sache
52761323Sachevoid
52890110Simpcolorquit(int sig)
52961291Sache{
53061321Sache	endcolor(sig);
53161294Sache
53288602Sjoe	(void)signal(sig, SIG_DFL);
53388602Sjoe	(void)kill(getpid(), sig);
53461291Sache}
53588602Sjoe
53688602Sjoe#endif /* COLORLS */
53788602Sjoe
5381556Srgrimesstatic void
53990110Simpprintlink(FTSENT *p)
5401556Srgrimes{
54188594Sjoe	int lnklen;
54288594Sjoe	char name[MAXPATHLEN + 1];
54388594Sjoe	char path[MAXPATHLEN + 1];
5441556Srgrimes
5451556Srgrimes	if (p->fts_level == FTS_ROOTLEVEL)
5461556Srgrimes		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
5478855Srgrimes	else
5481556Srgrimes		(void)snprintf(name, sizeof(name),
5491556Srgrimes		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
5501556Srgrimes	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
5511556Srgrimes		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
5521556Srgrimes		return;
5531556Srgrimes	}
5541556Srgrimes	path[lnklen] = '\0';
55562597Sassar	(void)printf(" -> ");
55690150Smarkm	(void)printname(path);
5571556Srgrimes}
55888591Sjoe
55988591Sjoestatic void
56090110Simpprintsize(size_t width, off_t bytes)
56188591Sjoe{
56288591Sjoe	unit_t unit;
56388602Sjoe
56488591Sjoe	if (f_humanval) {
56588591Sjoe		unit = unit_adjust(&bytes);
56688591Sjoe
56788591Sjoe		if (bytes == 0)
56888591Sjoe			(void)printf("%*s ", width, "0B");
56988591Sjoe		else
57090150Smarkm			(void)printf("%*lld%c ", width - 1, bytes,
57188602Sjoe			    "BKMGTPE"[unit]);
57288602Sjoe	} else
57390150Smarkm		(void)printf("%*lld ", width, bytes);
57488591Sjoe}
57588591Sjoe
57688591Sjoe/*
57788591Sjoe * Output in "human-readable" format.  Uses 3 digits max and puts
57888591Sjoe * unit suffixes at the end.  Makes output compact and easy to read,
57988591Sjoe * especially on huge disks.
58088591Sjoe *
58188591Sjoe */
58288591Sjoeunit_t
58390110Simpunit_adjust(off_t *val)
58488591Sjoe{
58588595Sjoe	double abval;
58688595Sjoe	unit_t unit;
58788595Sjoe	unsigned int unit_sz;
58888591Sjoe
58990150Smarkm	abval = fabs((double)*val);
59088591Sjoe
59188595Sjoe	unit_sz = abval ? ilogb(abval) / 10 : 0;
59288591Sjoe
59388595Sjoe	if (unit_sz >= UNIT_MAX) {
59488595Sjoe		unit = NONE;
59588595Sjoe	} else {
59688595Sjoe		unit = unitp[unit_sz];
59788595Sjoe		*val /= (double)vals_base2[unit_sz];
59888595Sjoe	}
59988591Sjoe
60088595Sjoe	return (unit);
60188591Sjoe}
602