1 #ifndef lint
2 static char *copyright =
3 "LC - Copyright University of Waterloo, 1978,1985,1987";
4 #endif /* lint */
5 /*
6 * lc [directory ...]
7 */
8
9 #include <sys/types.h>
10 #include <sys/param.h>
11 #include <sys/stat.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <errno.h>
15 #include <string.h>
16 #include <dirent.h>
17 typedef struct dirent DirType;
18
19 #ifndef MAXPATHLEN
20 # define MAXPATHLEN 1024 /* For older systems */
21 #endif
22
23 /* this assumes that S_IFMT is a mask of contiguous 1s */
24 #define IFMT_OFFSET 12 /* may be system-dependent */
25 #define IFMT (S_IFMT >> IFMT_OFFSET)
26
27 #define MODEX(m) (((m)>>IFMT_OFFSET)&IFMT) /* IFMT to table index */
28
29 #define NMALLOC 100 /* how much to malloc in growlist() */
30 #define COLUMNWIDTH 15 /* number of characters in a column */
31 #define INDENT " " /* blanks at beginning of a column */
32
33 static struct filelist {
34 char **names; /* pointer to array of names */
35 int size; /* how many elements */
36 int end; /* next element to use */
37 int flag;
38 char *title;
39 }
40 dlist = {(char **) NULL, 0, 0, 0, "Directories"},
41 flist = {(char **) NULL, 0, 0, 0, "Files"},
42 plist = {(char **) NULL, 0, 0, 0, "Pipes"},
43 blist = {(char **) NULL, 0, 0, 0, "Block Spec. Files"},
44 clist = {(char **) NULL, 0, 0, 0, "Char. Spec. Files"},
45 mpclist = {(char **) NULL, 0, 0, 0, "MPX Char. Files"},
46 mpblist = {(char **) NULL, 0, 0, 0, "MPX Block Files"},
47 symlist = {(char **) NULL, 0, 0, 0, "Unsatisfied Symbolic Links"},
48 soclist = {(char **) NULL, 0, 0, 0, "Sockets"},
49 /* flag is always on for this list */
50 goklist = {(char **) NULL, 0, 0, 1, "**GOK"};
51
52 static struct filelist *printlist[] = {
53 &dlist, &flist, &plist, &blist, &clist, &mpclist, &mpblist, &symlist,
54 &soclist, &goklist, 0
55 };
56
57 static struct filelist *listtype[IFMT+1];
58
59 static struct xinit {
60 int x_flag;
61 struct filelist *x_list;
62 } xinit[] ={
63 #ifdef S_IPIPE
64 S_IPIPE, &plist,
65 #endif
66 #ifdef S_IFPIP
67 S_IFPIP, &plist,
68 #endif
69 #ifdef S_IFIFO
70 S_IFIFO, &plist,
71 #endif
72 S_IFREG, &flist,
73 S_IFDIR, &dlist,
74 S_IFCHR, &clist,
75 S_IFBLK, &blist,
76 #ifdef S_IFMPC
77 S_IFMPC, &mpclist,
78 #endif
79 #ifdef S_IFMPB
80 S_IFMPB, &mpblist,
81 #endif
82 #ifdef S_IFLNK
83 S_IFLNK, &symlist,
84 #endif
85 #ifdef S_IFSOCK
86 S_IFSOCK, &soclist,
87 #endif
88 -1,
89 };
90
91 static int nfl; /* flag; this is not the first line of output */
92 static int errcall; /* flag; last line of output was error message */
93 static int notfirst; /* flag; means not the first thing in this directory */
94 static int nflg; /* flag; no output - just want exit status */
95 static int ncols = 5; /* number of columns */
96 static int linewidth;
97 static int manyflg;
98 static int anyfound;
99 static int all = 1;
100 static char pathbuf[MAXPATHLEN];
101 static char *fnptr = pathbuf;
102 static int aflg;
103
104
105 static void
warn(name)106 warn(name)
107 char *name;
108 {
109 if(nfl && !errcall)
110 putchar('\n');
111 fprintf(stdout, "%s: %s\n", name, strerror(errno));
112 fflush(stdout);
113 errcall=nfl=1;
114 errno=0;
115 }
116
117 static void
growlist(list)118 growlist( list )
119 struct filelist *list;
120 {
121 register int oldsize, newsize;
122 register char **newlist;
123
124 oldsize = list->size * sizeof (char *);
125 newsize = oldsize + (NMALLOC * sizeof (char *));
126
127 newlist = (char **) malloc( newsize );
128
129 if (oldsize != 0) {
130 memcpy( newlist, list->names, oldsize );
131 free( (char *)list->names );
132 }
133
134 list->names = newlist;
135 list->size += NMALLOC;
136 }
137
138 static void
build(list,name)139 build(list, name)
140 struct filelist *list;
141 char *name;
142 {
143 register int n;
144
145 if(list->flag == 0)
146 return;
147 anyfound++;
148 if(nflg)
149 return;
150 if (list->end >= list->size)
151 growlist(list);
152 n = strlen( name ) + 1;
153
154 (list->names)[list->end++] = strncpy( malloc( n ), name, n );
155 }
156
157 static void
release(list)158 release( list )
159 struct filelist *list;
160 {
161 register char **p;
162 register int i;
163
164 for (p = list->names, i = 0; i < list->end; i++)
165 free( p[i] );
166
167 list->end = 0;
168 }
169
170 static void
print(list)171 print(list)
172 struct filelist *list;
173 {
174 register int cursor, i;
175 register char **p;
176
177 if(notfirst++)
178 putchar('\n');
179 if(ncols!=1) {
180 if (manyflg)
181 fputs(INDENT, stdout);
182 printf("%s:\n", list->title);
183 }
184 cursor = 0;
185 for(p = list->names, i = 0; i < list->end; i++) {
186 int len;
187 int posused; /* positions used by blanks and filename */
188 register char *fname;
189
190 fname = p[i];
191 len = strlen(fname);
192 posused = len + ((cursor == 0) ? 0 : COLUMNWIDTH - cursor%COLUMNWIDTH);
193 if ((cursor + posused) > linewidth) {
194 printf("\n");
195 cursor = 0;
196 posused = len;
197 }
198 if (manyflg && (cursor == 0)) fputs(INDENT, stdout);
199 printf("%*s", posused, fname);
200 cursor += posused;
201 }
202 if(cursor != 0)
203 printf("\n");
204 errcall = 0;
205 if (manyflg)
206 release(list);
207 }
208
209 static int
pstrcmp(pa,pb)210 pstrcmp( pa, pb )
211 char *pa, *pb;
212 {
213 auto char *a = *(char**)pa;
214 auto char *b = *(char**)pb;
215
216 return (strcmp( a, b ));
217 }
218
219 static void
listdir(path)220 listdir(path)
221 char *path;
222 {
223 register char *p;
224 DirType *d;
225 struct filelist **ppr, *pr;
226 DIR *u;
227 char *dirname;
228 struct stat ibuf;
229
230 if (!manyflg) {
231 if (chdir(path) < 0) {
232 warn(path);
233 return;
234 }
235 dirname = ".";
236 } else
237 dirname = path;
238 if (stat(dirname, &ibuf) < 0) {
239 warn(path);
240 return;
241 }
242 if ((ibuf.st_mode&S_IFMT) != S_IFDIR) {
243 if(!manyflg){
244 errno=ENOTDIR;
245 warn(path);
246 }
247 return;
248 }
249 if ((u = opendir(dirname)) == NULL) {
250 warn(path);
251 return;
252 }
253 if(manyflg) {
254 if(nfl++)
255 putchar('\n');
256 printf("%s:\n", path);
257 }
258 while((d = readdir(u)) != NULL) {
259 if (!aflg) { /* skip "." and ".." */
260 p = d->d_name;
261 if(*p++ == '.' && (*p == '\0'
262 || *p++ == '.' && *p == '\0'))
263 continue;
264 }
265 if ((fnptr + strlen(d->d_name)) >= &pathbuf[MAXPATHLEN]) {
266 errno=ENAMETOOLONG;
267 warn(pathbuf);
268 /*
269 err("%s: Component `%s' makes pathname > %d bytes.\n",
270 pathbuf, d->d_name, MAXPATHLEN);
271 */
272 continue;
273 }
274 (void)strcpy(fnptr, d->d_name);
275 if(stat(pathbuf, &ibuf) < 0 && lstat(pathbuf, &ibuf) < 0) {
276 warn(pathbuf);
277 continue;
278 }
279 build(listtype[MODEX(ibuf.st_mode)], d->d_name);
280 }
281
282 closedir(u);
283 notfirst = 0;
284 for (ppr = printlist; 0 != (pr = *ppr); ppr++)
285 if(pr->names && pr->end != 0) {
286 qsort( (char *)pr->names, pr->end,
287 sizeof(char *), pstrcmp );
288 print(pr);
289 }
290 fflush(stdout);
291 }
292
293
294 int /*GOTO*/
main(argc,argv)295 main(argc, argv)
296 char **argv;
297 {
298 register char *path, *p, *q;
299 struct xinit *xp;
300 int i;
301
302 for (i = 0 ; i < IFMT ; i++)
303 listtype[i] = &goklist;
304 for (xp = xinit; xp->x_flag != -1; xp++)
305 listtype[MODEX(xp->x_flag)] = xp->x_list;
306 #ifdef TIOCGWINSZ
307 if (isatty(1)) {
308 struct winsize win;
309 if (ioctl(1, TIOCGWINSZ, &win) != -1) {
310 ncols = (win.ws_col == 0 ? 5 : (win.ws_col / COLUMNWIDTH));
311 ncols = ncols ? ncols : 1; /* can't have 0 columns */
312 }
313 }
314 #endif /* TIOGCWINSZ */
315 if(argc >= 2 && argv[1][0] == '-') {
316 argv++;
317 argc--;
318 for(p = &argv[0][1]; *p; p++)
319 switch(*p) {
320 case 'a':
321 aflg++;
322 break;
323
324 case 'n':
325 nflg++;
326 break;
327
328 case '1':
329 ncols=1;
330 break;
331
332 default:
333 switch(*p) {
334 case 'f':
335 flist.flag++;
336 break;
337
338 case 'd':
339 dlist.flag++;
340 break;
341
342 case 'b':
343 blist.flag++;
344 break;
345
346 case 'c':
347 clist.flag++;
348 break;
349
350 case 'B':
351 mpblist.flag++;
352 break;
353
354 case 'C':
355 mpclist.flag++;
356 break;
357
358 case 's':
359 blist.flag++;
360 clist.flag++;
361 mpblist.flag++;
362 mpclist.flag++;
363 break;
364
365 case 'p':
366 plist.flag++;
367 break;
368
369 default:
370 fprintf(stderr, "Unknown flag: %c\n",
371 *p);
372 continue;
373 }
374 all = 0;
375 }
376 }
377
378 if (all)
379 flist.flag = dlist.flag = blist.flag = clist.flag
380 = mpblist.flag = mpclist.flag
381 = symlist.flag = soclist.flag
382 = plist.flag = 1;
383
384 linewidth = ncols * COLUMNWIDTH;
385
386 if(argc < 3) {
387 path = argc == 1 ? "." : argv[1];
388 listdir(path);
389 } else {
390 manyflg++;
391 while(--argc) {
392 path = p = *++argv;
393 if(strlen(path) >= MAXPATHLEN) {/* = for '/' */
394 errno=ENAMETOOLONG;
395 warn(path);
396 continue;
397 }
398 q = pathbuf;
399 while (0 != (*q++ = *p++));
400 q[-1] = '/';
401 fnptr = q;
402 listdir(path);
403 }
404 }
405 exit(anyfound==0);
406 }
407