blob: f23c1e086d385b32e38c7a38ac726ee52fc7df05 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersen9d3aba71999-10-06 09:04:55 +00002/*
Eric Andersencc8ed391999-10-05 16:24:54 +00003 * tiny-ls.c version 0.1.0: A minimalist 'ls'
4 * Copyright (C) 1996 Brian Candler <B.Candler@pobox.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21/*
22 * To achieve a small memory footprint, this version of 'ls' doesn't do any
23 * file sorting, and only has the most essential command line switches
24 * (i.e. the ones I couldn't live without :-) All features which involve
25 * linking in substantial chunks of libc can be disabled.
26 *
27 * Although I don't really want to add new features to this program to
28 * keep it small, I *am* interested to receive bug fixes and ways to make
29 * it more portable.
30 *
31 * KNOWN BUGS:
32 * 1. messy output if you mix files and directories on the command line
33 * 2. ls -l of a directory doesn't give "total <blocks>" header
34 * 3. ls of a symlink to a directory doesn't list directory contents
35 * 4. hidden files can make column width too large
36 * NON-OPTIMAL BEHAVIOUR:
37 * 1. autowidth reads directories twice
38 * 2. if you do a short directory listing without filetype characters
39 * appended, there's no need to stat each one
40 * PORTABILITY:
41 * 1. requires lstat (BSD) - how do you do it without?
42 */
43
Erik Andersene49d5ec2000-02-08 19:58:47 +000044#define TERMINAL_WIDTH 80 /* use 79 if your terminal has linefold bug */
45#define COLUMN_WIDTH 14 /* default if AUTOWIDTH not defined */
46#define COLUMN_GAP 2 /* includes the file type char, if present */
Eric Andersen3c163821999-10-14 22:16:57 +000047#define HAS_REWINDDIR
Eric Andersencc8ed391999-10-05 16:24:54 +000048
49/************************************************************************/
50
Eric Andersene77ae3a1999-10-19 20:03:34 +000051#include "internal.h"
52#if !defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
Erik Andersene49d5ec2000-02-08 19:58:47 +000053# include <linux/types.h>
Eric Andersencc8ed391999-10-05 16:24:54 +000054#else
Erik Andersene49d5ec2000-02-08 19:58:47 +000055# include <sys/types.h>
Eric Andersencc8ed391999-10-05 16:24:54 +000056#endif
57#include <sys/stat.h>
58#include <stdio.h>
59#include <unistd.h>
60#include <dirent.h>
61#include <errno.h>
62#include <stdio.h>
Eric Andersene1850dd1999-11-19 05:42:32 +000063#ifdef BB_FEATURE_LS_TIMESTAMPS
Eric Andersencc8ed391999-10-05 16:24:54 +000064#include <time.h>
65#endif
66
67#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
68#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
Eric Andersene1850dd1999-11-19 05:42:32 +000069#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +000070#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
71#endif
72
73#ifndef MAJOR
74#define MAJOR(dev) (((dev)>>8)&0xff)
75#define MINOR(dev) ((dev)&0xff)
76#endif
77
Eric Andersencc8ed391999-10-05 16:24:54 +000078#define FMT_AUTO 0
Erik Andersene49d5ec2000-02-08 19:58:47 +000079#define FMT_LONG 1 /* one record per line, extended info */
80#define FMT_SINGLE 2 /* one record per line */
81#define FMT_ROWS 3 /* print across rows */
82#define FMT_COLUMNS 3 /* fill columns (same, since we don't sort) */
Eric Andersencc8ed391999-10-05 16:24:54 +000083
84#define TIME_MOD 0
85#define TIME_CHANGE 1
86#define TIME_ACCESS 2
87
Erik Andersene49d5ec2000-02-08 19:58:47 +000088#define DISP_FTYPE 1 /* show character for file type */
89#define DISP_EXEC 2 /* show '*' if regular executable file */
90#define DISP_HIDDEN 4 /* show files starting . (except . and ..) */
91#define DISP_DOT 8 /* show . and .. */
92#define DISP_NUMERIC 16 /* numeric uid and gid */
93#define DISP_FULLTIME 32 /* show extended time display */
94#define DIR_NOLIST 64 /* show directory as itself, not contents */
95#define DISP_DIRNAME 128 /* show directory name (for internal use) */
96#define DIR_RECURSE 256 /* -R (not yet implemented) */
Eric Andersencc8ed391999-10-05 16:24:54 +000097
Erik Andersene49d5ec2000-02-08 19:58:47 +000098static unsigned char display_fmt = FMT_AUTO;
99static unsigned short opts = 0;
100static unsigned short column = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000101
Eric Andersene1850dd1999-11-19 05:42:32 +0000102#ifdef BB_FEATURE_AUTOWIDTH
Eric Andersencc8ed391999-10-05 16:24:54 +0000103static unsigned short terminal_width = 0, column_width = 0;
104#else
105#define terminal_width TERMINAL_WIDTH
106#define column_width COLUMN_WIDTH
107#endif
108
Eric Andersene1850dd1999-11-19 05:42:32 +0000109#ifdef BB_FEATURE_LS_TIMESTAMPS
Eric Andersencc8ed391999-10-05 16:24:54 +0000110static unsigned char time_fmt = TIME_MOD;
111#endif
112
113#define wr(data,len) fwrite(data, 1, len, stdout)
114
115static void writenum(long val, short minwidth)
116{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000117 char scratch[128];
Eric Andersencc8ed391999-10-05 16:24:54 +0000118
119 char *p = scratch + sizeof(scratch);
120 short len = 0;
121 short neg = (val < 0);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000122
123 if (neg)
124 val = -val;
Eric Andersencc8ed391999-10-05 16:24:54 +0000125 do
126 *--p = (val % 10) + '0', len++, val /= 10;
127 while (val);
128 if (neg)
129 *--p = '-', len++;
130 while (len < minwidth)
131 *--p = ' ', len++;
132 wr(p, len);
133 column += len;
134}
135
136static void newline(void)
137{
138 if (column > 0) {
139 wr("\n", 1);
140 column = 0;
141 }
142}
143
144static void tab(short col)
145{
146 static const char spaces[] = " ";
Erik Andersene49d5ec2000-02-08 19:58:47 +0000147
148#define nspaces ((sizeof spaces)-1) /* null terminator! */
149
Eric Andersencc8ed391999-10-05 16:24:54 +0000150 short n = col - column;
151
152 if (n > 0) {
153 column = col;
154 while (n > nspaces) {
155 wr(spaces, nspaces);
156 n -= nspaces;
157 }
158 /* must be 1...(sizeof spaces) left */
159 wr(spaces, n);
160 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000161#undef nspaces
Eric Andersencc8ed391999-10-05 16:24:54 +0000162}
163
Eric Andersene1850dd1999-11-19 05:42:32 +0000164#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersene77ae3a1999-10-19 20:03:34 +0000165static char append_char(mode_t mode)
Eric Andersencc8ed391999-10-05 16:24:54 +0000166{
167 if (!(opts & DISP_FTYPE))
168 return '\0';
Erik Andersene49d5ec2000-02-08 19:58:47 +0000169 if ((opts & DISP_EXEC) && S_ISREG(mode)
170 && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*';
Eric Andersencc8ed391999-10-05 16:24:54 +0000171 return APPCHAR(mode);
172}
173#endif
174
175/**
176 **
177 ** Display a file or directory as a single item
178 ** (in either long or short format)
179 **
180 **/
181
Erik Andersene49d5ec2000-02-08 19:58:47 +0000182static void list_single(const char *name, struct stat *info,
183 const char *fullname)
Eric Andersencc8ed391999-10-05 16:24:54 +0000184{
Erik Andersenfac10d72000-02-07 05:29:42 +0000185 char scratch[PATH_MAX + 1];
Eric Andersencc8ed391999-10-05 16:24:54 +0000186 short len = strlen(name);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000187
Eric Andersene1850dd1999-11-19 05:42:32 +0000188#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000189 char append = append_char(info->st_mode);
190#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000191
Eric Andersencc8ed391999-10-05 16:24:54 +0000192 if (display_fmt == FMT_LONG) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000193 mode_t mode = info->st_mode;
194
Eric Andersencc8ed391999-10-05 16:24:54 +0000195 newline();
Eric Andersen50d63601999-11-09 01:47:36 +0000196 wr(modeString(mode), 10);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000197 column = 10;
198 writenum((long) info->st_nlink, (short) 5);
Eric Andersencc8ed391999-10-05 16:24:54 +0000199 fputs(" ", stdout);
Eric Andersene1850dd1999-11-19 05:42:32 +0000200#ifdef BB_FEATURE_LS_USERNAME
Eric Andersencc8ed391999-10-05 16:24:54 +0000201 if (!(opts & DISP_NUMERIC)) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000202 memset(scratch, 0, sizeof(scratch));
203 my_getpwuid(scratch, info->st_uid);
Erik Andersen1266a131999-12-29 22:19:46 +0000204 if (*scratch) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000205 fputs(scratch, stdout);
206 if (strlen(scratch) <= 8)
207 wr(" ", 9 - strlen(scratch));
208 } else {
209 writenum((long) info->st_uid, (short) 8);
Eric Andersen394f7641999-11-23 21:38:12 +0000210 fputs(" ", stdout);
211 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000212 } else
213#endif
Eric Andersen394f7641999-11-23 21:38:12 +0000214 {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000215 writenum((long) info->st_uid, (short) 8);
216 fputs(" ", stdout);
Eric Andersen394f7641999-11-23 21:38:12 +0000217 }
Eric Andersene1850dd1999-11-19 05:42:32 +0000218#ifdef BB_FEATURE_LS_USERNAME
Eric Andersencc8ed391999-10-05 16:24:54 +0000219 if (!(opts & DISP_NUMERIC)) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000220 memset(scratch, 0, sizeof(scratch));
221 my_getgrgid(scratch, info->st_gid);
Erik Andersen1266a131999-12-29 22:19:46 +0000222 if (*scratch) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000223 fputs(scratch, stdout);
224 if (strlen(scratch) <= 8)
225 wr(" ", 8 - strlen(scratch));
226 } else
227 writenum((long) info->st_gid, (short) 8);
Eric Andersencc8ed391999-10-05 16:24:54 +0000228 } else
229#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000230 writenum((long) info->st_gid, (short) 8);
Erik Andersen1266a131999-12-29 22:19:46 +0000231 //tab(26);
Eric Andersencc8ed391999-10-05 16:24:54 +0000232 if (S_ISBLK(mode) || S_ISCHR(mode)) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000233 writenum((long) MAJOR(info->st_rdev), (short) 3);
Eric Andersencc8ed391999-10-05 16:24:54 +0000234 fputs(", ", stdout);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000235 writenum((long) MINOR(info->st_rdev), (short) 3);
236 } else
237 writenum((long) info->st_size, (short) 8);
Eric Andersencc8ed391999-10-05 16:24:54 +0000238 fputs(" ", stdout);
Erik Andersen1266a131999-12-29 22:19:46 +0000239 //tab(32);
Eric Andersene1850dd1999-11-19 05:42:32 +0000240#ifdef BB_FEATURE_LS_TIMESTAMPS
Eric Andersencc8ed391999-10-05 16:24:54 +0000241 {
242 time_t cal;
243 char *string;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000244
245 switch (time_fmt) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000246 case TIME_CHANGE:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000247 cal = info->st_ctime;
248 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000249 case TIME_ACCESS:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000250 cal = info->st_atime;
251 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000252 default:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000253 cal = info->st_mtime;
254 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000255 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000256 string = ctime(&cal);
Eric Andersencc8ed391999-10-05 16:24:54 +0000257 if (opts & DISP_FULLTIME)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000258 wr(string, 24);
Eric Andersencc8ed391999-10-05 16:24:54 +0000259 else {
260 time_t age = time(NULL) - cal;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000261
262 wr(string + 4, 7); /* mmm_dd_ */
263 if (age < 3600L * 24 * 365 / 2 && age > -15 * 60)
Eric Andersencc8ed391999-10-05 16:24:54 +0000264 /* hh:mm if less than 6 months old */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000265 wr(string + 11, 5);
Eric Andersencc8ed391999-10-05 16:24:54 +0000266 else
267 /* _yyyy otherwise */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000268 wr(string + 19, 5);
Eric Andersencc8ed391999-10-05 16:24:54 +0000269 }
270 wr(" ", 1);
271 }
272#else
273 fputs("--- -- ----- ", stdout);
274#endif
275 wr(name, len);
276 if (S_ISLNK(mode)) {
277 wr(" -> ", 4);
Eric Andersen07e52971999-11-07 07:38:08 +0000278 len = readlink(fullname, scratch, sizeof scratch);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000279 if (len > 0)
280 fwrite(scratch, 1, len, stdout);
Eric Andersene1850dd1999-11-19 05:42:32 +0000281#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000282 /* show type of destination */
283 if (opts & DISP_FTYPE) {
Eric Andersen07e52971999-11-07 07:38:08 +0000284 if (!stat(fullname, info)) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000285 append = append_char(info->st_mode);
286 if (append)
287 fputc(append, stdout);
288 }
289 }
290#endif
291 }
Eric Andersene1850dd1999-11-19 05:42:32 +0000292#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000293 else if (append)
294 wr(&append, 1);
295#endif
296 } else {
297 static short nexttab = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000298
Eric Andersencc8ed391999-10-05 16:24:54 +0000299 /* sort out column alignment */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000300 if (column == 0); /* nothing to do */
Eric Andersencc8ed391999-10-05 16:24:54 +0000301 else if (display_fmt == FMT_SINGLE)
302 newline();
303 else {
304 if (nexttab + column_width > terminal_width
Eric Andersene1850dd1999-11-19 05:42:32 +0000305#ifndef BB_FEATURE_AUTOWIDTH
Erik Andersene49d5ec2000-02-08 19:58:47 +0000306 || nexttab + len >= terminal_width
Eric Andersencc8ed391999-10-05 16:24:54 +0000307#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000308 )
Eric Andersencc8ed391999-10-05 16:24:54 +0000309 newline();
310 else
311 tab(nexttab);
312 }
313 /* work out where next column starts */
Eric Andersene1850dd1999-11-19 05:42:32 +0000314#ifdef BB_FEATURE_AUTOWIDTH
Eric Andersencc8ed391999-10-05 16:24:54 +0000315 /* we know the calculated width is big enough */
316 nexttab = column + column_width + COLUMN_GAP;
317#else
318 /* might cover more than one fixed-width column */
319 nexttab = column;
320 do
321 nexttab += column_width + COLUMN_GAP;
322 while (nexttab < (column + len + COLUMN_GAP));
323#endif
324 /* now write the data */
325 wr(name, len);
326 column = column + len;
Eric Andersene1850dd1999-11-19 05:42:32 +0000327#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000328 if (append)
329 wr(&append, 1), column++;
330#endif
331 }
332}
333
334/**
335 **
336 ** List the given file or directory, expanding a directory
337 ** to show its contents if required
338 **
339 **/
340
341static int list_item(const char *name)
342{
343 struct stat info;
344 DIR *dir;
345 struct dirent *entry;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000346 char fullname[MAXNAMLEN + 1], *fnend;
347
Eric Andersencc8ed391999-10-05 16:24:54 +0000348 if (lstat(name, &info))
349 goto listerr;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000350
351 if (!S_ISDIR(info.st_mode) || (opts & DIR_NOLIST)) {
Eric Andersen07e52971999-11-07 07:38:08 +0000352 list_single(name, &info, name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000353 return 0;
354 }
355
356 /* Otherwise, it's a directory we want to list the contents of */
357
Erik Andersene49d5ec2000-02-08 19:58:47 +0000358 if (opts & DISP_DIRNAME) { /* identify the directory */
Eric Andersencc8ed391999-10-05 16:24:54 +0000359 if (column)
360 wr("\n\n", 2), column = 0;
361 wr(name, strlen(name));
362 wr(":\n", 2);
363 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000364
Eric Andersencc8ed391999-10-05 16:24:54 +0000365 dir = opendir(name);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000366 if (!dir)
367 goto listerr;
Eric Andersene1850dd1999-11-19 05:42:32 +0000368#ifdef BB_FEATURE_AUTOWIDTH
Eric Andersencc8ed391999-10-05 16:24:54 +0000369 column_width = 0;
370 while ((entry = readdir(dir)) != NULL) {
371 short w = strlen(entry->d_name);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000372
Eric Andersencc8ed391999-10-05 16:24:54 +0000373 if (column_width < w)
374 column_width = w;
375 }
376#ifdef HAS_REWINDDIR
377 rewinddir(dir);
378#else
379 closedir(dir);
380 dir = opendir(name);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000381 if (!dir)
382 goto listerr;
Eric Andersencc8ed391999-10-05 16:24:54 +0000383#endif
384#endif
385
386 /* List the contents */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000387
388 strcpy(fullname, name); /* *** ignore '.' by itself */
389 fnend = fullname + strlen(fullname);
Eric Andersencc8ed391999-10-05 16:24:54 +0000390 if (fnend[-1] != '/')
391 *fnend++ = '/';
Erik Andersene49d5ec2000-02-08 19:58:47 +0000392
Eric Andersencc8ed391999-10-05 16:24:54 +0000393 while ((entry = readdir(dir)) != NULL) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000394 const char *en = entry->d_name;
395
Eric Andersencc8ed391999-10-05 16:24:54 +0000396 if (en[0] == '.') {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000397 if (!en[1] || (en[1] == '.' && !en[2])) { /* . or .. */
Eric Andersencc8ed391999-10-05 16:24:54 +0000398 if (!(opts & DISP_DOT))
399 continue;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000400 } else if (!(opts & DISP_HIDDEN))
Eric Andersencc8ed391999-10-05 16:24:54 +0000401 continue;
402 }
403 /* FIXME: avoid stat if not required */
404 strcpy(fnend, entry->d_name);
405 if (lstat(fullname, &info))
Erik Andersene49d5ec2000-02-08 19:58:47 +0000406 goto direrr; /* (shouldn't fail) */
Eric Andersen07e52971999-11-07 07:38:08 +0000407 list_single(entry->d_name, &info, fullname);
Eric Andersencc8ed391999-10-05 16:24:54 +0000408 }
409 closedir(dir);
410 return 0;
411
Erik Andersene49d5ec2000-02-08 19:58:47 +0000412 direrr:
413 closedir(dir);
414 listerr:
Eric Andersencc8ed391999-10-05 16:24:54 +0000415 newline();
Eric Andersen9d3aba71999-10-06 09:04:55 +0000416 perror(name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000417 return 1;
418}
419
Eric Andersenf5a38381999-10-19 22:26:25 +0000420static const char ls_usage[] = "ls [-1a"
Eric Andersene1850dd1999-11-19 05:42:32 +0000421#ifdef BB_FEATURE_LS_TIMESTAMPS
Eric Andersencc8ed391999-10-05 16:24:54 +0000422 "c"
423#endif
424 "d"
Eric Andersene1850dd1999-11-19 05:42:32 +0000425#ifdef BB_FEATURE_LS_TIMESTAMPS
Eric Andersencc8ed391999-10-05 16:24:54 +0000426 "e"
427#endif
428 "ln"
Eric Andersene1850dd1999-11-19 05:42:32 +0000429#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000430 "p"
431#endif
Eric Andersene1850dd1999-11-19 05:42:32 +0000432#ifdef BB_FEATURE_LS_TIMESTAMPS
Eric Andersencc8ed391999-10-05 16:24:54 +0000433 "u"
434#endif
435 "xAC"
Eric Andersene1850dd1999-11-19 05:42:32 +0000436#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000437 "F"
438#endif
439#ifdef FEATURE_RECURSIVE
440 "R"
441#endif
442 "] [filenames...]\n";
443
Erik Andersene49d5ec2000-02-08 19:58:47 +0000444extern int ls_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000445{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000446 int argi = 1, i;
447
Eric Andersencc8ed391999-10-05 16:24:54 +0000448 /* process options */
449 while (argi < argc && argv[argi][0] == '-') {
450 const char *p = &argv[argi][1];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000451
452 if (!*p)
453 goto print_usage_message; /* "-" by itself not allowed */
Eric Andersencc8ed391999-10-05 16:24:54 +0000454 if (*p == '-') {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000455 if (!p[1]) { /* "--" forces end of options */
Eric Andersencc8ed391999-10-05 16:24:54 +0000456 argi++;
457 break;
458 }
459 /* it's a long option name - we don't support them */
460 goto print_usage_message;
461 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000462
Eric Andersencc8ed391999-10-05 16:24:54 +0000463 while (*p)
464 switch (*p++) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000465 case 'l':
466 display_fmt = FMT_LONG;
467 break;
468 case '1':
469 display_fmt = FMT_SINGLE;
470 break;
471 case 'x':
472 display_fmt = FMT_ROWS;
473 break;
474 case 'C':
475 display_fmt = FMT_COLUMNS;
476 break;
Eric Andersene1850dd1999-11-19 05:42:32 +0000477#ifdef BB_FEATURE_LS_FILETYPES
Erik Andersene49d5ec2000-02-08 19:58:47 +0000478 case 'p':
479 opts |= DISP_FTYPE;
480 break;
481 case 'F':
482 opts |= DISP_FTYPE | DISP_EXEC;
483 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000484#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000485 case 'A':
486 opts |= DISP_HIDDEN;
487 break;
488 case 'a':
489 opts |= DISP_HIDDEN | DISP_DOT;
490 break;
491 case 'n':
492 opts |= DISP_NUMERIC;
493 break;
494 case 'd':
495 opts |= DIR_NOLIST;
496 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000497#ifdef FEATURE_RECURSIVE
Erik Andersene49d5ec2000-02-08 19:58:47 +0000498 case 'R':
499 opts |= DIR_RECURSE;
500 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000501#endif
Eric Andersene1850dd1999-11-19 05:42:32 +0000502#ifdef BB_FEATURE_LS_TIMESTAMPS
Erik Andersene49d5ec2000-02-08 19:58:47 +0000503 case 'u':
504 time_fmt = TIME_ACCESS;
505 break;
506 case 'c':
507 time_fmt = TIME_CHANGE;
508 break;
509 case 'e':
510 opts |= DISP_FULLTIME;
511 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000512#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000513 default:
514 goto print_usage_message;
Eric Andersencc8ed391999-10-05 16:24:54 +0000515 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000516
Eric Andersencc8ed391999-10-05 16:24:54 +0000517 argi++;
518 }
519
520 /* choose a display format */
521 if (display_fmt == FMT_AUTO)
Eric Andersen08b10341999-11-19 02:38:58 +0000522 display_fmt = isatty(fileno(stdout)) ? FMT_COLUMNS : FMT_SINGLE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000523 if (argi < argc - 1)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000524 opts |= DISP_DIRNAME; /* 2 or more items? label directories */
Eric Andersene1850dd1999-11-19 05:42:32 +0000525#ifdef BB_FEATURE_AUTOWIDTH
Eric Andersencc8ed391999-10-05 16:24:54 +0000526 /* could add a -w option and/or TIOCGWINSZ call */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000527 if (terminal_width < 1)
528 terminal_width = TERMINAL_WIDTH;
529
Eric Andersencc8ed391999-10-05 16:24:54 +0000530 for (i = argi; i < argc; i++) {
531 int len = strlen(argv[i]);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000532
Eric Andersencc8ed391999-10-05 16:24:54 +0000533 if (column_width < len)
534 column_width = len;
535 }
536#endif
537
538 /* process files specified, or current directory if none */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000539 i = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000540 if (argi == argc)
541 i = list_item(".");
542 while (argi < argc)
543 i |= list_item(argv[argi++]);
544 newline();
Erik Andersene49d5ec2000-02-08 19:58:47 +0000545 exit(i);
Eric Andersencc8ed391999-10-05 16:24:54 +0000546
Erik Andersene49d5ec2000-02-08 19:58:47 +0000547 print_usage_message:
548 usage(ls_usage);
549 exit(FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000550}