print.c revision 102577
11558Srgrimes/*
293492Sphk * Copyright (c) 1989, 1993, 1994
393492Sphk *	The Regents of the University of California.  All rights reserved.
493492Sphk *
51558Srgrimes * This code is derived from software contributed to Berkeley by
693492Sphk * Michael Fischbein.
793492Sphk *
893492Sphk * Redistribution and use in source and binary forms, with or without
993492Sphk * modification, are permitted provided that the following conditions
1093492Sphk * are met:
111558Srgrimes * 1. Redistributions of source code must retain the above copyright
121558Srgrimes *    notice, this list of conditions and the following disclaimer.
131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141558Srgrimes *    notice, this list of conditions and the following disclaimer in the
151558Srgrimes *    documentation and/or other materials provided with the distribution.
161558Srgrimes * 3. All advertising materials mentioning features or use of this software
171558Srgrimes *    must display the following acknowledgement:
181558Srgrimes *	This product includes software developed by the University of
1993492Sphk *	California, Berkeley and its contributors.
2093492Sphk * 4. Neither the name of the University nor the names of its contributors
2193492Sphk *    may be used to endorse or promote products derived from this software
221558Srgrimes *    without specific prior written permission.
2393492Sphk *
241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2693492Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3496049Sfenner * SUCH DAMAGE.
3596049Sfenner */
3696049Sfenner
3796049Sfenner#if 0
3896049Sfenner#ifndef lint
3996049Sfennerstatic char sccsid[] = "@(#)print.c	8.4 (Berkeley) 4/17/94";
4096049Sfenner#endif /* not lint */
4196049Sfenner#endif
4296049Sfenner#include <sys/cdefs.h>
4396049Sfenner__FBSDID("$FreeBSD: head/bin/ls/print.c 102577 2002-08-29 14:29:09Z keramida $");
4496049Sfenner
4596049Sfenner#include <sys/param.h>
4696049Sfenner#include <sys/stat.h>
4796049Sfenner
4896049Sfenner#include <err.h>
4996049Sfenner#include <errno.h>
5096049Sfenner#include <fts.h>
5196049Sfenner#include <math.h>
5296049Sfenner#include <langinfo.h>
5396049Sfenner#include <stdio.h>
5496049Sfenner#include <stdlib.h>
5596049Sfenner#include <string.h>
5696049Sfenner#include <time.h>
5796049Sfenner#include <unistd.h>
5896049Sfenner#ifdef COLORLS
5996049Sfenner#include <ctype.h>
6096049Sfenner#include <termcap.h>
6196049Sfenner#include <signal.h>
6296049Sfenner#endif
6396049Sfenner
6496049Sfenner#include "ls.h"
651558Srgrimes#include "extern.h"
661558Srgrimes
6795183Scharnierstatic int	printaname(FTSENT *, u_long, u_long);
6895183Scharnierstatic void	printlink(FTSENT *);
6995183Scharnierstatic void	printtime(time_t);
7096049Sfennerstatic int	printtype(u_int);
7194580Smarcelstatic void	printsize(size_t, off_t);
7294580Smarcel#ifdef COLORLS
7396025Smuxstatic void	endcolor(int);
7496025Smuxstatic int	colortype(mode_t);
7594580Smarcel#endif
7694580Smarcel
7793492Sphk#define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
7893492Sphk
7996025Smux#define KILO_SZ(n) (n)
8096049Sfenner#define MEGA_SZ(n) ((n) * (n))
8194580Smarcel#define GIGA_SZ(n) ((n) * (n) * (n))
8294580Smarcel#define TERA_SZ(n) ((n) * (n) * (n) * (n))
8394580Smarcel#define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n))
8496049Sfenner
8593492Sphk#define KILO_2_SZ (KILO_SZ(1024ULL))
8693492Sphk#define MEGA_2_SZ (MEGA_SZ(1024ULL))
871558Srgrimes#define GIGA_2_SZ (GIGA_SZ(1024ULL))
8897746Smarcel#define TERA_2_SZ (TERA_SZ(1024ULL))
8997746Smarcel#define PETA_2_SZ (PETA_SZ(1024ULL))
9097746Smarcel
91142533Sobrienstatic unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ};
92142533Sobrien
93142533Sobrientypedef enum {
94142359Sobrien	NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX
95133814Sru} unit_t;
96133814Srustatic unit_t unit_adjust(off_t *);
9794580Smarcel
9896049Sfennerstatic int unitp[] = {NONE, KILO, MEGA, GIGA, TERA, PETA};
9996049Sfenner
10093492Sphk#ifdef COLORLS
10194580Smarcel/* Most of these are taken from <sys/stat.h> */
102142359Sobrientypedef enum Colors {
1031558Srgrimes	C_DIR,			/* directory */
10493717Smarcel	C_LNK,			/* symbolic link */
10593492Sphk	C_SOCK,			/* socket */
106142359Sobrien	C_FIFO,			/* pipe */
1071558Srgrimes	C_EXEC,			/* executable */
108142359Sobrien	C_BLK,			/* block special */
10993492Sphk	C_CHR,			/* character special */
110150818Smaxim	C_SUID,			/* setuid executable */
111150818Smaxim	C_SGID,			/* setgid executable */
11293717Smarcel	C_WSDIR,		/* directory writeble to others, with sticky
113142359Sobrien				 * bit */
11493717Smarcel	C_WDIR,			/* directory writeble to others, without
11593717Smarcel				 * sticky bit */
11693717Smarcel	C_NUMCOLORS		/* just a place-holder */
11793492Sphk} Colors;
11893492Sphk
119142359Sobrienstatic const char *defcolors = "exfxcxdxbxegedabagacad";
120142359Sobrien
121142359Sobrien/* colors for file types */
122142359Sobrienstatic struct {
12396049Sfenner	int	num[2];
124142359Sobrien	int	bold;
125142359Sobrien} colors[C_NUMCOLORS];
126142359Sobrien#endif
127142533Sobrien
128142533Sobrienvoid
129142359Sobrienprintscol(DISPLAY *dp)
130142533Sobrien{
131142533Sobrien	FTSENT *p;
132142359Sobrien
133142533Sobrien	for (p = dp->list; p; p = p->fts_link) {
134142359Sobrien		if (IS_NOPRINT(p))
135142359Sobrien			continue;
13695039Sphk		(void)printaname(p, dp->s_inode, dp->s_block);
1371558Srgrimes		(void)putchar('\n');
1381558Srgrimes	}
13996049Sfenner}
14096049Sfenner
14196049Sfenner/*
14296049Sfenner * print name in current style
14396049Sfenner */
14496049Sfennerstatic int
14596049Sfennerprintname(const char *name)
14696049Sfenner{
14796049Sfenner	if (f_octal || f_octal_escape)
148150105Srwatson		return prn_octal(name);
149150105Srwatson	else if (f_nonprint)
150147506Sdwhite		return prn_printable(name);
15196049Sfenner	else
15296049Sfenner		return printf("%s", name);
15396049Sfenner}
15496049Sfenner
15596049Sfennervoid
156147506Sdwhiteprintlong(DISPLAY *dp)
15796049Sfenner{
15896049Sfenner	struct stat *sp;
15996049Sfenner	FTSENT *p;
16096049Sfenner	NAMES *np;
16196049Sfenner	char buf[20];
16296049Sfenner#ifdef COLORLS
163147506Sdwhite	int color_printed = 0;
164147506Sdwhite#endif
16596049Sfenner
166147506Sdwhite	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
167147506Sdwhite		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
168147506Sdwhite
16996049Sfenner	for (p = dp->list; p; p = p->fts_link) {
17096049Sfenner		if (IS_NOPRINT(p))
17196049Sfenner			continue;
172147506Sdwhite		sp = p->fts_statp;
17396049Sfenner		if (f_inode)
17496049Sfenner			(void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
17596049Sfenner		if (f_size)
176147506Sdwhite			(void)printf("%*lld ",
17796049Sfenner			    dp->s_block, howmany(sp->st_blocks, blocksize));
178147506Sdwhite		strmode(sp->st_mode, buf);
17996049Sfenner		np = p->fts_pointer;
18096049Sfenner		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
18196049Sfenner		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
18296025Smux		    np->group);
18396025Smux		if (f_flags)
18496025Smux			(void)printf("%-*s ", dp->s_flags, np->flags);
18596025Smux		if (f_lomac)
18696025Smux			(void)printf("%-*s ", dp->s_lattr, np->lattr);
187146763Sdelphij		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
18896025Smux			if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
18996025Smux				(void)printf("%3d, 0x%08x ",
19096049Sfenner				    major(sp->st_rdev),
19196025Smux				    (u_int)minor(sp->st_rdev));
19296025Smux			else
19393717Smarcel				(void)printf("%3d, %3d ",
19496049Sfenner				    major(sp->st_rdev), minor(sp->st_rdev));
19596049Sfenner		else if (dp->bcfile)
19696049Sfenner			(void)printf("%*s%*lld ",
19796049Sfenner			    8 - dp->s_size, "", dp->s_size, sp->st_size);
19896025Smux		else
19996025Smux			printsize(dp->s_size, sp->st_size);
20096025Smux		if (f_accesstime)
20196025Smux			printtime(sp->st_atime);
20296025Smux		else if (f_statustime)
20396025Smux			printtime(sp->st_ctime);
20496025Smux		else
20596025Smux			printtime(sp->st_mtime);
20696025Smux#ifdef COLORLS
20796025Smux		if (f_color)
20896025Smux			color_printed = colortype(sp->st_mode);
20996025Smux#endif
21096025Smux		(void)printname(p->fts_name);
21196025Smux#ifdef COLORLS
21296049Sfenner		if (f_color && color_printed)
21396025Smux			endcolor(0);
21496049Sfenner#endif
21596049Sfenner		if (f_type)
21696025Smux			(void)printtype(sp->st_mode);
21796025Smux		if (S_ISLNK(sp->st_mode))
21896025Smux			printlink(p);
21996025Smux		(void)putchar('\n');
22096025Smux	}
22196049Sfenner}
22296049Sfenner
22396025Smuxvoid
22496025Smuxprintstream(DISPLAY *dp)
22596025Smux{
22696049Sfenner	FTSENT *p;
22796049Sfenner	extern int termwidth;
22896025Smux	int chcnt;
229174923Srwatson
230174923Srwatson	for (p = dp->list, chcnt = 0; p; p = p->fts_link) {
231174923Srwatson		if (p->fts_number == NO_PRINT)
232174923Srwatson			continue;
233174923Srwatson		if (strlen(p->fts_name) + chcnt +
234174923Srwatson		    (p->fts_link ? 2 : 0) >= (unsigned)termwidth) {
235174923Srwatson			putchar('\n');
236174923Srwatson			chcnt = 0;
237174923Srwatson		}
238174923Srwatson		chcnt += printaname(p, dp->s_inode, dp->s_block);
239174923Srwatson		if (p->fts_link) {
240174923Srwatson			printf(", ");
241174923Srwatson			chcnt += 2;
242174923Srwatson		}
243174923Srwatson	}
244174923Srwatson	if (chcnt)
245174923Srwatson		putchar('\n');
246174923Srwatson}
247174923Srwatson
248174923Srwatsonvoid
249174923Srwatsonprintcol(DISPLAY *dp)
250174923Srwatson{
251174923Srwatson	extern int termwidth;
252174923Srwatson	static FTSENT **array;
253174923Srwatson	static int lastentries = -1;
254174923Srwatson	FTSENT *p;
255174923Srwatson	int base;
256174923Srwatson	int chcnt;
257174923Srwatson	int cnt;
258174923Srwatson	int col;
259174923Srwatson	int colwidth;
260174923Srwatson	int endcol;
261174923Srwatson	int num;
262174923Srwatson	int numcols;
263174923Srwatson	int numrows;
264174923Srwatson	int row;
265174923Srwatson	int tabwidth;
266174923Srwatson
267174923Srwatson	if (f_notabs)
268174923Srwatson		tabwidth = 1;
269174923Srwatson	else
270174923Srwatson		tabwidth = 8;
271174923Srwatson
272174923Srwatson	/*
273174923Srwatson	 * Have to do random access in the linked list -- build a table
274174923Srwatson	 * of pointers.
275174923Srwatson	 */
276174923Srwatson	if (dp->entries > lastentries) {
277174923Srwatson		lastentries = dp->entries;
278174923Srwatson		if ((array =
279174923Srwatson		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
280174923Srwatson			warn(NULL);
281174923Srwatson			printscol(dp);
282174923Srwatson		}
283174923Srwatson	}
284174923Srwatson	for (p = dp->list, num = 0; p; p = p->fts_link)
285174923Srwatson		if (p->fts_number != NO_PRINT)
286174923Srwatson			array[num++] = p;
287174923Srwatson
288174923Srwatson	colwidth = dp->maxlen;
289174923Srwatson	if (f_inode)
290174923Srwatson		colwidth += dp->s_inode + 1;
291174923Srwatson	if (f_size)
292174923Srwatson		colwidth += dp->s_block + 1;
293174923Srwatson	if (f_type)
294174923Srwatson		colwidth += 1;
295174923Srwatson
296174923Srwatson	colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
297174923Srwatson	if (termwidth < 2 * colwidth) {
298174923Srwatson		printscol(dp);
299174923Srwatson		return;
300174923Srwatson	}
301174923Srwatson	numcols = termwidth / colwidth;
302174923Srwatson	numrows = num / numcols;
303174923Srwatson	if (num % numcols)
304174923Srwatson		++numrows;
305174923Srwatson
306174923Srwatson	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
307174923Srwatson		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
308174923Srwatson
309174923Srwatson	base = 0;
310174923Srwatson	for (row = 0; row < numrows; ++row) {
311174923Srwatson		endcol = colwidth;
312174923Srwatson		if (!f_sortacross)
313174923Srwatson			base = row;
314174923Srwatson		for (col = 0, chcnt = 0; col < numcols; ++col) {
315174923Srwatson			chcnt += printaname(array[base], dp->s_inode,
316174923Srwatson			    dp->s_block);
317174923Srwatson			if (f_sortacross)
318174923Srwatson				base++;
319174923Srwatson			else
320174923Srwatson				base += numrows;
321174923Srwatson			if (base >= num)
322174923Srwatson				break;
323174923Srwatson			while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
324174923Srwatson			    <= endcol) {
325174923Srwatson				if (f_sortacross && col + 1 >= numcols)
326174923Srwatson					break;
327174923Srwatson				(void)putchar(f_notabs ? ' ' : '\t');
328174923Srwatson				chcnt = cnt;
329174923Srwatson			}
330174923Srwatson			endcol += colwidth;
331174923Srwatson		}
332174923Srwatson		(void)putchar('\n');
333174923Srwatson	}
334174923Srwatson}
335174923Srwatson
336174923Srwatson/*
337174923Srwatson * print [inode] [size] name
338174923Srwatson * return # of characters printed, no trailing characters.
339174923Srwatson */
340174923Srwatsonstatic int
341174923Srwatsonprintaname(FTSENT *p, u_long inodefield, u_long sizefield)
342174923Srwatson{
343174923Srwatson	struct stat *sp;
344174923Srwatson	int chcnt;
345174923Srwatson#ifdef COLORLS
346174923Srwatson	int color_printed = 0;
347174923Srwatson#endif
348174923Srwatson
349174923Srwatson	sp = p->fts_statp;
350174923Srwatson	chcnt = 0;
351174923Srwatson	if (f_inode)
352174923Srwatson		chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
353174923Srwatson	if (f_size)
354174923Srwatson		chcnt += printf("%*lld ",
355174923Srwatson		    (int)sizefield, howmany(sp->st_blocks, blocksize));
356174923Srwatson#ifdef COLORLS
357174923Srwatson	if (f_color)
358174923Srwatson		color_printed = colortype(sp->st_mode);
359174923Srwatson#endif
360174923Srwatson	chcnt += printname(p->fts_name);
361174923Srwatson#ifdef COLORLS
362174923Srwatson	if (f_color && color_printed)
36393492Sphk		endcolor(0);
364146763Sdelphij#endif
3651558Srgrimes	if (f_type)
366174923Srwatson		chcnt += printtype(sp->st_mode);
36797340Smarcel	return (chcnt);
36894580Smarcel}
369174923Srwatson
37096049Sfennerstatic void
371142533Sobrienprinttime(time_t ftime)
372174923Srwatson{
373142359Sobrien	char longstring[80];
37494580Smarcel	static time_t now;
375174923Srwatson	const char *format;
3768871Srgrimes	static int d_first = -1;
377142359Sobrien
37896049Sfenner	if (d_first < 0)
379142359Sobrien		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
38096049Sfenner	if (now == 0)
38197340Smarcel		now = time(NULL);
38297746Smarcel
38397340Smarcel#define	SIXMONTHS	((365 / 2) * 86400)
38497340Smarcel	if (f_sectime)
38597340Smarcel		/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
38697340Smarcel		format = d_first ? "%e %b %T %Y " : "%b %e %T %Y ";
38797340Smarcel	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
38897340Smarcel		/* mmm dd hh:mm || dd mmm hh:mm */
38994580Smarcel		format = d_first ? "%e %b %R " : "%b %e %R ";
39096049Sfenner	else
39194580Smarcel		/* mmm dd  yyyy || dd mmm  yyyy */
39294580Smarcel		format = d_first ? "%e %b  %Y " : "%b %e  %Y ";
39393492Sphk	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
39496049Sfenner	fputs(longstring, stdout);
39593492Sphk}
39647095Sluoqi
39797340Smarcelstatic int
39893492Sphkprinttype(u_int mode)
39993492Sphk{
40093492Sphk
40193492Sphk	if (f_slash) {
40296049Sfenner		if ((mode & S_IFMT) == S_IFDIR) {
40396049Sfenner			(void)putchar('/');
40494580Smarcel			return (1);
4051558Srgrimes		}
40694580Smarcel		return (0);
40794580Smarcel	}
40896049Sfenner
40996049Sfenner	switch (mode & S_IFMT) {
41094580Smarcel	case S_IFDIR:
41194580Smarcel		(void)putchar('/');
41293492Sphk		return (1);
41393492Sphk	case S_IFIFO:
41493492Sphk		(void)putchar('|');
41593492Sphk		return (1);
41696049Sfenner	case S_IFLNK:
41796049Sfenner		(void)putchar('@');
41894580Smarcel		return (1);
41994580Smarcel	case S_IFSOCK:
4201558Srgrimes		(void)putchar('=');
421174923Srwatson		return (1);
422174944Srwatson	case S_IFWHT:
42394580Smarcel		(void)putchar('%');
424174923Srwatson		return (1);
425174923Srwatson	default:
426174923Srwatson		break;
427174944Srwatson	}
428174944Srwatson	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
429174944Srwatson		(void)putchar('*');
430174944Srwatson		return (1);
431174944Srwatson	}
432174944Srwatson	return (0);
433174944Srwatson}
434174944Srwatson
435174944Srwatson#ifdef COLORLS
436174944Srwatsonstatic int
437174944Srwatsonputch(int c)
438174944Srwatson{
439174944Srwatson	(void)putchar(c);
440174944Srwatson	return 0;
441174944Srwatson}
442174944Srwatson
443174944Srwatsonstatic int
444174944Srwatsonwritech(int c)
445174944Srwatson{
446174944Srwatson	char tmp = c;
447174944Srwatson
448174923Srwatson	(void)write(STDOUT_FILENO, &tmp, 1);
44996049Sfenner	return 0;
45094580Smarcel}
45196049Sfenner
452142359Sobrienstatic void
45396049Sfennerprintcolor(Colors c)
45496049Sfenner{
45596049Sfenner	char *ansiseq;
45696049Sfenner
45796049Sfenner	if (colors[c].bold)
45896049Sfenner		tputs(enter_bold, 1, putch);
45996049Sfenner
46096049Sfenner	if (colors[c].num[0] != -1) {
46196049Sfenner		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
46296049Sfenner		if (ansiseq)
46396049Sfenner			tputs(ansiseq, 1, putch);
46496049Sfenner	}
46596049Sfenner	if (colors[c].num[1] != -1) {
466174944Srwatson		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
467174944Srwatson		if (ansiseq)
468174944Srwatson			tputs(ansiseq, 1, putch);
469174944Srwatson	}
470174944Srwatson}
471174944Srwatson
472174944Srwatsonstatic void
473174944Srwatsonendcolor(int sig)
474174944Srwatson{
4751558Srgrimes	tputs(ansi_coloff, 1, sig ? writech : putch);
476142359Sobrien	tputs(attrs_off, 1, sig ? writech : putch);
47794580Smarcel}
47894580Smarcel
47994580Smarcelstatic int
48094580Smarcelcolortype(mode_t mode)
48194580Smarcel{
48296049Sfenner	switch (mode & S_IFMT) {
48396049Sfenner	case S_IFDIR:
48496025Smux		if (mode & S_IWOTH)
485142359Sobrien			if (mode & S_ISTXT)
486142359Sobrien				printcolor(C_WSDIR);
487142359Sobrien			else
48894580Smarcel				printcolor(C_WDIR);
48993717Smarcel		else
49093717Smarcel			printcolor(C_DIR);
49193492Sphk		return (1);
49293492Sphk	case S_IFLNK:
49393492Sphk		printcolor(C_LNK);
49496049Sfenner		return (1);
49596049Sfenner	case S_IFSOCK:
49694580Smarcel		printcolor(C_SOCK);
49796025Smux		return (1);
49894580Smarcel	case S_IFIFO:
4991558Srgrimes		printcolor(C_FIFO);
500142359Sobrien		return (1);
501142359Sobrien	case S_IFBLK:
502142359Sobrien		printcolor(C_BLK);
503142359Sobrien		return (1);
504142359Sobrien	case S_IFCHR:
505142359Sobrien		printcolor(C_CHR);
506142359Sobrien		return (1);
507142359Sobrien	}
508142359Sobrien	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
509142359Sobrien		if (mode & S_ISUID)
51093492Sphk			printcolor(C_SUID);
51196049Sfenner		else if (mode & S_ISGID)
51296049Sfenner			printcolor(C_SGID);
51396025Smux		else
514142359Sobrien			printcolor(C_EXEC);
515142359Sobrien		return (1);
516142359Sobrien	}
517142359Sobrien	return (0);
518142359Sobrien}
51966429Sdes
52094580Smarcelvoid
521119734Sdougbparsecolors(const char *cs)
522119734Sdougb{
523119734Sdougb	int i;
524119734Sdougb	int j;
525119734Sdougb	int len;
526119734Sdougb	char c[2];
52796049Sfenner	short legacy_warn = 0;
52896049Sfenner
52996049Sfenner	if (cs == NULL)
53096049Sfenner		cs = "";	/* LSCOLORS not set */
53194580Smarcel	len = strlen(cs);
53296049Sfenner	for (i = 0; i < C_NUMCOLORS; i++) {
53396049Sfenner		colors[i].bold = 0;
53496025Smux
53596025Smux		if (len <= 2 * i) {
53696025Smux			c[0] = defcolors[2 * i];
53796025Smux			c[1] = defcolors[2 * i + 1];
53896049Sfenner		} else {
539147506Sdwhite			c[0] = cs[2 * i];
540147506Sdwhite			c[1] = cs[2 * i + 1];
54196049Sfenner		}
54296049Sfenner		for (j = 0; j < 2; j++) {
54394580Smarcel			/* Legacy colours used 0-7 */
544142359Sobrien			if (c[j] >= '0' && c[j] <= '7') {
54594580Smarcel				colors[i].num[j] = c[j] - '0';
54694580Smarcel				if (!legacy_warn) {
54793492Sphk					fprintf(stderr,
54896049Sfenner					    "warn: LSCOLORS should use "
54996025Smux					    "characters a-h instead of 0-9 ("
55094580Smarcel					    "see the manual page)\n");
5511558Srgrimes				}
55296049Sfenner				legacy_warn = 1;
55396049Sfenner			} else if (c[j] >= 'a' && c[j] <= 'h')
554174923Srwatson				colors[i].num[j] = c[j] - 'a';
555174923Srwatson			else if (c[j] >= 'A' && c[j] <= 'H') {
556174923Srwatson				colors[i].num[j] = c[j] - 'A';
55796049Sfenner				colors[i].bold = 1;
558174923Srwatson			} else if (tolower((unsigned char)c[j] == 'x'))
559174923Srwatson				colors[i].num[j] = -1;
560174923Srwatson			else {
56196049Sfenner				fprintf(stderr,
56296049Sfenner				    "error: invalid character '%c' in LSCOLORS"
563174923Srwatson				    " env var\n", c[j]);
56494580Smarcel				colors[i].num[j] = -1;
56596025Smux			}
56694580Smarcel		}
56793492Sphk	}
56896049Sfenner}
56996049Sfenner
57093492Sphkvoid
57194580Smarcelcolorquit(int sig)
572170054Skevlo{
573170054Skevlo	endcolor(sig);
574170054Skevlo
575170054Skevlo	(void)signal(sig, SIG_DFL);
576170054Skevlo	(void)kill(getpid(), sig);
577170054Skevlo}
57894580Smarcel
579142359Sobrien#endif /* COLORLS */
58094580Smarcel
581142359Sobrienstatic void
58296049Sfennerprintlink(FTSENT *p)
58394580Smarcel{
58496049Sfenner	int lnklen;
585174923Srwatson	char name[MAXPATHLEN + 1];
58694580Smarcel	char path[MAXPATHLEN + 1];
587174923Srwatson
588174923Srwatson	if (p->fts_level == FTS_ROOTLEVEL)
589174923Srwatson		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
59094580Smarcel	else
591174923Srwatson		(void)snprintf(name, sizeof(name),
592174923Srwatson		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
593174923Srwatson	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
59494580Smarcel		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
59567264Sdes		return;
59696049Sfenner	}
59796049Sfenner	path[lnklen] = '\0';
59896049Sfenner	(void)printf(" -> ");
59996049Sfenner	(void)printname(path);
600174923Srwatson}
60196049Sfenner
60296049Sfennerstatic void
60396049Sfennerprintsize(size_t width, off_t bytes)
60496025Smux{
60594580Smarcel	unit_t unit;
60694580Smarcel
60796049Sfenner	if (f_humanval) {
60894580Smarcel		unit = unit_adjust(&bytes);
60996049Sfenner
61094580Smarcel		if (bytes == 0)
61194580Smarcel			(void)printf("%*s ", width, "0B");
61296049Sfenner		else
61396049Sfenner			(void)printf("%*lld%c ", width - 1, bytes,
61494580Smarcel			    "BKMGTPE"[unit]);
61594580Smarcel	} else
61694580Smarcel		(void)printf("%*lld ", width, bytes);
61796049Sfenner}
61896049Sfenner
61994580Smarcel/*
62094580Smarcel * Output in "human-readable" format.  Uses 3 digits max and puts
62194580Smarcel * unit suffixes at the end.  Makes output compact and easy to read,
62294580Smarcel * especially on huge disks.
62396049Sfenner *
62496049Sfenner */
62594580Smarcelunit_t
62696049Sfennerunit_adjust(off_t *val)
62794580Smarcel{
6281558Srgrimes	double abval;
6291558Srgrimes	unit_t unit;
63093492Sphk	unsigned int unit_sz;
63193492Sphk
6321558Srgrimes	abval = fabs((double)*val);
633141611Sru
634141611Sru	unit_sz = abval ? ilogb(abval) / 10 : 0;
635141611Sru
636141611Sru	if (unit_sz >= UNIT_MAX) {
63793492Sphk		unit = NONE;
6381558Srgrimes	} else {
6391558Srgrimes		unit = unitp[unit_sz];
64018914Sfenner		*val /= (double)vals_base2[unit_sz];
64193492Sphk	}
6421558Srgrimes
643146763Sdelphij	return (unit);
644142533Sobrien}
64593492Sphk