print.c revision 88595
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 88595 2001-12-28 21:55:23Z joe $";
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 <time.h>
601556Srgrimes#include <unistd.h>
6161294Sache#ifdef COLORLS
6261294Sache#include <ctype.h>
6361294Sache#include <termcap.h>
6461294Sache#include <signal.h>
6561294Sache#endif
661556Srgrimes
671556Srgrimes#include "ls.h"
681556Srgrimes#include "extern.h"
691556Srgrimes
701556Srgrimesstatic int	printaname __P((FTSENT *, u_long, u_long));
711556Srgrimesstatic void	printlink __P((FTSENT *));
721556Srgrimesstatic void	printtime __P((time_t));
731556Srgrimesstatic int	printtype __P((u_int));
7488591Sjoestatic void	printsize __P((size_t, off_t));
7561321Sache#ifdef COLORLS
7688594Sjoestatic void	endcolor __P((int));
7788594Sjoestatic int	colortype __P((mode_t));
7861321Sache#endif
791556Srgrimes
801556Srgrimes#define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
8188591Sjoe#define UNITS_2 2
821556Srgrimes
8388591Sjoe#define KILO_SZ(n) (n)
8488591Sjoe#define MEGA_SZ(n) ((n) * (n))
8588591Sjoe#define GIGA_SZ(n) ((n) * (n) * (n))
8688591Sjoe#define TERA_SZ(n) ((n) * (n) * (n) * (n))
8788591Sjoe#define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n))
8888591Sjoe
8988591Sjoe#define KILO_2_SZ (KILO_SZ(1024ULL))
9088591Sjoe#define MEGA_2_SZ (MEGA_SZ(1024ULL))
9188591Sjoe#define GIGA_2_SZ (GIGA_SZ(1024ULL))
9288591Sjoe#define TERA_2_SZ (TERA_SZ(1024ULL))
9388591Sjoe#define PETA_2_SZ (PETA_SZ(1024ULL))
9488591Sjoe
9588595Sjoeunsigned long long vals_base2[] = { 1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ };
9688591Sjoe
9788591Sjoetypedef enum { NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX } unit_t;
9888595Sjoestatic unit_t unit_adjust __P((off_t *));
9988591Sjoe
10088591Sjoeint unitp [] = { NONE, KILO, MEGA, GIGA, TERA, PETA };
10188591Sjoe
10261268Sjoe#ifdef COLORLS
10361178Sjoe/* Most of these are taken from <sys/stat.h> */
10461178Sjoetypedef enum Colors {
10588586Sjoe	C_DIR,		/* directory */
10688586Sjoe	C_LNK,		/* symbolic link */
10788586Sjoe	C_SOCK,		/* socket */
10888586Sjoe	C_FIFO,		/* pipe */
10988586Sjoe	C_EXEC,		/* executable */
11088586Sjoe	C_BLK,		/* block special */
11188586Sjoe	C_CHR,		/* character special */
11288586Sjoe	C_SUID,		/* setuid executable */
11388586Sjoe	C_SGID,		/* setgid executable */
11488586Sjoe	C_WSDIR,	/* directory writeble to others, with sticky bit */
11588586Sjoe	C_WDIR,		/* directory writeble to others, without sticky bit */
11688586Sjoe	C_NUMCOLORS	/* just a place-holder */
11788586Sjoe} Colors;
11861178Sjoe
11988587Sjoeconst char *defcolors = "exfxcxdxbxegedabagacad";
12061178Sjoe
12188583Sjoe/* colors for file types */
12288583Sjoestatic struct {
12388586Sjoe	int	num[2];
12488586Sjoe	int	bold;
12588583Sjoe} colors[C_NUMCOLORS];
12688583Sjoe
12761268Sjoe#endif
12861178Sjoe
1291556Srgrimesvoid
1301556Srgrimesprintscol(dp)
13188594Sjoe	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
14762597Sassarprintname(name)
14862597Sassar	const char *name;
14962597Sassar{
15062597Sassar	if (f_octal || f_octal_escape)
15162597Sassar		return prn_octal(name);
15262597Sassar	else if (f_nonprint)
15362597Sassar		return prn_printable(name);
15462597Sassar	else
15562597Sassar		return printf("%s", name);
15662597Sassar}
15762597Sassar
1581556Srgrimesvoid
1591556Srgrimesprintlong(dp)
1601556Srgrimes	DISPLAY *dp;
1611556Srgrimes{
1621556Srgrimes	struct stat *sp;
16388594Sjoe	FTSENT *p;
16488594Sjoe	NAMES *np;
16588594Sjoe	char buf[20];
16661292Sache#ifdef COLORLS
16788594Sjoe	int color_printed = 0;
16861292Sache#endif
1691556Srgrimes
1701556Srgrimes	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
1711556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
1721556Srgrimes
1731556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1741556Srgrimes		if (IS_NOPRINT(p))
1751556Srgrimes			continue;
1761556Srgrimes		sp = p->fts_statp;
1771556Srgrimes		if (f_inode)
17820417Ssteve			(void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
1791556Srgrimes		if (f_size)
1801556Srgrimes			(void)printf("%*qd ",
1811556Srgrimes			    dp->s_block, howmany(sp->st_blocks, blocksize));
1821556Srgrimes		(void)strmode(sp->st_mode, buf);
1831556Srgrimes		np = p->fts_pointer;
1841556Srgrimes		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
1851556Srgrimes		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
1861556Srgrimes		    np->group);
1871556Srgrimes		if (f_flags)
1881556Srgrimes			(void)printf("%-*s ", dp->s_flags, np->flags);
18986922Sgreen		if (f_lomac)
19086922Sgreen			(void)printf("%-*s ", dp->s_lattr, np->lattr);
1911556Srgrimes		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
19255514Sbde			if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
19313120Sjoerg				(void)printf("%3d, 0x%08x ",
19455514Sbde				    major(sp->st_rdev),
19555514Sbde				    (u_int)minor(sp->st_rdev));
19613120Sjoerg			else
19713120Sjoerg				(void)printf("%3d, %3d ",
19813120Sjoerg				    major(sp->st_rdev), minor(sp->st_rdev));
1991556Srgrimes		else if (dp->bcfile)
2001556Srgrimes			(void)printf("%*s%*qd ",
2011556Srgrimes			    8 - dp->s_size, "", dp->s_size, sp->st_size);
2021556Srgrimes		else
20388591Sjoe			printsize(dp->s_size, sp->st_size);
2041556Srgrimes		if (f_accesstime)
2051556Srgrimes			printtime(sp->st_atime);
2061556Srgrimes		else if (f_statustime)
2071556Srgrimes			printtime(sp->st_ctime);
2081556Srgrimes		else
2091556Srgrimes			printtime(sp->st_mtime);
21061268Sjoe#ifdef COLORLS
21161178Sjoe		if (f_color)
21261291Sache			color_printed = colortype(sp->st_mode);
21361268Sjoe#endif
21462597Sassar		(void)printname(p->fts_name);
21561268Sjoe#ifdef COLORLS
21661291Sache		if (f_color && color_printed)
21761321Sache			endcolor(0);
21861268Sjoe#endif
2191556Srgrimes		if (f_type)
2201556Srgrimes			(void)printtype(sp->st_mode);
2211556Srgrimes		if (S_ISLNK(sp->st_mode))
2221556Srgrimes			printlink(p);
2231556Srgrimes		(void)putchar('\n');
2241556Srgrimes	}
2251556Srgrimes}
2261556Srgrimes
2271556Srgrimesvoid
2281556Srgrimesprintcol(dp)
22988594Sjoe	DISPLAY *dp;
2301556Srgrimes{
2311556Srgrimes	extern int termwidth;
2321556Srgrimes	static FTSENT **array;
2331556Srgrimes	static int lastentries = -1;
23488594Sjoe	FTSENT *p;
23588594Sjoe	int base;
23688594Sjoe	int chcnt;
23788594Sjoe	int cnt;
23888594Sjoe	int col;
23988594Sjoe	int colwidth;
24088594Sjoe	int endcol;
24188594Sjoe	int num;
24288594Sjoe	int numcols;
24388594Sjoe	int numrows;
24488594Sjoe	int row;
24588594Sjoe	int tabwidth;
2461556Srgrimes
24737932Shoek	if (f_notabs)
24837932Shoek		tabwidth = 1;
24937932Shoek	else
25037932Shoek		tabwidth = 8;
25137932Shoek
2521556Srgrimes	/*
2531556Srgrimes	 * Have to do random access in the linked list -- build a table
2541556Srgrimes	 * of pointers.
2551556Srgrimes	 */
2561556Srgrimes	if (dp->entries > lastentries) {
2571556Srgrimes		lastentries = dp->entries;
2581556Srgrimes		if ((array =
2591556Srgrimes		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
2601556Srgrimes			warn(NULL);
2611556Srgrimes			printscol(dp);
2621556Srgrimes		}
2631556Srgrimes	}
2641556Srgrimes	for (p = dp->list, num = 0; p; p = p->fts_link)
2651556Srgrimes		if (p->fts_number != NO_PRINT)
2661556Srgrimes			array[num++] = p;
2671556Srgrimes
2681556Srgrimes	colwidth = dp->maxlen;
2691556Srgrimes	if (f_inode)
2701556Srgrimes		colwidth += dp->s_inode + 1;
2711556Srgrimes	if (f_size)
2721556Srgrimes		colwidth += dp->s_block + 1;
2731556Srgrimes	if (f_type)
2741556Srgrimes		colwidth += 1;
2751556Srgrimes
27637932Shoek	colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
2771556Srgrimes	if (termwidth < 2 * colwidth) {
2781556Srgrimes		printscol(dp);
2791556Srgrimes		return;
2801556Srgrimes	}
2811556Srgrimes
2821556Srgrimes	numcols = termwidth / colwidth;
2831556Srgrimes	numrows = num / numcols;
2841556Srgrimes	if (num % numcols)
2851556Srgrimes		++numrows;
2861556Srgrimes
2871556Srgrimes	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
2881556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
2891556Srgrimes	for (row = 0; row < numrows; ++row) {
2901556Srgrimes		endcol = colwidth;
2911556Srgrimes		for (base = row, chcnt = col = 0; col < numcols; ++col) {
2921556Srgrimes			chcnt += printaname(array[base], dp->s_inode,
2931556Srgrimes			    dp->s_block);
2941556Srgrimes			if ((base += numrows) >= num)
2951556Srgrimes				break;
29637932Shoek			while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
29788595Sjoe			    <= endcol) {
29837932Shoek				(void)putchar(f_notabs ? ' ' : '\t');
2991556Srgrimes				chcnt = cnt;
3001556Srgrimes			}
3011556Srgrimes			endcol += colwidth;
3021556Srgrimes		}
3031556Srgrimes		(void)putchar('\n');
3041556Srgrimes	}
3051556Srgrimes}
3061556Srgrimes
3071556Srgrimes/*
3081556Srgrimes * print [inode] [size] name
3091556Srgrimes * return # of characters printed, no trailing characters.
3101556Srgrimes */
3111556Srgrimesstatic int
3121556Srgrimesprintaname(p, inodefield, sizefield)
31388594Sjoe	FTSENT *p;
31488594Sjoe	u_long inodefield;
31588594Sjoe	u_long sizefield;
3161556Srgrimes{
3171556Srgrimes	struct stat *sp;
31888594Sjoe	int chcnt;
31961292Sache#ifdef COLORLS
32088594Sjoe	int color_printed = 0;
32161292Sache#endif
3221556Srgrimes
3231556Srgrimes	sp = p->fts_statp;
3241556Srgrimes	chcnt = 0;
3251556Srgrimes	if (f_inode)
32620417Ssteve		chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
3271556Srgrimes	if (f_size)
3281556Srgrimes		chcnt += printf("%*qd ",
3291556Srgrimes		    (int)sizefield, howmany(sp->st_blocks, blocksize));
33061268Sjoe#ifdef COLORLS
33161178Sjoe	if (f_color)
33261291Sache		color_printed = colortype(sp->st_mode);
33361268Sjoe#endif
33462597Sassar	chcnt += printname(p->fts_name);
33561268Sjoe#ifdef COLORLS
33661291Sache	if (f_color && color_printed)
33761321Sache		endcolor(0);
33861268Sjoe#endif
3391556Srgrimes	if (f_type)
3401556Srgrimes		chcnt += printtype(sp->st_mode);
3411556Srgrimes	return (chcnt);
3421556Srgrimes}
3431556Srgrimes
3441556Srgrimesstatic void
3451556Srgrimesprinttime(ftime)
34688594Sjoe	time_t ftime;
3471556Srgrimes{
34888594Sjoe	char longstring[80];
34988594Sjoe	static time_t now;
35088594Sjoe	const char *format;
35188594Sjoe	static int d_first = -1;
3521556Srgrimes
35374566Sache	if (d_first < 0)
35474566Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
35521545Smpp	if (now == 0)
35621545Smpp		now = time(NULL);
35721545Smpp
3589987Swollman#define	SIXMONTHS	((365 / 2) * 86400)
3591556Srgrimes	if (f_sectime)
36061920Sjoe		/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
36174566Sache		format = d_first ? "%e %b %T %Y " : "%b %e %T %Y ";
36221545Smpp	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
36361920Sjoe		/* mmm dd hh:mm || dd mmm hh:mm */
36474566Sache		format = d_first ? "%e %b %R " : "%b %e %R ";
36561814Sjoe	else
36661920Sjoe		/* mmm dd  yyyy || dd mmm  yyyy */
36774566Sache		format = d_first ? "%e %b  %Y " : "%b %e  %Y ";
36861814Sjoe	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
36961814Sjoe	fputs(longstring, stdout);
3701556Srgrimes}
3711556Srgrimes
3721556Srgrimesstatic int
3731556Srgrimesprinttype(mode)
37488594Sjoe	u_int mode;
3751556Srgrimes{
3761556Srgrimes	switch (mode & S_IFMT) {
3771556Srgrimes	case S_IFDIR:
3781556Srgrimes		(void)putchar('/');
3791556Srgrimes		return (1);
3801556Srgrimes	case S_IFIFO:
3811556Srgrimes		(void)putchar('|');
3821556Srgrimes		return (1);
3831556Srgrimes	case S_IFLNK:
3841556Srgrimes		(void)putchar('@');
3851556Srgrimes		return (1);
3861556Srgrimes	case S_IFSOCK:
3871556Srgrimes		(void)putchar('=');
3881556Srgrimes		return (1);
38920417Ssteve	case S_IFWHT:
39020417Ssteve		(void)putchar('%');
39120417Ssteve		return (1);
3921556Srgrimes	}
3931556Srgrimes	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
3941556Srgrimes		(void)putchar('*');
3951556Srgrimes		return (1);
3961556Srgrimes	}
3971556Srgrimes	return (0);
3981556Srgrimes}
3991556Srgrimes
40061268Sjoe#ifdef COLORLS
40161323Sachestatic int
40261323Sacheputch(c)
40388594Sjoe	int c;
40461291Sache{
40561321Sache	(void) putchar(c);
40661321Sache	return 0;
40761291Sache}
40861291Sache
40961323Sachestatic int
41061323Sachewritech(c)
41188594Sjoe	int c;
41261321Sache{
41388594Sjoe	char tmp = c;
41461291Sache
41561321Sache	(void) write(STDOUT_FILENO, &tmp, 1);
41661321Sache	return 0;
41761321Sache}
41861321Sache
41961323Sachestatic void
42061178Sjoeprintcolor(c)
42188594Sjoe	Colors c;
42261178Sjoe{
42388594Sjoe	char *ansiseq;
42461268Sjoe
42588583Sjoe	if (colors[c].bold)
42688583Sjoe		tputs(enter_bold, 1, putch);
42788583Sjoe
42888583Sjoe	if (colors[c].num[0] != -1) {
42988583Sjoe		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
43061321Sache		if (ansiseq)
43161291Sache			tputs(ansiseq, 1, putch);
43261178Sjoe	}
43361268Sjoe
43488583Sjoe	if (colors[c].num[1] != -1) {
43588583Sjoe		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
43661321Sache		if (ansiseq)
43761291Sache			tputs(ansiseq, 1, putch);
43861268Sjoe	}
43961178Sjoe}
44061178Sjoe
44161321Sachestatic void
44261321Sacheendcolor(sig)
44388594Sjoe	int sig;
44461268Sjoe{
44561321Sache	tputs(ansi_coloff, 1, sig ? writech : putch);
44688583Sjoe	tputs(attrs_off, 1, sig ? writech : putch);
44761268Sjoe}
44861268Sjoe
44961321Sachestatic int
45061178Sjoecolortype(mode)
45188594Sjoe	mode_t mode;
45261178Sjoe{
45361178Sjoe	switch(mode & S_IFMT) {
45488595Sjoe	case S_IFDIR:
45561178Sjoe		if (mode & S_IWOTH)
45688595Sjoe			if (mode & S_ISTXT)
45788595Sjoe				printcolor(C_WSDIR);
45888595Sjoe			else
45988595Sjoe				printcolor(C_WDIR);
46061178Sjoe		else
46188595Sjoe			printcolor(C_DIR);
46261178Sjoe		return(1);
46388595Sjoe	case S_IFLNK:
46461178Sjoe		printcolor(C_LNK);
46561178Sjoe		return(1);
46688595Sjoe	case S_IFSOCK:
46761178Sjoe		printcolor(C_SOCK);
46861178Sjoe		return(1);
46988595Sjoe	case S_IFIFO:
47061178Sjoe		printcolor(C_FIFO);
47161178Sjoe		return(1);
47288595Sjoe	case S_IFBLK:
47361178Sjoe		printcolor(C_BLK);
47461178Sjoe		return(1);
47588595Sjoe	case S_IFCHR:
47661178Sjoe		printcolor(C_CHR);
47761178Sjoe		return(1);
47861178Sjoe	}
47961178Sjoe	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
48061178Sjoe		if (mode & S_ISUID)
48188595Sjoe			printcolor(C_SUID);
48261178Sjoe		else if (mode & S_ISGID)
48388595Sjoe			printcolor(C_SGID);
48461178Sjoe		else
48588595Sjoe			printcolor(C_EXEC);
48661178Sjoe		return(1);
48761178Sjoe	}
48861178Sjoe	return(0);
48961178Sjoe}
49061178Sjoe
49161178Sjoevoid
49261178Sjoeparsecolors(cs)
49388587Sjoe	const char *cs;
49461178Sjoe{
49588594Sjoe	int i;
49688594Sjoe	int j;
49788594Sjoe	int len;
49888594Sjoe	char c[2];
49988594Sjoe	short legacy_warn = 0;
50061321Sache
50188586Sjoe	if (cs == NULL)
50288586Sjoe		cs = ""; /* LSCOLORS not set */
50361178Sjoe	len = strlen(cs);
50461178Sjoe	for (i = 0 ; i < C_NUMCOLORS ; i++) {
50588583Sjoe		colors[i].bold = 0;
50688583Sjoe
50788586Sjoe		if (len <= 2 * i) {
50888586Sjoe			c[0] = defcolors[2 * i];
50988586Sjoe			c[1] = defcolors[2 * i + 1];
51061178Sjoe		}
51161178Sjoe		else {
51288586Sjoe			c[0] = cs[2 * i];
51388586Sjoe			c[1] = cs[2 * i + 1];
51461178Sjoe		}
51561178Sjoe		for (j = 0 ; j < 2 ; j++) {
51688583Sjoe			/* Legacy colours used 0-7 */
51788583Sjoe			if (c[j] >= '0' && c[j] <= '7') {
51888583Sjoe				colors[i].num[j] = c[j] - '0';
51988583Sjoe				if (!legacy_warn) {
52088583Sjoe					fprintf(stderr,
52188588Sjoe					    "warn: LSCOLOURS should use "
52288588Sjoe					    "characters a-h instead of 0-9 ("
52388588Sjoe					    "see the manual page)\n");
52488583Sjoe				}
52588583Sjoe				legacy_warn = 1;
52688583Sjoe			} else if (c[j] >= 'a' && c[j] <= 'h')
52788583Sjoe				colors[i].num[j] = c[j] - 'a';
52888583Sjoe			else if (c[j] >= 'A' && c[j] <= 'H') {
52988583Sjoe				colors[i].num[j] = c[j] - 'A';
53088583Sjoe				colors[i].bold = 1;
53188583Sjoe			} else if (tolower((unsigned char)c[j] == 'x'))
53288583Sjoe				colors[i].num[j] = -1;
53388583Sjoe			else {
53461178Sjoe				fprintf(stderr,
53588583Sjoe				    "error: invalid character '%c' in LSCOLORS"
53688583Sjoe				    " env var\n", c[j]);
53788584Sjoe				colors[i].num[j] = -1;
53861178Sjoe			}
53961178Sjoe		}
54061178Sjoe	}
54161178Sjoe}
54261291Sache
54361323Sachevoid
54461323Sachecolorquit(sig)
54588594Sjoe	int sig;
54661291Sache{
54761321Sache	endcolor(sig);
54861294Sache
54961294Sache	(void) signal(sig, SIG_DFL);
55061294Sache	(void) kill(getpid(), sig);
55161291Sache}
55261268Sjoe#endif /*COLORLS*/
55361178Sjoe
5541556Srgrimesstatic void
5551556Srgrimesprintlink(p)
55688594Sjoe	FTSENT *p;
5571556Srgrimes{
55888594Sjoe	int lnklen;
55988594Sjoe	char name[MAXPATHLEN + 1];
56088594Sjoe	char path[MAXPATHLEN + 1];
5611556Srgrimes
5621556Srgrimes	if (p->fts_level == FTS_ROOTLEVEL)
5631556Srgrimes		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
5648855Srgrimes	else
5651556Srgrimes		(void)snprintf(name, sizeof(name),
5661556Srgrimes		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
5671556Srgrimes	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
5681556Srgrimes		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
5691556Srgrimes		return;
5701556Srgrimes	}
5711556Srgrimes	path[lnklen] = '\0';
57262597Sassar	(void)printf(" -> ");
57362597Sassar	printname(path);
5741556Srgrimes}
57588591Sjoe
57688591Sjoestatic void
57788591Sjoeprintsize(width, bytes)
57888591Sjoe	size_t width;
57988591Sjoe	off_t bytes;
58088591Sjoe{
58188591Sjoe	unit_t unit;
58288591Sjoe
58388591Sjoe	if (f_humanval) {
58488591Sjoe		unit = unit_adjust(&bytes);
58588591Sjoe
58688591Sjoe		if (bytes == 0)
58788591Sjoe			(void)printf("%*s ", width, "0B");
58888591Sjoe		else
58988591Sjoe			(void)printf("%*qd%c ", width - 1, bytes,
59088591Sjoe				"BKMGTPE"[unit]);
59188591Sjoe	}
59288591Sjoe	else
59388591Sjoe		(void)printf("%*qd ", width, bytes);
59488591Sjoe}
59588591Sjoe
59688591Sjoe/*
59788591Sjoe * Output in "human-readable" format.  Uses 3 digits max and puts
59888591Sjoe * unit suffixes at the end.  Makes output compact and easy to read,
59988591Sjoe * especially on huge disks.
60088591Sjoe *
60188591Sjoe */
60288591Sjoeunit_t
60388591Sjoeunit_adjust(val)
60488595Sjoe	off_t *val;
60588591Sjoe{
60688595Sjoe	double abval;
60788595Sjoe	unit_t unit;
60888595Sjoe	unsigned int unit_sz;
60988591Sjoe
61088595Sjoe	abval = fabs(*val);
61188591Sjoe
61288595Sjoe	unit_sz = abval ? ilogb(abval) / 10 : 0;
61388591Sjoe
61488595Sjoe	if (unit_sz >= UNIT_MAX) {
61588595Sjoe		unit = NONE;
61688595Sjoe	} else {
61788595Sjoe		unit = unitp[unit_sz];
61888595Sjoe		*val /= (double)vals_base2[unit_sz];
61988595Sjoe	}
62088591Sjoe
62188595Sjoe	return (unit);
62288591Sjoe}
623