/* 'dir', 'vdir' and 'ls' directory listing programs for GNU. This is the ls utility
Copyright (C) 1985-2018 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ The GNUv3 license
/* If ls_mode is LS_MULTI_COL,
the multi-column format is the default regardless
of the type of output device.
This is for the 'dir' program.
If ls_mode is LS_LONG_FORMAT,
the long format is the default regardless of the
type of output device.
This is for the 'vdir' program.
If ls_mode is LS_LS,
the output format depends on whether the output
device is a terminal.
This is for the 'ls' program. */
/* Written by Richard Stallman and David MacKenzie. */
/* Color support by Peter Anvin <Peter.Anvin@linux.org> and Dennis
Flaherty <dennisf@denix.elk.miles.com> based on original patches by
Greg Lee <lee@uhunix.uhcc.hawaii.edu>. */
#include <config.h> Provides system specific information
#include <sys/types.h> Provides system data types
#include <termios.h> ...!includes auto-comment...
#if HAVE_STROPTS_H Line 42
# include <stropts.h> Line 43
#endif Line 44
#include <sys/ioctl.h> ...!includes auto-comment...
#ifdef WINSIZE_IN_PTEM Line 47
# include <sys/stream.h> Line 48
# include <sys/ptem.h> Line 49
#endif Line 50
#include <stdio.h> Provides standard I/O capability
#include <assert.h> ...!includes auto-comment...
#include <setjmp.h> ...!includes auto-comment...
#include <pwd.h> ...!includes auto-comment...
#include <getopt.h> ...!includes auto-comment...
#include <signal.h> ...!includes auto-comment...
#include <selinux/selinux.h> ...!includes auto-comment......!includes auto-comment...
#include <wchar.h> ...!includes auto-comment...
#if HAVE_LANGINFO_CODESET Line 61
# include <langinfo.h> ...!includes auto-comment...
#endif Line 63
/* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
present. */
#ifndef SA_NOCLDSTOP Line 67
# define SA_NOCLDSTOP 0 Line 68
# define sigprocmask(How, Set, Oset) /* empty */ Line 69
# define sigset_t int Line 70
# if ! HAVE_SIGINTERRUPT Line 71
# define siginterrupt(sig, flag) /* empty */ Line 72
# endif Line 73
#endif Line 74
/* NonStop circa 2011 lacks both SA_RESTART and siginterrupt, so don't
restart syscalls after a signal handler fires. This may cause
colors to get messed up on the screen if 'ls' is interrupted, but
that's the best we can do on such a platform. */
#ifndef SA_RESTART Line 80
# define SA_RESTART 0 Line 81
#endif Line 82
#include "system.h" ...!includes auto-comment...
#include <fnmatch.h> ...!includes auto-comment...
#include "acl.h" ...!includes auto-comment...
#include "argmatch.h" ...!includes auto-comment...
#include "c-strcase.h" ...!includes auto-comment...
#include "dev-ino.h" ...!includes auto-comment...
#include "die.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "filenamecat.h" ...!includes auto-comment...
#include "hard-locale.h" ...!includes auto-comment...
#include "hash.h" ...!includes auto-comment...
#include "human.h" ...!includes auto-comment...
#include "filemode.h" ...!includes auto-comment...
#include "filevercmp.h" ...!includes auto-comment...
#include "idcache.h" ...!includes auto-comment...
#include "ls.h" ...!includes auto-comment...
#include "mbswidth.h" ...!includes auto-comment...
#include "mpsort.h" ...!includes auto-comment...
#include "obstack.h" ...!includes auto-comment...
#include "quote.h" ...!includes auto-comment...
#include "smack.h" ...!includes auto-comment...
#include "stat-size.h" ...!includes auto-comment...
#include "stat-time.h" ...!includes auto-comment...
#include "strftime.h" ...!includes auto-comment...
#include "xdectoint.h" ...!includes auto-comment...
#include "xstrtol.h" ...!includes auto-comment...
#include "areadlink.h" ...!includes auto-comment...
#include "mbsalign.h" ...!includes auto-comment...
#include "dircolors.h" ...!includes auto-comment...
#include "xgethostname.h" ...!includes auto-comment...
#include "c-ctype.h" ...!includes auto-comment...
#include "canonicalize.h" ...!includes auto-comment...
/* Include <sys/capability.h> last to avoid a clash of <sys/types.h>
include guards with some premature versions of libcap.
For more details, see <https://bugzilla.redhat.com/483548>. */
#ifdef HAVE_CAP Line 121
# include <sys/capability.h> Line 122
#endif Line 123
#define PROGRAM_NAME (ls_mode == LS_LS ? "ls" \ Line 125
: (ls_mode == LS_MULTI_COL \ Line 126
? "dir" : "vdir")) Line 127
#define AUTHORS \ Line 129
proper_name ("Richard M. Stallman"), \ Line 130
proper_name ("David MacKenzie") Line 131
#define obstack_chunk_alloc malloc Line 133
#define obstack_chunk_free free Line 134
/* Return an int indicating the result of comparing two integers.
Subtracting doesn't always work, due to overflow. */
#define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b)) Line 138
/* Unix-based readdir implementations have historically returned a dirent.d_ino
value that is sometimes not equal to the stat-obtained st_ino value for
that same entry. This error occurs for a readdir entry that refers
to a mount point. readdir's error is to return the inode number of
the underlying directory -- one that typically cannot be stat'ed, as
long as a file system is mounted on that directory. RELIABLE_D_INO
encapsulates whether we can use the more efficient approach of relying
on readdir-supplied d_ino values, or whether we must incur the cost of
calling stat or lstat to obtain each guaranteed-valid inode number. */
#ifndef READDIR_LIES_ABOUT_MOUNTPOINT_D_INO Line 150
# define READDIR_LIES_ABOUT_MOUNTPOINT_D_INO 1 Line 151
#endif Line 152
#if READDIR_LIES_ABOUT_MOUNTPOINT_D_INO Line 154
# define RELIABLE_D_INO(dp) NOT_AN_INODE_NUMBER Line 155
#else Line 156
# define RELIABLE_D_INO(dp) D_INO (dp) Line 157
#endif Line 158
#if ! HAVE_STRUCT_STAT_ST_AUTHOR Line 160
# define st_author st_uid Line 161
#endif Line 162
enum filetype Line 164
{
unknown, Line 166
fifo, Line 167
chardev, Line 168
directory, Line 169
blockdev, Line 170
normal, Line 171
symbolic_link, Line 172
sock, Line 173
whiteout, Line 174
arg_directory Line 175
}; Block 1
/* Display letters and indicators for each filetype.
Keep these in sync with enum filetype. */
static char const filetype_letter[] = "?pcdb-lswd"; Line 180
/* Ensure that filetype and filetype_letter have the same
number of elements. */
verify (sizeof filetype_letter - 1 == arg_directory + 1); Line 184
#define FILETYPE_INDICATORS \ Line 186
{ \ Line 187
C_ORPHAN, C_FIFO, C_CHR, C_DIR, C_BLK, C_FILE, \ Line 188
C_LINK, C_SOCK, C_FILE, C_DIR \ Line 189
} Block 2
enum acl_type Line 192
{
ACL_T_NONE, Line 194
ACL_T_LSM_CONTEXT_ONLY, Line 195
ACL_T_YES Line 196
}; Block 3
struct fileinfo Line 199
{
/* The file name. */
char *name; Line 202
/* For symbolic link, name of the file linked to, otherwise zero. */
char *linkname; Line 205
/* For terminal hyperlinks. */
char *absolute_name; Line 208
struct stat stat; Line 210
enum filetype filetype; Line 212
/* For symbolic link and long listing, st_mode of file linked to, otherwise
zero. */
mode_t linkmode; Line 216
/* security context. */
char *scontext; Line 219
bool stat_ok; Line 221
/* For symbolic link and color printing, true if linked-to file
exists, otherwise false. */
bool linkok; Line 225
/* For long listings, true if the file has an access control list,
or a security context. */
enum acl_type acl_type; Line 229
/* For color listings, true if a regular file has capability info. */
bool has_capability; Line 232
/* Whether file name needs quoting. tri-state with -1 == unknown. */
int quoted; Line 235
};
#define LEN_STR_PAIR(s) sizeof (s) - 1, s Line 238
/* Null is a valid character in a color indicator (think about Epson
printers, for example) so we have to use a length/buffer string
type. */
struct bin_str Line 244
{
size_t len; /* Number of bytes */ Line 246
const char *string; /* Pointer to the same */ Line 247
}; Block 5
#if ! HAVE_TCGETPGRP Line 250
# define tcgetpgrp(Fd) 0 Line 251
#endif Line 252
static size_t quote_name (char const *name, Line 254
struct quoting_options const *options, Line 255
int needs_general_quoting, Line 256
const struct bin_str *color, Line 257
bool allow_pad, struct obstack *stack, Line 258
char const *absolute_name); Line 259
static size_t quote_name_buf (char **inbuf, size_t bufsize, char *name, Line 260
struct quoting_options const *options, Line 261
int needs_general_quoting, size_t *width, Line 262
bool *pad); Line 263
static char *make_link_name (char const *name, char const *linkname); Line 264
static int decode_switches (int argc, char **argv); Line 265
static bool file_ignored (char const *name); Line 266
static uintmax_t gobble_file (char const *name, enum filetype type, Line 267
ino_t inode, bool command_line_arg, Line 268
char const *dirname); Line 269
static const struct bin_str * get_color_indicator (const struct fileinfo *f, Line 270
bool symlink_target); Line 271
static bool print_color_indicator (const struct bin_str *ind); Line 272
static void put_indicator (const struct bin_str *ind); Line 273
static void add_ignore_pattern (const char *pattern); Line 274
static void attach (char *dest, const char *dirname, const char *name); Line 275
static void clear_files (void); Line 276
static void extract_dirs_from_files (char const *dirname, Line 277
bool command_line_arg); Line 278
static void get_link_name (char const *filename, struct fileinfo *f, Line 279
bool command_line_arg); Line 280
static void indent (size_t from, size_t to); Line 281
static size_t calculate_columns (bool by_columns); Line 282
static void print_current_files (void); Line 283
static void print_dir (char const *name, char const *realname, Line 284
bool command_line_arg); Line 285
static size_t print_file_name_and_frills (const struct fileinfo *f, Line 286
size_t start_col); Line 287
static void print_horizontal (void); Line 288
static int format_user_width (uid_t u); Line 289
static int format_group_width (gid_t g); Line 290
static void print_long_format (const struct fileinfo *f); Line 291
static void print_many_per_line (void); Line 292
static size_t print_name_with_quoting (const struct fileinfo *f, Line 293
bool symlink_target, Line 294
struct obstack *stack, Line 295
size_t start_col); Line 296
static void prep_non_filename_text (void); Line 297
static bool print_type_indicator (bool stat_ok, mode_t mode, Line 298
enum filetype type); Line 299
static void print_with_separator (char sep); Line 300
static void queue_directory (char const *name, char const *realname, Line 301
bool command_line_arg); Line 302
static void sort_files (void); Line 303
static void parse_ls_color (void); Line 304
static void getenv_quoting_style (void); Line 306
/* Initial size of hash table.
Most hierarchies are likely to be shallower than this. */
#define INITIAL_TABLE_SIZE 30 Line 310
/* The set of 'active' directories, from the current command-line argument
to the level in the hierarchy at which files are being listed.
A directory is represented by its device and inode numbers (struct dev_ino).
A directory is added to this set when ls begins listing it or its
entries, and it is removed from the set just after ls has finished
processing it. This set is used solely to detect loops, e.g., with
mkdir loop; cd loop; ln -s ../loop sub; ls -RL */
static Hash_table *active_dir_set; Line 319
#define LOOP_DETECT (!!active_dir_set) Line 321
/* The table of files in the current directory:
'cwd_file' points to a vector of 'struct fileinfo', one per file.
'cwd_n_alloc' is the number of elements space has been allocated for.
'cwd_n_used' is the number actually in use. */
/* Address of block containing the files that are described. */
static struct fileinfo *cwd_file; Line 330
/* Length of block that 'cwd_file' points to, measured in files. */
static size_t cwd_n_alloc; Line 333
/* Index of first unused slot in 'cwd_file'. */
static size_t cwd_n_used; Line 336
/* Whether files needs may need padding due to quoting. */
static bool cwd_some_quoted; Line 339
/* Whether quoting style _may_ add outer quotes,
and whether aligning those is useful. */
static bool align_variable_outer_quotes; Line 343
/* Vector of pointers to files, in proper sorted order, and the number
of entries allocated for it. */
static void **sorted_file; Line 347
static size_t sorted_file_alloc; Line 348
/* When true, in a color listing, color each symlink name according to the
type of file it points to. Otherwise, color them according to the 'ln'
directive in LS_COLORS. Dangling (orphan) symlinks are treated specially,
regardless. This is set when 'ln=target' appears in LS_COLORS. */
static bool color_symlink_as_referent; Line 355
static char const *hostname; Line 357
/* mode of appropriate file for colorization */
#define FILE_OR_LINK_MODE(File) \ Line 360
((color_symlink_as_referent && (File)->linkok) \ Line 361
? (File)->linkmode : (File)->stat.st_mode) Line 362
/* Record of one pending directory waiting to be listed. */
struct pending Line 367
{
char *name; Line 369
/* If the directory is actually the file pointed to by a symbolic link we
were told to list, 'realname' will contain the name of the symbolic
link, otherwise zero. */
char *realname; Line 373
bool command_line_arg; Line 374
struct pending *next; Line 375
}; Block 6
static struct pending *pending_dirs; Line 378
/* Current time in seconds and nanoseconds since 1970, updated as
needed when deciding whether a file is recent. */
static struct timespec current_time; Line 383
static bool print_scontext; Line 385
static char UNKNOWN_SECURITY_CONTEXT[] = "?"; Line 386
/* Whether any of the files has an ACL. This affects the width of the
mode column. */
static bool any_has_acl; Line 391
/* The number of columns to use for columns containing inode numbers,
block sizes, link counts, owners, groups, authors, major device
numbers, minor device numbers, and file sizes, respectively. */
static int inode_number_width; Line 397
static int block_size_width; Line 398
static int nlink_width; Line 399
static int scontext_width; Line 400
static int owner_width; Line 401
static int group_width; Line 402
static int author_width; Line 403
static int major_device_number_width; Line 404
static int minor_device_number_width; Line 405
static int file_size_width; Line 406
/* Option flags */
/* long_format for lots of info, one per line.
one_per_line for just names, one per line.
many_per_line for just names, many per line, sorted vertically.
horizontal for just names, many per line, sorted horizontally.
with_commas for just names, many per line, separated by commas.
-l (and other options that imply -l), -1, -C, -x and -m control
this parameter. */
enum format Line 419
{
long_format, /* -l and other options that imply -l */ Line 421
one_per_line, /* -1 */ Line 422
many_per_line, /* -C */ Line 423
horizontal, /* -x */ Line 424
with_commas /* -m */ Line 425
}; Block 7
static enum format format; Line 428
/* 'full-iso' uses full ISO-style dates and times. 'long-iso' uses longer
ISO-style timestamps, though shorter than 'full-iso'. 'iso' uses shorter
ISO-style timestamps. 'locale' uses locale-dependent timestamps. */
enum time_style Line 433
{
full_iso_time_style, /* --time-style=full-iso */ Line 435
long_iso_time_style, /* --time-style=long-iso */ Line 436
iso_time_style, /* --time-style=iso */ Line 437
locale_time_style /* --time-style=locale */ Line 438
}; Block 8
static char const *const time_style_args[] = Line 441
{
"full-iso", "long-iso", "iso", "locale", NULL Line 443
}; Block 9
static enum time_style const time_style_types[] = Line 445
{
full_iso_time_style, long_iso_time_style, iso_time_style, Line 447
locale_time_style Line 448
}; Block 10
ARGMATCH_VERIFY (time_style_args, time_style_types); Line 450
/* Type of time to print or sort by. Controlled by -c and -u.
The values of each item of this enum are important since they are
used as indices in the sort functions array (see sort_files()). */
enum time_type Line 456
{
time_mtime, /* default */ Line 458
time_ctime, /* -c */ Line 459
time_atime, /* -u */ Line 460
time_numtypes /* the number of elements of this enum */ Line 461
}; Block 11
static enum time_type time_type; Line 464
/* The file characteristic to sort by. Controlled by -t, -S, -U, -X, -v.
The values of each item of this enum are important since they are
used as indices in the sort functions array (see sort_files()). */
enum sort_type Line 470
{
sort_none = -1, /* -U */ Line 472
sort_name, /* default */ Line 473
sort_extension, /* -X */ Line 474
sort_size, /* -S */ Line 475
sort_version, /* -v */ Line 476
sort_time, /* -t */ Line 477
sort_numtypes /* the number of elements of this enum */ Line 478
}; Block 12
static enum sort_type sort_type; Line 481
/* Direction of sort.
false means highest first if numeric,
lowest first if alphabetic;
these are the defaults.
true means the opposite order in each case. -r */
static bool sort_reverse; Line 489
/* True means to display owner information. -g turns this off. */
static bool print_owner = true; Line 493
/* True means to display author information. */
static bool print_author; Line 497
/* True means to display group information. -G and -o turn this off. */
static bool print_group = true; Line 501
/* True means print the user and group id's as numbers rather
than as names. -n */
static bool numeric_ids; Line 506
/* True means mention the size in blocks of each file. -s */
static bool print_block_size; Line 510
/* Human-readable options for output, when printing block counts. */
static int human_output_opts; Line 513
/* The units to use when printing block counts. */
static uintmax_t output_block_size; Line 516
/* Likewise, but for file sizes. */
static int file_human_output_opts; Line 519
static uintmax_t file_output_block_size = 1; Line 520
/* Follow the output with a special string. Using this format,
Emacs' dired mode starts up twice as fast, and can handle all
strange characters in file names. */
static bool dired; Line 525
/* 'none' means don't mention the type of files.
'slash' means mention directories only, with a '/'.
'file_type' means mention file types.
'classify' means mention file types and mark executables.
Controlled by -F, -p, and --indicator-style. */
enum indicator_style Line 534
{
none, /* --indicator-style=none */ Line 536
slash, /* -p, --indicator-style=slash */ Line 537
file_type, /* --indicator-style=file-type */ Line 538
classify /* -F, --indicator-style=classify */ Line 539
}; Block 13
static enum indicator_style indicator_style; Line 542
/* Names of indicator styles. */
static char const *const indicator_style_args[] = Line 545
{
"none", "slash", "file-type", "classify", NULL Line 547
}; Block 14
static enum indicator_style const indicator_style_types[] = Line 549
{
none, slash, file_type, classify Line 551
}; Block 15
ARGMATCH_VERIFY (indicator_style_args, indicator_style_types); Line 553
/* True means use colors to mark types. Also define the different
colors as well as the stuff for the LS_COLORS environment variable.
The LS_COLORS variable is now in a termcap-like format. */
static bool print_with_color; Line 559
static bool print_hyperlink; Line 561
/* Whether we used any colors in the output so far. If so, we will
need to restore the default color later. If not, we will need to
call prep_non_filename_text before using color for the first time. */
static bool used_color = false; Line 567
enum when_type Line 569
{
when_never, /* 0: default or --color=never */ Line 571
when_always, /* 1: --color=always */ Line 572
when_if_tty /* 2: --color=tty */ Line 573
}; Block 16
enum Dereference_symlink Line 576
{
DEREF_UNDEFINED = 1, Line 578
DEREF_NEVER, Line 579
DEREF_COMMAND_LINE_ARGUMENTS, /* -H */ Line 580
DEREF_COMMAND_LINE_SYMLINK_TO_DIR, /* the default, in certain cases */ Line 581
DEREF_ALWAYS /* -L */ Line 582
}; Block 17
enum indicator_no Line 585
{
C_LEFT, C_RIGHT, C_END, C_RESET, C_NORM, C_FILE, C_DIR, C_LINK, Line 587
C_FIFO, C_SOCK, Line 588
C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC, C_DOOR, C_SETUID, C_SETGID, Line 589
C_STICKY, C_OTHER_WRITABLE, C_STICKY_OTHER_WRITABLE, C_CAP, C_MULTIHARDLINK,Line 590
C_CLR_TO_EOL Line 591
}; Block 18
static const char *const indicator_name[]= Line 594
{
"lc", "rc", "ec", "rs", "no", "fi", "di", "ln", "pi", "so", Line 596
"bd", "cd", "mi", "or", "ex", "do", "su", "sg", "st", Line 597
"ow", "tw", "ca", "mh", "cl", NULL Line 598
}; Block 19
struct color_ext_type Line 601
{
struct bin_str ext; /* The extension we're looking for */ Line 603
struct bin_str seq; /* The sequence to output when we do */ Line 604
struct color_ext_type *next; /* Next in list */ Line 605
}; Block 20
static struct bin_str color_indicator[] = Line 608
{
{ LEN_STR_PAIR ("\033[") }, /* lc: Left of color sequence */ Line 610
{ LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */ Line 611
{ 0, NULL }, /* ec: End color (replaces lc+rs+rc) */ Line 612
{ LEN_STR_PAIR ("0") }, /* rs: Reset to ordinary colors */ Line 613
{ 0, NULL }, /* no: Normal */ Line 614
{ 0, NULL }, /* fi: File: default */ Line 615
{ LEN_STR_PAIR ("01;34") }, /* di: Directory: bright blue */ Line 616
{ LEN_STR_PAIR ("01;36") }, /* ln: Symlink: bright cyan */ Line 617
{ LEN_STR_PAIR ("33") }, /* pi: Pipe: yellow/brown */ Line 618
{ LEN_STR_PAIR ("01;35") }, /* so: Socket: bright magenta */ Line 619
{ LEN_STR_PAIR ("01;33") }, /* bd: Block device: bright yellow */ Line 620
{ LEN_STR_PAIR ("01;33") }, /* cd: Char device: bright yellow */ Line 621
{ 0, NULL }, /* mi: Missing file: undefined */ Line 622
{ 0, NULL }, /* or: Orphaned symlink: undefined */ Line 623
{ LEN_STR_PAIR ("01;32") }, /* ex: Executable: bright green */ Line 624
{ LEN_STR_PAIR ("01;35") }, /* do: Door: bright magenta */ Line 625
{ LEN_STR_PAIR ("37;41") }, /* su: setuid: white on red */ Line 626
{ LEN_STR_PAIR ("30;43") }, /* sg: setgid: black on yellow */ Line 627
{ LEN_STR_PAIR ("37;44") }, /* st: sticky: black on blue */ Line 628
{ LEN_STR_PAIR ("34;42") }, /* ow: other-writable: blue on green */ Line 629
{ LEN_STR_PAIR ("30;42") }, /* tw: ow w/ sticky: black on green */ Line 630
{ LEN_STR_PAIR ("30;41") }, /* ca: black on red */ Line 631
{ 0, NULL }, /* mh: disabled by default */ Line 632
{ LEN_STR_PAIR ("\033[K") }, /* cl: clear to end of line */ Line 633
}; Block 21
/* FIXME: comment */
static struct color_ext_type *color_ext_list = NULL; Line 637
/* Buffer for color sequences */
static char *color_buf; Line 640
/* True means to check for orphaned symbolic link, for displaying
colors. */
static bool check_symlink_color; Line 645
/* True means mention the inode number of each file. -i */
static bool print_inode; Line 649
/* What to do with symbolic links. Affected by -d, -F, -H, -l (and
other options that imply -l), and -L. */
static enum Dereference_symlink dereference; Line 654
/* True means when a directory is found, display info on its
contents. -R */
static bool recursive; Line 659
/* True means when an argument is a directory name, display info
on it itself. -d */
static bool immediate_dirs; Line 664
/* True means that directories are grouped before files. */
static bool directories_first; Line 668
/* Which files to ignore. */
static enum Line 672
{
/* Ignore files whose names start with '.', and files specified by
--hide and --ignore. */
IGNORE_DEFAULT, Line 676
/* Ignore '.', '..', and files specified by --ignore. */
IGNORE_DOT_AND_DOTDOT, Line 679
/* Ignore only files specified by --ignore. */
IGNORE_MINIMAL Line 682
} ignore_mode; Line 683
/* A linked list of shell-style globbing patterns. If a non-argument
file name matches any of these patterns, it is ignored.
Controlled by -I. Multiple -I options accumulate.
The -B option adds '*~' and '.*~' to this list. */
struct ignore_pattern Line 690
{
const char *pattern; Line 692
struct ignore_pattern *next; Line 693
}; Block 23
static struct ignore_pattern *ignore_patterns; Line 696
/* Similar to IGNORE_PATTERNS, except that -a or -A causes this
variable itself to be ignored. */
static struct ignore_pattern *hide_patterns; Line 700
/* True means output nongraphic chars in file names as '?'.
(-q, --hide-control-chars)
qmark_funny_chars and the quoting style (-Q, --quoting-style=WORD) are
independent. The algorithm is: first, obey the quoting style to get a
string representing the file name; then, if qmark_funny_chars is set,
replace all nonprintable chars in that string with '?'. It's necessary
to replace nonprintable chars even in quoted strings, because we don't
want to mess up the terminal if control chars get sent to it, and some
quoting methods pass through control chars as-is. */
static bool qmark_funny_chars; Line 711
/* Quoting options for file and dir name output. */
static struct quoting_options *filename_quoting_options; Line 715
static struct quoting_options *dirname_quoting_options; Line 716
/* The number of chars per hardware tab stop. Setting this to zero
inhibits the use of TAB characters for separating columns. -T */
static size_t tabsize; Line 720
/* True means print each directory name before listing it. */
static bool print_dir_name; Line 724
/* The line length to use for breaking lines in many-per-line format.
Can be set with -w. */
static size_t line_length; Line 729
/* The local time zone rules, as per the TZ environment variable. */
static timezone_t localtz; Line 733
/* If true, the file listing format requires that stat be called on
each file. */
static bool format_needs_stat; Line 738
/* Similar to 'format_needs_stat', but set if only the file type is
needed. */
static bool format_needs_type; Line 743
/* An arbitrary limit on the number of bytes in a printed timestamp.
This is set to a relatively small value to avoid the need to worry
about denial-of-service attacks on servers that run "ls" on behalf
of remote clients. 1000 bytes should be enough for any practical
timestamp format. */
enum { TIME_STAMP_LEN_MAXIMUM = MAX (1000, INT_STRLEN_BOUND (time_t)) }; Line 751
/* strftime formats for non-recent and recent files, respectively, in
-l output. */
static char const *long_time_format[2] = Line 756
{
/* strftime format for non-recent files (older than 6 months), in
-l output. This should contain the year, month and day (at
least), in an order that is understood by people in your
locale's territory. Please try to keep the number of used
screen columns small, because many people work in windows with
only 80 columns. But make this as wide as the other string
below, for recent files. */
/* TRANSLATORS: ls output needs to be aligned for ease of reading,
so be wary of using variable width fields from the locale.
Note %b is handled specially by ls and aligned correctly.
Note also that specifying a width as in %5b is erroneous as strftime
will count bytes rather than characters in multibyte locales. */
N_("%b %e %Y"), Line 770
/* strftime format for recent files (younger than 6 months), in -l
output. This should contain the month, day and time (at
least), in an order that is understood by people in your
locale's territory. Please try to keep the number of used
screen columns small, because many people work in windows with
only 80 columns. But make this as wide as the other string
above, for non-recent files. */
/* TRANSLATORS: ls output needs to be aligned for ease of reading,
so be wary of using variable width fields from the locale.
Note %b is handled specially by ls and aligned correctly.
Note also that specifying a width as in %5b is erroneous as strftime
will count bytes rather than characters in multibyte locales. */
N_("%b %e %H:%M") Line 783
};
/* The set of signals that are caught. */
static sigset_t caught_signals; Line 788
/* If nonzero, the value of the pending fatal signal. */
static sig_atomic_t volatile interrupt_signal; Line 792
/* A count of the number of pending stop signals that have been received. */
static sig_atomic_t volatile stop_signal_count; Line 796
/* Desired exit status. */
static int exit_status; Line 800
/* Exit statuses. */
enum Line 803
{
/* "ls" had a minor problem. E.g., while processing a directory,
ls obtained the name of an entry via readdir, yet was later
unable to stat that name. This happens when listing a directory
in which entries are actively being removed or renamed. */
LS_MINOR_PROBLEM = 1, Line 809
/* "ls" had more serious trouble (e.g., memory exhausted, invalid
option or failure to stat a command line argument. */
LS_FAILURE = 2 Line 813
};
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum Line 818
{
AUTHOR_OPTION = CHAR_MAX + 1, Line 820
BLOCK_SIZE_OPTION, Line 821
COLOR_OPTION, Line 822
DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION, Line 823
FILE_TYPE_INDICATOR_OPTION, Line 824
FORMAT_OPTION, Line 825
FULL_TIME_OPTION, Line 826
GROUP_DIRECTORIES_FIRST_OPTION, Line 827
HIDE_OPTION, Line 828
HYPERLINK_OPTION, Line 829
INDICATOR_STYLE_OPTION, Line 830
QUOTING_STYLE_OPTION, Line 831
SHOW_CONTROL_CHARS_OPTION, Line 832
SI_OPTION, Line 833
SORT_OPTION, Line 834
TIME_OPTION, Line 835
TIME_STYLE_OPTION Line 836
}; Block 27
static struct option const long_options[] = Line 839
{
{"all", no_argument, NULL, 'a'}, Line 841
{"escape", no_argument, NULL, 'b'}, Line 842
{"directory", no_argument, NULL, 'd'}, Line 843
{"dired", no_argument, NULL, 'D'}, Line 844
{"full-time", no_argument, NULL, FULL_TIME_OPTION}, Line 845
{"group-directories-first", no_argument, NULL, Line 846
GROUP_DIRECTORIES_FIRST_OPTION}, Line 847
{"human-readable", no_argument, NULL, 'h'}, Line 848
{"inode", no_argument, NULL, 'i'}, Line 849
{"kibibytes", no_argument, NULL, 'k'}, Line 850
{"numeric-uid-gid", no_argument, NULL, 'n'}, Line 851
{"no-group", no_argument, NULL, 'G'}, Line 852
{"hide-control-chars", no_argument, NULL, 'q'}, Line 853
{"reverse", no_argument, NULL, 'r'}, Line 854
{"size", no_argument, NULL, 's'}, Line 855
{"width", required_argument, NULL, 'w'}, Line 856
{"almost-all", no_argument, NULL, 'A'}, Line 857
{"ignore-backups", no_argument, NULL, 'B'}, Line 858
{"classify", no_argument, NULL, 'F'}, Line 859
{"file-type", no_argument, NULL, FILE_TYPE_INDICATOR_OPTION}, Line 860
{"si", no_argument, NULL, SI_OPTION}, Line 861
{"dereference-command-line", no_argument, NULL, 'H'}, Line 862
{"dereference-command-line-symlink-to-dir", no_argument, NULL, Line 863
DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION}, Line 864
{"hide", required_argument, NULL, HIDE_OPTION}, Line 865
{"ignore", required_argument, NULL, 'I'}, Line 866
{"indicator-style", required_argument, NULL, INDICATOR_STYLE_OPTION}, Line 867
{"dereference", no_argument, NULL, 'L'}, Line 868
{"literal", no_argument, NULL, 'N'}, Line 869
{"quote-name", no_argument, NULL, 'Q'}, Line 870
{"quoting-style", required_argument, NULL, QUOTING_STYLE_OPTION}, Line 871
{"recursive", no_argument, NULL, 'R'}, Line 872
{"format", required_argument, NULL, FORMAT_OPTION}, Line 873
{"show-control-chars", no_argument, NULL, SHOW_CONTROL_CHARS_OPTION}, Line 874
{"sort", required_argument, NULL, SORT_OPTION}, Line 875
{"tabsize", required_argument, NULL, 'T'}, Line 876
{"time", required_argument, NULL, TIME_OPTION}, Line 877
{"time-style", required_argument, NULL, TIME_STYLE_OPTION}, Line 878
{"color", optional_argument, NULL, COLOR_OPTION}, Line 879
{"hyperlink", optional_argument, NULL, HYPERLINK_OPTION}, Line 880
{"block-size", required_argument, NULL, BLOCK_SIZE_OPTION}, Line 881
{"context", no_argument, 0, 'Z'}, Line 882
{"author", no_argument, NULL, AUTHOR_OPTION}, Line 883
{GETOPT_HELP_OPTION_DECL}, Line 884
{GETOPT_VERSION_OPTION_DECL}, Line 885
{NULL, 0, NULL, 0} Line 886
}; Block 28
static char const *const format_args[] = Line 889
{
"verbose", "long", "commas", "horizontal", "across", Line 891
"vertical", "single-column", NULL Line 892
}; Block 29
static enum format const format_types[] = Line 894
{
long_format, long_format, with_commas, horizontal, horizontal, Line 896
many_per_line, one_per_line Line 897
}; Block 30
ARGMATCH_VERIFY (format_args, format_types); Line 899
static char const *const sort_args[] = Line 901
{
"none", "time", "size", "extension", "version", NULL Line 903
}; Block 31
static enum sort_type const sort_types[] = Line 905
{
sort_none, sort_time, sort_size, sort_extension, sort_version Line 907
}; Block 32
ARGMATCH_VERIFY (sort_args, sort_types); Line 909
static char const *const time_args[] = Line 911
{
"atime", "access", "use", "ctime", "status", NULL Line 913
}; Block 33
static enum time_type const time_types[] = Line 915
{
time_atime, time_atime, time_atime, time_ctime, time_ctime Line 917
}; Block 34
ARGMATCH_VERIFY (time_args, time_types); Line 919
static char const *const when_args[] = Line 921
{
/* force and none are for compatibility with another color-ls version */
"always", "yes", "force", Line 924
"never", "no", "none", Line 925
"auto", "tty", "if-tty", NULL Line 926
};
static enum when_type const when_types[] = Line 928
{
when_always, when_always, when_always, Line 930
when_never, when_never, when_never, Line 931
when_if_tty, when_if_tty, when_if_tty Line 932
}; Block 36
ARGMATCH_VERIFY (when_args, when_types); Line 934
/* Information about filling a column. */
struct column_info Line 937
{
bool valid_len; Line 939
size_t line_len; Line 940
size_t *col_arr; Line 941
}; Block 37
/* Array with information about column filledness. */
static struct column_info *column_info; Line 945
/* Maximum number of columns ever possible for this display. */
static size_t max_idx; Line 948
/* The minimum width of a column is 3: 1 character for the name and 2
for the separating white space. */
#define MIN_COLUMN_WIDTH 3 Line 952
/* This zero-based index is used solely with the --dired option.
When that option is in effect, this counter is incremented for each
byte of output generated by this program so that the beginning
and ending indices (in that output) of every file name can be recorded
and later output themselves. */
static size_t dired_pos; Line 960
#define DIRED_PUTCHAR(c) do {putchar ((c)); ++dired_pos;} while (0) Line 962
/* Write S to STREAM and increment DIRED_POS by S_LEN. */
#define DIRED_FPUTS(s, stream, s_len) \ Line 965
do {fputs (s, stream); dired_pos += s_len;} while (0) Line 966
/* Like DIRED_FPUTS, but for use when S is a literal string. */
#define DIRED_FPUTS_LITERAL(s, stream) \ Line 969
do {fputs (s, stream); dired_pos += sizeof (s) - 1;} while (0) Line 970
#define DIRED_INDENT() \ Line 972
do \ Line 973
{ \ Line 974
if (dired) \ Line 975
DIRED_FPUTS_LITERAL (" ", stdout); \ Line 976
} \ Line 977Block 41
while (0) Line 978
/* With --dired, store pairs of beginning and ending indices of file names. */
static struct obstack dired_obstack; Line 981
/* With --dired, store pairs of beginning and ending indices of any
directory names that appear as headers (just before 'total' line)
for lists of directory entries. Such directory names are seen when
listing hierarchies using -R and when a directory is listed with at
least one other command line argument. */
static struct obstack subdired_obstack; Line 988
/* Save the current index on the specified obstack, OBS. */
#define PUSH_CURRENT_DIRED_POS(obs) \ Line 991
do \ Line 992
{ \ Line 993
if (dired) \ Line 994
obstack_grow (obs, &dired_pos, sizeof (dired_pos)); \ Line 995
} \ Line 996Block 42
while (0) Line 997
/* With -R, this stack is used to help detect directory cycles.
The device/inode pairs on this stack mirror the pairs in the
active_dir_set hash table. */
static struct obstack dev_ino_obstack; Line 1002
/* Push a pair onto the device/inode stack. */
static void Line 1005
dev_ino_push (dev_t dev, ino_t ino) Line 1006
{
void *vdi; Line 1008
struct dev_ino *di; Line 1009
int dev_ino_size = sizeof *di; Line 1010
obstack_blank (&dev_ino_obstack, dev_ino_size); Line 1011
vdi = obstack_next_free (&dev_ino_obstack); Line 1012
di = vdi; Line 1013
di--; Line 1014
di->st_dev = dev; Line 1015
di->st_ino = ino; Line 1016
} Block 43
/* Pop a dev/ino struct off the global dev_ino_obstack
and return that struct. */
static struct dev_ino Line 1021
dev_ino_pop (void) Line 1022
{
void *vdi; Line 1024
struct dev_ino *di; Line 1025
int dev_ino_size = sizeof *di; Line 1026
assert (dev_ino_size <= obstack_object_size (&dev_ino_obstack)); Line 1027
obstack_blank_fast (&dev_ino_obstack, -dev_ino_size); Line 1028
vdi = obstack_next_free (&dev_ino_obstack); Line 1029
di = vdi; Line 1030
return *di; Line 1031
} Block 44
/* Note the use commented out below:
#define ASSERT_MATCHING_DEV_INO(Name, Di) \
do \
{ \
struct stat sb; \
assert (Name); \
assert (0 <= stat (Name, &sb)); \
assert (sb.st_dev == Di.st_dev); \
assert (sb.st_ino == Di.st_ino); \
} \
while (0)
*/
/* Write to standard output PREFIX, followed by the quoting style and
a space-separated list of the integers stored in OS all on one line. */
static void Line 1050
dired_dump_obstack (const char *prefix, struct obstack *os) Line 1051
{
size_t n_pos; Line 1053
n_pos = obstack_object_size (os) / sizeof (dired_pos); Line 1055
if (n_pos > 0) Line 1056
{
size_t *pos = (size_t *) obstack_finish (os); Line 1058
fputs (prefix, stdout); Line 1059
for (size_t i = 0; i < n_pos; i++) Line 1060
printf (" %lu", (unsigned long int) pos[i]); Line 1061
putchar ('\n'); Line 1062
}
} Block 45
/* Return the address of the first plain %b spec in FMT, or NULL if
there is no such spec. %5b etc. do not match, so that user
widths/flags are honored. */
static char const * _GL_ATTRIBUTE_PURE Line 1070
first_percent_b (char const *fmt) Line 1071
{
for (; *fmt; fmt++) Line 1073
if (fmt[0] == '%') Line 1074
switch (fmt[1]) Line 1075
{
case 'b': return fmt; Line 1077
case '%': fmt++; break; Line 1078
}
return NULL; Line 1080
} Block 46
static char RFC3986[256]; Line 1083
static void Line 1084
file_escape_init (void) Line 1085
{
for (int i = 0; i < 256; i++) Line 1087
RFC3986[i] |= c_isalnum (i) || i == '~' || i == '-' || i == '.' || i == '_';Line 1088
} Block 47
/* Read the abbreviated month names from the locale, to align them
and to determine the max width of the field and to truncate names
greater than our max allowed.
Note even though this handles multibyte locales correctly
it's not restricted to them as single byte locales can have
variable width abbreviated months and also precomputing/caching
the names was seen to increase the performance of ls significantly. */
/* max number of display cells to use.
As of 2018 the abmon for Arabic has entries with width 12.
It doesn't make much sense to support wider than this
and locales should aim for abmon entries of width <= 5. */
enum { MAX_MON_WIDTH = 12 }; Line 1103
/* abformat[RECENT][MON] is the format to use for timestamps with
recentness RECENT and month MON. */
enum { ABFORMAT_SIZE = 128 }; Line 1106Block 49
static char abformat[2][12][ABFORMAT_SIZE]; Line 1107
/* True if precomputed formats should be used. This can be false if
nl_langinfo fails, if a format or month abbreviation is unusually
long, or if a month abbreviation contains '%'. */
static bool use_abformat; Line 1111
/* Store into ABMON the abbreviated month names, suitably aligned.
Return true if successful. */
static bool Line 1116
abmon_init (char abmon[12][ABFORMAT_SIZE]) Line 1117
{
#ifndef HAVE_NL_LANGINFO Line 1119
return false; Line 1120
#else Line 1121
size_t required_mon_width = MAX_MON_WIDTH; Line 1122
size_t curr_max_width; Line 1123
do
{
curr_max_width = required_mon_width; Line 1126
required_mon_width = 0; Line 1127
for (int i = 0; i < 12; i++) Line 1128
{
size_t width = curr_max_width; Line 1130
char const *abbr = nl_langinfo (ABMON_1 + i); Line 1131
if (strchr (abbr, '%')) Line 1132
return false; Line 1133
size_t req = mbsalign (abbr, abmon[i], ABFORMAT_SIZE, Line 1134
&width, MBS_ALIGN_LEFT, 0); Line 1135
if (! (req < ABFORMAT_SIZE)) Line 1136
return false; Line 1137
required_mon_width = MAX (required_mon_width, width); Line 1138
}
}
while (curr_max_width > required_mon_width); Line 1141
return true; Line 1143
#endif Line 1144
} Block 50
/* Initialize ABFORMAT and USE_ABFORMAT. */
static void Line 1149
abformat_init (void) Line 1150
{
char const *pb[2]; Line 1152
for (int recent = 0; recent < 2; recent++) Line 1153
pb[recent] = first_percent_b (long_time_format[recent]); Line 1154
if (! (pb[0] || pb[1])) Line 1155
return; Line 1156
char abmon[12][ABFORMAT_SIZE]; Line 1158
if (! abmon_init (abmon)) Line 1159
return; Line 1160
for (int recent = 0; recent < 2; recent++) Line 1162
{
char const *fmt = long_time_format[recent]; Line 1164
for (int i = 0; i < 12; i++) Line 1165
{
char *nfmt = abformat[recent][i]; Line 1167
int nbytes; Line 1168
if (! pb[recent]) Line 1170
nbytes = snprintf (nfmt, ABFORMAT_SIZE, "%s", fmt); Line 1171
else Line 1172
{
if (! (pb[recent] - fmt <= MIN (ABFORMAT_SIZE, INT_MAX))) Line 1174
return; Line 1175
int prefix_len = pb[recent] - fmt; Line 1176
nbytes = snprintf (nfmt, ABFORMAT_SIZE, "%.*s%s%s", Line 1177
prefix_len, fmt, abmon[i], pb[recent] + 2); Line 1178
}
if (! (0 <= nbytes && nbytes < ABFORMAT_SIZE)) Line 1181
return; Line 1182
}
}
use_abformat = true; Line 1186
} Block 51
static size_t Line 1189
dev_ino_hash (void const *x, size_t table_size) Line 1190
{
struct dev_ino const *p = x; Line 1192
return (uintmax_t) p->st_ino % table_size; Line 1193
} Block 52
static bool Line 1196
dev_ino_compare (void const *x, void const *y) Line 1197
{
struct dev_ino const *a = x; Line 1199
struct dev_ino const *b = y; Line 1200
return SAME_INODE (*a, *b) ? true : false; Line 1201
} Block 53
static void Line 1204
dev_ino_free (void *x) Line 1205
{
free (x); Line 1207
} Block 54
/* Add the device/inode pair (P->st_dev/P->st_ino) to the set of
active directories. Return true if there is already a matching
entry in the table. */
static bool Line 1214
visit_dir (dev_t dev, ino_t ino) Line 1215
{
struct dev_ino *ent; Line 1217
struct dev_ino *ent_from_table; Line 1218
bool found_match; Line 1219
ent = xmalloc (sizeof *ent); Line 1221
ent->st_ino = ino; Line 1222
ent->st_dev = dev; Line 1223
/* Attempt to insert this entry into the table. */
ent_from_table = hash_insert (active_dir_set, ent); Line 1226
if (ent_from_table == NULL) Line 1228
{
/* Insertion failed due to lack of memory. */
xalloc_die (); ...!common auto-comment...
}
found_match = (ent_from_table != ent); Line 1234
if (found_match) Line 1236
{
/* ent was not inserted, so free it. */
free (ent); Line 1239
}
return found_match; Line 1242
} Block 55
static void Line 1245
free_pending_ent (struct pending *p) Line 1246
{
free (p->name); Line 1248
free (p->realname); Line 1249
free (p); Line 1250
} Block 56
static bool Line 1253
is_colored (enum indicator_no type) Line 1254
{
size_t len = color_indicator[type].len; Line 1256
char const *s = color_indicator[type].string; Line 1257
return ! (len == 0 Line 1258
|| (len == 1 && STRNCMP_LIT (s, "0") == 0) Line 1259
|| (len == 2 && STRNCMP_LIT (s, "00") == 0)); Line 1260
} Block 57
static void Line 1263
restore_default_color (void) Line 1264
{
put_indicator (&color_indicator[C_LEFT]); Line 1266
put_indicator (&color_indicator[C_RIGHT]); Line 1267
} Block 58
static void Line 1270
set_normal_color (void) Line 1271
{
if (print_with_color && is_colored (C_NORM)) Line 1273
{
put_indicator (&color_indicator[C_LEFT]); Line 1275
put_indicator (&color_indicator[C_NORM]); Line 1276
put_indicator (&color_indicator[C_RIGHT]); Line 1277
}
} Block 59
/* An ordinary signal was received; arrange for the program to exit. */
static void Line 1283
sighandler (int sig) Line 1284
{
if (! SA_NOCLDSTOP) Line 1286
signal (sig, SIG_IGN); Line 1287
if (! interrupt_signal) Line 1288
interrupt_signal = sig; Line 1289
} Block 60
/* A SIGTSTP was received; arrange for the program to suspend itself. */
static void Line 1294
stophandler (int sig) Line 1295
{
if (! SA_NOCLDSTOP) Line 1297
signal (sig, stophandler); Line 1298
if (! interrupt_signal) Line 1299
stop_signal_count++; Line 1300
} Block 61
/* Process any pending signals. If signals are caught, this function
should be called periodically. Ideally there should never be an
unbounded amount of time when signals are not being processed.
Signal handling can restore the default colors, so callers must
immediately change colors after invoking this function. */
static void Line 1309
process_signals (void) Line 1310
{
while (interrupt_signal || stop_signal_count) Line 1312
{
int sig; Line 1314
int stops; Line 1315
sigset_t oldset; Line 1316
if (used_color) Line 1318
restore_default_color (); Line 1319
fflush (stdout); Line 1320
sigprocmask (SIG_BLOCK, &caught_signals, &oldset); Line 1322
/* Reload interrupt_signal and stop_signal_count, in case a new
signal was handled before sigprocmask took effect. */
sig = interrupt_signal; Line 1326
stops = stop_signal_count; Line 1327
/* SIGTSTP is special, since the application can receive that signal
more than once. In this case, don't set the signal handler to the
default. Instead, just raise the uncatchable SIGSTOP. */
if (stops) Line 1332
{
stop_signal_count = stops - 1; Line 1334
sig = SIGSTOP; Line 1335
}
else Line 1337
signal (sig, SIG_DFL); Line 1338
/* Exit or suspend the program. */
raise (sig); Line 1341
sigprocmask (SIG_SETMASK, &oldset, NULL); Line 1342
/* If execution reaches here, then the program has been
continued (after being suspended). */
}
} Block 62
/* Setup signal handlers if INIT is true,
otherwise restore to the default. */
static void Line 1352
signal_setup (bool init) Line 1353
{
/* The signals that are trapped, and the number of such signals. */
static int const sig[] = Line 1356
{
/* This one is handled specially. */
SIGTSTP, Line 1359
/* The usual suspects. */
SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGTERM, Line 1362
#ifdef SIGPOLL Line 1363
SIGPOLL, Line 1364
#endif Line 1365
#ifdef SIGPROF Line 1366
SIGPROF, Line 1367
#endif Line 1368
#ifdef SIGVTALRM Line 1369
SIGVTALRM, Line 1370
#endif Line 1371
#ifdef SIGXCPU Line 1372
SIGXCPU, Line 1373
#endif Line 1374
#ifdef SIGXFSZ Line 1375
SIGXFSZ, Line 1376
#endif Line 1377
};
enum { nsigs = ARRAY_CARDINALITY (sig) }; Line 1379
#if ! SA_NOCLDSTOP Line 1381
static bool caught_sig[nsigs]; Line 1382
#endif Line 1383
int j; Line 1385
if (init) Line 1387
{
#if SA_NOCLDSTOP Line 1389
struct sigaction act; Line 1390
sigemptyset (&caught_signals); Line 1392
for (j = 0; j < nsigs; j++) Line 1393
{
sigaction (sig[j], NULL, &act); Line 1395
if (act.sa_handler != SIG_IGN) Line 1396
sigaddset (&caught_signals, sig[j]); Line 1397
}
act.sa_mask = caught_signals; Line 1400
act.sa_flags = SA_RESTART; Line 1401
for (j = 0; j < nsigs; j++) Line 1403
if (sigismember (&caught_signals, sig[j])) Line 1404
{
act.sa_handler = sig[j] == SIGTSTP ? stophandler : sighandler; Line 1406
sigaction (sig[j], &act, NULL); Line 1407
}
#else Line 1409
for (j = 0; j < nsigs; j++) Line 1410
{
caught_sig[j] = (signal (sig[j], SIG_IGN) != SIG_IGN); Line 1412
if (caught_sig[j]) Line 1413
{
signal (sig[j], sig[j] == SIGTSTP ? stophandler : sighandler); Line 1415
siginterrupt (sig[j], 0); Line 1416
}
}
#endif Line 1419
}
else /* restore. */ Line 1421
{
#if SA_NOCLDSTOP Line 1423
for (j = 0; j < nsigs; j++) Line 1424
if (sigismember (&caught_signals, sig[j])) Line 1425
signal (sig[j], SIG_DFL); Line 1426
#else Line 1427
for (j = 0; j < nsigs; j++) Line 1428
if (caught_sig[j]) Line 1429
signal (sig[j], SIG_DFL); Line 1430
#endif Line 1431
}
}
static inline void Line 1435
signal_init (void) Line 1436
{
signal_setup (true); Line 1438
} Block 64
static inline void Line 1441
signal_restore (void) Line 1442
{
signal_setup (false); Line 1444
} Block 65
int
main (int argc, char **argv) Line 1448
{
int i; Line 1450
struct pending *thispend; Line 1451
int n_files; Line 1452
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
initialize_exit_failure (LS_FAILURE); Line 1460
atexit (close_stdout); Close stdout on exit (see gnulib)
assert (ARRAY_CARDINALITY (color_indicator) + 1 Line 1463
== ARRAY_CARDINALITY (indicator_name)); Line 1464
exit_status = EXIT_SUCCESS; Line 1466
print_dir_name = true; Line 1467
pending_dirs = NULL; Line 1468
current_time.tv_sec = TYPE_MINIMUM (time_t); Line 1470
current_time.tv_nsec = -1; Line 1471
i = decode_switches (argc, argv); Line 1473
if (print_with_color) Line 1475
parse_ls_color (); Line 1476
/* Test print_with_color again, because the call to parse_ls_color
may have just reset it -- e.g., if LS_COLORS is invalid. */
if (print_with_color) Line 1480
{
/* Avoid following symbolic links when possible. */
if (is_colored (C_ORPHAN) Line 1483
|| (is_colored (C_EXEC) && color_symlink_as_referent) Line 1484
|| (is_colored (C_MISSING) && format == long_format)) Line 1485
check_symlink_color = true; Line 1486
}
if (dereference == DEREF_UNDEFINED) Line 1489
dereference = ((immediate_dirs Line 1490
|| indicator_style == classify Line 1491
|| format == long_format) Line 1492
? DEREF_NEVER Line 1493
: DEREF_COMMAND_LINE_SYMLINK_TO_DIR); Line 1494
/* When using -R, initialize a data structure we'll use to
detect any directory cycles. */
if (recursive) Line 1498
{
active_dir_set = hash_initialize (INITIAL_TABLE_SIZE, NULL, Line 1500
dev_ino_hash, Line 1501
dev_ino_compare, Line 1502
dev_ino_free); Line 1503
if (active_dir_set == NULL) Line 1504
xalloc_die (); ...!common auto-comment...
obstack_init (&dev_ino_obstack); Line 1507
}
localtz = tzalloc (getenv ("TZ")); Line 1510
format_needs_stat = sort_type == sort_time || sort_type == sort_size Line 1512
|| format == long_format Line 1513
|| print_scontext Line 1514
|| print_block_size; Line 1515
format_needs_type = (! format_needs_stat Line 1516
&& (recursive Line 1517
|| print_with_color Line 1518
|| indicator_style != none Line 1519
|| directories_first)); Line 1520
if (dired) Line 1522
{
obstack_init (&dired_obstack); Line 1524
obstack_init (&subdired_obstack); Line 1525
}
if (print_hyperlink) Line 1528
{
file_escape_init (); Line 1530
hostname = xgethostname (); Line 1532
/* The hostname is generally ignored,
so ignore failures obtaining it. */
if (! hostname) Line 1535
hostname = ""; Line 1536
}
cwd_n_alloc = 100; Line 1539
cwd_file = xnmalloc (cwd_n_alloc, sizeof *cwd_file); Line 1540
cwd_n_used = 0; Line 1541
clear_files (); Line 1543
n_files = argc - i; Line 1545
if (n_files <= 0) Line 1547
{
if (immediate_dirs) Line 1549
gobble_file (".", directory, NOT_AN_INODE_NUMBER, true, ""); Line 1550
else Line 1551
queue_directory (".", NULL, true); Line 1552
}
else Line 1554
do
gobble_file (argv[i++], unknown, NOT_AN_INODE_NUMBER, true, ""); Line 1556
while (i < argc); Line 1557
if (cwd_n_used) Line 1559
{
sort_files (); Line 1561
if (!immediate_dirs) Line 1562
extract_dirs_from_files (NULL, true); Line 1563
/* 'cwd_n_used' might be zero now. */
}
/* In the following if/else blocks, it is sufficient to test 'pending_dirs'
(and not pending_dirs->name) because there may be no markers in the queue
at this point. A marker may be enqueued when extract_dirs_from_files is
called with a non-empty string or via print_dir. */
if (cwd_n_used) Line 1571
{
print_current_files (); Line 1573
if (pending_dirs) Line 1574
DIRED_PUTCHAR ('\n'); Line 1575
}
else if (n_files <= 1 && pending_dirs && pending_dirs->next == 0) Line 1577
print_dir_name = false; Line 1578
while (pending_dirs) Line 1580
{
thispend = pending_dirs; Line 1582
pending_dirs = pending_dirs->next; Line 1583
if (LOOP_DETECT) Line 1585
{
if (thispend->name == NULL) Line 1587
{
/* thispend->name == NULL means this is a marker entry
indicating we've finished processing the directory.
Use its dev/ino numbers to remove the corresponding
entry from the active_dir_set hash table. */
struct dev_ino di = dev_ino_pop (); Line 1593
struct dev_ino *found = hash_delete (active_dir_set, &di); Line 1594
/* ASSERT_MATCHING_DEV_INO (thispend->realname, di); */
assert (found); Line 1596
dev_ino_free (found); Line 1597
free_pending_ent (thispend); Line 1598
continue; Line 1599
}
}
print_dir (thispend->name, thispend->realname, Line 1603
thispend->command_line_arg); Line 1604
free_pending_ent (thispend); Line 1606
print_dir_name = true; Line 1607
}
if (print_with_color && used_color) Line 1610
{
int j; Line 1612
/* Skip the restore when it would be a no-op, i.e.,
when left is "\033[" and right is "m". */
if (!(color_indicator[C_LEFT].len == 2 Line 1616
&& memcmp (color_indicator[C_LEFT].string, "\033[", 2) == 0 Line 1617
&& color_indicator[C_RIGHT].len == 1 Line 1618
&& color_indicator[C_RIGHT].string[0] == 'm')) Line 1619
restore_default_color (); Line 1620
fflush (stdout); Line 1622
signal_restore (); Line 1624
/* Act on any signals that arrived before the default was restored.
This can process signals out of order, but there doesn't seem to
be an easy way to do them in order, and the order isn't that
important anyway. */
for (j = stop_signal_count; j; j--) Line 1630
raise (SIGSTOP); Line 1631
j = interrupt_signal; Line 1632
if (j) Line 1633
raise (j); Line 1634
}
if (dired) Line 1637
{
/* No need to free these since we're about to exit. */
dired_dump_obstack ("//DIRED//", &dired_obstack); Line 1640
dired_dump_obstack ("//SUBDIRED//", &subdired_obstack); Line 1641
printf ("//DIRED-OPTIONS// --quoting-style=%s\n", Line 1642
quoting_style_args[get_quoting_style (filename_quoting_options)]);Line 1643
}
if (LOOP_DETECT) Line 1646
{
assert (hash_get_n_entries (active_dir_set) == 0); Line 1648
hash_free (active_dir_set); Line 1649
}
return exit_status; Line 1652
} Block 66
/* Set the line length to the value given by SPEC. Return true if
successful. 0 means no limit on line length. */
static bool Line 1658
set_line_length (char const *spec) Line 1659
{
uintmax_t val; Line 1661
/* Treat too-large values as if they were SIZE_MAX, which is
effectively infinity. */
switch (xstrtoumax (spec, NULL, 0, &val, "")) Line 1665
{
case LONGINT_OK: Line 1667
line_length = MIN (val, SIZE_MAX); Line 1668
return true; Line 1669
case LONGINT_OVERFLOW: Line 1671
line_length = SIZE_MAX; Line 1672
return true; Line 1673
default: Line 1675
return false; Line 1676
}
} Block 67
/* Set all the option flags according to the switches specified.
Return the index of the first non-option argument. */
static int Line 1683
decode_switches (int argc, char **argv) Line 1684
{
char *time_style_option = NULL; Line 1686
bool sort_type_specified = false; Line 1688
bool kibibytes_specified = false; Line 1689
qmark_funny_chars = false; Line 1691
/* initialize all switches to default settings */
switch (ls_mode) Line 1695
{
case LS_MULTI_COL: Line 1697
/* This is for the 'dir' program. */
format = many_per_line; Line 1699
set_quoting_style (NULL, escape_quoting_style); Line 1700
break; Line 1701
case LS_LONG_FORMAT: Line 1703
/* This is for the 'vdir' program. */
format = long_format; Line 1705
set_quoting_style (NULL, escape_quoting_style); Line 1706
break; Line 1707
case LS_LS: Line 1709
/* This is for the 'ls' program. */
if (isatty (STDOUT_FILENO)) Line 1711
{
format = many_per_line; Line 1713
set_quoting_style (NULL, shell_escape_quoting_style); Line 1714
/* See description of qmark_funny_chars, above. */
qmark_funny_chars = true; Line 1716
}
else Line 1718
{
format = one_per_line; Line 1720
qmark_funny_chars = false; Line 1721
}
break; Line 1723
default: Line 1725
abort (); ...!common auto-comment...
}
time_type = time_mtime; Line 1729
sort_type = sort_name; Line 1730
sort_reverse = false; Line 1731
numeric_ids = false; Line 1732
print_block_size = false; Line 1733
indicator_style = none; Line 1734
print_inode = false; Line 1735
dereference = DEREF_UNDEFINED; Line 1736
recursive = false; Line 1737
immediate_dirs = false; Line 1738
ignore_mode = IGNORE_DEFAULT; Line 1739
ignore_patterns = NULL; Line 1740
hide_patterns = NULL; Line 1741
print_scontext = false; Line 1742
getenv_quoting_style (); Line 1744
line_length = 80; Line 1746
{
char const *p = getenv ("COLUMNS"); Line 1748
if (p && *p && ! set_line_length (p)) Line 1749
error (0, 0, Line 1750
_("ignoring invalid width in environment variable COLUMNS: %s"), Line 1751
quote (p)); Line 1752
}
#ifdef TIOCGWINSZ Line 1755
{
struct winsize ws; Line 1757
if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 Line 1759...!syscalls auto-comment...
&& 0 < ws.ws_col && ws.ws_col == (size_t) ws.ws_col) Line 1760
line_length = ws.ws_col; Line 1761
}
#endif Line 1763
{
char const *p = getenv ("TABSIZE"); Line 1766
tabsize = 8; Line 1767
if (p) Line 1768
{
unsigned long int tmp_ulong; Line 1770
if (xstrtoul (p, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK Line 1771
&& tmp_ulong <= SIZE_MAX) Line 1772
{
tabsize = tmp_ulong; Line 1774
}
else Line 1776
{
error (0, 0, Line 1778
_("ignoring invalid tab size in environment variable TABSIZE: %s"),Line 1779
quote (p)); Line 1780
}
}
}
while (true) Line 1785
{
int oi = -1; Line 1787
int c = getopt_long (argc, argv, Line 1788
"abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1", Line 1789
long_options, &oi); Line 1790
if (c == -1) Line 1791
break; Line 1792
switch (c) Line 1794
{
case 'a': Line 1796
ignore_mode = IGNORE_MINIMAL; Line 1797
break; Line 1798
case 'b': Line 1800
set_quoting_style (NULL, escape_quoting_style); Line 1801
break; Line 1802
case 'c': Line 1804
time_type = time_ctime; Line 1805
break; Line 1806
case 'd': Line 1808
immediate_dirs = true; Line 1809
break; Line 1810
case 'f': Line 1812
/* Same as enabling -a -U and disabling -l -s. */
ignore_mode = IGNORE_MINIMAL; Line 1814
sort_type = sort_none; Line 1815
sort_type_specified = true; Line 1816
/* disable -l */
if (format == long_format) Line 1818
format = (isatty (STDOUT_FILENO) ? many_per_line : one_per_line); Line 1819
print_block_size = false; /* disable -s */ Line 1820
print_with_color = false; /* disable --color */ Line 1821
print_hyperlink = false; /* disable --hyperlink */ Line 1822
break; Line 1823
case FILE_TYPE_INDICATOR_OPTION: /* --file-type */ Line 1825
indicator_style = file_type; Line 1826
break; Line 1827
case 'g': Line 1829
format = long_format; Line 1830
print_owner = false; Line 1831
break; Line 1832
case 'h': Line 1834
file_human_output_opts = human_output_opts = Line 1835
human_autoscale | human_SI | human_base_1024; Line 1836
file_output_block_size = output_block_size = 1; Line 1837
break; Line 1838
case 'i': Line 1840
print_inode = true; Line 1841
break; Line 1842
case 'k': Line 1844
kibibytes_specified = true; Line 1845
break; Line 1846
case 'l': Line 1848
format = long_format; Line 1849
break; Line 1850
case 'm': Line 1852
format = with_commas; Line 1853
break; Line 1854
case 'n': Line 1856
numeric_ids = true; Line 1857
format = long_format; Line 1858
break; Line 1859
case 'o': /* Just like -l, but don't display group info. */ Line 1861
format = long_format; Line 1862
print_group = false; Line 1863
break; Line 1864
case 'p': Line 1866
indicator_style = slash; Line 1867
break; Line 1868
case 'q': Line 1870
qmark_funny_chars = true; Line 1871
break; Line 1872
case 'r': Line 1874
sort_reverse = true; Line 1875
break; Line 1876
case 's': Line 1878
print_block_size = true; Line 1879
break; Line 1880
case 't': Line 1882
sort_type = sort_time; Line 1883
sort_type_specified = true; Line 1884
break; Line 1885
case 'u': Line 1887
time_type = time_atime; Line 1888
break; Line 1889
case 'v': Line 1891
sort_type = sort_version; Line 1892
sort_type_specified = true; Line 1893
break; Line 1894
case 'w': Line 1896
if (! set_line_length (optarg)) Line 1897
die (LS_FAILURE, 0, "%s: %s", _("invalid line width"), Line 1898
quote (optarg)); Line 1899
break; Line 1900
case 'x': Line 1902
format = horizontal; Line 1903
break; Line 1904
case 'A': Line 1906
ignore_mode = IGNORE_DOT_AND_DOTDOT; Line 1907
break; Line 1908
case 'B': Line 1910
add_ignore_pattern ("*~"); Line 1911
add_ignore_pattern (".*~"); Line 1912
break; Line 1913
case 'C': Line 1915
format = many_per_line; Line 1916
break; Line 1917
case 'D': Line 1919
dired = true; Line 1920
break; Line 1921
case 'F': Line 1923
indicator_style = classify; Line 1924
break; Line 1925
case 'G': /* inhibit display of group info */ Line 1927
print_group = false; Line 1928
break; Line 1929
case 'H': Line 1931
dereference = DEREF_COMMAND_LINE_ARGUMENTS; Line 1932
break; Line 1933
case DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION: Line 1935
dereference = DEREF_COMMAND_LINE_SYMLINK_TO_DIR; Line 1936
break; Line 1937
case 'I': Line 1939
add_ignore_pattern (optarg); Line 1940
break; Line 1941
case 'L': Line 1943
dereference = DEREF_ALWAYS; Line 1944
break; Line 1945
case 'N': Line 1947
set_quoting_style (NULL, literal_quoting_style); Line 1948
break; Line 1949
case 'Q': Line 1951
set_quoting_style (NULL, c_quoting_style); Line 1952
break; Line 1953
case 'R': Line 1955
recursive = true; Line 1956
break; Line 1957
case 'S': Line 1959
sort_type = sort_size; Line 1960
sort_type_specified = true; Line 1961
break; Line 1962
case 'T': Line 1964
tabsize = xnumtoumax (optarg, 0, 0, SIZE_MAX, "", Line 1965
_("invalid tab size"), LS_FAILURE); Line 1966
break; Line 1967
case 'U': Line 1969
sort_type = sort_none; Line 1970
sort_type_specified = true; Line 1971
break; Line 1972
case 'X': Line 1974
sort_type = sort_extension; Line 1975
sort_type_specified = true; Line 1976
break; Line 1977
case '1': Line 1979
/* -1 has no effect after -l. */
if (format != long_format) Line 1981
format = one_per_line; Line 1982
break; Line 1983
case AUTHOR_OPTION: Line 1985
print_author = true; Line 1986
break; Line 1987
case HIDE_OPTION: Line 1989
{
struct ignore_pattern *hide = xmalloc (sizeof *hide); Line 1991
hide->pattern = optarg; Line 1992
hide->next = hide_patterns; Line 1993
hide_patterns = hide; Line 1994
}
break; Line 1996
case SORT_OPTION: Line 1998
sort_type = XARGMATCH ("--sort", optarg, sort_args, sort_types); Line 1999
sort_type_specified = true; Line 2000
break; Line 2001
case GROUP_DIRECTORIES_FIRST_OPTION: Line 2003
directories_first = true; Line 2004
break; Line 2005
case TIME_OPTION: Line 2007
time_type = XARGMATCH ("--time", optarg, time_args, time_types); Line 2008
break; Line 2009
case FORMAT_OPTION: Line 2011
format = XARGMATCH ("--format", optarg, format_args, format_types); Line 2012
break; Line 2013
case FULL_TIME_OPTION: Line 2015
format = long_format; Line 2016
time_style_option = bad_cast ("full-iso"); Line 2017
break; Line 2018
case COLOR_OPTION: Line 2020
{
int i; Line 2022
if (optarg) Line 2023
i = XARGMATCH ("--color", optarg, when_args, when_types); Line 2024
else Line 2025
/* Using --color with no argument is equivalent to using
--color=always. */
i = when_always; Line 2028
print_with_color = (i == when_always Line 2030
|| (i == when_if_tty Line 2031
&& isatty (STDOUT_FILENO))); Line 2032
if (print_with_color) Line 2034
{
/* Don't use TAB characters in output. Some terminal
emulators can't handle the combination of tabs and
color codes on the same line. */
tabsize = 0; Line 2039
}
break; Line 2041
}
case HYPERLINK_OPTION: Line 2044
{
int i; Line 2046
if (optarg) Line 2047
i = XARGMATCH ("--hyperlink", optarg, when_args, when_types); Line 2048
else Line 2049
/* Using --hyperlink with no argument is equivalent to using
--hyperlink=always. */
i = when_always; Line 2052
print_hyperlink = (i == when_always Line 2054
|| (i == when_if_tty Line 2055
&& isatty (STDOUT_FILENO))); Line 2056
break; Line 2057
}
case INDICATOR_STYLE_OPTION: Line 2060
indicator_style = XARGMATCH ("--indicator-style", optarg, Line 2061
indicator_style_args, Line 2062
indicator_style_types); Line 2063
break; Line 2064
case QUOTING_STYLE_OPTION: Line 2066
set_quoting_style (NULL, Line 2067
XARGMATCH ("--quoting-style", optarg, Line 2068
quoting_style_args, Line 2069
quoting_style_vals)); Line 2070
break; Line 2071
case TIME_STYLE_OPTION: Line 2073
time_style_option = optarg; Line 2074
break; Line 2075
case SHOW_CONTROL_CHARS_OPTION: Line 2077
qmark_funny_chars = false; Line 2078
break; Line 2079
case BLOCK_SIZE_OPTION: Line 2081
{
enum strtol_error e = human_options (optarg, &human_output_opts, Line 2083
&output_block_size); Line 2084
if (e != LONGINT_OK) Line 2085
xstrtol_fatal (e, oi, 0, long_options, optarg); Line 2086
file_human_output_opts = human_output_opts; Line 2087
file_output_block_size = output_block_size; Line 2088
}
break; Line 2090
case SI_OPTION: Line 2092
file_human_output_opts = human_output_opts = Line 2093
human_autoscale | human_SI; Line 2094
file_output_block_size = output_block_size = 1; Line 2095
break; Line 2096
case 'Z': Line 2098
print_scontext = true; Line 2099
break; Line 2100
case_GETOPT_HELP_CHAR; Line 2102
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 2104
default: Line 2106
usage (LS_FAILURE); Line 2107
}
}
if (! output_block_size) Line 2111
{
char const *ls_block_size = getenv ("LS_BLOCK_SIZE"); Line 2113
human_options (ls_block_size, Line 2114
&human_output_opts, &output_block_size); Line 2115
if (ls_block_size || getenv ("BLOCK_SIZE")) Line 2116
{
file_human_output_opts = human_output_opts; Line 2118
file_output_block_size = output_block_size; Line 2119
}
if (kibibytes_specified) Line 2121
{
human_output_opts = 0; Line 2123
output_block_size = 1024; Line 2124
}
}
/* Determine the max possible number of display columns. */
max_idx = line_length / MIN_COLUMN_WIDTH; Line 2129
/* Account for first display column not having a separator,
or line_lengths shorter than MIN_COLUMN_WIDTH. */
max_idx += line_length % MIN_COLUMN_WIDTH != 0; Line 2132
enum quoting_style qs = get_quoting_style (NULL); Line 2134
align_variable_outer_quotes = format != with_commas Line 2135
&& format != one_per_line Line 2136
&& (line_length || format == long_format) Line 2137
&& (qs == shell_quoting_style Line 2138
|| qs == shell_escape_quoting_style Line 2139
|| qs == c_maybe_quoting_style); Line 2140
filename_quoting_options = clone_quoting_options (NULL); Line 2141
if (qs == escape_quoting_style) Line 2142
set_char_quoting (filename_quoting_options, ' ', 1); Line 2143
if (file_type <= indicator_style) Line 2144
{
char const *p; Line 2146
for (p = &"*=>@|"[indicator_style - file_type]; *p; p++) Line 2147
set_char_quoting (filename_quoting_options, *p, 1); Line 2148
}
dirname_quoting_options = clone_quoting_options (NULL); Line 2151
set_char_quoting (dirname_quoting_options, ':', 1); Line 2152
/* --dired is meaningful only with --format=long (-l).
Otherwise, ignore it. FIXME: warn about this?
Alternatively, make --dired imply --format=long? */
if (dired && (format != long_format || print_hyperlink)) Line 2157
dired = false; Line 2158
/* If -c or -u is specified and not -l (or any other option that implies -l),
and no sort-type was specified, then sort by the ctime (-c) or atime (-u).
The behavior of ls when using either -c or -u but with neither -l nor -t
appears to be unspecified by POSIX. So, with GNU ls, '-u' alone means
sort by atime (this is the one that's not specified by the POSIX spec),
-lu means show atime and sort by name, -lut means show atime and sort
by atime. */
if ((time_type == time_ctime || time_type == time_atime) Line 2168
&& !sort_type_specified && format != long_format) Line 2169
{
sort_type = sort_time; Line 2171
}
if (format == long_format) Line 2174
{
char *style = time_style_option; Line 2176
static char const posix_prefix[] = "posix-"; Line 2177
if (! style) Line 2179
if (! (style = getenv ("TIME_STYLE"))) Line 2180
style = bad_cast ("locale"); Line 2181
while (STREQ_LEN (style, posix_prefix, sizeof posix_prefix - 1)) Line 2183
{
if (! hard_locale (LC_TIME)) Line 2185
return optind; Line 2186
style += sizeof posix_prefix - 1; Line 2187
}
if (*style == '+') Line 2190
{
char *p0 = style + 1; Line 2192
char *p1 = strchr (p0, '\n'); Line 2193
if (! p1) Line 2194
p1 = p0; Line 2195
else Line 2196
{
if (strchr (p1 + 1, '\n')) Line 2198
die (LS_FAILURE, 0, _("invalid time style format %s"), Line 2199
quote (p0)); Line 2200
*p1++ = '\0'; Line 2201
}
long_time_format[0] = p0; Line 2203
long_time_format[1] = p1; Line 2204
}
else Line 2206
{
ptrdiff_t res = argmatch (style, time_style_args, Line 2208
(char const *) time_style_types, Line 2209
sizeof (*time_style_types)); Line 2210
if (res < 0) Line 2211
{
/* This whole block used to be a simple use of XARGMATCH.
but that didn't print the "posix-"-prefixed variants or
the "+"-prefixed format string option upon failure. */
argmatch_invalid ("time style", style, res); Line 2216
/* The following is a manual expansion of argmatch_valid,
but with the added "+ ..." description and the [posix-]
prefixes prepended. Note that this simplification works
only because all four existing time_style_types values
are distinct. */
fputs (_("Valid arguments are:\n"), stderr); Line 2223
char const *const *p = time_style_args; Line 2224
while (*p) Line 2225
fprintf (stderr, " - [posix-]%s\n", *p++); Line 2226
fputs (_(" - +FORMAT (e.g., +%H:%M) for a 'date'-style" Line 2227
" format\n"), stderr); Line 2228
usage (LS_FAILURE); Line 2229
}
switch (res) Line 2231
{
case full_iso_time_style: Line 2233
long_time_format[0] = long_time_format[1] = Line 2234
"%Y-%m-%d %H:%M:%S.%N %z"; Line 2235
break; Line 2236
case long_iso_time_style: Line 2238
long_time_format[0] = long_time_format[1] = "%Y-%m-%d %H:%M"; Line 2239
break; Line 2240
case iso_time_style: Line 2242
long_time_format[0] = "%Y-%m-%d "; Line 2243
long_time_format[1] = "%m-%d %H:%M"; Line 2244
break; Line 2245
case locale_time_style: Line 2247
if (hard_locale (LC_TIME)) Line 2248
{
for (int i = 0; i < 2; i++) Line 2250
long_time_format[i] = Line 2251
dcgettext (NULL, long_time_format[i], LC_TIME); Line 2252
}
}
}
abformat_init (); Line 2257
}
return optind; Line 2260
} Block 68
/* Parse a string as part of the LS_COLORS variable; this may involve
decoding all kinds of escape characters. If equals_end is set an
unescaped equal sign ends the string, otherwise only a : or \0
does. Set *OUTPUT_COUNT to the number of bytes output. Return
true if successful.
The resulting string is *not* null-terminated, but may contain
embedded nulls.
Note that both dest and src are char **; on return they point to
the first free byte after the array and the character that ended
the input string, respectively. */
static bool Line 2276
get_funky_string (char **dest, const char **src, bool equals_end, Line 2277
size_t *output_count) Line 2278
{
char num; /* For numerical codes */ Line 2280
size_t count; /* Something to count with */ Line 2281
enum { Line 2282
ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR Line 2283
} state; Line 2284
const char *p; Line 2285
char *q; Line 2286
p = *src; /* We don't want to double-indirect */ Line 2288
q = *dest; /* the whole darn time. */ Line 2289
count = 0; /* No characters counted in yet. */ Line 2291
num = 0; Line 2292
state = ST_GND; /* Start in ground state. */ Line 2294
while (state < ST_END) Line 2295
{
switch (state) Line 2297
{
case ST_GND: /* Ground state (no escapes) */ Line 2299
switch (*p) Line 2300
{
case ':': Line 2302
case '\0': Line 2303
state = ST_END; /* End of string */ Line 2304
break; Line 2305
case '\\': Line 2306
state = ST_BACKSLASH; /* Backslash escape sequence */ Line 2307
++p; Line 2308
break; Line 2309
case '^': Line 2310
state = ST_CARET; /* Caret escape */ Line 2311
++p; Line 2312
break; Line 2313
case '=': Line 2314
if (equals_end) Line 2315
{
state = ST_END; /* End */ Line 2317
break; Line 2318
}
FALLTHROUGH; Line 2320
default: Line 2321
*(q++) = *(p++); Line 2322
++count; Line 2323
break; Line 2324
}
break; Line 2326
case ST_BACKSLASH: /* Backslash escaped character */ Line 2328
switch (*p) Line 2329
{
case '0': Line 2331
case '1': Line 2332
case '2': Line 2333
case '3': Line 2334
case '4': Line 2335
case '5': Line 2336
case '6': Line 2337
case '7': Line 2338
state = ST_OCTAL; /* Octal sequence */ Line 2339
num = *p - '0'; Line 2340
break; Line 2341
case 'x': Line 2342
case 'X': Line 2343
state = ST_HEX; /* Hex sequence */ Line 2344
num = 0; Line 2345
break; Line 2346
case 'a': /* Bell */ Line 2347
num = '\a'; Line 2348
break; Line 2349
case 'b': /* Backspace */ Line 2350
num = '\b'; Line 2351
break; Line 2352
case 'e': /* Escape */ Line 2353
num = 27; Line 2354
break; Line 2355
case 'f': /* Form feed */ Line 2356
num = '\f'; Line 2357
break; Line 2358
case 'n': /* Newline */ Line 2359
num = '\n'; Line 2360
break; Line 2361
case 'r': /* Carriage return */ Line 2362
num = '\r'; Line 2363
break; Line 2364
case 't': /* Tab */ Line 2365
num = '\t'; Line 2366
break; Line 2367
case 'v': /* Vtab */ Line 2368
num = '\v'; Line 2369
break; Line 2370
case '?': /* Delete */ Line 2371
num = 127; Line 2372
break; Line 2373
case '_': /* Space */ Line 2374
num = ' '; Line 2375
break; Line 2376
case '\0': /* End of string */ Line 2377
state = ST_ERROR; /* Error! */ Line 2378
break; Line 2379
default: /* Escaped character like \ ^ : = */ Line 2380
num = *p; Line 2381
break; Line 2382
}
if (state == ST_BACKSLASH) Line 2384
{
*(q++) = num; Line 2386
++count; Line 2387
state = ST_GND; Line 2388
}
++p; Line 2390
break; Line 2391
case ST_OCTAL: /* Octal sequence */ Line 2393
if (*p < '0' || *p > '7') Line 2394
{
*(q++) = num; Line 2396
++count; Line 2397
state = ST_GND; Line 2398
}
else Line 2400
num = (num << 3) + (*(p++) - '0'); Line 2401
break; Line 2402
case ST_HEX: /* Hex sequence */ Line 2404
switch (*p) Line 2405
{
case '0': Line 2407
case '1': Line 2408
case '2': Line 2409
case '3': Line 2410
case '4': Line 2411
case '5': Line 2412
case '6': Line 2413
case '7': Line 2414
case '8': Line 2415
case '9': Line 2416
num = (num << 4) + (*(p++) - '0'); Line 2417
break; Line 2418
case 'a': Line 2419
case 'b': Line 2420
case 'c': Line 2421
case 'd': Line 2422
case 'e': Line 2423
case 'f': Line 2424
num = (num << 4) + (*(p++) - 'a') + 10; Line 2425
break; Line 2426
case 'A': Line 2427
case 'B': Line 2428
case 'C': Line 2429
case 'D': Line 2430
case 'E': Line 2431
case 'F': Line 2432
num = (num << 4) + (*(p++) - 'A') + 10; Line 2433
break; Line 2434
default: Line 2435
*(q++) = num; Line 2436
++count; Line 2437
state = ST_GND; Line 2438
break; Line 2439
}
break; Line 2441
case ST_CARET: /* Caret escape */ Line 2443
state = ST_GND; /* Should be the next state... */ Line 2444
if (*p >= '@' && *p <= '~') Line 2445
{
*(q++) = *(p++) & 037; Line 2447
++count; Line 2448
}
else if (*p == '?') Line 2450
{
*(q++) = 127; Line 2452
++count; Line 2453
}
else Line 2455
state = ST_ERROR; Line 2456
break; Line 2457
default: Line 2459
abort (); ...!common auto-comment...
}
}
*dest = q; Line 2464
*src = p; Line 2465
*output_count = count; Line 2466
return state != ST_ERROR; Line 2468
} Block 69
enum parse_state Line 2471
{
PS_START = 1, Line 2473
PS_2, Line 2474
PS_3, Line 2475
PS_4, Line 2476
PS_DONE, Line 2477
PS_FAIL Line 2478
}; Block 70
/* Check if the content of TERM is a valid name in dircolors. */
static bool Line 2484
known_term_type (void) Line 2485
{
char const *term = getenv ("TERM"); Line 2487
if (! term || ! *term) Line 2488
return false; Line 2489
char const *line = G_line; Line 2491
while (line - G_line < sizeof (G_line)) Line 2492
{
if (STRNCMP_LIT (line, "TERM ") == 0) Line 2494
{
if (fnmatch (line + 5, term, 0) == 0) Line 2496
return true; Line 2497
}
line += strlen (line) + 1; Line 2499
}
return false; Line 2502
} Block 71
static void Line 2505
parse_ls_color (void) Line 2506
{
const char *p; /* Pointer to character being parsed */ Line 2508
char *buf; /* color_buf buffer pointer */ Line 2509
int ind_no; /* Indicator number */ Line 2510
char label[3]; /* Indicator label */ Line 2511
struct color_ext_type *ext; /* Extension we are working on */ Line 2512
if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0') Line 2514
{
/* LS_COLORS takes precedence, but if that's not set then
honor the COLORTERM and TERM env variables so that
we only go with the internal ANSI color codes if the
former is non empty or the latter is set to a known value. */
char const *colorterm = getenv ("COLORTERM"); Line 2520
if (! (colorterm && *colorterm) && ! known_term_type ()) Line 2521
print_with_color = false; Line 2522
return; Line 2523
}
ext = NULL; Line 2526
strcpy (label, "??"); Line 2527
/* This is an overly conservative estimate, but any possible
LS_COLORS string will *not* generate a color_buf longer than
itself, so it is a safe way of allocating a buffer in
advance. */
buf = color_buf = xstrdup (p); Line 2533
enum parse_state state = PS_START; Line 2535
while (true) Line 2536
{
switch (state) Line 2538
{
case PS_START: /* First label character */ Line 2540
switch (*p) Line 2541
{
case ':': Line 2543
++p; Line 2544
break; Line 2545
case '*': Line 2547
/* Allocate new extension block and add to head of
linked list (this way a later definition will
override an earlier one, which can be useful for
having terminal-specific defs override global). */
ext = xmalloc (sizeof *ext); Line 2553
ext->next = color_ext_list; Line 2554
color_ext_list = ext; Line 2555
++p; Line 2557
ext->ext.string = buf; Line 2558
state = (get_funky_string (&buf, &p, true, &ext->ext.len) Line 2560
? PS_4 : PS_FAIL); Line 2561
break; Line 2562
case '\0': Line 2564
state = PS_DONE; /* Done! */ Line 2565
goto done; Line 2566
default: /* Assume it is file type label */ Line 2568
label[0] = *(p++); Line 2569
state = PS_2; Line 2570
break; Line 2571
}
break; Line 2573
case PS_2: /* Second label character */ Line 2575
if (*p) Line 2576
{
label[1] = *(p++); Line 2578
state = PS_3; Line 2579
}
else Line 2581
state = PS_FAIL; /* Error */ Line 2582
break; Line 2583
case PS_3: /* Equal sign after indicator label */ Line 2585
state = PS_FAIL; /* Assume failure... */ Line 2586
if (*(p++) == '=')/* It *should* be... */ Line 2587
{
for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no) Line 2589
{
if (STREQ (label, indicator_name[ind_no])) Line 2591
{
color_indicator[ind_no].string = buf; Line 2593
state = (get_funky_string (&buf, &p, false, Line 2594
&color_indicator[ind_no].len) Line 2595
? PS_START : PS_FAIL); Line 2596
break; Line 2597
}
}
if (state == PS_FAIL) Line 2600
error (0, 0, _("unrecognized prefix: %s"), quote (label)); Line 2601
}
break; Line 2603
case PS_4: /* Equal sign after *.ext */ Line 2605
if (*(p++) == '=') Line 2606
{
ext->seq.string = buf; Line 2608
state = (get_funky_string (&buf, &p, false, &ext->seq.len) Line 2609
? PS_START : PS_FAIL); Line 2610
}
else Line 2612
state = PS_FAIL; Line 2613
break; Line 2614
case PS_FAIL: Line 2616
goto done; Line 2617
default: Line 2619
abort (); ...!common auto-comment...
}
}
done: Line 2623
if (state == PS_FAIL) Line 2625
{
struct color_ext_type *e; Line 2627
struct color_ext_type *e2; Line 2628
error (0, 0, Line 2630
_("unparsable value for LS_COLORS environment variable")); Line 2631
free (color_buf); Line 2632
for (e = color_ext_list; e != NULL; /* empty */) Line 2633
{
e2 = e; Line 2635
e = e->next; Line 2636
free (e2); Line 2637
}
print_with_color = false; Line 2639
}
if (color_indicator[C_LINK].len == 6 Line 2642
&& !STRNCMP_LIT (color_indicator[C_LINK].string, "target")) Line 2643
color_symlink_as_referent = true; Line 2644
} Block 72
/* Set the quoting style default if the environment variable
QUOTING_STYLE is set. */
static void Line 2650
getenv_quoting_style (void) Line 2651
{
char const *q_style = getenv ("QUOTING_STYLE"); Line 2653
if (q_style) Line 2654
{
int i = ARGMATCH (q_style, quoting_style_args, quoting_style_vals); Line 2656
if (0 <= i) Line 2657
set_quoting_style (NULL, quoting_style_vals[i]); Line 2658
else Line 2659
error (0, 0, Line 2660
_("ignoring invalid value of environment variable QUOTING_STYLE: %s"), Line 2661
quote (q_style)); Line 2662
}
} Block 73
/* Set the exit status to report a failure. If SERIOUS, it is a
serious failure; otherwise, it is merely a minor problem. */
static void Line 2669
set_exit_status (bool serious) Line 2670
{
if (serious) Line 2672
exit_status = LS_FAILURE; Line 2673
else if (exit_status == EXIT_SUCCESS) Line 2674
exit_status = LS_MINOR_PROBLEM; Line 2675
} Block 74
/* Assuming a failure is serious if SERIOUS, use the printf-style
MESSAGE to report the failure to access a file named FILE. Assume
errno is set appropriately for the failure. */
static void Line 2682
file_failure (bool serious, char const *message, char const *file) Line 2683
{
error (0, errno, message, quoteaf (file)); Line 2685
set_exit_status (serious); Line 2686
} Block 75
/* Request that the directory named NAME have its contents listed later.
If REALNAME is nonzero, it will be used instead of NAME when the
directory name is printed. This allows symbolic links to directories
to be treated as regular directories but still be listed under their
real names. NAME == NULL is used to insert a marker entry for the
directory named in REALNAME.
If NAME is non-NULL, we use its dev/ino information to save
a call to stat -- when doing a recursive (-R) traversal.
COMMAND_LINE_ARG means this directory was mentioned on the command line. */
static void Line 2699
queue_directory (char const *name, char const *realname, bool command_line_arg) Line 2700
{
struct pending *new = xmalloc (sizeof *new); Line 2702
new->realname = realname ? xstrdup (realname) : NULL; Line 2703
new->name = name ? xstrdup (name) : NULL; Line 2704
new->command_line_arg = command_line_arg; Line 2705
new->next = pending_dirs; Line 2706
pending_dirs = new; Line 2707
} Block 76
/* Read directory NAME, and list the files in it.
If REALNAME is nonzero, print its name instead of NAME;
this is used for symbolic links to directories.
COMMAND_LINE_ARG means this directory was mentioned on the command line. */
static void Line 2715
print_dir (char const *name, char const *realname, bool command_line_arg) Line 2716
{
DIR *dirp; Line 2718
struct dirent *next; Line 2719
uintmax_t total_blocks = 0; Line 2720
static bool first = true; Line 2721
errno = 0; Line 2723
dirp = opendir (name); Line 2724
if (!dirp) Line 2725
{
file_failure (command_line_arg, _("cannot open directory %s"), name); Line 2727
return; Line 2728
}
if (LOOP_DETECT) Line 2731
{
struct stat dir_stat; Line 2733
int fd = dirfd (dirp); Line 2734
/* If dirfd failed, endure the overhead of using stat. */
if ((0 <= fd Line 2737
? fstat (fd, &dir_stat) Line 2738...!syscalls auto-comment......!syscalls auto-comment...
: stat (name, &dir_stat)) < 0) Line 2739...!syscalls auto-comment...
{
file_failure (command_line_arg, Line 2741
_("cannot determine device and inode of %s"), name); Line 2742
closedir (dirp); Line 2743
return; Line 2744
}
/* If we've already visited this dev/inode pair, warn that
we've found a loop, and do not process this directory. */
if (visit_dir (dir_stat.st_dev, dir_stat.st_ino)) Line 2749
{
error (0, 0, _("%s: not listing already-listed directory"), Line 2751
quotef (name)); Line 2752
closedir (dirp); Line 2753
set_exit_status (true); Line 2754
return; Line 2755
}
dev_ino_push (dir_stat.st_dev, dir_stat.st_ino); Line 2758
}
clear_files (); Line 2761
if (recursive || print_dir_name) Line 2763
{
if (!first) Line 2765
DIRED_PUTCHAR ('\n'); Line 2766
first = false; Line 2767
DIRED_INDENT (); Line 2768
char *absolute_name = NULL; Line 2770
if (print_hyperlink) Line 2771
{
absolute_name = canonicalize_filename_mode (name, CAN_MISSING); Line 2773
if (! absolute_name) Line 2774
file_failure (command_line_arg, Line 2775
_("error canonicalizing %s"), name); Line 2776
}
quote_name (realname ? realname : name, dirname_quoting_options, -1, Line 2778
NULL, true, &subdired_obstack, absolute_name); Line 2779
free (absolute_name); Line 2781
DIRED_FPUTS_LITERAL (":\n", stdout); Line 2783
}
/* Read the directory entries, and insert the subfiles into the 'cwd_file'
table. */
while (1) Line 2789
{
/* Set errno to zero so we can distinguish between a readdir failure
and when readdir simply finds that there are no more entries. */
errno = 0; Line 2793
next = readdir (dirp); Line 2794
if (next) Line 2795
{
if (! file_ignored (next->d_name)) Line 2797
{
enum filetype type = unknown; Line 2799
#if HAVE_STRUCT_DIRENT_D_TYPE Line 2801
switch (next->d_type) Line 2802
{
case DT_BLK: type = blockdev; break; Line 2804
case DT_CHR: type = chardev; break; Line 2805
case DT_DIR: type = directory; break; Line 2806
case DT_FIFO: type = fifo; break; Line 2807
case DT_LNK: type = symbolic_link; break; Line 2808
case DT_REG: type = normal; break; Line 2809
case DT_SOCK: type = sock; break; Line 2810
# ifdef DT_WHT Line 2811
case DT_WHT: type = whiteout; break; Line 2812
# endif Line 2813
}
#endif Line 2815
total_blocks += gobble_file (next->d_name, type, Line 2816
RELIABLE_D_INO (next), Line 2817
false, name); Line 2818
/* In this narrow case, print out each name right away, so
ls uses constant memory while processing the entries of
this directory. Useful when there are many (millions)
of entries in a directory. */
if (format == one_per_line && sort_type == sort_none Line 2824
&& !print_block_size && !recursive) Line 2825
{
/* We must call sort_files in spite of
"sort_type == sort_none" for its initialization
of the sorted_file vector. */
sort_files (); Line 2830
print_current_files (); Line 2831
clear_files (); Line 2832
}
}
}
else if (errno != 0) Line 2836
{
file_failure (command_line_arg, _("reading directory %s"), name); Line 2838
if (errno != EOVERFLOW) Line 2839
break; Line 2840
}
else Line 2842
break; Line 2843
/* When processing a very large directory, and since we've inhibited
interrupts, this loop would take so long that ls would be annoyingly
uninterruptible. This ensures that it handles signals promptly. */
process_signals (); Line 2848
}
if (closedir (dirp) != 0) Line 2851
{
file_failure (command_line_arg, _("closing directory %s"), name); Line 2853
/* Don't return; print whatever we got. */
}
/* Sort the directory contents. */
sort_files (); Line 2858
/* If any member files are subdirectories, perhaps they should have their
contents listed rather than being mentioned here as files. */
if (recursive) Line 2863
extract_dirs_from_files (name, false); Line 2864
if (format == long_format || print_block_size) Line 2866
{
const char *p; Line 2868
char buf[LONGEST_HUMAN_READABLE + 1]; Line 2869
DIRED_INDENT (); Line 2871
p = _("total"); Line 2872
DIRED_FPUTS (p, stdout, strlen (p)); Line 2873
DIRED_PUTCHAR (' '); Line 2874
p = human_readable (total_blocks, buf, human_output_opts, Line 2875
ST_NBLOCKSIZE, output_block_size); Line 2876
DIRED_FPUTS (p, stdout, strlen (p)); Line 2877
DIRED_PUTCHAR ('\n'); Line 2878
}
if (cwd_n_used) Line 2881
print_current_files (); Line 2882
} Block 77
/* Add 'pattern' to the list of patterns for which files that match are
not listed. */
static void Line 2888
add_ignore_pattern (const char *pattern) Line 2889
{
struct ignore_pattern *ignore; Line 2891
ignore = xmalloc (sizeof *ignore); Line 2893
ignore->pattern = pattern; Line 2894
/* Add it to the head of the linked list. */
ignore->next = ignore_patterns; Line 2896
ignore_patterns = ignore; Line 2897
} Block 78
/* Return true if one of the PATTERNS matches FILE. */
static bool Line 2902
patterns_match (struct ignore_pattern const *patterns, char const *file) Line 2903
{
struct ignore_pattern const *p; Line 2905
for (p = patterns; p; p = p->next) Line 2906
if (fnmatch (p->pattern, file, FNM_PERIOD) == 0) Line 2907
return true; Line 2908
return false; Line 2909
} Block 79
/* Return true if FILE should be ignored. */
static bool Line 2914
file_ignored (char const *name) Line 2915
{
return ((ignore_mode != IGNORE_MINIMAL Line 2917
&& name[0] == '.' Line 2918
&& (ignore_mode == IGNORE_DEFAULT || ! name[1 + (name[1] == '.')])) Line 2919
|| (ignore_mode == IGNORE_DEFAULT Line 2920
&& patterns_match (hide_patterns, name)) Line 2921
|| patterns_match (ignore_patterns, name)); Line 2922
} Block 80
/* POSIX requires that a file size be printed without a sign, even
when negative. Assume the typical case where negative sizes are
actually positive values that have wrapped around. */
static uintmax_t Line 2929
unsigned_file_size (off_t size) Line 2930
{
return size + (size < 0) * ((uintmax_t) OFF_T_MAX - OFF_T_MIN + 1); Line 2932
} Block 81
#ifdef HAVE_CAP Line 2935
/* Return true if NAME has a capability (see linux/capability.h) */
static bool Line 2937
has_capability (char const *name) Line 2938
{
char *result; Line 2940
bool has_cap; Line 2941
cap_t cap_d = cap_get_file (name); Line 2943
if (cap_d == NULL) Line 2944
return false; Line 2945
result = cap_to_text (cap_d, NULL); Line 2947
cap_free (cap_d); Line 2948
if (!result) Line 2949
return false; Line 2950
/* check if human-readable capability string is empty */
has_cap = !!*result; Line 2953
cap_free (result); Line 2955
return has_cap; Line 2956
} Block 82
#else Line 2958
static bool Line 2959
has_capability (char const *name _GL_UNUSED) Line 2960
{
errno = ENOTSUP; Line 2962
return false; Line 2963
} Block 83
#endif Line 2965
/* Enter and remove entries in the table 'cwd_file'. */
static void Line 2969
free_ent (struct fileinfo *f) Line 2970
{
free (f->name); Line 2972
free (f->linkname); Line 2973
free (f->absolute_name); Line 2974
if (f->scontext != UNKNOWN_SECURITY_CONTEXT) Line 2975
{
if (is_smack_enabled ()) ...!common auto-comment...
free (f->scontext); Line 2978
else Line 2979
freecon (f->scontext); Line 2980
}
} Block 84
/* Empty the table of files. */
static void Line 2985
clear_files (void) Line 2986
{
for (size_t i = 0; i < cwd_n_used; i++) Line 2988
{
struct fileinfo *f = sorted_file[i]; Line 2990
free_ent (f); Line 2991
}
cwd_n_used = 0; Line 2994
cwd_some_quoted = false; Line 2995
any_has_acl = false; Line 2996
inode_number_width = 0; Line 2997
block_size_width = 0; Line 2998
nlink_width = 0; Line 2999
owner_width = 0; Line 3000
group_width = 0; Line 3001
author_width = 0; Line 3002
scontext_width = 0; Line 3003
major_device_number_width = 0; Line 3004
minor_device_number_width = 0; Line 3005
file_size_width = 0; Line 3006
} Block 85
/* Return true if ERR implies lack-of-support failure by a
getxattr-calling function like getfilecon or file_has_acl. */
static bool Line 3011
errno_unsupported (int err) Line 3012
{
return (err == EINVAL || err == ENOSYS || is_ENOTSUP (err)); Line 3014
} Block 86
/* Cache *getfilecon failure, when it's trivial to do so.
Like getfilecon/lgetfilecon, but when F's st_dev says it's doesn't
support getting the security context, fail with ENOTSUP immediately. */
static int Line 3020
getfilecon_cache (char const *file, struct fileinfo *f, bool deref) Line 3021
{
/* st_dev of the most recently processed device for which we've
found that [l]getfilecon fails indicating lack of support. */
static dev_t unsupported_device; Line 3025
if (f->stat.st_dev == unsupported_device) Line 3027
{
errno = ENOTSUP; Line 3029
return -1; Line 3030
}
int r = 0; Line 3032
#ifdef HAVE_SMACK Line 3033
if (is_smack_enabled ()) ...!common auto-comment...
r = smack_new_label_from_path (file, "security.SMACK64", deref, Line 3035
&f->scontext); Line 3036
else Line 3037
#endif Line 3038
r = (deref Line 3039
? getfilecon (file, &f->scontext) Line 3040
: lgetfilecon (file, &f->scontext)); Line 3041
if (r < 0 && errno_unsupported (errno)) Line 3042
unsupported_device = f->stat.st_dev; Line 3043
return r; Line 3044
}
/* Cache file_has_acl failure, when it's trivial to do.
Like file_has_acl, but when F's st_dev says it's on a file
system lacking ACL support, return 0 with ENOTSUP immediately. */
static int Line 3050
file_has_acl_cache (char const *file, struct fileinfo *f) Line 3051
{
/* st_dev of the most recently processed device for which we've
found that file_has_acl fails indicating lack of support. */
static dev_t unsupported_device; Line 3055
if (f->stat.st_dev == unsupported_device) Line 3057
{
errno = ENOTSUP; Line 3059
return 0; Line 3060
}
/* Zero errno so that we can distinguish between two 0-returning cases:
"has-ACL-support, but only a default ACL" and "no ACL support". */
errno = 0; Line 3065
int n = file_has_acl (file, &f->stat); Line 3066
if (n <= 0 && errno_unsupported (errno)) Line 3067
unsupported_device = f->stat.st_dev; Line 3068
return n; Line 3069
}
/* Cache has_capability failure, when it's trivial to do.
Like has_capability, but when F's st_dev says it's on a file
system lacking capability support, return 0 with ENOTSUP immediately. */
static bool Line 3075
has_capability_cache (char const *file, struct fileinfo *f) Line 3076
{
/* st_dev of the most recently processed device for which we've
found that has_capability fails indicating lack of support. */
static dev_t unsupported_device; Line 3080
if (f->stat.st_dev == unsupported_device) Line 3082
{
errno = ENOTSUP; Line 3084
return 0; Line 3085
}
bool b = has_capability (file); Line 3088
if ( !b && errno_unsupported (errno)) Line 3089
unsupported_device = f->stat.st_dev; Line 3090
return b; Line 3091
}
static bool Line 3094
needs_quoting (char const* name) Line 3095
{
char test[2]; Line 3097
size_t len = quotearg_buffer (test, sizeof test , name, -1, Line 3098
filename_quoting_options); Line 3099
return *name != *test || strlen (name) != len; Line 3100
} Block 90
/* Add a file to the current table of files.
Verify that the file exists, and print an error message if it does not.
Return the number of blocks that the file occupies. */
static uintmax_t Line 3106
gobble_file (char const *name, enum filetype type, ino_t inode, Line 3107
bool command_line_arg, char const *dirname) Line 3108
{
uintmax_t blocks = 0; Line 3110
struct fileinfo *f; Line 3111
/* An inode value prior to gobble_file necessarily came from readdir,
which is not used for command line arguments. */
assert (! command_line_arg || inode == NOT_AN_INODE_NUMBER); Line 3115
if (cwd_n_used == cwd_n_alloc) Line 3117
{
cwd_file = xnrealloc (cwd_file, cwd_n_alloc, 2 * sizeof *cwd_file); Line 3119
cwd_n_alloc *= 2; Line 3120
}
f = &cwd_file[cwd_n_used]; Line 3123
memset (f, '\0', sizeof *f); Line 3124
f->stat.st_ino = inode; Line 3125
f->filetype = type; Line 3126
f->quoted = -1; Line 3128
if ((! cwd_some_quoted) && align_variable_outer_quotes) Line 3129
{
/* Determine if any quoted for padding purposes. */
f->quoted = needs_quoting (name); Line 3132
if (f->quoted) Line 3133
cwd_some_quoted = 1; Line 3134
}
if (command_line_arg Line 3137
|| print_hyperlink Line 3138
|| format_needs_stat Line 3139
/* When coloring a directory (we may know the type from
direct.d_type), we have to stat it in order to indicate
sticky and/or other-writable attributes. */
|| (type == directory && print_with_color Line 3143
&& (is_colored (C_OTHER_WRITABLE) Line 3144
|| is_colored (C_STICKY) Line 3145
|| is_colored (C_STICKY_OTHER_WRITABLE))) Line 3146
/* When dereferencing symlinks, the inode and type must come from
stat, but readdir provides the inode and type of lstat. */
|| ((print_inode || format_needs_type) Line 3149
&& (type == symbolic_link || type == unknown) Line 3150
&& (dereference == DEREF_ALWAYS Line 3151
|| color_symlink_as_referent || check_symlink_color)) Line 3152
/* Command line dereferences are already taken care of by the above
assertion that the inode number is not yet known. */
|| (print_inode && inode == NOT_AN_INODE_NUMBER) Line 3155
|| (format_needs_type Line 3156
&& (type == unknown || command_line_arg Line 3157
/* --indicator-style=classify (aka -F)
requires that we stat each regular file
to see if it's executable. */
|| (type == normal && (indicator_style == classify Line 3161
/* This is so that --color ends up
highlighting files with these mode
bits set even when options like -F are
not specified. Note we do a redundant
stat in the very unlikely case where
C_CAP is set but not the others. */
|| (print_with_color Line 3168
&& (is_colored (C_EXEC) Line 3169
|| is_colored (C_SETUID) Line 3170
|| is_colored (C_SETGID) Line 3171
|| is_colored (C_CAP))) Line 3172
))))) Line 3173
{
/* Absolute name of this file. */
char *full_name; Line 3177
bool do_deref; Line 3178
int err; Line 3179
if (name[0] == '/' || dirname[0] == 0) Line 3181
full_name = (char *) name; Line 3182
else Line 3183
{
full_name = alloca (strlen (name) + strlen (dirname) + 2); Line 3185
attach (full_name, dirname, name); Line 3186
}
if (print_hyperlink) Line 3189
{
f->absolute_name = canonicalize_filename_mode (full_name, Line 3191
CAN_MISSING); Line 3192
if (! f->absolute_name) Line 3193
file_failure (command_line_arg, Line 3194
_("error canonicalizing %s"), full_name); Line 3195
}
switch (dereference) Line 3198
{
case DEREF_ALWAYS: Line 3200
err = stat (full_name, &f->stat); Line 3201...!syscalls auto-comment...
do_deref = true; Line 3202
break; Line 3203
case DEREF_COMMAND_LINE_ARGUMENTS: Line 3205
case DEREF_COMMAND_LINE_SYMLINK_TO_DIR: Line 3206
if (command_line_arg) Line 3207
{
bool need_lstat; Line 3209
err = stat (full_name, &f->stat); Line 3210...!syscalls auto-comment...
do_deref = true; Line 3211
if (dereference == DEREF_COMMAND_LINE_ARGUMENTS) Line 3213
break; Line 3214
need_lstat = (err < 0 Line 3216
? errno == ENOENT Line 3217
: ! S_ISDIR (f->stat.st_mode)); Line 3218
if (!need_lstat) Line 3219
break; Line 3220
/* stat failed because of ENOENT, maybe indicating a dangling
symlink. Or stat succeeded, FULL_NAME does not refer to a
directory, and --dereference-command-line-symlink-to-dir is
in effect. Fall through so that we call lstat instead. */
}
FALLTHROUGH; Line 3227
default: /* DEREF_NEVER */ Line 3229
err = lstat (full_name, &f->stat); Line 3230...!syscalls auto-comment...
do_deref = false; Line 3231
break; Line 3232
}
if (err != 0) Line 3235
{
/* Failure to stat a command line argument leads to
an exit status of 2. For other files, stat failure
provokes an exit status of 1. */
file_failure (command_line_arg, Line 3240
_("cannot access %s"), full_name); Line 3241
if (command_line_arg) Line 3242
return 0; Line 3243
f->name = xstrdup (name); Line 3245
cwd_n_used++; Line 3246
return 0; Line 3248
}
f->stat_ok = true; Line 3251
/* Note has_capability() adds around 30% runtime to 'ls --color' */
if ((type == normal || S_ISREG (f->stat.st_mode)) Line 3254
&& print_with_color && is_colored (C_CAP)) Line 3255
f->has_capability = has_capability_cache (full_name, f); Line 3256
if (format == long_format || print_scontext) Line 3258
{
bool have_scontext = false; Line 3260
bool have_acl = false; Line 3261
int attr_len = getfilecon_cache (full_name, f, do_deref); Line 3262
err = (attr_len < 0); Line 3263
if (err == 0) Line 3265
{
if (is_smack_enabled ()) ...!common auto-comment...
have_scontext = ! STREQ ("_", f->scontext); Line 3268
else Line 3269
have_scontext = ! STREQ ("unlabeled", f->scontext); Line 3270
}
else Line 3272
{
f->scontext = UNKNOWN_SECURITY_CONTEXT; Line 3274
/* When requesting security context information, don't make
ls fail just because the file (even a command line argument)
isn't on the right type of file system. I.e., a getfilecon
failure isn't in the same class as a stat failure. */
if (is_ENOTSUP (errno) || errno == ENODATA) Line 3280
err = 0; Line 3281
}
if (err == 0 && format == long_format) Line 3284
{
int n = file_has_acl_cache (full_name, f); Line 3286
err = (n < 0); Line 3287
have_acl = (0 < n); Line 3288
}
f->acl_type = (!have_scontext && !have_acl Line 3291
? ACL_T_NONE Line 3292
: (have_scontext && !have_acl Line 3293
? ACL_T_LSM_CONTEXT_ONLY Line 3294
: ACL_T_YES)); Line 3295
any_has_acl |= f->acl_type != ACL_T_NONE; Line 3296
if (err) Line 3298
error (0, errno, "%s", quotef (full_name)); Line 3299
}
if (S_ISLNK (f->stat.st_mode) Line 3302
&& (format == long_format || check_symlink_color)) Line 3303
{
struct stat linkstats; Line 3305
get_link_name (full_name, f, command_line_arg); Line 3307
char *linkname = make_link_name (full_name, f->linkname); Line 3308
/* Use the slower quoting path for this entry, though
don't update CWD_SOME_QUOTED since alignment not affected. */
if (linkname && f->quoted == 0 && needs_quoting (f->linkname)) Line 3312
f->quoted = -1; Line 3313
/* Avoid following symbolic links when possible, ie, when
they won't be traced and when no indicator is needed. */
if (linkname Line 3317
&& (file_type <= indicator_style || check_symlink_color) Line 3318
&& stat (linkname, &linkstats) == 0) Line 3319...!syscalls auto-comment...
{
f->linkok = true; Line 3321
/* Symbolic links to directories that are mentioned on the
command line are automatically traced if not being
listed as files. */
if (!command_line_arg || format == long_format Line 3326
|| !S_ISDIR (linkstats.st_mode)) Line 3327
{
/* Get the linked-to file's mode for the filetype indicator
in long listings. */
f->linkmode = linkstats.st_mode; Line 3331
}
}
free (linkname); Line 3334
}
if (S_ISLNK (f->stat.st_mode)) Line 3337
f->filetype = symbolic_link; Line 3338
else if (S_ISDIR (f->stat.st_mode)) Line 3339
{
if (command_line_arg && !immediate_dirs) Line 3341
f->filetype = arg_directory; Line 3342
else Line 3343
f->filetype = directory; Line 3344
}
else Line 3346
f->filetype = normal; Line 3347
blocks = ST_NBLOCKS (f->stat); Line 3349
if (format == long_format || print_block_size) Line 3350
{
char buf[LONGEST_HUMAN_READABLE + 1]; Line 3352
int len = mbswidth (human_readable (blocks, buf, human_output_opts, Line 3353
ST_NBLOCKSIZE, output_block_size),Line 3354
0);
if (block_size_width < len) Line 3356
block_size_width = len; Line 3357
}
if (format == long_format) Line 3360
{
if (print_owner) Line 3362
{
int len = format_user_width (f->stat.st_uid); Line 3364
if (owner_width < len) Line 3365
owner_width = len; Line 3366
}
if (print_group) Line 3369
{
int len = format_group_width (f->stat.st_gid); Line 3371
if (group_width < len) Line 3372
group_width = len; Line 3373
}
if (print_author) Line 3376
{
int len = format_user_width (f->stat.st_author); Line 3378
if (author_width < len) Line 3379
author_width = len; Line 3380
}
}
if (print_scontext) Line 3384
{
int len = strlen (f->scontext); Line 3386
if (scontext_width < len) Line 3387
scontext_width = len; Line 3388
}
if (format == long_format) Line 3391
{
char b[INT_BUFSIZE_BOUND (uintmax_t)]; Line 3393
int b_len = strlen (umaxtostr (f->stat.st_nlink, b)); Line 3394
if (nlink_width < b_len) Line 3395
nlink_width = b_len; Line 3396
if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)) Line 3398
{
char buf[INT_BUFSIZE_BOUND (uintmax_t)]; Line 3400
int len = strlen (umaxtostr (major (f->stat.st_rdev), buf)); Line 3401
if (major_device_number_width < len) Line 3402
major_device_number_width = len; Line 3403
len = strlen (umaxtostr (minor (f->stat.st_rdev), buf)); Line 3404
if (minor_device_number_width < len) Line 3405
minor_device_number_width = len; Line 3406
len = major_device_number_width + 2 + minor_device_number_width; Line 3407
if (file_size_width < len) Line 3408
file_size_width = len; Line 3409
}
else Line 3411
{
char buf[LONGEST_HUMAN_READABLE + 1]; Line 3413
uintmax_t size = unsigned_file_size (f->stat.st_size); Line 3414
int len = mbswidth (human_readable (size, buf, Line 3415
file_human_output_opts, Line 3416
1, file_output_block_size), Line 3417
0);
if (file_size_width < len) Line 3419
file_size_width = len; Line 3420
}
}
}
if (print_inode) Line 3425
{
char buf[INT_BUFSIZE_BOUND (uintmax_t)]; Line 3427
int len = strlen (umaxtostr (f->stat.st_ino, buf)); Line 3428
if (inode_number_width < len) Line 3429
inode_number_width = len; Line 3430
}
f->name = xstrdup (name); Line 3433
cwd_n_used++; Line 3434
return blocks; Line 3436
} Block 91
/* Return true if F refers to a directory. */
static bool Line 3440
is_directory (const struct fileinfo *f) Line 3441
{
return f->filetype == directory || f->filetype == arg_directory; Line 3443
} Block 92
/* Put the name of the file that FILENAME is a symbolic link to
into the LINKNAME field of 'f'. COMMAND_LINE_ARG indicates whether
FILENAME is a command-line argument. */
static void Line 3450
get_link_name (char const *filename, struct fileinfo *f, bool command_line_arg) Line 3451
{
f->linkname = areadlink_with_size (filename, f->stat.st_size); Line 3453
if (f->linkname == NULL) Line 3454
file_failure (command_line_arg, _("cannot read symbolic link %s"), Line 3455
filename); Line 3456
} Block 93
/* If LINKNAME is a relative name and NAME contains one or more
leading directories, return LINKNAME with those directories
prepended; otherwise, return a copy of LINKNAME.
If LINKNAME is NULL, return NULL. */
static char * Line 3464
make_link_name (char const *name, char const *linkname) Line 3465
{
if (!linkname) Line 3467
return NULL; Line 3468
if (IS_ABSOLUTE_FILE_NAME (linkname)) Line 3470
return xstrdup (linkname); Line 3471
/* The link is to a relative name. Prepend any leading directory
in 'name' to the link name. */
size_t prefix_len = dir_len (name); Line 3475
if (prefix_len == 0) Line 3476
return xstrdup (linkname); Line 3477
char *p = xmalloc (prefix_len + 1 + strlen (linkname) + 1); Line 3479
/* PREFIX_LEN usually specifies a string not ending in slash.
In that case, extend it by one, since the next byte *is* a slash.
Otherwise, the prefix is "/", so leave the length unchanged. */
if ( ! ISSLASH (name[prefix_len - 1])) Line 3484
++prefix_len; Line 3485
stpcpy (stpncpy (p, name, prefix_len), linkname); Line 3487
return p; Line 3488
} Block 94
/* Return true if the last component of NAME is '.' or '..'
This is so we don't try to recurse on '././././. ...' */
static bool Line 3494
basename_is_dot_or_dotdot (const char *name) Line 3495
{
char const *base = last_component (name); Line 3497
return dot_or_dotdot (base); Line 3498
} Block 95
/* Remove any entries from CWD_FILE that are for directories,
and queue them to be listed as directories instead.
DIRNAME is the prefix to prepend to each dirname
to make it correct relative to ls's working dir;
if it is null, no prefix is needed and "." and ".." should not be ignored.
If COMMAND_LINE_ARG is true, this directory was mentioned at the top level,
This is desirable when processing directories recursively. */
static void Line 3509
extract_dirs_from_files (char const *dirname, bool command_line_arg) Line 3510
{
size_t i; Line 3512
size_t j; Line 3513
bool ignore_dot_and_dot_dot = (dirname != NULL); Line 3514
if (dirname && LOOP_DETECT) Line 3516
{
/* Insert a marker entry first. When we dequeue this marker entry,
we'll know that DIRNAME has been processed and may be removed
from the set of active directories. */
queue_directory (NULL, dirname, false); Line 3521
}
/* Queue the directories last one first, because queueing reverses the
order. */
for (i = cwd_n_used; i-- != 0; ) Line 3526
{
struct fileinfo *f = sorted_file[i]; Line 3528
if (is_directory (f) Line 3530
&& (! ignore_dot_and_dot_dot Line 3531
|| ! basename_is_dot_or_dotdot (f->name))) Line 3532
{
if (!dirname || f->name[0] == '/') Line 3534
queue_directory (f->name, f->linkname, command_line_arg); Line 3535
else Line 3536
{
char *name = file_name_concat (dirname, f->name, NULL); Line 3538
queue_directory (name, f->linkname, command_line_arg); Line 3539
free (name); Line 3540
}
if (f->filetype == arg_directory) Line 3542
free_ent (f); Line 3543
}
}
/* Now delete the directories from the table, compacting all the remaining
entries. */
for (i = 0, j = 0; i < cwd_n_used; i++) Line 3550
{
struct fileinfo *f = sorted_file[i]; Line 3552
sorted_file[j] = f; Line 3553
j += (f->filetype != arg_directory); Line 3554
}
cwd_n_used = j; Line 3556
} Block 96
/* Use strcoll to compare strings in this locale. If an error occurs,
report an error and longjmp to failed_strcoll. */
static jmp_buf failed_strcoll; Line 3562
static int Line 3564
xstrcoll (char const *a, char const *b) Line 3565
{
int diff; Line 3567
errno = 0; Line 3568
diff = strcoll (a, b); Line 3569
if (errno) Line 3570
{
error (0, errno, _("cannot compare file names %s and %s"), Line 3572
quote_n (0, a), quote_n (1, b)); Line 3573
set_exit_status (false); Line 3574
longjmp (failed_strcoll, 1); Line 3575
}
return diff; Line 3577
} Block 97
/* Comparison routines for sorting the files. */
typedef void const *V; Line 3582
typedef int (*qsortFunc)(V a, V b); Line 3583
/* Used below in DEFINE_SORT_FUNCTIONS for _df_ sort function variants.
The do { ... } while(0) makes it possible to use the macro more like
a statement, without violating C89 rules: */
#define DIRFIRST_CHECK(a, b) \ Line 3588
do \ Line 3589
{ \ Line 3590
bool a_is_dir = is_directory ((struct fileinfo const *) a); \ Line 3591
bool b_is_dir = is_directory ((struct fileinfo const *) b); \ Line 3592
if (a_is_dir && !b_is_dir) \ Line 3593
return -1; /* a goes before b */ \ Line 3594
if (!a_is_dir && b_is_dir) \ Line 3595
return 1; /* b goes before a */ \ Line 3596
} \ Line 3597Block 98
while (0) Line 3598
/* Define the 8 different sort function variants required for each sortkey.
KEY_NAME is a token describing the sort key, e.g., ctime, atime, size.
KEY_CMP_FUNC is a function to compare records based on that key, e.g.,
ctime_cmp, atime_cmp, size_cmp. Append KEY_NAME to the string,
'[rev_][x]str{cmp|coll}[_df]_', to create each function name. */
#define DEFINE_SORT_FUNCTIONS(key_name, key_cmp_func) \ Line 3605
/* direct, non-dirfirst versions */ \
static int xstrcoll_##key_name (V a, V b) \ Line 3607
{ return key_cmp_func (a, b, xstrcoll); } \ Line 3608Block 99
static int _GL_ATTRIBUTE_PURE strcmp_##key_name (V a, V b) \ Line 3609
{ return key_cmp_func (a, b, strcmp); } \ Line 3610
\
/* reverse, non-dirfirst versions */ \
static int rev_xstrcoll_##key_name (V a, V b) \ Line 3613
{ return key_cmp_func (b, a, xstrcoll); } \ Line 3614Block 101
static int _GL_ATTRIBUTE_PURE rev_strcmp_##key_name (V a, V b) \ Line 3615
{ return key_cmp_func (b, a, strcmp); } \ Line 3616
\
/* direct, dirfirst versions */ \
static int xstrcoll_df_##key_name (V a, V b) \ Line 3619
{ DIRFIRST_CHECK (a, b); return key_cmp_func (a, b, xstrcoll); } \ Line 3620Block 103
static int _GL_ATTRIBUTE_PURE strcmp_df_##key_name (V a, V b) \ Line 3621
{ DIRFIRST_CHECK (a, b); return key_cmp_func (a, b, strcmp); } \ Line 3622
\
/* reverse, dirfirst versions */ \
static int rev_xstrcoll_df_##key_name (V a, V b) \ Line 3625
{ DIRFIRST_CHECK (a, b); return key_cmp_func (b, a, xstrcoll); } \ Line 3626Block 105
static int _GL_ATTRIBUTE_PURE rev_strcmp_df_##key_name (V a, V b) \ Line 3627
{ DIRFIRST_CHECK (a, b); return key_cmp_func (b, a, strcmp); } Line 3628
static inline int Line 3630
cmp_ctime (struct fileinfo const *a, struct fileinfo const *b, Line 3631
int (*cmp) (char const *, char const *)) Line 3632
{
int diff = timespec_cmp (get_stat_ctime (&b->stat), Line 3634
get_stat_ctime (&a->stat)); Line 3635
return diff ? diff : cmp (a->name, b->name); Line 3636
} Block 107
static inline int Line 3639
cmp_mtime (struct fileinfo const *a, struct fileinfo const *b, Line 3640
int (*cmp) (char const *, char const *)) Line 3641
{
int diff = timespec_cmp (get_stat_mtime (&b->stat), Line 3643
get_stat_mtime (&a->stat)); Line 3644
return diff ? diff : cmp (a->name, b->name); Line 3645
} Block 108
static inline int Line 3648
cmp_atime (struct fileinfo const *a, struct fileinfo const *b, Line 3649
int (*cmp) (char const *, char const *)) Line 3650
{
int diff = timespec_cmp (get_stat_atime (&b->stat), Line 3652
get_stat_atime (&a->stat)); Line 3653
return diff ? diff : cmp (a->name, b->name); Line 3654
} Block 109
static inline int Line 3657
cmp_size (struct fileinfo const *a, struct fileinfo const *b, Line 3658
int (*cmp) (char const *, char const *)) Line 3659
{
int diff = longdiff (b->stat.st_size, a->stat.st_size); Line 3661
return diff ? diff : cmp (a->name, b->name); Line 3662
} Block 110
static inline int Line 3665
cmp_name (struct fileinfo const *a, struct fileinfo const *b, Line 3666
int (*cmp) (char const *, char const *)) Line 3667
{
return cmp (a->name, b->name); Line 3669
} Block 111
/* Compare file extensions. Files with no extension are 'smallest'.
If extensions are the same, compare by file names instead. */
static inline int Line 3675
cmp_extension (struct fileinfo const *a, struct fileinfo const *b, Line 3676
int (*cmp) (char const *, char const *)) Line 3677
{
char const *base1 = strrchr (a->name, '.'); Line 3679
char const *base2 = strrchr (b->name, '.'); Line 3680
int diff = cmp (base1 ? base1 : "", base2 ? base2 : ""); Line 3681
return diff ? diff : cmp (a->name, b->name); Line 3682
} Block 112
DEFINE_SORT_FUNCTIONS (ctime, cmp_ctime) Line 3685
DEFINE_SORT_FUNCTIONS (mtime, cmp_mtime) Line 3686
DEFINE_SORT_FUNCTIONS (atime, cmp_atime) Line 3687
DEFINE_SORT_FUNCTIONS (size, cmp_size) Line 3688
DEFINE_SORT_FUNCTIONS (name, cmp_name) Line 3689
DEFINE_SORT_FUNCTIONS (extension, cmp_extension) Line 3690
/* Compare file versions.
Unlike all other compare functions above, cmp_version depends only
on filevercmp, which does not fail (even for locale reasons), and does not
need a secondary sort key. See lib/filevercmp.h for function description.
All the other sort options, in fact, need xstrcoll and strcmp variants,
because they all use a string comparison (either as the primary or secondary
sort key), and xstrcoll has the ability to do a longjmp if strcoll fails for
locale reasons. Lastly, filevercmp is ALWAYS available with gnulib. */
static inline int Line 3701
cmp_version (struct fileinfo const *a, struct fileinfo const *b) Line 3702
{
return filevercmp (a->name, b->name); Line 3704
} Block 113
static int xstrcoll_version (V a, V b) Line 3707
{ return cmp_version (a, b); } Line 3708Block 114
static int rev_xstrcoll_version (V a, V b) Line 3709
{ return cmp_version (b, a); } Line 3710Block 115
static int xstrcoll_df_version (V a, V b) Line 3711
{ DIRFIRST_CHECK (a, b); return cmp_version (a, b); } Line 3712Block 116
static int rev_xstrcoll_df_version (V a, V b) Line 3713
{ DIRFIRST_CHECK (a, b); return cmp_version (b, a); } Line 3714
/* We have 2^3 different variants for each sort-key function
(for 3 independent sort modes).
The function pointers stored in this array must be dereferenced as:
sort_variants[sort_key][use_strcmp][reverse][dirs_first]
Note that the order in which sort keys are listed in the function pointer
array below is defined by the order of the elements in the time_type and
sort_type enums! */
#define LIST_SORTFUNCTION_VARIANTS(key_name) \ Line 3727
{ \ Line 3728
{ \ Line 3729
{ xstrcoll_##key_name, xstrcoll_df_##key_name }, \ Line 3730
{ rev_xstrcoll_##key_name, rev_xstrcoll_df_##key_name }, \ Line 3731
}, \ Line 3732
{ \ Line 3733
{ strcmp_##key_name, strcmp_df_##key_name }, \ Line 3734
{ rev_strcmp_##key_name, rev_strcmp_df_##key_name }, \ Line 3735
} \ Line 3736
} Block 118
static qsortFunc const sort_functions[][2][2][2] = Line 3739
{
LIST_SORTFUNCTION_VARIANTS (name), Line 3741
LIST_SORTFUNCTION_VARIANTS (extension), Line 3742
LIST_SORTFUNCTION_VARIANTS (size), Line 3743
{
{
{ xstrcoll_version, xstrcoll_df_version }, Line 3747
{ rev_xstrcoll_version, rev_xstrcoll_df_version }, Line 3748
},
/* We use NULL for the strcmp variants of version comparison
since as explained in cmp_version definition, version comparison
does not rely on xstrcoll, so it will never longjmp, and never
need to try the strcmp fallback. */
{
{ NULL, NULL }, Line 3756
{ NULL, NULL }, Line 3757
}
},
/* last are time sort functions */
LIST_SORTFUNCTION_VARIANTS (mtime), Line 3762
LIST_SORTFUNCTION_VARIANTS (ctime), Line 3763
LIST_SORTFUNCTION_VARIANTS (atime) Line 3764
}; Block 119
/* The number of sort keys is calculated as the sum of
the number of elements in the sort_type enum (i.e., sort_numtypes)
the number of elements in the time_type enum (i.e., time_numtypes) - 1
This is because when sort_type==sort_time, we have up to
time_numtypes possible sort keys.
This line verifies at compile-time that the array of sort functions has been
initialized for all possible sort keys. */
verify (ARRAY_CARDINALITY (sort_functions) Line 3775
== sort_numtypes + time_numtypes - 1 ); Line 3776
/* Set up SORTED_FILE to point to the in-use entries in CWD_FILE, in order. */
static void Line 3780
initialize_ordering_vector (void) Line 3781
{
for (size_t i = 0; i < cwd_n_used; i++) Line 3783
sorted_file[i] = &cwd_file[i]; Line 3784
} Block 120
/* Sort the files now in the table. */
static void Line 3789
sort_files (void) Line 3790
{
bool use_strcmp; Line 3792
if (sorted_file_alloc < cwd_n_used + cwd_n_used / 2) Line 3794
{
free (sorted_file); Line 3796
sorted_file = xnmalloc (cwd_n_used, 3 * sizeof *sorted_file); Line 3797
sorted_file_alloc = 3 * cwd_n_used; Line 3798
}
initialize_ordering_vector (); Line 3801
if (sort_type == sort_none) Line 3803
return; Line 3804
/* Try strcoll. If it fails, fall back on strcmp. We can't safely
ignore strcoll failures, as a failing strcoll might be a
comparison function that is not a total order, and if we ignored
the failure this might cause qsort to dump core. */
if (! setjmp (failed_strcoll)) Line 3811
use_strcmp = false; /* strcoll() succeeded */ Line 3812
else Line 3813
{
use_strcmp = true; Line 3815
assert (sort_type != sort_version); Line 3816
initialize_ordering_vector (); Line 3817
}
/* When sort_type == sort_time, use time_type as subindex. */
mpsort ((void const **) sorted_file, cwd_n_used, Line 3821
sort_functions[sort_type + (sort_type == sort_time ? time_type : 0)] Line 3822
[use_strcmp][sort_reverse] Line 3823
[directories_first]); Line 3824
} Block 121
/* List all the files now in the table. */
static void Line 3829
print_current_files (void) Line 3830
{
size_t i; Line 3832
switch (format) Line 3834
{
case one_per_line: Line 3836
for (i = 0; i < cwd_n_used; i++) Line 3837
{
print_file_name_and_frills (sorted_file[i], 0); Line 3839
putchar ('\n'); Line 3840
}
break; Line 3842
case many_per_line: Line 3844
if (! line_length) Line 3845
print_with_separator (' '); Line 3846
else Line 3847
print_many_per_line (); Line 3848
break; Line 3849
case horizontal: Line 3851
if (! line_length) Line 3852
print_with_separator (' '); Line 3853
else Line 3854
print_horizontal (); Line 3855
break; Line 3856
case with_commas: Line 3858
print_with_separator (','); Line 3859
break; Line 3860
case long_format: Line 3862
for (i = 0; i < cwd_n_used; i++) Line 3863
{
set_normal_color (); Line 3865
print_long_format (sorted_file[i]); Line 3866
DIRED_PUTCHAR ('\n'); Line 3867
}
break; Line 3869
}
} Block 122
/* Replace the first %b with precomputed aligned month names.
Note on glibc-2.7 at least, this speeds up the whole 'ls -lU'
process by around 17%, compared to letting strftime() handle the %b. */
static size_t Line 3877
align_nstrftime (char *buf, size_t size, bool recent, struct tm const *tm, Line 3878
timezone_t tz, int ns) Line 3879
{
char const *nfmt = (use_abformat Line 3881
? abformat[recent][tm->tm_mon] Line 3882
: long_time_format[recent]); Line 3883
return nstrftime (buf, size, nfmt, tm, tz, ns); Line 3884
} Block 123
/* Return the expected number of columns in a long-format timestamp,
or zero if it cannot be calculated. */
static int Line 3890
long_time_expected_width (void) Line 3891
{
static int width = -1; Line 3893
if (width < 0) Line 3895
{
time_t epoch = 0; Line 3897
struct tm tm; Line 3898
char buf[TIME_STAMP_LEN_MAXIMUM + 1]; Line 3899
/* In case you're wondering if localtime_rz can fail with an input time_t
value of 0, let's just say it's very unlikely, but not inconceivable.
The TZ environment variable would have to specify a time zone that
is 2**31-1900 years or more ahead of UTC. This could happen only on
a 64-bit system that blindly accepts e.g., TZ=UTC+20000000000000.
However, this is not possible with Solaris 10 or glibc-2.3.5, since
their implementations limit the offset to 167:59 and 24:00, resp. */
if (localtime_rz (localtz, &epoch, &tm)) Line 3908
{
size_t len = align_nstrftime (buf, sizeof buf, false, Line 3910
&tm, localtz, 0); Line 3911
if (len != 0) Line 3912
width = mbsnwidth (buf, len, 0); Line 3913
}
if (width < 0) Line 3916
width = 0; Line 3917
}
return width; Line 3920
} Block 124
/* Print the user or group name NAME, with numeric id ID, using a
print width of WIDTH columns. */
static void Line 3926
format_user_or_group (char const *name, unsigned long int id, int width) Line 3927
{
size_t len; Line 3929
if (name) Line 3931
{
int width_gap = width - mbswidth (name, 0); Line 3933
int pad = MAX (0, width_gap); Line 3934
fputs (name, stdout); Line 3935
len = strlen (name) + pad; Line 3936
do
putchar (' '); Line 3939
while (pad--); Line 3940
}
else Line 3942
{
printf ("%*lu ", width, id); Line 3944
len = width; Line 3945
}
dired_pos += len + 1; Line 3948
} Block 125
/* Print the name or id of the user with id U, using a print width of
WIDTH. */
static void Line 3954
format_user (uid_t u, int width, bool stat_ok) Line 3955
{
format_user_or_group (! stat_ok ? "?" : Line 3957
(numeric_ids ? NULL : getuser (u)), u, width); Line 3958
} Block 126
/* Likewise, for groups. */
static void Line 3963
format_group (gid_t g, int width, bool stat_ok) Line 3964
{
format_user_or_group (! stat_ok ? "?" : Line 3966
(numeric_ids ? NULL : getgroup (g)), g, width); Line 3967
} Block 127
/* Return the number of columns that format_user_or_group will print. */
static int Line 3972
format_user_or_group_width (char const *name, unsigned long int id) Line 3973
{
if (name) Line 3975
{
int len = mbswidth (name, 0); Line 3977
return MAX (0, len); Line 3978
}
else Line 3980
{
char buf[INT_BUFSIZE_BOUND (id)]; Line 3982
sprintf (buf, "%lu", id); Line 3983
return strlen (buf); Line 3984
}
} Block 128
/* Return the number of columns that format_user will print. */
static int Line 3990
format_user_width (uid_t u) Line 3991
{
return format_user_or_group_width (numeric_ids ? NULL : getuser (u), u); Line 3993
} Block 129
/* Likewise, for groups. */
static int Line 3998
format_group_width (gid_t g) Line 3999
{
return format_user_or_group_width (numeric_ids ? NULL : getgroup (g), g); Line 4001
} Block 130
/* Return a pointer to a formatted version of F->stat.st_ino,
possibly using buffer, BUF, of length BUFLEN, which must be at least
INT_BUFSIZE_BOUND (uintmax_t) bytes. */
static char * Line 4007
format_inode (char *buf, size_t buflen, const struct fileinfo *f) Line 4008
{
assert (INT_BUFSIZE_BOUND (uintmax_t) <= buflen); Line 4010
return (f->stat_ok && f->stat.st_ino != NOT_AN_INODE_NUMBER Line 4011
? umaxtostr (f->stat.st_ino, buf) Line 4012
: (char *) "?"); Line 4013
} Block 131
/* Print information about F in long format. */
static void Line 4017
print_long_format (const struct fileinfo *f) Line 4018
{
char modebuf[12]; Line 4020
char buf Line 4021
[LONGEST_HUMAN_READABLE + 1 /* inode */ Line 4022
+ LONGEST_HUMAN_READABLE + 1 /* size in blocks */ Line 4023
+ sizeof (modebuf) - 1 + 1 /* mode string */ Line 4024
+ INT_BUFSIZE_BOUND (uintmax_t) /* st_nlink */ Line 4025
+ LONGEST_HUMAN_READABLE + 2 /* major device number */ Line 4026
+ LONGEST_HUMAN_READABLE + 1 /* minor device number */ Line 4027
+ TIME_STAMP_LEN_MAXIMUM + 1 /* max length of time/date */ Line 4028
];
size_t s; Line 4030
char *p; Line 4031
struct timespec when_timespec; Line 4032
struct tm when_local; Line 4033
/* Compute the mode string, except remove the trailing space if no
file in this directory has an ACL or security context. */
if (f->stat_ok) Line 4037
filemodestring (&f->stat, modebuf); Line 4038
else Line 4039
{
modebuf[0] = filetype_letter[f->filetype]; Line 4041
memset (modebuf + 1, '?', 10); Line 4042
modebuf[11] = '\0'; Line 4043
}
if (! any_has_acl) Line 4045
modebuf[10] = '\0'; Line 4046
else if (f->acl_type == ACL_T_LSM_CONTEXT_ONLY) Line 4047
modebuf[10] = '.'; Line 4048
else if (f->acl_type == ACL_T_YES) Line 4049
modebuf[10] = '+'; Line 4050
switch (time_type) Line 4052
{
case time_ctime: Line 4054
when_timespec = get_stat_ctime (&f->stat); Line 4055
break; Line 4056
case time_mtime: Line 4057
when_timespec = get_stat_mtime (&f->stat); Line 4058
break; Line 4059
case time_atime: Line 4060
when_timespec = get_stat_atime (&f->stat); Line 4061
break; Line 4062
default: Line 4063
abort (); ...!common auto-comment...
}
p = buf; Line 4067
if (print_inode) Line 4069
{
char hbuf[INT_BUFSIZE_BOUND (uintmax_t)]; Line 4071
sprintf (p, "%*s ", inode_number_width, Line 4072
format_inode (hbuf, sizeof hbuf, f)); Line 4073
/* Increment by strlen (p) here, rather than by inode_number_width + 1.
The latter is wrong when inode_number_width is zero. */
p += strlen (p); Line 4076
}
if (print_block_size) Line 4079
{
char hbuf[LONGEST_HUMAN_READABLE + 1]; Line 4081
char const *blocks = Line 4082
(! f->stat_ok Line 4083
? "?" Line 4084
: human_readable (ST_NBLOCKS (f->stat), hbuf, human_output_opts, Line 4085
ST_NBLOCKSIZE, output_block_size)); Line 4086
int pad; Line 4087
for (pad = block_size_width - mbswidth (blocks, 0); 0 < pad; pad--) Line 4088
*p++ = ' '; Line 4089
while ((*p++ = *blocks++)) Line 4090
continue; Line 4091
p[-1] = ' '; Line 4092
}
/* The last byte of the mode string is the POSIX
"optional alternate access method flag". */
{
char hbuf[INT_BUFSIZE_BOUND (uintmax_t)]; Line 4098
sprintf (p, "%s %*s ", modebuf, nlink_width, Line 4099
! f->stat_ok ? "?" : umaxtostr (f->stat.st_nlink, hbuf)); Line 4100
}
/* Increment by strlen (p) here, rather than by, e.g.,
sizeof modebuf - 2 + any_has_acl + 1 + nlink_width + 1.
The latter is wrong when nlink_width is zero. */
p += strlen (p); Line 4105
DIRED_INDENT (); Line 4107
if (print_owner || print_group || print_author || print_scontext) Line 4109
{
DIRED_FPUTS (buf, stdout, p - buf); Line 4111
if (print_owner) Line 4113
format_user (f->stat.st_uid, owner_width, f->stat_ok); Line 4114
if (print_group) Line 4116
format_group (f->stat.st_gid, group_width, f->stat_ok); Line 4117
if (print_author) Line 4119
format_user (f->stat.st_author, author_width, f->stat_ok); Line 4120
if (print_scontext) Line 4122
format_user_or_group (f->scontext, 0, scontext_width); Line 4123
p = buf; Line 4125
}
if (f->stat_ok Line 4128
&& (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))) Line 4129
{
char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)]; Line 4131
char minorbuf[INT_BUFSIZE_BOUND (uintmax_t)]; Line 4132
int blanks_width = (file_size_width Line 4133
- (major_device_number_width + 2 Line 4134
+ minor_device_number_width)); Line 4135
sprintf (p, "%*s, %*s ", Line 4136
major_device_number_width + MAX (0, blanks_width), Line 4137
umaxtostr (major (f->stat.st_rdev), majorbuf), Line 4138
minor_device_number_width, Line 4139
umaxtostr (minor (f->stat.st_rdev), minorbuf)); Line 4140
p += file_size_width + 1; Line 4141
}
else Line 4143
{
char hbuf[LONGEST_HUMAN_READABLE + 1]; Line 4145
char const *size = Line 4146
(! f->stat_ok Line 4147
? "?" Line 4148
: human_readable (unsigned_file_size (f->stat.st_size), Line 4149
hbuf, file_human_output_opts, 1, Line 4150
file_output_block_size)); Line 4151
int pad; Line 4152
for (pad = file_size_width - mbswidth (size, 0); 0 < pad; pad--) Line 4153
*p++ = ' '; Line 4154
while ((*p++ = *size++)) Line 4155
continue; Line 4156
p[-1] = ' '; Line 4157
}
s = 0; Line 4160
*p = '\1'; Line 4161
if (f->stat_ok && localtime_rz (localtz, &when_timespec.tv_sec, &when_local)) Line 4163
{
struct timespec six_months_ago; Line 4165
bool recent; Line 4166
/* If the file appears to be in the future, update the current
time, in case the file happens to have been modified since
the last time we checked the clock. */
if (timespec_cmp (current_time, when_timespec) < 0) Line 4171
gettime (¤t_time); Line 4172
/* Consider a time to be recent if it is within the past six months.
A Gregorian year has 365.2425 * 24 * 60 * 60 == 31556952 seconds
on the average. Write this value as an integer constant to
avoid floating point hassles. */
six_months_ago.tv_sec = current_time.tv_sec - 31556952 / 2; Line 4178
six_months_ago.tv_nsec = current_time.tv_nsec; Line 4179
recent = (timespec_cmp (six_months_ago, when_timespec) < 0 Line 4181
&& (timespec_cmp (when_timespec, current_time) < 0)); Line 4182
/* We assume here that all time zones are offset from UTC by a
whole number of seconds. */
s = align_nstrftime (p, TIME_STAMP_LEN_MAXIMUM + 1, recent, Line 4186
&when_local, localtz, when_timespec.tv_nsec); Line 4187
}
if (s || !*p) Line 4190
{
p += s; Line 4192
*p++ = ' '; Line 4193
/* NUL-terminate the string -- fputs (via DIRED_FPUTS) requires it. */
*p = '\0'; Line 4196
}
else Line 4198
{
/* The time cannot be converted using the desired format, so
print it as a huge integer number of seconds. */
char hbuf[INT_BUFSIZE_BOUND (intmax_t)]; Line 4202
sprintf (p, "%*s ", long_time_expected_width (), Line 4203
(! f->stat_ok Line 4204
? "?" Line 4205
: timetostr (when_timespec.tv_sec, hbuf))); Line 4206
/* FIXME: (maybe) We discarded when_timespec.tv_nsec. */
p += strlen (p); Line 4208
}
DIRED_FPUTS (buf, stdout, p - buf); Line 4211
size_t w = print_name_with_quoting (f, false, &dired_obstack, p - buf); Line 4212
if (f->filetype == symbolic_link) Line 4214
{
if (f->linkname) Line 4216
{
DIRED_FPUTS_LITERAL (" -> ", stdout); Line 4218
print_name_with_quoting (f, true, NULL, (p - buf) + w + 4); Line 4219
if (indicator_style != none) Line 4220
print_type_indicator (true, f->linkmode, unknown); Line 4221
}
}
else if (indicator_style != none) Line 4224
print_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype); Line 4225
} Block 132
/* Write to *BUF a quoted representation of the file name NAME, if non-NULL,
using OPTIONS to control quoting. *BUF is set to NAME if no quoting
is required. *BUF is allocated if more space required (and the original
*BUF is not deallocated).
Store the number of screen columns occupied by NAME's quoted
representation into WIDTH, if non-NULL.
Store into PAD whether an initial space is needed for padding.
Return the number of bytes in *BUF. */
static size_t Line 4237
quote_name_buf (char **inbuf, size_t bufsize, char *name, Line 4238
struct quoting_options const *options, Line 4239
int needs_general_quoting, size_t *width, bool *pad) Line 4240
{
char *buf = *inbuf; Line 4242
size_t displayed_width IF_LINT ( = 0); Line 4243
size_t len = 0; Line 4244
bool quoted; Line 4245
enum quoting_style qs = get_quoting_style (options); Line 4247
bool needs_further_quoting = qmark_funny_chars Line 4248
&& (qs == shell_quoting_style Line 4249
|| qs == shell_always_quoting_style Line 4250
|| qs == literal_quoting_style); Line 4251
if (needs_general_quoting != 0) Line 4253
{
len = quotearg_buffer (buf, bufsize, name, -1, options); Line 4255
if (bufsize <= len) Line 4256
{
buf = xmalloc (len + 1); Line 4258
quotearg_buffer (buf, len + 1, name, -1, options); Line 4259
}
quoted = (*name != *buf) || strlen (name) != len; Line 4262
}
else if (needs_further_quoting) Line 4264
{
len = strlen (name); Line 4266
if (bufsize <= len) Line 4267
buf = xmalloc (len + 1); Line 4268
memcpy (buf, name, len + 1); Line 4269
quoted = false; Line 4271
}
else Line 4273
{
len = strlen (name); Line 4275
buf = name; Line 4276
quoted = false; Line 4277
}
if (needs_further_quoting) Line 4280
{
if (MB_CUR_MAX > 1) Line 4282
{
char const *p = buf; Line 4284
char const *plimit = buf + len; Line 4285
char *q = buf; Line 4286
displayed_width = 0; Line 4287
while (p < plimit) Line 4289
switch (*p) Line 4290
{
case ' ': case '!': case '"': case '#': case '%': Line 4292
case '&': case '\'': case '(': case ')': case '*': Line 4293
case '+': case ',': case '-': case '.': case '/': Line 4294
case '0': case '1': case '2': case '3': case '4': Line 4295
case '5': case '6': case '7': case '8': case '9': Line 4296
case ':': case ';': case '<': case '=': case '>': Line 4297
case '?': Line 4298
case 'A': case 'B': case 'C': case 'D': case 'E': Line 4299
case 'F': case 'G': case 'H': case 'I': case 'J': Line 4300
case 'K': case 'L': case 'M': case 'N': case 'O': Line 4301
case 'P': case 'Q': case 'R': case 'S': case 'T': Line 4302
case 'U': case 'V': case 'W': case 'X': case 'Y': Line 4303
case 'Z': Line 4304
case '[': case '\\': case ']': case '^': case '_': Line 4305
case 'a': case 'b': case 'c': case 'd': case 'e': Line 4306
case 'f': case 'g': case 'h': case 'i': case 'j': Line 4307
case 'k': case 'l': case 'm': case 'n': case 'o': Line 4308
case 'p': case 'q': case 'r': case 's': case 't': Line 4309
case 'u': case 'v': case 'w': case 'x': case 'y': Line 4310
case 'z': case '{': case '|': case '}': case '~': Line 4311
/* These characters are printable ASCII characters. */
*q++ = *p++; Line 4313
displayed_width += 1; Line 4314
break; Line 4315
default: Line 4316
/* If we have a multibyte sequence, copy it until we
reach its end, replacing each non-printable multibyte
character with a single question mark. */
{
mbstate_t mbstate = { 0, }; Line 4321
do
{
wchar_t wc; Line 4324
size_t bytes; Line 4325
int w; Line 4326
bytes = mbrtowc (&wc, p, plimit - p, &mbstate); Line 4328
if (bytes == (size_t) -1) Line 4330
{
/* An invalid multibyte sequence was
encountered. Skip one input byte, and
put a question mark. */
p++; Line 4335
*q++ = '?'; Line 4336
displayed_width += 1; Line 4337
break; Line 4338
}
if (bytes == (size_t) -2) Line 4341
{
/* An incomplete multibyte character
at the end. Replace it entirely with
a question mark. */
p = plimit; Line 4346
*q++ = '?'; Line 4347
displayed_width += 1; Line 4348
break; Line 4349
}
if (bytes == 0) Line 4352
/* A null wide character was encountered. */
bytes = 1; Line 4354
w = wcwidth (wc); Line 4356
if (w >= 0) Line 4357
{
/* A printable multibyte character.
Keep it. */
for (; bytes > 0; --bytes) Line 4361
*q++ = *p++; Line 4362
displayed_width += w; Line 4363
}
else Line 4365
{
/* An unprintable multibyte character.
Replace it entirely with a question
mark. */
p += bytes; Line 4370
*q++ = '?'; Line 4371
displayed_width += 1; Line 4372
}
}
while (! mbsinit (&mbstate)); Line 4375
}
break; Line 4377
}
/* The buffer may have shrunk. */
len = q - buf; Line 4381
}
else Line 4383
{
char *p = buf; Line 4385
char const *plimit = buf + len; Line 4386
while (p < plimit) Line 4388
{
if (! isprint (to_uchar (*p))) Line 4390
*p = '?'; Line 4391
p++; Line 4392
}
displayed_width = len; Line 4394
}
}
else if (width != NULL) Line 4397
{
if (MB_CUR_MAX > 1) Line 4399
displayed_width = mbsnwidth (buf, len, 0); Line 4400
else Line 4401
{
char const *p = buf; Line 4403
char const *plimit = buf + len; Line 4404
displayed_width = 0; Line 4406
while (p < plimit) Line 4407
{
if (isprint (to_uchar (*p))) Line 4409
displayed_width++; Line 4410
p++; Line 4411
}
}
}
/* Set padding to better align quoted items,
and also give a visual indication that quotes are
not actually part of the name. */
*pad = (align_variable_outer_quotes && cwd_some_quoted && ! quoted); Line 4419
if (width != NULL) Line 4421
*width = displayed_width; Line 4422
*inbuf = buf; Line 4424
return len; Line 4426
} Block 133
static size_t Line 4429
quote_name_width (const char *name, struct quoting_options const *options, Line 4430
int needs_general_quoting) Line 4431
{
char smallbuf[BUFSIZ]; Line 4433
char *buf = smallbuf; Line 4434
size_t width; Line 4435
bool pad; Line 4436
quote_name_buf (&buf, sizeof smallbuf, (char *) name, options, Line 4438
needs_general_quoting, &width, &pad); Line 4439
if (buf != smallbuf && buf != name) Line 4441
free (buf); Line 4442
width += pad; Line 4444
return width; Line 4446
} Block 134
/* %XX escape any input out of range as defined in RFC3986,
and also if PATH, convert all path separators to '/'. */
static char * Line 4451
file_escape (const char *str, bool path) Line 4452
{
char *esc = xnmalloc (3, strlen (str) + 1); Line 4454
char *p = esc; Line 4455
while (*str) Line 4456
{
if (path && ISSLASH (*str)) Line 4458
{
*p++ = '/'; Line 4460
str++; Line 4461
}
else if (RFC3986[to_uchar (*str)]) Line 4463
*p++ = *str++; Line 4464
else Line 4465
p += sprintf (p, "%%%02x", to_uchar (*str++)); Line 4466
}
*p = '\0'; Line 4468
return esc; Line 4469
} Block 135
static size_t Line 4472
quote_name (char const *name, struct quoting_options const *options, Line 4473
int needs_general_quoting, const struct bin_str *color, Line 4474
bool allow_pad, struct obstack *stack, char const *absolute_name) Line 4475
{
char smallbuf[BUFSIZ]; Line 4477
char *buf = smallbuf; Line 4478
size_t len; Line 4479
bool pad; Line 4480
len = quote_name_buf (&buf, sizeof smallbuf, (char *) name, options, Line 4482
needs_general_quoting, NULL, &pad); Line 4483
if (pad && allow_pad) Line 4485
DIRED_PUTCHAR (' '); Line 4486
if (color) Line 4488
print_color_indicator (color); Line 4489
/* If we're padding, then don't include the outer quotes in
the --hyperlink, to improve the alignment of those links. */
bool skip_quotes = false; Line 4493
if (absolute_name) Line 4495
{
if (align_variable_outer_quotes && cwd_some_quoted && ! pad) Line 4497
{
skip_quotes = true; Line 4499
putchar (*buf); Line 4500
}
char *h = file_escape (hostname, /* path= */ false); Line 4502
char *n = file_escape (absolute_name, /* path= */ true); Line 4503
/* TODO: It would be good to be able to define parameters
to give hints to the terminal as how best to render the URI.
For example since ls is outputting a dense block of URIs
it would be best to not underline by default, and only
do so upon hover etc. */
printf ("\033]8;;file://%s%s%s\a", h, *n == '/' ? "" : "/", n); Line 4509
free (h); Line 4510
free (n); Line 4511
}
if (stack) Line 4514
PUSH_CURRENT_DIRED_POS (stack); Line 4515
fwrite (buf + skip_quotes, 1, len - (skip_quotes * 2), stdout); Line 4517...!syscalls auto-comment...
dired_pos += len; Line 4519
if (stack) Line 4521
PUSH_CURRENT_DIRED_POS (stack); Line 4522
if (absolute_name) Line 4524
{
fputs ("\033]8;;\a", stdout); Line 4526
if (skip_quotes) Line 4527
putchar (*(buf + len - 1)); Line 4528
}
if (buf != smallbuf && buf != name) Line 4531
free (buf); Line 4532
return len + pad; Line 4534
} Block 136
static size_t Line 4537
print_name_with_quoting (const struct fileinfo *f, Line 4538
bool symlink_target, Line 4539
struct obstack *stack, Line 4540
size_t start_col) Line 4541
{
const char* name = symlink_target ? f->linkname : f->name; Line 4543
const struct bin_str *color = print_with_color ? Line 4545
get_color_indicator (f, symlink_target) : NULL; Line 4546
bool used_color_this_time = (print_with_color Line 4548
&& (color || is_colored (C_NORM))); Line 4549
size_t len = quote_name (name, filename_quoting_options, f->quoted, Line 4551
color, !symlink_target, stack, f->absolute_name); Line 4552
process_signals (); Line 4554
if (used_color_this_time) Line 4555
{
prep_non_filename_text (); Line 4557
/* We use the byte length rather than display width here as
an optimization to avoid accurately calculating the width,
because we only output the clear to EOL sequence if the name
_might_ wrap to the next line. This may output a sequence
unnecessarily in multi-byte locales for example,
but in that case it's inconsequential to the output. */
if (line_length Line 4565
&& (start_col / line_length != (start_col + len - 1) / line_length)) Line 4566
put_indicator (&color_indicator[C_CLR_TO_EOL]); Line 4567
}
return len; Line 4570
} Block 137
static void Line 4573
prep_non_filename_text (void) Line 4574
{
if (color_indicator[C_END].string != NULL) Line 4576
put_indicator (&color_indicator[C_END]); Line 4577
else Line 4578
{
put_indicator (&color_indicator[C_LEFT]); Line 4580
put_indicator (&color_indicator[C_RESET]); Line 4581
put_indicator (&color_indicator[C_RIGHT]); Line 4582
}
} Block 138
/* Print the file name of 'f' with appropriate quoting.
Also print file size, inode number, and filetype indicator character,
as requested by switches. */
static size_t Line 4590
print_file_name_and_frills (const struct fileinfo *f, size_t start_col) Line 4591
{
char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))]; Line 4593
set_normal_color (); Line 4595
if (print_inode) Line 4597
printf ("%*s ", format == with_commas ? 0 : inode_number_width, Line 4598
format_inode (buf, sizeof buf, f)); Line 4599
if (print_block_size) Line 4601
printf ("%*s ", format == with_commas ? 0 : block_size_width, Line 4602
! f->stat_ok ? "?" Line 4603
: human_readable (ST_NBLOCKS (f->stat), buf, human_output_opts, Line 4604
ST_NBLOCKSIZE, output_block_size)); Line 4605
if (print_scontext) Line 4607
printf ("%*s ", format == with_commas ? 0 : scontext_width, f->scontext); Line 4608
size_t width = print_name_with_quoting (f, false, NULL, start_col); Line 4610
if (indicator_style != none) Line 4612
width += print_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype); Line 4613
return width; Line 4615
} Block 139
/* Given these arguments describing a file, return the single-byte
type indicator, or 0. */
static char Line 4620
get_type_indicator (bool stat_ok, mode_t mode, enum filetype type) Line 4621
{
char c; Line 4623
if (stat_ok ? S_ISREG (mode) : type == normal) Line 4625
{
if (stat_ok && indicator_style == classify && (mode & S_IXUGO)) Line 4627
c = '*'; Line 4628
else Line 4629
c = 0; Line 4630
}
else Line 4632
{
if (stat_ok ? S_ISDIR (mode) : type == directory || type == arg_directory)Line 4634
c = '/'; Line 4635
else if (indicator_style == slash) Line 4636
c = 0; Line 4637
else if (stat_ok ? S_ISLNK (mode) : type == symbolic_link) Line 4638
c = '@'; Line 4639
else if (stat_ok ? S_ISFIFO (mode) : type == fifo) Line 4640
c = '|'; Line 4641
else if (stat_ok ? S_ISSOCK (mode) : type == sock) Line 4642
c = '='; Line 4643
else if (stat_ok && S_ISDOOR (mode)) Line 4644
c = '>'; Line 4645
else Line 4646
c = 0; Line 4647
}
return c; Line 4649
} Block 140
static bool Line 4652
print_type_indicator (bool stat_ok, mode_t mode, enum filetype type) Line 4653
{
char c = get_type_indicator (stat_ok, mode, type); Line 4655
if (c) Line 4656
DIRED_PUTCHAR (c); Line 4657
return !!c; Line 4658
} Block 141
/* Returns if color sequence was printed. */
static bool Line 4662
print_color_indicator (const struct bin_str *ind) Line 4663
{
if (ind) Line 4665
{
/* Need to reset so not dealing with attribute combinations */
if (is_colored (C_NORM)) Line 4668
restore_default_color (); Line 4669
put_indicator (&color_indicator[C_LEFT]); Line 4670
put_indicator (ind); Line 4671
put_indicator (&color_indicator[C_RIGHT]); Line 4672
}
return ind != NULL; Line 4675
} Block 142
/* Returns color indicator or NULL if none. */
static const struct bin_str* _GL_ATTRIBUTE_PURE Line 4679
get_color_indicator (const struct fileinfo *f, bool symlink_target) Line 4680
{
enum indicator_no type; Line 4682
struct color_ext_type *ext; /* Color extension */ Line 4683
size_t len; /* Length of name */ Line 4684
const char* name; Line 4686
mode_t mode; Line 4687
int linkok; Line 4688
if (symlink_target) Line 4689
{
name = f->linkname; Line 4691
mode = f->linkmode; Line 4692
linkok = f->linkok ? 0 : -1; Line 4693
}
else Line 4695
{
name = f->name; Line 4697
mode = FILE_OR_LINK_MODE (f); Line 4698
linkok = f->linkok; Line 4699
}
/* Is this a nonexistent file? If so, linkok == -1. */
if (linkok == -1 && is_colored (C_MISSING)) Line 4704
type = C_MISSING; Line 4705
else if (!f->stat_ok) Line 4706
{
static enum indicator_no filetype_indicator[] = FILETYPE_INDICATORS; Line 4708
type = filetype_indicator[f->filetype]; Line 4709
}
else Line 4711
{
if (S_ISREG (mode)) Line 4713
{
type = C_FILE; Line 4715
if ((mode & S_ISUID) != 0 && is_colored (C_SETUID)) Line 4717
type = C_SETUID; Line 4718
else if ((mode & S_ISGID) != 0 && is_colored (C_SETGID)) Line 4719
type = C_SETGID; Line 4720
else if (is_colored (C_CAP) && f->has_capability) Line 4721
type = C_CAP; Line 4722
else if ((mode & S_IXUGO) != 0 && is_colored (C_EXEC)) Line 4723
type = C_EXEC; Line 4724
else if ((1 < f->stat.st_nlink) && is_colored (C_MULTIHARDLINK)) Line 4725
type = C_MULTIHARDLINK; Line 4726
}
else if (S_ISDIR (mode)) Line 4728
{
type = C_DIR; Line 4730
if ((mode & S_ISVTX) && (mode & S_IWOTH) Line 4732
&& is_colored (C_STICKY_OTHER_WRITABLE)) Line 4733
type = C_STICKY_OTHER_WRITABLE; Line 4734
else if ((mode & S_IWOTH) != 0 && is_colored (C_OTHER_WRITABLE)) Line 4735
type = C_OTHER_WRITABLE; Line 4736
else if ((mode & S_ISVTX) != 0 && is_colored (C_STICKY)) Line 4737
type = C_STICKY; Line 4738
}
else if (S_ISLNK (mode)) Line 4740
type = C_LINK; Line 4741
else if (S_ISFIFO (mode)) Line 4742
type = C_FIFO; Line 4743
else if (S_ISSOCK (mode)) Line 4744
type = C_SOCK; Line 4745
else if (S_ISBLK (mode)) Line 4746
type = C_BLK; Line 4747
else if (S_ISCHR (mode)) Line 4748
type = C_CHR; Line 4749
else if (S_ISDOOR (mode)) Line 4750
type = C_DOOR; Line 4751
else Line 4752
{
/* Classify a file of some other type as C_ORPHAN. */
type = C_ORPHAN; Line 4755
}
}
/* Check the file's suffix only if still classified as C_FILE. */
ext = NULL; Line 4760
if (type == C_FILE) Line 4761
{
/* Test if NAME has a recognized suffix. */
len = strlen (name); Line 4765
name += len; /* Pointer to final \0. */ Line 4766
for (ext = color_ext_list; ext != NULL; ext = ext->next) Line 4767
{
if (ext->ext.len <= len Line 4769
&& c_strncasecmp (name - ext->ext.len, ext->ext.string, Line 4770
ext->ext.len) == 0) Line 4771
break; Line 4772
}
}
/* Adjust the color for orphaned symlinks. */
if (type == C_LINK && !linkok) Line 4777
{
if (color_symlink_as_referent || is_colored (C_ORPHAN)) Line 4779
type = C_ORPHAN; Line 4780
}
const struct bin_str *const s Line 4783
= ext ? &(ext->seq) : &color_indicator[type]; Line 4784
return s->string ? s : NULL; Line 4786
} Block 143
/* Output a color indicator (which may contain nulls). */
static void Line 4790
put_indicator (const struct bin_str *ind) Line 4791
{
if (! used_color) Line 4793
{
used_color = true; Line 4795
/* If the standard output is a controlling terminal, watch out
for signals, so that the colors can be restored to the
default state if "ls" is suspended or interrupted. */
if (0 <= tcgetpgrp (STDOUT_FILENO)) Line 4801
signal_init (); Line 4802
prep_non_filename_text (); Line 4804
}
fwrite (ind->string, ind->len, 1, stdout); Line 4807...!syscalls auto-comment...
} Block 144
static size_t Line 4810
length_of_file_name_and_frills (const struct fileinfo *f) Line 4811
{
size_t len = 0; Line 4813
char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))]; Line 4814
if (print_inode) Line 4816
len += 1 + (format == with_commas Line 4817
? strlen (umaxtostr (f->stat.st_ino, buf)) Line 4818
: inode_number_width); Line 4819
if (print_block_size) Line 4821
len += 1 + (format == with_commas Line 4822
? strlen (! f->stat_ok ? "?" Line 4823
: human_readable (ST_NBLOCKS (f->stat), buf, Line 4824
human_output_opts, ST_NBLOCKSIZE, Line 4825
output_block_size)) Line 4826
: block_size_width); Line 4827
if (print_scontext) Line 4829
len += 1 + (format == with_commas ? strlen (f->scontext) : scontext_width); Line 4830
len += quote_name_width (f->name, filename_quoting_options, f->quoted); Line 4832
if (indicator_style != none) Line 4834
{
char c = get_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype); Line 4836
len += (c != 0); Line 4837
}
return len; Line 4840
} Block 145
static void Line 4843
print_many_per_line (void) Line 4844
{
size_t row; /* Current row. */ Line 4846
size_t cols = calculate_columns (true); Line 4847
struct column_info const *line_fmt = &column_info[cols - 1]; Line 4848
/* Calculate the number of rows that will be in each column except possibly
for a short column on the right. */
size_t rows = cwd_n_used / cols + (cwd_n_used % cols != 0); Line 4852
for (row = 0; row < rows; row++) Line 4854
{
size_t col = 0; Line 4856
size_t filesno = row; Line 4857
size_t pos = 0; Line 4858
/* Print the next row. */
while (1) Line 4861
{
struct fileinfo const *f = sorted_file[filesno]; Line 4863
size_t name_length = length_of_file_name_and_frills (f); Line 4864
size_t max_name_length = line_fmt->col_arr[col++]; Line 4865
print_file_name_and_frills (f, pos); Line 4866
filesno += rows; Line 4868
if (filesno >= cwd_n_used) Line 4869
break; Line 4870
indent (pos + name_length, pos + max_name_length); Line 4872
pos += max_name_length; Line 4873
}
putchar ('\n'); Line 4875
}
} Block 146
static void Line 4879
print_horizontal (void) Line 4880
{
size_t filesno; Line 4882
size_t pos = 0; Line 4883
size_t cols = calculate_columns (false); Line 4884
struct column_info const *line_fmt = &column_info[cols - 1]; Line 4885
struct fileinfo const *f = sorted_file[0]; Line 4886
size_t name_length = length_of_file_name_and_frills (f); Line 4887
size_t max_name_length = line_fmt->col_arr[0]; Line 4888
/* Print first entry. */
print_file_name_and_frills (f, 0); Line 4891
/* Now the rest. */
for (filesno = 1; filesno < cwd_n_used; ++filesno) Line 4894
{
size_t col = filesno % cols; Line 4896
if (col == 0) Line 4898
{
putchar ('\n'); Line 4900
pos = 0; Line 4901
}
else Line 4903
{
indent (pos + name_length, pos + max_name_length); Line 4905
pos += max_name_length; Line 4906
}
f = sorted_file[filesno]; Line 4909
print_file_name_and_frills (f, pos); Line 4910
name_length = length_of_file_name_and_frills (f); Line 4912
max_name_length = line_fmt->col_arr[col]; Line 4913
}
putchar ('\n'); Line 4915
} Block 147
/* Output name + SEP + ' '. */
static void Line 4920
print_with_separator (char sep) Line 4921
{
size_t filesno; Line 4923
size_t pos = 0; Line 4924
for (filesno = 0; filesno < cwd_n_used; filesno++) Line 4926
{
struct fileinfo const *f = sorted_file[filesno]; Line 4928
size_t len = line_length ? length_of_file_name_and_frills (f) : 0; Line 4929
if (filesno != 0) Line 4931
{
char separator; Line 4933
if (! line_length Line 4935
|| ((pos + len + 2 < line_length) Line 4936
&& (pos <= SIZE_MAX - len - 2))) Line 4937
{
pos += 2; Line 4939
separator = ' '; Line 4940
}
else Line 4942
{
pos = 0; Line 4944
separator = '\n'; Line 4945
}
putchar (sep); Line 4948
putchar (separator); Line 4949
}
print_file_name_and_frills (f, pos); Line 4952
pos += len; Line 4953
}
putchar ('\n'); Line 4955
} Block 148
/* Assuming cursor is at position FROM, indent up to position TO.
Use a TAB character instead of two or more spaces whenever possible. */
static void Line 4961
indent (size_t from, size_t to) Line 4962
{
while (from < to) Line 4964
{
if (tabsize != 0 && to / tabsize > (from + 1) / tabsize) Line 4966
{
putchar ('\t'); Line 4968
from += tabsize - from % tabsize; Line 4969
}
else Line 4971
{
putchar (' '); Line 4973
from++; Line 4974
}
}
} Block 149
/* Put DIRNAME/NAME into DEST, handling '.' and '/' properly. */
/* FIXME: maybe remove this function someday. See about using a
non-malloc'ing version of file_name_concat. */
static void Line 4983
attach (char *dest, const char *dirname, const char *name) Line 4984
{
const char *dirnamep = dirname; Line 4986
/* Copy dirname if it is not ".". */
if (dirname[0] != '.' || dirname[1] != 0) Line 4989
{
while (*dirnamep) Line 4991
*dest++ = *dirnamep++; Line 4992
/* Add '/' if 'dirname' doesn't already end with it. */
if (dirnamep > dirname && dirnamep[-1] != '/') Line 4994
*dest++ = '/'; Line 4995
}
while (*name) Line 4997
*dest++ = *name++; Line 4998
*dest = 0; Line 4999
} Block 150
/* Allocate enough column info suitable for the current number of
files and display columns, and initialize the info to represent the
narrowest possible columns. */
static void Line 5006
init_column_info (void) Line 5007
{
size_t i; Line 5009
size_t max_cols = MIN (max_idx, cwd_n_used); Line 5010
/* Currently allocated columns in column_info. */
static size_t column_info_alloc; Line 5013
if (column_info_alloc < max_cols) Line 5015
{
size_t new_column_info_alloc; Line 5017
size_t *p; Line 5018
if (max_cols < max_idx / 2) Line 5020
{
/* The number of columns is far less than the display width
allows. Grow the allocation, but only so that it's
double the current requirements. If the display is
extremely wide, this avoids allocating a lot of memory
that is never needed. */
column_info = xnrealloc (column_info, max_cols, Line 5027
2 * sizeof *column_info); Line 5028
new_column_info_alloc = 2 * max_cols; Line 5029
}
else Line 5031
{
column_info = xnrealloc (column_info, max_idx, sizeof *column_info); Line 5033
new_column_info_alloc = max_idx; Line 5034
}
/* Allocate the new size_t objects by computing the triangle
formula n * (n + 1) / 2, except that we don't need to
allocate the part of the triangle that we've already
allocated. Check for address arithmetic overflow. */
{
size_t column_info_growth = new_column_info_alloc - column_info_alloc; Line 5042
size_t s = column_info_alloc + 1 + new_column_info_alloc; Line 5043
size_t t = s * column_info_growth; Line 5044
if (s < new_column_info_alloc || t / column_info_growth != s) Line 5045
xalloc_die (); ...!common auto-comment...
p = xnmalloc (t / 2, sizeof *p); Line 5047
}
/* Grow the triangle by parceling out the cells just allocated. */
for (i = column_info_alloc; i < new_column_info_alloc; i++) Line 5051
{
column_info[i].col_arr = p; Line 5053
p += i + 1; Line 5054
}
column_info_alloc = new_column_info_alloc; Line 5057
}
for (i = 0; i < max_cols; ++i) Line 5060
{
size_t j; Line 5062
column_info[i].valid_len = true; Line 5064
column_info[i].line_len = (i + 1) * MIN_COLUMN_WIDTH; Line 5065
for (j = 0; j <= i; ++j) Line 5066
column_info[i].col_arr[j] = MIN_COLUMN_WIDTH; Line 5067
}
} Block 151
/* Calculate the number of columns needed to represent the current set
of files in the current display width. */
static size_t Line 5074
calculate_columns (bool by_columns) Line 5075
{
size_t filesno; /* Index into cwd_file. */ Line 5077
size_t cols; /* Number of files across. */ Line 5078
/* Normally the maximum number of columns is determined by the
screen width. But if few files are available this might limit it
as well. */
size_t max_cols = MIN (max_idx, cwd_n_used); Line 5083
init_column_info (); Line 5085
/* Compute the maximum number of possible columns. */
for (filesno = 0; filesno < cwd_n_used; ++filesno) Line 5088
{
struct fileinfo const *f = sorted_file[filesno]; Line 5090
size_t name_length = length_of_file_name_and_frills (f); Line 5091
for (size_t i = 0; i < max_cols; ++i) Line 5093
{
if (column_info[i].valid_len) Line 5095
{
size_t idx = (by_columns Line 5097
? filesno / ((cwd_n_used + i) / (i + 1)) Line 5098
: filesno % (i + 1)); Line 5099
size_t real_length = name_length + (idx == i ? 0 : 2); Line 5100
if (column_info[i].col_arr[idx] < real_length) Line 5102
{
column_info[i].line_len += (real_length Line 5104
- column_info[i].col_arr[idx]); Line 5105
column_info[i].col_arr[idx] = real_length; Line 5106
column_info[i].valid_len = (column_info[i].line_len Line 5107
< line_length); Line 5108
}
}
}
}
/* Find maximum allowed columns. */
for (cols = max_cols; 1 < cols; --cols) Line 5115
{
if (column_info[cols - 1].valid_len) Line 5117
break; Line 5118
}
return cols; Line 5121
} Block 152
void Line 5124
usage (int status) Line 5125
{
if (status != EXIT_SUCCESS) Line 5127
emit_try_help (); ...!common auto-comment...
else Line 5129
{
printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); Line 5131
fputs (_("\ Line 5132
List information about the FILEs (the current directory by default).\n\ Line 5133
Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.\n\ Line 5134
"), stdout); Line 5135
emit_mandatory_arg_note (); ...!common auto-comment...
fputs (_("\ Line 5139
-a, --all do not ignore entries starting with .\n\ Line 5140
-A, --almost-all do not list implied . and ..\n\ Line 5141
--author with -l, print the author of each file\n\ Line 5142
-b, --escape print C-style escapes for nongraphic characters\n\ Line 5143
"), stdout); Line 5144
fputs (_("\ Line 5145
--block-size=SIZE with -l, scale sizes by SIZE when printing them;\n\Line 5146
e.g., '--block-size=M'; see SIZE format below\n\ Line 5147
"), stdout); Line 5148
fputs (_("\ Line 5149
-B, --ignore-backups do not list implied entries ending with ~\n\ Line 5150
-c with -lt: sort by, and show, ctime (time of last\n\Line 5151
modification of file status information);\n\ Line 5152
with -l: show ctime and sort by name;\n\ Line 5153
otherwise: sort by ctime, newest first\n\ Line 5154
"), stdout); Line 5155
fputs (_("\ Line 5156
-C list entries by columns\n\ Line 5157
--color[=WHEN] colorize the output; WHEN can be 'always' (default\Line 5158
\n\
if omitted), 'auto', or 'never'; more info below\Line 5160
\n\
-d, --directory list directories themselves, not their contents\n\ Line 5162
-D, --dired generate output designed for Emacs' dired mode\n\ Line 5163
"), stdout); Line 5164
fputs (_("\ Line 5165
-f do not sort, enable -aU, disable -ls --color\n\ Line 5166
-F, --classify append indicator (one of */=>@|) to entries\n\
--file-type likewise, except do not append '*'\n\ Line 5168
--format=WORD across -x, commas -m, horizontal -x, long -l,\n\ Line 5169
single-column -1, verbose -l, vertical -C\n\ Line 5170
--full-time like -l --time-style=full-iso\n\ Line 5171
"), stdout); Line 5172
fputs (_("\ Line 5173
-g like -l, but do not list owner\n\ Line 5174
"), stdout); Line 5175
fputs (_("\ Line 5176
--group-directories-first\n\ Line 5177
group directories before files;\n\ Line 5178
can be augmented with a --sort option, but any\n\Line 5179
use of --sort=none (-U) disables grouping\n\ Line 5180
"), stdout); Line 5181
fputs (_("\ Line 5182
-G, --no-group in a long listing, don't print group names\n\ Line 5183
"), stdout); Line 5184
fputs (_("\ Line 5185
-h, --human-readable with -l and -s, print sizes like 1K 234M 2G etc.\n\Line 5186
--si likewise, but use powers of 1000 not 1024\n\ Line 5187
"), stdout); Line 5188
fputs (_("\ Line 5189
-H, --dereference-command-line\n\ Line 5190
follow symbolic links listed on the command line\n\Line 5191
--dereference-command-line-symlink-to-dir\n\ Line 5192
follow each command line symbolic link\n\ Line 5193
that points to a directory\n\ Line 5194
--hide=PATTERN do not list implied entries matching shell PATTERN\Line 5195
\n\
(overridden by -a or -A)\n\ Line 5197
"), stdout); Line 5198
fputs (_("\ Line 5199
--hyperlink[=WHEN] hyperlink file names; WHEN can be 'always'\n\ Line 5200
(default if omitted), 'auto', or 'never'\n\ Line 5201
"), stdout); Line 5202
fputs (_("\ Line 5203
--indicator-style=WORD append indicator with style WORD to entry names:\ Line 5204
\n\
none (default), slash (-p),\n\ Line 5206
file-type (--file-type), classify (-F)\n\ Line 5207
-i, --inode print the index number of each file\n\ Line 5208
-I, --ignore=PATTERN do not list implied entries matching shell PATTERN\Line 5209
\n\
"), stdout); Line 5211
fputs (_("\ Line 5212
-k, --kibibytes default to 1024-byte blocks for disk usage;\n\ Line 5213
used only with -s and per directory totals\n\ Line 5214
"), stdout); Line 5215
fputs (_("\ Line 5216
-l use a long listing format\n\ Line 5217
-L, --dereference when showing file information for a symbolic\n\ Line 5218
link, show information for the file the link\n\ Line 5219
references rather than for the link itself\n\ Line 5220
-m fill width with a comma separated list of entries\ Line 5221
\n\
"), stdout); Line 5223
fputs (_("\ Line 5224
-n, --numeric-uid-gid like -l, but list numeric user and group IDs\n\ Line 5225
-N, --literal print entry names without quoting\n\ Line 5226
-o like -l, but do not list group information\n\ Line 5227
-p, --indicator-style=slash\n\ Line 5228
append / indicator to directories\n\ Line 5229
"), stdout); Line 5230
fputs (_("\ Line 5231
-q, --hide-control-chars print ? instead of nongraphic characters\n\ Line 5232
--show-control-chars show nongraphic characters as-is (the default,\n\ Line 5233
unless program is 'ls' and output is a terminal)\Line 5234
\n\
-Q, --quote-name enclose entry names in double quotes\n\ Line 5236
--quoting-style=WORD use quoting style WORD for entry names:\n\ Line 5237
literal, locale, shell, shell-always,\n\ Line 5238
shell-escape, shell-escape-always, c, escape\n\ Line 5239
(overrides QUOTING_STYLE environment variable)\n\Line 5240
"), stdout); Line 5241
fputs (_("\ Line 5242
-r, --reverse reverse order while sorting\n\ Line 5243
-R, --recursive list subdirectories recursively\n\ Line 5244
-s, --size print the allocated size of each file, in blocks\n\Line 5245
"), stdout); Line 5246
fputs (_("\ Line 5247
-S sort by file size, largest first\n\ Line 5248
--sort=WORD sort by WORD instead of name: none (-U), size (-S)\Line 5249
,\n\ Line 5250
time (-t), version (-v), extension (-X)\n\ Line 5251
--time=WORD with -l, show time as WORD instead of default\n\ Line 5252
modification time: atime or access or use (-u);\ Line 5253
\n\
ctime or status (-c); also use specified time\n\ Line 5255
as sort key if --sort=time (newest first)\n\ Line 5256
"), stdout); Line 5257
fputs (_("\ Line 5258
--time-style=TIME_STYLE time/date format with -l; see TIME_STYLE below\n\Line 5259
"), stdout); Line 5260
fputs (_("\ Line 5261
-t sort by modification time, newest first\n\ Line 5262
-T, --tabsize=COLS assume tab stops at each COLS instead of 8\n\ Line 5263
"), stdout); Line 5264
fputs (_("\ Line 5265
-u with -lt: sort by, and show, access time;\n\ Line 5266
with -l: show access time and sort by name;\n\ Line 5267
otherwise: sort by access time, newest first\n\ Line 5268
-U do not sort; list entries in directory order\n\ Line 5269
-v natural sort of (version) numbers within text\n\ Line 5270
"), stdout); Line 5271
fputs (_("\ Line 5272
-w, --width=COLS set output width to COLS. 0 means no limit\n\ Line 5273
-x list entries by lines instead of by columns\n\ Line 5274
-X sort alphabetically by entry extension\n\ Line 5275
-Z, --context print any security context of each file\n\ Line 5276
-1 list one file per line. Avoid '\\n' with -q or -b\Line 5277
\n\
"), stdout); Line 5279
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 5280
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 5281
emit_size_note (); Line 5282
fputs (_("\ Line 5283
\n\
The TIME_STYLE argument can be full-iso, long-iso, iso, locale, or +FORMAT.\n\ Line 5285
FORMAT is interpreted like in date(1). If FORMAT is FORMAT1<newline>FORMAT2,\n\Line 5286
then FORMAT1 applies to non-recent files and FORMAT2 to recent files.\n\ Line 5287
TIME_STYLE prefixed with 'posix-' takes effect only outside the POSIX locale.\n\Line 5288
Also the TIME_STYLE environment variable sets the default style to use.\n\ Line 5289
"), stdout); Line 5290
fputs (_("\ Line 5291
\n\
Using color to distinguish file types is disabled both by default and\n\ Line 5293
with --color=never. With --color=auto, ls emits color codes only when\n\ Line 5294
standard output is connected to a terminal. The LS_COLORS environment\n\ Line 5295
variable can change the settings. Use the dircolors command to set it.\n\ Line 5296
"), stdout); Line 5297
fputs (_("\ Line 5298
\n\
Exit status:\n\ Line 5300
0 if OK,\n\ Line 5301
1 if minor problems (e.g., cannot access subdirectory),\n\ Line 5302
2 if serious trouble (e.g., cannot access command-line argument).\n\ Line 5303
"), stdout); Line 5304
emit_ancillary_info (PROGRAM_NAME); Line 5305
}
exit (status); Line 5307
} Block 153