print.c revision 88668
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 88668 2001-12-29 10:13:43Z 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
9588602Sjoeunsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ};
9688591Sjoe
9788602Sjoetypedef enum {
9888602Sjoe	NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX
9988602Sjoe} unit_t;
10088595Sjoestatic unit_t unit_adjust __P((off_t *));
10188591Sjoe
10288602Sjoeint unitp[] = {NONE, KILO, MEGA, GIGA, TERA, PETA};
10388591Sjoe
10461268Sjoe#ifdef COLORLS
10561178Sjoe/* Most of these are taken from <sys/stat.h> */
10661178Sjoetypedef enum Colors {
10788602Sjoe	C_DIR,			/* directory */
10888602Sjoe	C_LNK,			/* symbolic link */
10988602Sjoe	C_SOCK,			/* socket */
11088602Sjoe	C_FIFO,			/* pipe */
11188602Sjoe	C_EXEC,			/* executable */
11288602Sjoe	C_BLK,			/* block special */
11388602Sjoe	C_CHR,			/* character special */
11488602Sjoe	C_SUID,			/* setuid executable */
11588602Sjoe	C_SGID,			/* setgid executable */
11688602Sjoe	C_WSDIR,		/* directory writeble to others, with sticky
11788602Sjoe				 * bit */
11888602Sjoe	C_WDIR,			/* directory writeble to others, without
11988602Sjoe				 * sticky bit */
12088602Sjoe	C_NUMCOLORS		/* just a place-holder */
12188586Sjoe} Colors;
12261178Sjoe
12388587Sjoeconst char *defcolors = "exfxcxdxbxegedabagacad";
12461178Sjoe
12588583Sjoe/* colors for file types */
12688583Sjoestatic struct {
12788586Sjoe	int	num[2];
12888586Sjoe	int	bold;
12988583Sjoe} colors[C_NUMCOLORS];
13061268Sjoe#endif
13161178Sjoe
1321556Srgrimesvoid
1331556Srgrimesprintscol(dp)
13488594Sjoe	DISPLAY *dp;
1351556Srgrimes{
13688594Sjoe	FTSENT *p;
1371556Srgrimes
1381556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1391556Srgrimes		if (IS_NOPRINT(p))
1401556Srgrimes			continue;
1411556Srgrimes		(void)printaname(p, dp->s_inode, dp->s_block);
1421556Srgrimes		(void)putchar('\n');
1431556Srgrimes	}
1441556Srgrimes}
1451556Srgrimes
14662597Sassar/*
14762597Sassar * print name in current style
14862597Sassar */
14962597Sassarstatic int
15062597Sassarprintname(name)
15162597Sassar	const char *name;
15262597Sassar{
15362597Sassar	if (f_octal || f_octal_escape)
15462597Sassar		return prn_octal(name);
15562597Sassar	else if (f_nonprint)
15662597Sassar		return prn_printable(name);
15762597Sassar	else
15862597Sassar		return printf("%s", name);
15962597Sassar}
16062597Sassar
1611556Srgrimesvoid
1621556Srgrimesprintlong(dp)
1631556Srgrimes	DISPLAY *dp;
1641556Srgrimes{
1651556Srgrimes	struct stat *sp;
16688594Sjoe	FTSENT *p;
16788594Sjoe	NAMES *np;
16888594Sjoe	char buf[20];
16961292Sache#ifdef COLORLS
17088594Sjoe	int color_printed = 0;
17161292Sache#endif
1721556Srgrimes
1731556Srgrimes	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
1741556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
1751556Srgrimes
1761556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1771556Srgrimes		if (IS_NOPRINT(p))
1781556Srgrimes			continue;
1791556Srgrimes		sp = p->fts_statp;
1801556Srgrimes		if (f_inode)
18120417Ssteve			(void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
1821556Srgrimes		if (f_size)
1831556Srgrimes			(void)printf("%*qd ",
1841556Srgrimes			    dp->s_block, howmany(sp->st_blocks, blocksize));
1851556Srgrimes		(void)strmode(sp->st_mode, buf);
1861556Srgrimes		np = p->fts_pointer;
1871556Srgrimes		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
1881556Srgrimes		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
1891556Srgrimes		    np->group);
1901556Srgrimes		if (f_flags)
1911556Srgrimes			(void)printf("%-*s ", dp->s_flags, np->flags);
19286922Sgreen		if (f_lomac)
19386922Sgreen			(void)printf("%-*s ", dp->s_lattr, np->lattr);
1941556Srgrimes		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
19555514Sbde			if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
19613120Sjoerg				(void)printf("%3d, 0x%08x ",
19755514Sbde				    major(sp->st_rdev),
19855514Sbde				    (u_int)minor(sp->st_rdev));
19913120Sjoerg			else
20013120Sjoerg				(void)printf("%3d, %3d ",
20113120Sjoerg				    major(sp->st_rdev), minor(sp->st_rdev));
2021556Srgrimes		else if (dp->bcfile)
2031556Srgrimes			(void)printf("%*s%*qd ",
2041556Srgrimes			    8 - dp->s_size, "", dp->s_size, sp->st_size);
2051556Srgrimes		else
20688591Sjoe			printsize(dp->s_size, sp->st_size);
2071556Srgrimes		if (f_accesstime)
2081556Srgrimes			printtime(sp->st_atime);
2091556Srgrimes		else if (f_statustime)
2101556Srgrimes			printtime(sp->st_ctime);
2111556Srgrimes		else
2121556Srgrimes			printtime(sp->st_mtime);
21361268Sjoe#ifdef COLORLS
21461178Sjoe		if (f_color)
21561291Sache			color_printed = colortype(sp->st_mode);
21661268Sjoe#endif
21762597Sassar		(void)printname(p->fts_name);
21861268Sjoe#ifdef COLORLS
21961291Sache		if (f_color && color_printed)
22061321Sache			endcolor(0);
22161268Sjoe#endif
2221556Srgrimes		if (f_type)
2231556Srgrimes			(void)printtype(sp->st_mode);
2241556Srgrimes		if (S_ISLNK(sp->st_mode))
2251556Srgrimes			printlink(p);
2261556Srgrimes		(void)putchar('\n');
2271556Srgrimes	}
2281556Srgrimes}
2291556Srgrimes
2301556Srgrimesvoid
2311556Srgrimesprintcol(dp)
23288594Sjoe	DISPLAY *dp;
2331556Srgrimes{
2341556Srgrimes	extern int termwidth;
2351556Srgrimes	static FTSENT **array;
2361556Srgrimes	static int lastentries = -1;
23788594Sjoe	FTSENT *p;
23888594Sjoe	int base;
23988594Sjoe	int chcnt;
24088594Sjoe	int cnt;
24188594Sjoe	int col;
24288594Sjoe	int colwidth;
24388594Sjoe	int endcol;
24488594Sjoe	int num;
24588594Sjoe	int numcols;
24688594Sjoe	int numrows;
24788594Sjoe	int row;
24888594Sjoe	int tabwidth;
2491556Srgrimes
25037932Shoek	if (f_notabs)
25137932Shoek		tabwidth = 1;
25237932Shoek	else
25337932Shoek		tabwidth = 8;
25437932Shoek
2551556Srgrimes	/*
2561556Srgrimes	 * Have to do random access in the linked list -- build a table
2571556Srgrimes	 * of pointers.
2581556Srgrimes	 */
2591556Srgrimes	if (dp->entries > lastentries) {
2601556Srgrimes		lastentries = dp->entries;
2611556Srgrimes		if ((array =
2621556Srgrimes		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
2631556Srgrimes			warn(NULL);
2641556Srgrimes			printscol(dp);
2651556Srgrimes		}
2661556Srgrimes	}
2671556Srgrimes	for (p = dp->list, num = 0; p; p = p->fts_link)
2681556Srgrimes		if (p->fts_number != NO_PRINT)
2691556Srgrimes			array[num++] = p;
2701556Srgrimes
2711556Srgrimes	colwidth = dp->maxlen;
2721556Srgrimes	if (f_inode)
2731556Srgrimes		colwidth += dp->s_inode + 1;
2741556Srgrimes	if (f_size)
2751556Srgrimes		colwidth += dp->s_block + 1;
2761556Srgrimes	if (f_type)
2771556Srgrimes		colwidth += 1;
2781556Srgrimes
27937932Shoek	colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
2801556Srgrimes	if (termwidth < 2 * colwidth) {
2811556Srgrimes		printscol(dp);
2821556Srgrimes		return;
2831556Srgrimes	}
2841556Srgrimes	numcols = termwidth / colwidth;
2851556Srgrimes	numrows = num / numcols;
2861556Srgrimes	if (num % numcols)
2871556Srgrimes		++numrows;
2881556Srgrimes
2891556Srgrimes	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
2901556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
2911556Srgrimes	for (row = 0; row < numrows; ++row) {
2921556Srgrimes		endcol = colwidth;
2931556Srgrimes		for (base = row, chcnt = col = 0; col < numcols; ++col) {
2941556Srgrimes			chcnt += printaname(array[base], dp->s_inode,
2951556Srgrimes			    dp->s_block);
2961556Srgrimes			if ((base += numrows) >= num)
2971556Srgrimes				break;
29837932Shoek			while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
29988595Sjoe			    <= endcol) {
30037932Shoek				(void)putchar(f_notabs ? ' ' : '\t');
3011556Srgrimes				chcnt = cnt;
3021556Srgrimes			}
3031556Srgrimes			endcol += colwidth;
3041556Srgrimes		}
3051556Srgrimes		(void)putchar('\n');
3061556Srgrimes	}
3071556Srgrimes}
3081556Srgrimes
3091556Srgrimes/*
3101556Srgrimes * print [inode] [size] name
3111556Srgrimes * return # of characters printed, no trailing characters.
3121556Srgrimes */
3131556Srgrimesstatic int
3141556Srgrimesprintaname(p, inodefield, sizefield)
31588594Sjoe	FTSENT *p;
31688594Sjoe	u_long inodefield;
31788594Sjoe	u_long sizefield;
3181556Srgrimes{
3191556Srgrimes	struct stat *sp;
32088594Sjoe	int chcnt;
32161292Sache#ifdef COLORLS
32288594Sjoe	int color_printed = 0;
32361292Sache#endif
3241556Srgrimes
3251556Srgrimes	sp = p->fts_statp;
3261556Srgrimes	chcnt = 0;
3271556Srgrimes	if (f_inode)
32820417Ssteve		chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
3291556Srgrimes	if (f_size)
3301556Srgrimes		chcnt += printf("%*qd ",
3311556Srgrimes		    (int)sizefield, howmany(sp->st_blocks, blocksize));
33261268Sjoe#ifdef COLORLS
33361178Sjoe	if (f_color)
33461291Sache		color_printed = colortype(sp->st_mode);
33561268Sjoe#endif
33662597Sassar	chcnt += printname(p->fts_name);
33761268Sjoe#ifdef COLORLS
33861291Sache	if (f_color && color_printed)
33961321Sache		endcolor(0);
34061268Sjoe#endif
3411556Srgrimes	if (f_type)
3421556Srgrimes		chcnt += printtype(sp->st_mode);
3431556Srgrimes	return (chcnt);
3441556Srgrimes}
3451556Srgrimes
3461556Srgrimesstatic void
3471556Srgrimesprinttime(ftime)
34888594Sjoe	time_t ftime;
3491556Srgrimes{
35088594Sjoe	char longstring[80];
35188594Sjoe	static time_t now;
35288594Sjoe	const char *format;
35388594Sjoe	static int d_first = -1;
3541556Srgrimes
35574566Sache	if (d_first < 0)
35674566Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
35721545Smpp	if (now == 0)
35821545Smpp		now = time(NULL);
35921545Smpp
3609987Swollman#define	SIXMONTHS	((365 / 2) * 86400)
3611556Srgrimes	if (f_sectime)
36261920Sjoe		/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
36374566Sache		format = d_first ? "%e %b %T %Y " : "%b %e %T %Y ";
36421545Smpp	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
36561920Sjoe		/* mmm dd hh:mm || dd mmm hh:mm */
36674566Sache		format = d_first ? "%e %b %R " : "%b %e %R ";
36761814Sjoe	else
36861920Sjoe		/* mmm dd  yyyy || dd mmm  yyyy */
36974566Sache		format = d_first ? "%e %b  %Y " : "%b %e  %Y ";
37061814Sjoe	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
37161814Sjoe	fputs(longstring, stdout);
3721556Srgrimes}
3731556Srgrimes
3741556Srgrimesstatic int
3751556Srgrimesprinttype(mode)
37688594Sjoe	u_int mode;
3771556Srgrimes{
3781556Srgrimes	switch (mode & S_IFMT) {
3791556Srgrimes	case S_IFDIR:
3801556Srgrimes		(void)putchar('/');
3811556Srgrimes		return (1);
3821556Srgrimes	case S_IFIFO:
3831556Srgrimes		(void)putchar('|');
3841556Srgrimes		return (1);
3851556Srgrimes	case S_IFLNK:
3861556Srgrimes		(void)putchar('@');
3871556Srgrimes		return (1);
3881556Srgrimes	case S_IFSOCK:
3891556Srgrimes		(void)putchar('=');
3901556Srgrimes		return (1);
39120417Ssteve	case S_IFWHT:
39220417Ssteve		(void)putchar('%');
39320417Ssteve		return (1);
3941556Srgrimes	}
3951556Srgrimes	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
3961556Srgrimes		(void)putchar('*');
3971556Srgrimes		return (1);
3981556Srgrimes	}
3991556Srgrimes	return (0);
4001556Srgrimes}
4011556Srgrimes
40261268Sjoe#ifdef COLORLS
40361323Sachestatic int
40461323Sacheputch(c)
40588594Sjoe	int c;
40661291Sache{
40788602Sjoe	(void)putchar(c);
40861321Sache	return 0;
40961291Sache}
41061291Sache
41161323Sachestatic int
41261323Sachewritech(c)
41388594Sjoe	int c;
41461321Sache{
41588594Sjoe	char tmp = c;
41661291Sache
41788602Sjoe	(void)write(STDOUT_FILENO, &tmp, 1);
41861321Sache	return 0;
41961321Sache}
42061321Sache
42161323Sachestatic void
42261178Sjoeprintcolor(c)
42388594Sjoe	Colors c;
42461178Sjoe{
42588594Sjoe	char *ansiseq;
42661268Sjoe
42788583Sjoe	if (colors[c].bold)
42888583Sjoe		tputs(enter_bold, 1, putch);
42988583Sjoe
43088583Sjoe	if (colors[c].num[0] != -1) {
43188583Sjoe		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
43261321Sache		if (ansiseq)
43361291Sache			tputs(ansiseq, 1, putch);
43461178Sjoe	}
43588583Sjoe	if (colors[c].num[1] != -1) {
43688583Sjoe		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
43761321Sache		if (ansiseq)
43861291Sache			tputs(ansiseq, 1, putch);
43961268Sjoe	}
44061178Sjoe}
44161178Sjoe
44261321Sachestatic void
44361321Sacheendcolor(sig)
44488594Sjoe	int sig;
44561268Sjoe{
44661321Sache	tputs(ansi_coloff, 1, sig ? writech : putch);
44788583Sjoe	tputs(attrs_off, 1, sig ? writech : putch);
44861268Sjoe}
44961268Sjoe
45061321Sachestatic int
45161178Sjoecolortype(mode)
45288594Sjoe	mode_t mode;
45361178Sjoe{
45488602Sjoe	switch (mode & S_IFMT) {
45588595Sjoe	case S_IFDIR:
45661178Sjoe		if (mode & S_IWOTH)
45788595Sjoe			if (mode & S_ISTXT)
45888595Sjoe				printcolor(C_WSDIR);
45988595Sjoe			else
46088595Sjoe				printcolor(C_WDIR);
46161178Sjoe		else
46288595Sjoe			printcolor(C_DIR);
46388602Sjoe		return (1);
46488595Sjoe	case S_IFLNK:
46561178Sjoe		printcolor(C_LNK);
46688602Sjoe		return (1);
46788595Sjoe	case S_IFSOCK:
46861178Sjoe		printcolor(C_SOCK);
46988602Sjoe		return (1);
47088595Sjoe	case S_IFIFO:
47161178Sjoe		printcolor(C_FIFO);
47288602Sjoe		return (1);
47388595Sjoe	case S_IFBLK:
47461178Sjoe		printcolor(C_BLK);
47588602Sjoe		return (1);
47688595Sjoe	case S_IFCHR:
47761178Sjoe		printcolor(C_CHR);
47888602Sjoe		return (1);
47961178Sjoe	}
48061178Sjoe	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
48161178Sjoe		if (mode & S_ISUID)
48288595Sjoe			printcolor(C_SUID);
48361178Sjoe		else if (mode & S_ISGID)
48488595Sjoe			printcolor(C_SGID);
48561178Sjoe		else
48688595Sjoe			printcolor(C_EXEC);
48788602Sjoe		return (1);
48861178Sjoe	}
48988602Sjoe	return (0);
49061178Sjoe}
49161178Sjoe
49261178Sjoevoid
49361178Sjoeparsecolors(cs)
49488587Sjoe	const char *cs;
49561178Sjoe{
49688594Sjoe	int i;
49788594Sjoe	int j;
49888594Sjoe	int len;
49988594Sjoe	char c[2];
50088594Sjoe	short legacy_warn = 0;
50161321Sache
50288586Sjoe	if (cs == NULL)
50388602Sjoe		cs = "";	/* LSCOLORS not set */
50461178Sjoe	len = strlen(cs);
50588602Sjoe	for (i = 0; i < C_NUMCOLORS; i++) {
50688583Sjoe		colors[i].bold = 0;
50788583Sjoe
50888586Sjoe		if (len <= 2 * i) {
50988586Sjoe			c[0] = defcolors[2 * i];
51088586Sjoe			c[1] = defcolors[2 * i + 1];
51188602Sjoe		} else {
51288586Sjoe			c[0] = cs[2 * i];
51388586Sjoe			c[1] = cs[2 * i + 1];
51461178Sjoe		}
51588602Sjoe		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,
52188668Sjoe					    "warn: LSCOLORS 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
54988602Sjoe	(void)signal(sig, SIG_DFL);
55088602Sjoe	(void)kill(getpid(), sig);
55161291Sache}
55288602Sjoe
55388602Sjoe#endif /* COLORLS */
55488602Sjoe
5551556Srgrimesstatic void
5561556Srgrimesprintlink(p)
55788594Sjoe	FTSENT *p;
5581556Srgrimes{
55988594Sjoe	int lnklen;
56088594Sjoe	char name[MAXPATHLEN + 1];
56188594Sjoe	char path[MAXPATHLEN + 1];
5621556Srgrimes
5631556Srgrimes	if (p->fts_level == FTS_ROOTLEVEL)
5641556Srgrimes		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
5658855Srgrimes	else
5661556Srgrimes		(void)snprintf(name, sizeof(name),
5671556Srgrimes		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
5681556Srgrimes	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
5691556Srgrimes		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
5701556Srgrimes		return;
5711556Srgrimes	}
5721556Srgrimes	path[lnklen] = '\0';
57362597Sassar	(void)printf(" -> ");
57462597Sassar	printname(path);
5751556Srgrimes}
57688591Sjoe
57788591Sjoestatic void
57888591Sjoeprintsize(width, bytes)
57988591Sjoe	size_t width;
58088591Sjoe	off_t bytes;
58188591Sjoe{
58288591Sjoe	unit_t unit;
58388602Sjoe
58488591Sjoe	if (f_humanval) {
58588591Sjoe		unit = unit_adjust(&bytes);
58688591Sjoe
58788591Sjoe		if (bytes == 0)
58888591Sjoe			(void)printf("%*s ", width, "0B");
58988591Sjoe		else
59088602Sjoe			(void)printf("%*qd%c ", width - 1, bytes,
59188602Sjoe			    "BKMGTPE"[unit]);
59288602Sjoe	} 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