xref: /original-bsd/bin/ls/print.c (revision 4ba124f7)
11638ec87Sbostic /*
2f0cd4fbbSpendry  * Copyright (c) 1989, 1993, 1994
3b4eb6e17Smckusick  *	The Regents of the University of California.  All rights reserved.
41638ec87Sbostic  *
51ec844e4Sbostic  * This code is derived from software contributed to Berkeley by
61ec844e4Sbostic  * Michael Fischbein.
71ec844e4Sbostic  *
80e2304afSbostic  * %sccs.include.redist.c%
91638ec87Sbostic  */
101638ec87Sbostic 
111638ec87Sbostic #ifndef lint
12*4ba124f7Spendry static char sccsid[] = "@(#)print.c	8.5 (Berkeley) 07/28/94";
131638ec87Sbostic #endif /* not lint */
141638ec87Sbostic 
151638ec87Sbostic #include <sys/param.h>
161638ec87Sbostic #include <sys/stat.h>
17a13bcb1cSbostic 
18a13bcb1cSbostic #include <err.h>
190e2304afSbostic #include <errno.h>
20a13bcb1cSbostic #include <fts.h>
211638ec87Sbostic #include <grp.h>
221638ec87Sbostic #include <pwd.h>
230e2304afSbostic #include <stdio.h>
24a13bcb1cSbostic #include <stdlib.h>
2516de9baaSbostic #include <string.h>
26a13bcb1cSbostic #include <time.h>
27a13bcb1cSbostic #include <tzfile.h>
28a13bcb1cSbostic #include <unistd.h>
29a13bcb1cSbostic #include <utmp.h>
30a13bcb1cSbostic 
311638ec87Sbostic #include "ls.h"
320e2304afSbostic #include "extern.h"
331638ec87Sbostic 
3421d043d1Selan static int	printaname __P((FTSENT *, u_long, u_long));
356de7ee45Selan static void	printlink __P((FTSENT *));
360e2304afSbostic static void	printtime __P((time_t));
370e2304afSbostic static int	printtype __P((u_int));
380e2304afSbostic 
3921d043d1Selan #define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
406de7ee45Selan 
410e2304afSbostic void
printscol(dp)4221d043d1Selan printscol(dp)
4321d043d1Selan 	DISPLAY *dp;
441638ec87Sbostic {
456f3a9d47Spendry 	FTSENT *p;
466de7ee45Selan 
4721d043d1Selan 	for (p = dp->list; p; p = p->fts_link) {
4821d043d1Selan 		if (IS_NOPRINT(p))
4921d043d1Selan 			continue;
5021d043d1Selan 		(void)printaname(p, dp->s_inode, dp->s_block);
517b8eabf8Sbostic 		(void)putchar('\n');
527b8eabf8Sbostic 	}
537b8eabf8Sbostic }
547b8eabf8Sbostic 
550e2304afSbostic void
printlong(dp)5621d043d1Selan printlong(dp)
5721d043d1Selan 	DISPLAY *dp;
587b8eabf8Sbostic {
596f3a9d47Spendry 	struct stat *sp;
606f3a9d47Spendry 	FTSENT *p;
6121d043d1Selan 	NAMES *np;
6221d043d1Selan 	char buf[20];
63bc16eedbSbostic 
6421d043d1Selan 	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
6521d043d1Selan 		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
666de7ee45Selan 
6721d043d1Selan 	for (p = dp->list; p; p = p->fts_link) {
686de7ee45Selan 		if (IS_NOPRINT(p))
696de7ee45Selan 			continue;
706de7ee45Selan 		sp = p->fts_statp;
717b8eabf8Sbostic 		if (f_inode)
7221d043d1Selan 			(void)printf("%*lu ", dp->s_inode, sp->st_ino);
737b8eabf8Sbostic 		if (f_size)
74ba8aa5deSmckusick 			(void)printf("%*qd ",
7521d043d1Selan 			    dp->s_block, howmany(sp->st_blocks, blocksize));
7621d043d1Selan 		(void)strmode(sp->st_mode, buf);
7721d043d1Selan 		np = p->fts_pointer;
7821d043d1Selan 		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
7921d043d1Selan 		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
8021d043d1Selan 		    np->group);
8101bc9995Smckusick 		if (f_flags)
8221d043d1Selan 			(void)printf("%-*s ", dp->s_flags, np->flags);
8321d043d1Selan 		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
846de7ee45Selan 			(void)printf("%3d, %3d ",
856de7ee45Selan 			    major(sp->st_rdev), minor(sp->st_rdev));
86677edeabSbostic 		else if (dp->bcfile)
87677edeabSbostic 			(void)printf("%*s%*qd ",
88677edeabSbostic 			    8 - dp->s_size, "", dp->s_size, sp->st_size);
897b8eabf8Sbostic 		else
9092aa2c7bSmckusick 			(void)printf("%*qd ", dp->s_size, sp->st_size);
917b8eabf8Sbostic 		if (f_accesstime)
926de7ee45Selan 			printtime(sp->st_atime);
937b8eabf8Sbostic 		else if (f_statustime)
946de7ee45Selan 			printtime(sp->st_ctime);
957b8eabf8Sbostic 		else
966de7ee45Selan 			printtime(sp->st_mtime);
976de7ee45Selan 		(void)printf("%s", p->fts_name);
987b8eabf8Sbostic 		if (f_type)
996de7ee45Selan 			(void)printtype(sp->st_mode);
1006de7ee45Selan 		if (S_ISLNK(sp->st_mode))
1016de7ee45Selan 			printlink(p);
1027b8eabf8Sbostic 		(void)putchar('\n');
1037b8eabf8Sbostic 	}
1047b8eabf8Sbostic }
1057b8eabf8Sbostic 
106faffd191Sbostic #define	TAB	8
107faffd191Sbostic 
1080e2304afSbostic void
printcol(dp)10921d043d1Selan printcol(dp)
11021d043d1Selan 	DISPLAY *dp;
1117b8eabf8Sbostic {
1125442d5fdSbostic 	extern int termwidth;
1136de7ee45Selan 	static FTSENT **array;
1146de7ee45Selan 	static int lastentries = -1;
1156f3a9d47Spendry 	FTSENT *p;
1166f3a9d47Spendry 	int base, chcnt, cnt, col, colwidth, num;
117faffd191Sbostic 	int endcol, numcols, numrows, row;
1181638ec87Sbostic 
1196de7ee45Selan 	/*
1206de7ee45Selan 	 * Have to do random access in the linked list -- build a table
1216de7ee45Selan 	 * of pointers.
1226de7ee45Selan 	 */
12321d043d1Selan 	if (dp->entries > lastentries) {
12421d043d1Selan 		lastentries = dp->entries;
1250a11f9fcSbostic 		if ((array =
12621d043d1Selan 		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
127a13bcb1cSbostic 			warn(NULL);
12821d043d1Selan 			printscol(dp);
1296de7ee45Selan 		}
1306de7ee45Selan 	}
13121d043d1Selan 	for (p = dp->list, num = 0; p; p = p->fts_link)
1326de7ee45Selan 		if (p->fts_number != NO_PRINT)
1336de7ee45Selan 			array[num++] = p;
1346de7ee45Selan 
13521d043d1Selan 	colwidth = dp->maxlen;
1361638ec87Sbostic 	if (f_inode)
13721d043d1Selan 		colwidth += dp->s_inode + 1;
1381638ec87Sbostic 	if (f_size)
13921d043d1Selan 		colwidth += dp->s_block + 1;
1401638ec87Sbostic 	if (f_type)
141983624daSbostic 		colwidth += 1;
142249e4f75Sbostic 
143faffd191Sbostic 	colwidth = (colwidth + TAB) & ~(TAB - 1);
144249e4f75Sbostic 	if (termwidth < 2 * colwidth) {
14521d043d1Selan 		printscol(dp);
146249e4f75Sbostic 		return;
147249e4f75Sbostic 	}
1481638ec87Sbostic 
149983624daSbostic 	numcols = termwidth / colwidth;
150983624daSbostic 	numrows = num / numcols;
151983624daSbostic 	if (num % numcols)
152983624daSbostic 		++numrows;
153983624daSbostic 
15421d043d1Selan 	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
15521d043d1Selan 		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
156983624daSbostic 	for (row = 0; row < numrows; ++row) {
15741342febSbostic 		endcol = colwidth;
15841342febSbostic 		for (base = row, chcnt = col = 0; col < numcols; ++col) {
15921d043d1Selan 			chcnt += printaname(array[base], dp->s_inode,
16021d043d1Selan 			    dp->s_block);
161983624daSbostic 			if ((base += numrows) >= num)
1621638ec87Sbostic 				break;
16341342febSbostic 			while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) {
1641638ec87Sbostic 				(void)putchar('\t');
16541342febSbostic 				chcnt = cnt;
1661638ec87Sbostic 			}
16741342febSbostic 			endcol += colwidth;
1681638ec87Sbostic 		}
1696de7ee45Selan 		(void)putchar('\n');
1701638ec87Sbostic 	}
1711638ec87Sbostic }
1721638ec87Sbostic 
1731638ec87Sbostic /*
1741638ec87Sbostic  * print [inode] [size] name
1756de7ee45Selan  * return # of characters printed, no trailing characters.
1761638ec87Sbostic  */
1770e2304afSbostic static int
printaname(p,inodefield,sizefield)17821d043d1Selan printaname(p, inodefield, sizefield)
1796f3a9d47Spendry 	FTSENT *p;
18021d043d1Selan 	u_long sizefield, inodefield;
1811638ec87Sbostic {
1826de7ee45Selan 	struct stat *sp;
1837b8eabf8Sbostic 	int chcnt;
1841638ec87Sbostic 
1856de7ee45Selan 	sp = p->fts_statp;
1867b8eabf8Sbostic 	chcnt = 0;
1871638ec87Sbostic 	if (f_inode)
188a13bcb1cSbostic 		chcnt += printf("%*lu ", (int)inodefield, sp->st_ino);
1891638ec87Sbostic 	if (f_size)
190ba8aa5deSmckusick 		chcnt += printf("%*qd ",
191a13bcb1cSbostic 		    (int)sizefield, howmany(sp->st_blocks, blocksize));
1926de7ee45Selan 	chcnt += printf("%s", p->fts_name);
1931638ec87Sbostic 	if (f_type)
1946de7ee45Selan 		chcnt += printtype(sp->st_mode);
1951638ec87Sbostic 	return (chcnt);
1961638ec87Sbostic }
1971638ec87Sbostic 
1980e2304afSbostic static void
printtime(ftime)1991638ec87Sbostic printtime(ftime)
2001638ec87Sbostic 	time_t ftime;
2011638ec87Sbostic {
2021638ec87Sbostic 	int i;
2030e2304afSbostic 	char *longstring;
2041638ec87Sbostic 
20521d043d1Selan 	longstring = ctime(&ftime);
2061638ec87Sbostic 	for (i = 4; i < 11; ++i)
2071638ec87Sbostic 		(void)putchar(longstring[i]);
2081638ec87Sbostic 
2091638ec87Sbostic #define	SIXMONTHS	((DAYSPERNYEAR / 2) * SECSPERDAY)
2107b563e9fSbostic 	if (f_sectime)
2117b563e9fSbostic 		for (i = 11; i < 24; i++)
2127b563e9fSbostic 			(void)putchar(longstring[i]);
21321d043d1Selan 	else if (ftime + SIXMONTHS > time(NULL))
2141638ec87Sbostic 		for (i = 11; i < 16; ++i)
2151638ec87Sbostic 			(void)putchar(longstring[i]);
2161638ec87Sbostic 	else {
2171638ec87Sbostic 		(void)putchar(' ');
2181638ec87Sbostic 		for (i = 20; i < 24; ++i)
2191638ec87Sbostic 			(void)putchar(longstring[i]);
2201638ec87Sbostic 	}
2211638ec87Sbostic 	(void)putchar(' ');
2221638ec87Sbostic }
2231638ec87Sbostic 
2240e2304afSbostic static int
printtype(mode)2251638ec87Sbostic printtype(mode)
2260e2304afSbostic 	u_int mode;
2271638ec87Sbostic {
2281638ec87Sbostic 	switch (mode & S_IFMT) {
2291638ec87Sbostic 	case S_IFDIR:
2301638ec87Sbostic 		(void)putchar('/');
2311638ec87Sbostic 		return (1);
232537be046Sbostic 	case S_IFIFO:
233537be046Sbostic 		(void)putchar('|');
234537be046Sbostic 		return (1);
2351638ec87Sbostic 	case S_IFLNK:
2361638ec87Sbostic 		(void)putchar('@');
2371638ec87Sbostic 		return (1);
2381638ec87Sbostic 	case S_IFSOCK:
2391638ec87Sbostic 		(void)putchar('=');
2401638ec87Sbostic 		return (1);
241*4ba124f7Spendry 	case S_IFWHT:
242*4ba124f7Spendry 		(void)putchar('%');
243*4ba124f7Spendry 		return (1);
2441638ec87Sbostic 	}
2451638ec87Sbostic 	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
2461638ec87Sbostic 		(void)putchar('*');
2471638ec87Sbostic 		return (1);
2481638ec87Sbostic 	}
2491638ec87Sbostic 	return (0);
2501638ec87Sbostic }
2511638ec87Sbostic 
2520e2304afSbostic static void
printlink(p)2536de7ee45Selan printlink(p)
2546de7ee45Selan 	FTSENT *p;
2551638ec87Sbostic {
2561638ec87Sbostic 	int lnklen;
2576de7ee45Selan 	char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1];
2581638ec87Sbostic 
25998058b8cSelan 	if (p->fts_level == FTS_ROOTLEVEL)
26021d043d1Selan 		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
26198058b8cSelan 	else
26221d043d1Selan 		(void)snprintf(name, sizeof(name),
263e99f9988Sbostic 		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
264e99f9988Sbostic 	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
2651638ec87Sbostic 		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
2661638ec87Sbostic 		return;
2671638ec87Sbostic 	}
2681638ec87Sbostic 	path[lnklen] = '\0';
2691638ec87Sbostic 	(void)printf(" -> %s", path);
2701638ec87Sbostic }
271