print.c revision 88587
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 88587 2001-12-28 19:26:06Z 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>
5374566Sache#include <langinfo.h>
541556Srgrimes#include <pwd.h>
551556Srgrimes#include <stdio.h>
561556Srgrimes#include <stdlib.h>
571556Srgrimes#include <string.h>
581556Srgrimes#include <time.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
691556Srgrimesstatic int	printaname __P((FTSENT *, u_long, u_long));
701556Srgrimesstatic void	printlink __P((FTSENT *));
711556Srgrimesstatic void	printtime __P((time_t));
721556Srgrimesstatic int	printtype __P((u_int));
7361321Sache#ifdef COLORLS
7461321Sachestatic void     endcolor __P((int));
7561321Sachestatic int      colortype __P((mode_t));
7661321Sache#endif
771556Srgrimes
781556Srgrimes#define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
791556Srgrimes
8061268Sjoe#ifdef COLORLS
8161178Sjoe/* Most of these are taken from <sys/stat.h> */
8261178Sjoetypedef enum Colors {
8388586Sjoe	C_DIR,		/* directory */
8488586Sjoe	C_LNK,		/* symbolic link */
8588586Sjoe	C_SOCK,		/* socket */
8688586Sjoe	C_FIFO,		/* pipe */
8788586Sjoe	C_EXEC,		/* executable */
8888586Sjoe	C_BLK,		/* block special */
8988586Sjoe	C_CHR,		/* character special */
9088586Sjoe	C_SUID,		/* setuid executable */
9188586Sjoe	C_SGID,		/* setgid executable */
9288586Sjoe	C_WSDIR,	/* directory writeble to others, with sticky bit */
9388586Sjoe	C_WDIR,		/* directory writeble to others, without sticky bit */
9488586Sjoe	C_NUMCOLORS	/* just a place-holder */
9588586Sjoe} Colors;
9661178Sjoe
9788587Sjoeconst char *defcolors = "exfxcxdxbxegedabagacad";
9861178Sjoe
9988583Sjoe/* colors for file types */
10088583Sjoestatic struct {
10188586Sjoe	int	num[2];
10288586Sjoe	int	bold;
10388583Sjoe} colors[C_NUMCOLORS];
10488583Sjoe
10561268Sjoe#endif
10661178Sjoe
1071556Srgrimesvoid
1081556Srgrimesprintscol(dp)
10988586Sjoe	DISPLAY	*dp;
1101556Srgrimes{
11188586Sjoe	FTSENT	*p;
1121556Srgrimes
1131556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1141556Srgrimes		if (IS_NOPRINT(p))
1151556Srgrimes			continue;
1161556Srgrimes		(void)printaname(p, dp->s_inode, dp->s_block);
1171556Srgrimes		(void)putchar('\n');
1181556Srgrimes	}
1191556Srgrimes}
1201556Srgrimes
12162597Sassar/*
12262597Sassar * print name in current style
12362597Sassar */
12462597Sassarstatic int
12562597Sassarprintname(name)
12662597Sassar	const char *name;
12762597Sassar{
12862597Sassar	if (f_octal || f_octal_escape)
12962597Sassar		return prn_octal(name);
13062597Sassar	else if (f_nonprint)
13162597Sassar		return prn_printable(name);
13262597Sassar	else
13362597Sassar		return printf("%s", name);
13462597Sassar}
13562597Sassar
1361556Srgrimesvoid
1371556Srgrimesprintlong(dp)
1381556Srgrimes	DISPLAY *dp;
1391556Srgrimes{
1401556Srgrimes	struct stat *sp;
14188586Sjoe	FTSENT	*p;
14288586Sjoe	NAMES	*np;
14388586Sjoe	char	buf[20];
14461292Sache#ifdef COLORLS
14588586Sjoe	int	color_printed = 0;
14661292Sache#endif
1471556Srgrimes
1481556Srgrimes	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
1491556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
1501556Srgrimes
1511556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1521556Srgrimes		if (IS_NOPRINT(p))
1531556Srgrimes			continue;
1541556Srgrimes		sp = p->fts_statp;
1551556Srgrimes		if (f_inode)
15620417Ssteve			(void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
1571556Srgrimes		if (f_size)
1581556Srgrimes			(void)printf("%*qd ",
1591556Srgrimes			    dp->s_block, howmany(sp->st_blocks, blocksize));
1601556Srgrimes		(void)strmode(sp->st_mode, buf);
1611556Srgrimes		np = p->fts_pointer;
1621556Srgrimes		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
1631556Srgrimes		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
1641556Srgrimes		    np->group);
1651556Srgrimes		if (f_flags)
1661556Srgrimes			(void)printf("%-*s ", dp->s_flags, np->flags);
16786922Sgreen		if (f_lomac)
16886922Sgreen			(void)printf("%-*s ", dp->s_lattr, np->lattr);
1691556Srgrimes		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
17055514Sbde			if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
17113120Sjoerg				(void)printf("%3d, 0x%08x ",
17255514Sbde				    major(sp->st_rdev),
17355514Sbde				    (u_int)minor(sp->st_rdev));
17413120Sjoerg			else
17513120Sjoerg				(void)printf("%3d, %3d ",
17613120Sjoerg				    major(sp->st_rdev), minor(sp->st_rdev));
1771556Srgrimes		else if (dp->bcfile)
1781556Srgrimes			(void)printf("%*s%*qd ",
1791556Srgrimes			    8 - dp->s_size, "", dp->s_size, sp->st_size);
1801556Srgrimes		else
1811556Srgrimes			(void)printf("%*qd ", dp->s_size, sp->st_size);
1821556Srgrimes		if (f_accesstime)
1831556Srgrimes			printtime(sp->st_atime);
1841556Srgrimes		else if (f_statustime)
1851556Srgrimes			printtime(sp->st_ctime);
1861556Srgrimes		else
1871556Srgrimes			printtime(sp->st_mtime);
18861268Sjoe#ifdef COLORLS
18961178Sjoe		if (f_color)
19061291Sache			color_printed = colortype(sp->st_mode);
19161268Sjoe#endif
19262597Sassar		(void)printname(p->fts_name);
19361268Sjoe#ifdef COLORLS
19461291Sache		if (f_color && color_printed)
19561321Sache			endcolor(0);
19661268Sjoe#endif
1971556Srgrimes		if (f_type)
1981556Srgrimes			(void)printtype(sp->st_mode);
1991556Srgrimes		if (S_ISLNK(sp->st_mode))
2001556Srgrimes			printlink(p);
2011556Srgrimes		(void)putchar('\n');
2021556Srgrimes	}
2031556Srgrimes}
2041556Srgrimes
2051556Srgrimesvoid
2061556Srgrimesprintcol(dp)
20788586Sjoe	DISPLAY	*dp;
2081556Srgrimes{
2091556Srgrimes	extern int termwidth;
2101556Srgrimes	static FTSENT **array;
2111556Srgrimes	static int lastentries = -1;
21288586Sjoe	FTSENT	*p;
21388586Sjoe	int	base;
21488586Sjoe	int	chcnt;
21588586Sjoe	int	cnt;
21688586Sjoe	int	col;
21788586Sjoe	int	colwidth;
21888586Sjoe	int	endcol;
21988586Sjoe	int	num;
22088586Sjoe	int	numcols;
22188586Sjoe	int	numrows;
22288586Sjoe	int	row;
22388586Sjoe	int	tabwidth;
2241556Srgrimes
22537932Shoek	if (f_notabs)
22637932Shoek		tabwidth = 1;
22737932Shoek	else
22837932Shoek		tabwidth = 8;
22937932Shoek
2301556Srgrimes	/*
2311556Srgrimes	 * Have to do random access in the linked list -- build a table
2321556Srgrimes	 * of pointers.
2331556Srgrimes	 */
2341556Srgrimes	if (dp->entries > lastentries) {
2351556Srgrimes		lastentries = dp->entries;
2361556Srgrimes		if ((array =
2371556Srgrimes		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
2381556Srgrimes			warn(NULL);
2391556Srgrimes			printscol(dp);
2401556Srgrimes		}
2411556Srgrimes	}
2421556Srgrimes	for (p = dp->list, num = 0; p; p = p->fts_link)
2431556Srgrimes		if (p->fts_number != NO_PRINT)
2441556Srgrimes			array[num++] = p;
2451556Srgrimes
2461556Srgrimes	colwidth = dp->maxlen;
2471556Srgrimes	if (f_inode)
2481556Srgrimes		colwidth += dp->s_inode + 1;
2491556Srgrimes	if (f_size)
2501556Srgrimes		colwidth += dp->s_block + 1;
2511556Srgrimes	if (f_type)
2521556Srgrimes		colwidth += 1;
2531556Srgrimes
25437932Shoek	colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
2551556Srgrimes	if (termwidth < 2 * colwidth) {
2561556Srgrimes		printscol(dp);
2571556Srgrimes		return;
2581556Srgrimes	}
2591556Srgrimes
2601556Srgrimes	numcols = termwidth / colwidth;
2611556Srgrimes	numrows = num / numcols;
2621556Srgrimes	if (num % numcols)
2631556Srgrimes		++numrows;
2641556Srgrimes
2651556Srgrimes	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
2661556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
2671556Srgrimes	for (row = 0; row < numrows; ++row) {
2681556Srgrimes		endcol = colwidth;
2691556Srgrimes		for (base = row, chcnt = col = 0; col < numcols; ++col) {
2701556Srgrimes			chcnt += printaname(array[base], dp->s_inode,
2711556Srgrimes			    dp->s_block);
2721556Srgrimes			if ((base += numrows) >= num)
2731556Srgrimes				break;
27437932Shoek			while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
27537932Shoek			    <= endcol){
27637932Shoek				(void)putchar(f_notabs ? ' ' : '\t');
2771556Srgrimes				chcnt = cnt;
2781556Srgrimes			}
2791556Srgrimes			endcol += colwidth;
2801556Srgrimes		}
2811556Srgrimes		(void)putchar('\n');
2821556Srgrimes	}
2831556Srgrimes}
2841556Srgrimes
2851556Srgrimes/*
2861556Srgrimes * print [inode] [size] name
2871556Srgrimes * return # of characters printed, no trailing characters.
2881556Srgrimes */
2891556Srgrimesstatic int
2901556Srgrimesprintaname(p, inodefield, sizefield)
29188586Sjoe	FTSENT	*p;
29288586Sjoe	u_long	inodefield;
29388586Sjoe	u_long	sizefield;
2941556Srgrimes{
2951556Srgrimes	struct stat *sp;
29688586Sjoe	int	chcnt;
29761292Sache#ifdef COLORLS
29888586Sjoe	int	color_printed = 0;
29961292Sache#endif
3001556Srgrimes
3011556Srgrimes	sp = p->fts_statp;
3021556Srgrimes	chcnt = 0;
3031556Srgrimes	if (f_inode)
30420417Ssteve		chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
3051556Srgrimes	if (f_size)
3061556Srgrimes		chcnt += printf("%*qd ",
3071556Srgrimes		    (int)sizefield, howmany(sp->st_blocks, blocksize));
30861268Sjoe#ifdef COLORLS
30961178Sjoe	if (f_color)
31061291Sache		color_printed = colortype(sp->st_mode);
31161268Sjoe#endif
31262597Sassar	chcnt += printname(p->fts_name);
31361268Sjoe#ifdef COLORLS
31461291Sache	if (f_color && color_printed)
31561321Sache		endcolor(0);
31661268Sjoe#endif
3171556Srgrimes	if (f_type)
3181556Srgrimes		chcnt += printtype(sp->st_mode);
3191556Srgrimes	return (chcnt);
3201556Srgrimes}
3211556Srgrimes
3221556Srgrimesstatic void
3231556Srgrimesprinttime(ftime)
32488586Sjoe	time_t	ftime;
3251556Srgrimes{
32688586Sjoe	char		longstring[80];
32788586Sjoe	static time_t	now;
32888586Sjoe	const char	*format;
32988586Sjoe	static int	d_first = -1;
3301556Srgrimes
33174566Sache	if (d_first < 0)
33274566Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
33321545Smpp	if (now == 0)
33421545Smpp		now = time(NULL);
33521545Smpp
3369987Swollman#define	SIXMONTHS	((365 / 2) * 86400)
3371556Srgrimes	if (f_sectime)
33861920Sjoe		/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
33974566Sache		format = d_first ? "%e %b %T %Y " : "%b %e %T %Y ";
34021545Smpp	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
34161920Sjoe		/* mmm dd hh:mm || dd mmm hh:mm */
34274566Sache		format = d_first ? "%e %b %R " : "%b %e %R ";
34361814Sjoe	else
34461920Sjoe		/* mmm dd  yyyy || dd mmm  yyyy */
34574566Sache		format = d_first ? "%e %b  %Y " : "%b %e  %Y ";
34661814Sjoe	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
34761814Sjoe	fputs(longstring, stdout);
3481556Srgrimes}
3491556Srgrimes
3501556Srgrimesstatic int
3511556Srgrimesprinttype(mode)
35288586Sjoe	u_int	mode;
3531556Srgrimes{
3541556Srgrimes	switch (mode & S_IFMT) {
3551556Srgrimes	case S_IFDIR:
3561556Srgrimes		(void)putchar('/');
3571556Srgrimes		return (1);
3581556Srgrimes	case S_IFIFO:
3591556Srgrimes		(void)putchar('|');
3601556Srgrimes		return (1);
3611556Srgrimes	case S_IFLNK:
3621556Srgrimes		(void)putchar('@');
3631556Srgrimes		return (1);
3641556Srgrimes	case S_IFSOCK:
3651556Srgrimes		(void)putchar('=');
3661556Srgrimes		return (1);
36720417Ssteve	case S_IFWHT:
36820417Ssteve		(void)putchar('%');
36920417Ssteve		return (1);
3701556Srgrimes	}
3711556Srgrimes	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
3721556Srgrimes		(void)putchar('*');
3731556Srgrimes		return (1);
3741556Srgrimes	}
3751556Srgrimes	return (0);
3761556Srgrimes}
3771556Srgrimes
37861268Sjoe#ifdef COLORLS
37961323Sachestatic int
38061323Sacheputch(c)
38188586Sjoe	int	c;
38261291Sache{
38361321Sache	(void) putchar(c);
38461321Sache	return 0;
38561291Sache}
38661291Sache
38761323Sachestatic int
38861323Sachewritech(c)
38988586Sjoe	int	c;
39061321Sache{
39188586Sjoe	char	tmp = c;
39261291Sache
39361321Sache	(void) write(STDOUT_FILENO, &tmp, 1);
39461321Sache	return 0;
39561321Sache}
39661321Sache
39761323Sachestatic void
39861178Sjoeprintcolor(c)
39988586Sjoe	Colors	c;
40061178Sjoe{
40188586Sjoe	char	*ansiseq;
40261268Sjoe
40388583Sjoe	if (colors[c].bold)
40488583Sjoe		tputs(enter_bold, 1, putch);
40588583Sjoe
40688583Sjoe	if (colors[c].num[0] != -1) {
40788583Sjoe		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
40861321Sache		if (ansiseq)
40961291Sache			tputs(ansiseq, 1, putch);
41061178Sjoe	}
41161268Sjoe
41288583Sjoe	if (colors[c].num[1] != -1) {
41388583Sjoe		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
41461321Sache		if (ansiseq)
41561291Sache			tputs(ansiseq, 1, putch);
41661268Sjoe	}
41761178Sjoe}
41861178Sjoe
41961321Sachestatic void
42061321Sacheendcolor(sig)
42188586Sjoe	int	sig;
42261268Sjoe{
42361321Sache	tputs(ansi_coloff, 1, sig ? writech : putch);
42488583Sjoe	tputs(attrs_off, 1, sig ? writech : putch);
42561268Sjoe}
42661268Sjoe
42761321Sachestatic int
42861178Sjoecolortype(mode)
42988586Sjoe	mode_t	mode;
43061178Sjoe{
43161178Sjoe	switch(mode & S_IFMT) {
43261178Sjoe	      case S_IFDIR:
43361178Sjoe		if (mode & S_IWOTH)
43461178Sjoe		    if (mode & S_ISTXT)
43561178Sjoe			printcolor(C_WSDIR);
43661178Sjoe		    else
43761178Sjoe			printcolor(C_WDIR);
43861178Sjoe		else
43961178Sjoe		    printcolor(C_DIR);
44061178Sjoe		return(1);
44161178Sjoe	      case S_IFLNK:
44261178Sjoe		printcolor(C_LNK);
44361178Sjoe		return(1);
44461178Sjoe	      case S_IFSOCK:
44561178Sjoe		printcolor(C_SOCK);
44661178Sjoe		return(1);
44761178Sjoe	      case S_IFIFO:
44861178Sjoe		printcolor(C_FIFO);
44961178Sjoe		return(1);
45061178Sjoe	      case S_IFBLK:
45161178Sjoe		printcolor(C_BLK);
45261178Sjoe		return(1);
45361178Sjoe	      case S_IFCHR:
45461178Sjoe		printcolor(C_CHR);
45561178Sjoe		return(1);
45661178Sjoe	}
45761178Sjoe	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
45861178Sjoe		if (mode & S_ISUID)
45961178Sjoe		    printcolor(C_SUID);
46061178Sjoe		else if (mode & S_ISGID)
46161178Sjoe		    printcolor(C_SGID);
46261178Sjoe		else
46361178Sjoe		    printcolor(C_EXEC);
46461178Sjoe		return(1);
46561178Sjoe	}
46661178Sjoe	return(0);
46761178Sjoe}
46861178Sjoe
46961178Sjoevoid
47061178Sjoeparsecolors(cs)
47188587Sjoe	const char *cs;
47261178Sjoe{
47388586Sjoe	int	i;
47488586Sjoe	int	j;
47588586Sjoe	int	len;
47688586Sjoe	char	c[2];
47788586Sjoe	short	legacy_warn = 0;
47861321Sache
47988586Sjoe	if (cs == NULL)
48088586Sjoe		cs = ""; /* LSCOLORS not set */
48161178Sjoe	len = strlen(cs);
48261178Sjoe	for (i = 0 ; i < C_NUMCOLORS ; i++) {
48388583Sjoe		colors[i].bold = 0;
48488583Sjoe
48588586Sjoe		if (len <= 2 * i) {
48688586Sjoe			c[0] = defcolors[2 * i];
48788586Sjoe			c[1] = defcolors[2 * i + 1];
48861178Sjoe		}
48961178Sjoe		else {
49088586Sjoe			c[0] = cs[2 * i];
49188586Sjoe			c[1] = cs[2 * i + 1];
49261178Sjoe		}
49361178Sjoe		for (j = 0 ; j < 2 ; j++) {
49488583Sjoe			/* Legacy colours used 0-7 */
49588583Sjoe			if (c[j] >= '0' && c[j] <= '7') {
49688583Sjoe				colors[i].num[j] = c[j] - '0';
49788583Sjoe				if (!legacy_warn) {
49888583Sjoe					fprintf(stderr,
49988583Sjoe					    "warn: colors are now defined "
50088583Sjoe					    "using a-h instead of 0-9. "
50188583Sjoe					    "see manual page.\n");
50288583Sjoe				}
50388583Sjoe				legacy_warn = 1;
50488583Sjoe			} else if (c[j] >= 'a' && c[j] <= 'h')
50588583Sjoe				colors[i].num[j] = c[j] - 'a';
50688583Sjoe			else if (c[j] >= 'A' && c[j] <= 'H') {
50788583Sjoe				colors[i].num[j] = c[j] - 'A';
50888583Sjoe				colors[i].bold = 1;
50988583Sjoe			} else if (tolower((unsigned char)c[j] == 'x'))
51088583Sjoe				colors[i].num[j] = -1;
51188583Sjoe			else {
51261178Sjoe				fprintf(stderr,
51388583Sjoe				    "error: invalid character '%c' in LSCOLORS"
51488583Sjoe				    " env var\n", c[j]);
51588584Sjoe				colors[i].num[j] = -1;
51661178Sjoe			}
51761178Sjoe		}
51861178Sjoe	}
51961178Sjoe}
52061291Sache
52161323Sachevoid
52261323Sachecolorquit(sig)
52388586Sjoe	int	sig;
52461291Sache{
52561321Sache	endcolor(sig);
52661294Sache
52761294Sache	(void) signal(sig, SIG_DFL);
52861294Sache	(void) kill(getpid(), sig);
52961291Sache}
53061268Sjoe#endif /*COLORLS*/
53161178Sjoe
5321556Srgrimesstatic void
5331556Srgrimesprintlink(p)
53488586Sjoe	FTSENT	*p;
5351556Srgrimes{
53688586Sjoe	int	lnklen;
53788586Sjoe	char	name[MAXPATHLEN + 1];
53888586Sjoe	char	path[MAXPATHLEN + 1];
5391556Srgrimes
5401556Srgrimes	if (p->fts_level == FTS_ROOTLEVEL)
5411556Srgrimes		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
5428855Srgrimes	else
5431556Srgrimes		(void)snprintf(name, sizeof(name),
5441556Srgrimes		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
5451556Srgrimes	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
5461556Srgrimes		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
5471556Srgrimes		return;
5481556Srgrimes	}
5491556Srgrimes	path[lnklen] = '\0';
55062597Sassar	(void)printf(" -> ");
55162597Sassar	printname(path);
5521556Srgrimes}
553