xref: /original-bsd/bin/ls/print.c (revision 7e5c8007)
1 /*
2  * Copyright (c) 1989, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Michael Fischbein.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)print.c	8.4 (Berkeley) 04/17/94";
13 #endif /* not lint */
14 
15 #include <sys/param.h>
16 #include <sys/stat.h>
17 
18 #include <err.h>
19 #include <errno.h>
20 #include <fts.h>
21 #include <grp.h>
22 #include <pwd.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <tzfile.h>
28 #include <unistd.h>
29 #include <utmp.h>
30 
31 #include "ls.h"
32 #include "extern.h"
33 
34 static int	printaname __P((FTSENT *, u_long, u_long));
35 static void	printlink __P((FTSENT *));
36 static void	printtime __P((time_t));
37 static int	printtype __P((u_int));
38 
39 #define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
40 
41 void
42 printscol(dp)
43 	DISPLAY *dp;
44 {
45 	FTSENT *p;
46 
47 	for (p = dp->list; p; p = p->fts_link) {
48 		if (IS_NOPRINT(p))
49 			continue;
50 		(void)printaname(p, dp->s_inode, dp->s_block);
51 		(void)putchar('\n');
52 	}
53 }
54 
55 void
56 printlong(dp)
57 	DISPLAY *dp;
58 {
59 	struct stat *sp;
60 	FTSENT *p;
61 	NAMES *np;
62 	char buf[20];
63 
64 	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
65 		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
66 
67 	for (p = dp->list; p; p = p->fts_link) {
68 		if (IS_NOPRINT(p))
69 			continue;
70 		sp = p->fts_statp;
71 		if (f_inode)
72 			(void)printf("%*lu ", dp->s_inode, sp->st_ino);
73 		if (f_size)
74 			(void)printf("%*qd ",
75 			    dp->s_block, howmany(sp->st_blocks, blocksize));
76 		(void)strmode(sp->st_mode, buf);
77 		np = p->fts_pointer;
78 		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
79 		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
80 		    np->group);
81 		if (f_flags)
82 			(void)printf("%-*s ", dp->s_flags, np->flags);
83 		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
84 			(void)printf("%3d, %3d ",
85 			    major(sp->st_rdev), minor(sp->st_rdev));
86 		else if (dp->bcfile)
87 			(void)printf("%*s%*qd ",
88 			    8 - dp->s_size, "", dp->s_size, sp->st_size);
89 		else
90 			(void)printf("%*qd ", dp->s_size, sp->st_size);
91 		if (f_accesstime)
92 			printtime(sp->st_atime);
93 		else if (f_statustime)
94 			printtime(sp->st_ctime);
95 		else
96 			printtime(sp->st_mtime);
97 		(void)printf("%s", p->fts_name);
98 		if (f_type)
99 			(void)printtype(sp->st_mode);
100 		if (S_ISLNK(sp->st_mode))
101 			printlink(p);
102 		(void)putchar('\n');
103 	}
104 }
105 
106 #define	TAB	8
107 
108 void
109 printcol(dp)
110 	DISPLAY *dp;
111 {
112 	extern int termwidth;
113 	static FTSENT **array;
114 	static int lastentries = -1;
115 	FTSENT *p;
116 	int base, chcnt, cnt, col, colwidth, num;
117 	int endcol, numcols, numrows, row;
118 
119 	/*
120 	 * Have to do random access in the linked list -- build a table
121 	 * of pointers.
122 	 */
123 	if (dp->entries > lastentries) {
124 		lastentries = dp->entries;
125 		if ((array =
126 		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
127 			warn(NULL);
128 			printscol(dp);
129 		}
130 	}
131 	for (p = dp->list, num = 0; p; p = p->fts_link)
132 		if (p->fts_number != NO_PRINT)
133 			array[num++] = p;
134 
135 	colwidth = dp->maxlen;
136 	if (f_inode)
137 		colwidth += dp->s_inode + 1;
138 	if (f_size)
139 		colwidth += dp->s_block + 1;
140 	if (f_type)
141 		colwidth += 1;
142 
143 	colwidth = (colwidth + TAB) & ~(TAB - 1);
144 	if (termwidth < 2 * colwidth) {
145 		printscol(dp);
146 		return;
147 	}
148 
149 	numcols = termwidth / colwidth;
150 	numrows = num / numcols;
151 	if (num % numcols)
152 		++numrows;
153 
154 	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
155 		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
156 	for (row = 0; row < numrows; ++row) {
157 		endcol = colwidth;
158 		for (base = row, chcnt = col = 0; col < numcols; ++col) {
159 			chcnt += printaname(array[base], dp->s_inode,
160 			    dp->s_block);
161 			if ((base += numrows) >= num)
162 				break;
163 			while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) {
164 				(void)putchar('\t');
165 				chcnt = cnt;
166 			}
167 			endcol += colwidth;
168 		}
169 		(void)putchar('\n');
170 	}
171 }
172 
173 /*
174  * print [inode] [size] name
175  * return # of characters printed, no trailing characters.
176  */
177 static int
178 printaname(p, inodefield, sizefield)
179 	FTSENT *p;
180 	u_long sizefield, inodefield;
181 {
182 	struct stat *sp;
183 	int chcnt;
184 
185 	sp = p->fts_statp;
186 	chcnt = 0;
187 	if (f_inode)
188 		chcnt += printf("%*lu ", (int)inodefield, sp->st_ino);
189 	if (f_size)
190 		chcnt += printf("%*qd ",
191 		    (int)sizefield, howmany(sp->st_blocks, blocksize));
192 	chcnt += printf("%s", p->fts_name);
193 	if (f_type)
194 		chcnt += printtype(sp->st_mode);
195 	return (chcnt);
196 }
197 
198 static void
199 printtime(ftime)
200 	time_t ftime;
201 {
202 	int i;
203 	char *longstring;
204 
205 	longstring = ctime(&ftime);
206 	for (i = 4; i < 11; ++i)
207 		(void)putchar(longstring[i]);
208 
209 #define	SIXMONTHS	((DAYSPERNYEAR / 2) * SECSPERDAY)
210 	if (f_sectime)
211 		for (i = 11; i < 24; i++)
212 			(void)putchar(longstring[i]);
213 	else if (ftime + SIXMONTHS > time(NULL))
214 		for (i = 11; i < 16; ++i)
215 			(void)putchar(longstring[i]);
216 	else {
217 		(void)putchar(' ');
218 		for (i = 20; i < 24; ++i)
219 			(void)putchar(longstring[i]);
220 	}
221 	(void)putchar(' ');
222 }
223 
224 static int
225 printtype(mode)
226 	u_int mode;
227 {
228 	switch (mode & S_IFMT) {
229 	case S_IFDIR:
230 		(void)putchar('/');
231 		return (1);
232 	case S_IFIFO:
233 		(void)putchar('|');
234 		return (1);
235 	case S_IFLNK:
236 		(void)putchar('@');
237 		return (1);
238 	case S_IFSOCK:
239 		(void)putchar('=');
240 		return (1);
241 	}
242 	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
243 		(void)putchar('*');
244 		return (1);
245 	}
246 	return (0);
247 }
248 
249 static void
250 printlink(p)
251 	FTSENT *p;
252 {
253 	int lnklen;
254 	char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1];
255 
256 	if (p->fts_level == FTS_ROOTLEVEL)
257 		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
258 	else
259 		(void)snprintf(name, sizeof(name),
260 		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
261 	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
262 		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
263 		return;
264 	}
265 	path[lnklen] = '\0';
266 	(void)printf(" -> %s", path);
267 }
268