blob: 0c7f6522cea486c270dac3a268c726ed23f8e209 [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:
Erik Andersen9ffdaa62000-02-11 21:55:04 +000032 * 1. ls -l of a directory doesn't give "total <blocks>" header
33 * 2. ls of a symlink to a directory doesn't list directory contents
34 * 3. hidden files can make column width too large
35 *
Eric Andersencc8ed391999-10-05 16:24:54 +000036 * 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
Eric Andersencc8ed391999-10-05 16:24:54 +000073#define FMT_AUTO 0
Erik Andersene49d5ec2000-02-08 19:58:47 +000074#define FMT_LONG 1 /* one record per line, extended info */
75#define FMT_SINGLE 2 /* one record per line */
76#define FMT_ROWS 3 /* print across rows */
77#define FMT_COLUMNS 3 /* fill columns (same, since we don't sort) */
Eric Andersencc8ed391999-10-05 16:24:54 +000078
79#define TIME_MOD 0
80#define TIME_CHANGE 1
81#define TIME_ACCESS 2
82
Erik Andersene49d5ec2000-02-08 19:58:47 +000083#define DISP_FTYPE 1 /* show character for file type */
84#define DISP_EXEC 2 /* show '*' if regular executable file */
85#define DISP_HIDDEN 4 /* show files starting . (except . and ..) */
86#define DISP_DOT 8 /* show . and .. */
87#define DISP_NUMERIC 16 /* numeric uid and gid */
88#define DISP_FULLTIME 32 /* show extended time display */
89#define DIR_NOLIST 64 /* show directory as itself, not contents */
90#define DISP_DIRNAME 128 /* show directory name (for internal use) */
Eric Andersencc8ed391999-10-05 16:24:54 +000091
Erik Andersen1ad302a2000-03-24 00:54:46 +000092#ifndef MAJOR
93#define MAJOR(dev) (((dev)>>8)&0xff)
94#define MINOR(dev) ((dev)&0xff)
95#endif
96
Erik Andersene49d5ec2000-02-08 19:58:47 +000097static unsigned char display_fmt = FMT_AUTO;
98static unsigned short opts = 0;
99static unsigned short column = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000100
Eric Andersene1850dd1999-11-19 05:42:32 +0000101#ifdef BB_FEATURE_AUTOWIDTH
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000102static unsigned short terminal_width = 0;
103static unsigned short column_width = 0;
104static unsigned short toplevel_column_width = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000105#else
106#define terminal_width TERMINAL_WIDTH
107#define column_width COLUMN_WIDTH
108#endif
109
Eric Andersene1850dd1999-11-19 05:42:32 +0000110#ifdef BB_FEATURE_LS_TIMESTAMPS
Eric Andersencc8ed391999-10-05 16:24:54 +0000111static unsigned char time_fmt = TIME_MOD;
112#endif
113
114#define wr(data,len) fwrite(data, 1, len, stdout)
115
116static void writenum(long val, short minwidth)
117{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000118 char scratch[128];
Eric Andersencc8ed391999-10-05 16:24:54 +0000119
120 char *p = scratch + sizeof(scratch);
121 short len = 0;
122 short neg = (val < 0);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000123
124 if (neg)
125 val = -val;
Eric Andersencc8ed391999-10-05 16:24:54 +0000126 do
127 *--p = (val % 10) + '0', len++, val /= 10;
128 while (val);
129 if (neg)
130 *--p = '-', len++;
131 while (len < minwidth)
132 *--p = ' ', len++;
133 wr(p, len);
134 column += len;
135}
136
137static void newline(void)
138{
139 if (column > 0) {
140 wr("\n", 1);
141 column = 0;
142 }
143}
144
145static void tab(short col)
146{
147 static const char spaces[] = " ";
Erik Andersene49d5ec2000-02-08 19:58:47 +0000148
149#define nspaces ((sizeof spaces)-1) /* null terminator! */
150
Eric Andersencc8ed391999-10-05 16:24:54 +0000151 short n = col - column;
152
153 if (n > 0) {
154 column = col;
155 while (n > nspaces) {
156 wr(spaces, nspaces);
157 n -= nspaces;
158 }
159 /* must be 1...(sizeof spaces) left */
160 wr(spaces, n);
161 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000162#undef nspaces
Eric Andersencc8ed391999-10-05 16:24:54 +0000163}
164
Eric Andersene1850dd1999-11-19 05:42:32 +0000165#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersene77ae3a1999-10-19 20:03:34 +0000166static char append_char(mode_t mode)
Eric Andersencc8ed391999-10-05 16:24:54 +0000167{
168 if (!(opts & DISP_FTYPE))
169 return '\0';
Erik Andersene49d5ec2000-02-08 19:58:47 +0000170 if ((opts & DISP_EXEC) && S_ISREG(mode)
171 && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*';
Eric Andersencc8ed391999-10-05 16:24:54 +0000172 return APPCHAR(mode);
173}
174#endif
175
176/**
177 **
178 ** Display a file or directory as a single item
179 ** (in either long or short format)
180 **
181 **/
182
Erik Andersene49d5ec2000-02-08 19:58:47 +0000183static void list_single(const char *name, struct stat *info,
184 const char *fullname)
Eric Andersencc8ed391999-10-05 16:24:54 +0000185{
Erik Andersenfac10d72000-02-07 05:29:42 +0000186 char scratch[PATH_MAX + 1];
Eric Andersencc8ed391999-10-05 16:24:54 +0000187 short len = strlen(name);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000188
Eric Andersene1850dd1999-11-19 05:42:32 +0000189#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000190 char append = append_char(info->st_mode);
191#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000192
Eric Andersencc8ed391999-10-05 16:24:54 +0000193 if (display_fmt == FMT_LONG) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000194 mode_t mode = info->st_mode;
195
Eric Andersencc8ed391999-10-05 16:24:54 +0000196 newline();
Eric Andersen50d63601999-11-09 01:47:36 +0000197 wr(modeString(mode), 10);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000198 column = 10;
199 writenum((long) info->st_nlink, (short) 5);
Eric Andersencc8ed391999-10-05 16:24:54 +0000200 fputs(" ", stdout);
Eric Andersene1850dd1999-11-19 05:42:32 +0000201#ifdef BB_FEATURE_LS_USERNAME
Eric Andersencc8ed391999-10-05 16:24:54 +0000202 if (!(opts & DISP_NUMERIC)) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000203 memset(scratch, 0, sizeof(scratch));
204 my_getpwuid(scratch, info->st_uid);
Erik Andersen1266a131999-12-29 22:19:46 +0000205 if (*scratch) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000206 fputs(scratch, stdout);
207 if (strlen(scratch) <= 8)
208 wr(" ", 9 - strlen(scratch));
209 } else {
210 writenum((long) info->st_uid, (short) 8);
Eric Andersen394f7641999-11-23 21:38:12 +0000211 fputs(" ", stdout);
212 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000213 } else
214#endif
Eric Andersen394f7641999-11-23 21:38:12 +0000215 {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000216 writenum((long) info->st_uid, (short) 8);
217 fputs(" ", stdout);
Eric Andersen394f7641999-11-23 21:38:12 +0000218 }
Eric Andersene1850dd1999-11-19 05:42:32 +0000219#ifdef BB_FEATURE_LS_USERNAME
Eric Andersencc8ed391999-10-05 16:24:54 +0000220 if (!(opts & DISP_NUMERIC)) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000221 memset(scratch, 0, sizeof(scratch));
222 my_getgrgid(scratch, info->st_gid);
Erik Andersen1266a131999-12-29 22:19:46 +0000223 if (*scratch) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000224 fputs(scratch, stdout);
225 if (strlen(scratch) <= 8)
226 wr(" ", 8 - strlen(scratch));
227 } else
228 writenum((long) info->st_gid, (short) 8);
Eric Andersencc8ed391999-10-05 16:24:54 +0000229 } else
230#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000231 writenum((long) info->st_gid, (short) 8);
Erik Andersen1266a131999-12-29 22:19:46 +0000232 //tab(26);
Eric Andersencc8ed391999-10-05 16:24:54 +0000233 if (S_ISBLK(mode) || S_ISCHR(mode)) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000234 writenum((long) MAJOR(info->st_rdev), (short) 3);
Eric Andersencc8ed391999-10-05 16:24:54 +0000235 fputs(", ", stdout);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000236 writenum((long) MINOR(info->st_rdev), (short) 3);
237 } else
238 writenum((long) info->st_size, (short) 8);
Eric Andersencc8ed391999-10-05 16:24:54 +0000239 fputs(" ", stdout);
Erik Andersen1266a131999-12-29 22:19:46 +0000240 //tab(32);
Eric Andersene1850dd1999-11-19 05:42:32 +0000241#ifdef BB_FEATURE_LS_TIMESTAMPS
Eric Andersencc8ed391999-10-05 16:24:54 +0000242 {
243 time_t cal;
244 char *string;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000245
246 switch (time_fmt) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000247 case TIME_CHANGE:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000248 cal = info->st_ctime;
249 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000250 case TIME_ACCESS:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000251 cal = info->st_atime;
252 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000253 default:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000254 cal = info->st_mtime;
255 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000256 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000257 string = ctime(&cal);
Eric Andersencc8ed391999-10-05 16:24:54 +0000258 if (opts & DISP_FULLTIME)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000259 wr(string, 24);
Eric Andersencc8ed391999-10-05 16:24:54 +0000260 else {
261 time_t age = time(NULL) - cal;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000262
263 wr(string + 4, 7); /* mmm_dd_ */
264 if (age < 3600L * 24 * 365 / 2 && age > -15 * 60)
Eric Andersencc8ed391999-10-05 16:24:54 +0000265 /* hh:mm if less than 6 months old */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000266 wr(string + 11, 5);
Eric Andersencc8ed391999-10-05 16:24:54 +0000267 else
268 /* _yyyy otherwise */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000269 wr(string + 19, 5);
Eric Andersencc8ed391999-10-05 16:24:54 +0000270 }
271 wr(" ", 1);
272 }
273#else
274 fputs("--- -- ----- ", stdout);
275#endif
276 wr(name, len);
277 if (S_ISLNK(mode)) {
278 wr(" -> ", 4);
Eric Andersen07e52971999-11-07 07:38:08 +0000279 len = readlink(fullname, scratch, sizeof scratch);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000280 if (len > 0)
281 fwrite(scratch, 1, len, stdout);
Eric Andersene1850dd1999-11-19 05:42:32 +0000282#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000283 /* show type of destination */
284 if (opts & DISP_FTYPE) {
Eric Andersen07e52971999-11-07 07:38:08 +0000285 if (!stat(fullname, info)) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000286 append = append_char(info->st_mode);
287 if (append)
288 fputc(append, stdout);
289 }
290 }
291#endif
292 }
Eric Andersene1850dd1999-11-19 05:42:32 +0000293#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000294 else if (append)
295 wr(&append, 1);
296#endif
297 } else {
298 static short nexttab = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000299
Eric Andersencc8ed391999-10-05 16:24:54 +0000300 /* sort out column alignment */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000301 if (column == 0); /* nothing to do */
Eric Andersencc8ed391999-10-05 16:24:54 +0000302 else if (display_fmt == FMT_SINGLE)
303 newline();
304 else {
305 if (nexttab + column_width > terminal_width
Eric Andersene1850dd1999-11-19 05:42:32 +0000306#ifndef BB_FEATURE_AUTOWIDTH
Erik Andersene49d5ec2000-02-08 19:58:47 +0000307 || nexttab + len >= terminal_width
Eric Andersencc8ed391999-10-05 16:24:54 +0000308#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000309 )
Eric Andersencc8ed391999-10-05 16:24:54 +0000310 newline();
311 else
312 tab(nexttab);
313 }
314 /* work out where next column starts */
Eric Andersene1850dd1999-11-19 05:42:32 +0000315#ifdef BB_FEATURE_AUTOWIDTH
Eric Andersencc8ed391999-10-05 16:24:54 +0000316 /* we know the calculated width is big enough */
317 nexttab = column + column_width + COLUMN_GAP;
318#else
319 /* might cover more than one fixed-width column */
320 nexttab = column;
321 do
322 nexttab += column_width + COLUMN_GAP;
323 while (nexttab < (column + len + COLUMN_GAP));
324#endif
325 /* now write the data */
326 wr(name, len);
327 column = column + len;
Eric Andersene1850dd1999-11-19 05:42:32 +0000328#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000329 if (append)
330 wr(&append, 1), column++;
331#endif
332 }
333}
334
335/**
336 **
337 ** List the given file or directory, expanding a directory
338 ** to show its contents if required
339 **
340 **/
341
342static int list_item(const char *name)
343{
344 struct stat info;
345 DIR *dir;
346 struct dirent *entry;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000347 char fullname[MAXNAMLEN + 1], *fnend;
348
Eric Andersencc8ed391999-10-05 16:24:54 +0000349 if (lstat(name, &info))
350 goto listerr;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000351
352 if (!S_ISDIR(info.st_mode) || (opts & DIR_NOLIST)) {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000353#ifdef BB_FEATURE_AUTOWIDTH
354 column_width = toplevel_column_width;
355#endif
Eric Andersen07e52971999-11-07 07:38:08 +0000356 list_single(name, &info, name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000357 return 0;
358 }
359
360 /* Otherwise, it's a directory we want to list the contents of */
361
Erik Andersene49d5ec2000-02-08 19:58:47 +0000362 if (opts & DISP_DIRNAME) { /* identify the directory */
Eric Andersencc8ed391999-10-05 16:24:54 +0000363 if (column)
364 wr("\n\n", 2), column = 0;
365 wr(name, strlen(name));
366 wr(":\n", 2);
367 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000368
Eric Andersencc8ed391999-10-05 16:24:54 +0000369 dir = opendir(name);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000370 if (!dir)
371 goto listerr;
Eric Andersene1850dd1999-11-19 05:42:32 +0000372#ifdef BB_FEATURE_AUTOWIDTH
Eric Andersencc8ed391999-10-05 16:24:54 +0000373 column_width = 0;
374 while ((entry = readdir(dir)) != NULL) {
375 short w = strlen(entry->d_name);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000376
Eric Andersencc8ed391999-10-05 16:24:54 +0000377 if (column_width < w)
378 column_width = w;
379 }
380#ifdef HAS_REWINDDIR
381 rewinddir(dir);
382#else
383 closedir(dir);
384 dir = opendir(name);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000385 if (!dir)
386 goto listerr;
Eric Andersencc8ed391999-10-05 16:24:54 +0000387#endif
388#endif
389
390 /* List the contents */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000391
392 strcpy(fullname, name); /* *** ignore '.' by itself */
393 fnend = fullname + strlen(fullname);
Eric Andersencc8ed391999-10-05 16:24:54 +0000394 if (fnend[-1] != '/')
395 *fnend++ = '/';
Erik Andersene49d5ec2000-02-08 19:58:47 +0000396
Eric Andersencc8ed391999-10-05 16:24:54 +0000397 while ((entry = readdir(dir)) != NULL) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000398 const char *en = entry->d_name;
399
Eric Andersencc8ed391999-10-05 16:24:54 +0000400 if (en[0] == '.') {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000401 if (!en[1] || (en[1] == '.' && !en[2])) { /* . or .. */
Eric Andersencc8ed391999-10-05 16:24:54 +0000402 if (!(opts & DISP_DOT))
403 continue;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000404 } else if (!(opts & DISP_HIDDEN))
Eric Andersencc8ed391999-10-05 16:24:54 +0000405 continue;
406 }
407 /* FIXME: avoid stat if not required */
408 strcpy(fnend, entry->d_name);
409 if (lstat(fullname, &info))
Erik Andersene49d5ec2000-02-08 19:58:47 +0000410 goto direrr; /* (shouldn't fail) */
Eric Andersen07e52971999-11-07 07:38:08 +0000411 list_single(entry->d_name, &info, fullname);
Eric Andersencc8ed391999-10-05 16:24:54 +0000412 }
413 closedir(dir);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000414
415 if (opts & DISP_DIRNAME) { /* separate the directory */
416 if (column) {
417 wr("\n", 1);
418 }
419 wr("\n", 1);
420 column = 0;
421 }
422
Eric Andersencc8ed391999-10-05 16:24:54 +0000423 return 0;
424
Erik Andersene49d5ec2000-02-08 19:58:47 +0000425 direrr:
426 closedir(dir);
427 listerr:
Eric Andersencc8ed391999-10-05 16:24:54 +0000428 newline();
Eric Andersen9d3aba71999-10-06 09:04:55 +0000429 perror(name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000430 return 1;
431}
432
Eric Andersenf5a38381999-10-19 22:26:25 +0000433static const char ls_usage[] = "ls [-1a"
Eric Andersene1850dd1999-11-19 05:42:32 +0000434#ifdef BB_FEATURE_LS_TIMESTAMPS
Eric Andersencc8ed391999-10-05 16:24:54 +0000435 "c"
436#endif
437 "d"
Eric Andersene1850dd1999-11-19 05:42:32 +0000438#ifdef BB_FEATURE_LS_TIMESTAMPS
Eric Andersencc8ed391999-10-05 16:24:54 +0000439 "e"
440#endif
441 "ln"
Eric Andersene1850dd1999-11-19 05:42:32 +0000442#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000443 "p"
444#endif
Eric Andersene1850dd1999-11-19 05:42:32 +0000445#ifdef BB_FEATURE_LS_TIMESTAMPS
Eric Andersencc8ed391999-10-05 16:24:54 +0000446 "u"
447#endif
448 "xAC"
Eric Andersene1850dd1999-11-19 05:42:32 +0000449#ifdef BB_FEATURE_LS_FILETYPES
Eric Andersencc8ed391999-10-05 16:24:54 +0000450 "F"
451#endif
Erik Andersen9cf3bfa2000-04-13 18:49:43 +0000452 "] [filenames...]\n\n"
453 "Options:\n"
454 "\t-a\tdo not hide entries starting with .\n"
455#ifdef BB_FEATURE_LS_TIMESTAMPS
456 "\t-c\twith -l: show ctime (the time of last\n"
457 "\t\tmodification of file status information)\n"
Eric Andersencc8ed391999-10-05 16:24:54 +0000458#endif
Erik Andersen9cf3bfa2000-04-13 18:49:43 +0000459 "\t-d\tlist directory entries instead of contents\n"
460#ifdef BB_FEATURE_LS_TIMESTAMPS
461 "\t-e\tlist both full date and full time\n"
462#endif
463 "\t-l\tuse a long listing format\n"
464 "\t-n\tlist numeric UIDs and GIDs instead of names\n"
465#ifdef BB_FEATURE_LS_FILETYPES
466 "\t-p\tappend indicator (one of /=@|) to entries\n"
467#endif
468#ifdef BB_FEATURE_LS_TIMESTAMPS
469 "\t-u\twith -l: show access time (the time of last\n"
470 "\t\taccess of the file)\n"
471#endif
472 "\t-x\tlist entries by lines instead of by columns\n"
473 "\t-A\tdo not list implied . and ..\n"
474 "\t-C\tlist entries by columns\n"
475#ifdef BB_FEATURE_LS_FILETYPES
476 "\t-F\tappend indicator (one of */=@|) to entries\n"
477#endif
478 ;
Eric Andersencc8ed391999-10-05 16:24:54 +0000479
Erik Andersene49d5ec2000-02-08 19:58:47 +0000480extern int ls_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000481{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000482 int argi = 1, i;
483
Eric Andersencc8ed391999-10-05 16:24:54 +0000484 /* process options */
485 while (argi < argc && argv[argi][0] == '-') {
486 const char *p = &argv[argi][1];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000487
488 if (!*p)
489 goto print_usage_message; /* "-" by itself not allowed */
Eric Andersencc8ed391999-10-05 16:24:54 +0000490 if (*p == '-') {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000491 if (!p[1]) { /* "--" forces end of options */
Eric Andersencc8ed391999-10-05 16:24:54 +0000492 argi++;
493 break;
494 }
495 /* it's a long option name - we don't support them */
496 goto print_usage_message;
497 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000498
Eric Andersencc8ed391999-10-05 16:24:54 +0000499 while (*p)
500 switch (*p++) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000501 case 'l':
502 display_fmt = FMT_LONG;
503 break;
504 case '1':
505 display_fmt = FMT_SINGLE;
506 break;
507 case 'x':
508 display_fmt = FMT_ROWS;
509 break;
510 case 'C':
511 display_fmt = FMT_COLUMNS;
512 break;
Eric Andersene1850dd1999-11-19 05:42:32 +0000513#ifdef BB_FEATURE_LS_FILETYPES
Erik Andersene49d5ec2000-02-08 19:58:47 +0000514 case 'p':
515 opts |= DISP_FTYPE;
516 break;
517 case 'F':
518 opts |= DISP_FTYPE | DISP_EXEC;
519 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000520#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000521 case 'A':
522 opts |= DISP_HIDDEN;
523 break;
524 case 'a':
525 opts |= DISP_HIDDEN | DISP_DOT;
526 break;
527 case 'n':
528 opts |= DISP_NUMERIC;
529 break;
530 case 'd':
531 opts |= DIR_NOLIST;
532 break;
Eric Andersene1850dd1999-11-19 05:42:32 +0000533#ifdef BB_FEATURE_LS_TIMESTAMPS
Erik Andersene49d5ec2000-02-08 19:58:47 +0000534 case 'u':
535 time_fmt = TIME_ACCESS;
536 break;
537 case 'c':
538 time_fmt = TIME_CHANGE;
539 break;
540 case 'e':
541 opts |= DISP_FULLTIME;
542 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000543#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000544 default:
545 goto print_usage_message;
Eric Andersencc8ed391999-10-05 16:24:54 +0000546 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000547
Eric Andersencc8ed391999-10-05 16:24:54 +0000548 argi++;
549 }
550
551 /* choose a display format */
552 if (display_fmt == FMT_AUTO)
Eric Andersen08b10341999-11-19 02:38:58 +0000553 display_fmt = isatty(fileno(stdout)) ? FMT_COLUMNS : FMT_SINGLE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000554 if (argi < argc - 1)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000555 opts |= DISP_DIRNAME; /* 2 or more items? label directories */
Eric Andersene1850dd1999-11-19 05:42:32 +0000556#ifdef BB_FEATURE_AUTOWIDTH
Eric Andersencc8ed391999-10-05 16:24:54 +0000557 /* could add a -w option and/or TIOCGWINSZ call */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000558 if (terminal_width < 1)
559 terminal_width = TERMINAL_WIDTH;
560
Eric Andersencc8ed391999-10-05 16:24:54 +0000561 for (i = argi; i < argc; i++) {
562 int len = strlen(argv[i]);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000563
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000564 if (toplevel_column_width < len)
565 toplevel_column_width = len;
Eric Andersencc8ed391999-10-05 16:24:54 +0000566 }
567#endif
568
569 /* process files specified, or current directory if none */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000570 i = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000571 if (argi == argc)
572 i = list_item(".");
573 while (argi < argc)
574 i |= list_item(argv[argi++]);
575 newline();
Erik Andersene49d5ec2000-02-08 19:58:47 +0000576 exit(i);
Eric Andersencc8ed391999-10-05 16:24:54 +0000577
Erik Andersene49d5ec2000-02-08 19:58:47 +0000578 print_usage_message:
579 usage(ls_usage);
580 exit(FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000581}