Modification de la commande ls

Fermé
hektoumayo - 20 janv. 2006 à 13:47
 EminoMeneko - 28 janv. 2008 à 23:04
Bonjour,
Je voudrais faire des modifications sur la commande ls du shell. A titre d'exemple, je voudrais creer une option -stat pour la commande ls qui sur un repertoire donne pour chaque fichier son occupation en pourcentage.
Le problème est que je ne sais pas ou recuperer le code source de la commande ls pour le modifier.
Si quelqu'un avait le solution à mon problème ou s'il a une quelconque autre suggestion à faire sur le sujet , je lui serais reconnaissant de me l'indiquer.
Merci d'avance.
A voir également:

22 réponses

lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
27 janv. 2008 à 20:17
Et voilà à quoi se ressemble le code source que tu veux modifier

/* `dir', `vdir' and `ls' directory listing programs for GNU.
   Copyright (C) 85, 88, 90, 91, 1995-2007 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 2, 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, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

/* 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>
#include <sys/types.h>

#if HAVE_TERMIOS_H
# include <termios.h>
#endif
#if HAVE_STROPTS_H
# include <stropts.h>
#endif
#if HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif

#ifdef WINSIZE_IN_PTEM
# include <sys/stream.h>
# include <sys/ptem.h>
#endif

#include <stdio.h>
#include <assert.h>
#include <setjmp.h>
#include <grp.h>
#include <pwd.h>
#include <getopt.h>
#include <signal.h>

/* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
   present.  */
#ifndef SA_NOCLDSTOP
# define SA_NOCLDSTOP 0
# define sigprocmask(How, Set, Oset) /* empty */
# define sigset_t int
# if ! HAVE_SIGINTERRUPT
#  define siginterrupt(sig, flag) /* empty */
# endif
#endif
#ifndef SA_RESTART
# define SA_RESTART 0
#endif

#include "system.h"
#include <fnmatch.h>

#include "acl.h"
#include "argmatch.h"
#include "dev-ino.h"
#include "dirfd.h"
#include "error.h"
#include "filenamecat.h"
#include "hard-locale.h"
#include "hash.h"
#include "human.h"
#include "filemode.h"
#include "inttostr.h"
#include "ls.h"
#include "lstat.h"
#include "mbswidth.h"
#include "mpsort.h"
#include "obstack.h"
#include "quote.h"
#include "quotearg.h"
#include "same.h"
#include "stat-time.h"
#include "strftime.h"
#include "strverscmp.h"
#include "wcwidth.h"
#include "xstrtol.h"
#include "xreadlink.h"

#define PROGRAM_NAME (ls_mode == LS_LS ? "ls" \
		      : (ls_mode == LS_MULTI_COL \
			 ? "dir" : "vdir"))

#define AUTHORS "Richard Stallman", "David MacKenzie"

#define obstack_chunk_alloc malloc
#define obstack_chunk_free free

/* 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))

#if ! HAVE_STRUCT_STAT_ST_AUTHOR
# define st_author st_uid
#endif

enum filetype
  {
    unknown,
    fifo,
    chardev,
    directory,
    blockdev,
    normal,
    symbolic_link,
    sock,
    whiteout,
    arg_directory
  };

/* Display letters and indicators for each filetype.
   Keep these in sync with enum filetype.  */
static char const filetype_letter[] = "?pcdb-lswd";

/* Ensure that filetype and filetype_letter have the same
   number of elements.  */
verify (sizeof filetype_letter - 1 == arg_directory + 1);

#define FILETYPE_INDICATORS				\
  {							\
    C_ORPHAN, C_FIFO, C_CHR, C_DIR, C_BLK, C_FILE,	\
    C_LINK, C_SOCK, C_FILE, C_DIR			\
  }


struct fileinfo
  {
    /* The file name.  */
    char *name;

    /* For symbolic link, name of the file linked to, otherwise zero.  */
    char *linkname;

    struct stat stat;

    enum filetype filetype;

    /* For symbolic link and long listing, st_mode of file linked to, otherwise
       zero.  */
    mode_t linkmode;

    bool stat_ok;

    /* For symbolic link and color printing, true if linked-to file
       exists, otherwise false.  */
    bool linkok;

#if USE_ACL
    /* For long listings, true if the file has an access control list.  */
    bool have_acl;
#endif
  };

#if USE_ACL
# define FILE_HAS_ACL(F) ((F)->have_acl)
#else
# define FILE_HAS_ACL(F) 0
#endif

#define LEN_STR_PAIR(s) sizeof (s) - 1, s

/* 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
  {
    size_t len;			/* Number of bytes */
    const char *string;		/* Pointer to the same */
  };

char *getgroup ();
char *getuser ();

#if ! HAVE_TCGETPGRP
# define tcgetpgrp(Fd) 0
#endif

static size_t quote_name (FILE *out, const char *name,
			  struct quoting_options const *options,
			  size_t *width);
static char *make_link_name (char const *name, char const *linkname);
static int decode_switches (int argc, char **argv);
static bool file_ignored (char const *name);
static uintmax_t gobble_file (char const *name, enum filetype type,
			      ino_t inode, bool command_line_arg,
			      char const *dirname);
static void print_color_indicator (const char *name, mode_t mode, int linkok,
				   bool stat_ok, enum filetype type);
static void put_indicator (const struct bin_str *ind);
static void add_ignore_pattern (const char *pattern);
static void attach (char *dest, const char *dirname, const char *name);
static void clear_files (void);
static void extract_dirs_from_files (char const *dirname,
				     bool command_line_arg);
static void get_link_name (char const *filename, struct fileinfo *f,
			   bool command_line_arg);
static void indent (size_t from, size_t to);
static size_t calculate_columns (bool by_columns);
static void print_current_files (void);
static void print_dir (char const *name, char const *realname,
		       bool command_line_arg);
static void print_file_name_and_frills (const struct fileinfo *f);
static void print_horizontal (void);
static int format_user_width (uid_t u);
static int format_group_width (gid_t g);
static void print_long_format (const struct fileinfo *f);
static void print_many_per_line (void);
static void print_name_with_quoting (const char *p, mode_t mode,
				     int linkok, bool stat_ok,
				     enum filetype type,
				     struct obstack *stack);
static void prep_non_filename_text (void);
static void print_type_indicator (bool stat_ok, mode_t mode,
				  enum filetype type);
static void print_with_commas (void);
static void queue_directory (char const *name, char const *realname,
			     bool command_line_arg);
static void sort_files (void);
static void parse_ls_color (void);
void usage (int status);

/* The name this program was run with.  */
char *program_name;

/* Initial size of hash table.
   Most hierarchies are likely to be shallower than this.  */
#define INITIAL_TABLE_SIZE 30

/* 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;

#define LOOP_DETECT (!!active_dir_set)

/* 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;

/* Length of block that `cwd_file' points to, measured in files.  */
static size_t cwd_n_alloc;

/* Index of first unused slot in `cwd_file'.  */
static size_t cwd_n_used;

/* Vector of pointers to files, in proper sorted order, and the number
   of entries allocated for it.  */
static void **sorted_file;
static size_t sorted_file_alloc;

/* 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;

/* mode of appropriate file for colorization */
#define FILE_OR_LINK_MODE(File) \
    ((color_symlink_as_referent & (File)->linkok) \
     ? (File)->linkmode : (File)->stat.st_mode)


/* Record of one pending directory waiting to be listed.  */

struct pending
  {
    char *name;
    /* 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;
    bool command_line_arg;
    struct pending *next;
  };

static struct pending *pending_dirs;

/* Current time in seconds and nanoseconds since 1970, updated as
   needed when deciding whether a file is recent.  */

static time_t current_time = TYPE_MINIMUM (time_t);
static int current_time_ns = -1;

/* Whether any of the files has an ACL.  This affects the width of the
   mode column.  */

#if USE_ACL
static bool any_has_acl;
#else
enum { any_has_acl = false };
#endif

/* 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;
static int block_size_width;
static int nlink_width;
static int owner_width;
static int group_width;
static int author_width;
static int major_device_number_width;
static int minor_device_number_width;
static int file_size_width;

/* 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
  {
    long_format,		/* -l and other options that imply -l */
    one_per_line,		/* -1 */
    many_per_line,		/* -C */
    horizontal,			/* -x */
    with_commas			/* -m */
  };

static enum format format;

/* `full-iso' uses full ISO-style dates and times.  `long-iso' uses longer
   ISO-style time stamps, though shorter than `full-iso'.  `iso' uses shorter
   ISO-style time stamps.  `locale' uses locale-dependent time stamps.  */
enum time_style
  {
    full_iso_time_style,	/* --time-style=full-iso */
    long_iso_time_style,	/* --time-style=long-iso */
    iso_time_style,		/* --time-style=iso */
    locale_time_style		/* --time-style=locale */
  };

static char const *const time_style_args[] =
{
  "full-iso", "long-iso", "iso", "locale", NULL
};
static enum time_style const time_style_types[] =
{
  full_iso_time_style, long_iso_time_style, iso_time_style,
  locale_time_style
};
ARGMATCH_VERIFY (time_style_args, time_style_types);

/* 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
  {
    time_mtime,			/* default */
    time_ctime,			/* -c */
    time_atime,			/* -u */
    time_numtypes		/* the number of elements of this enum */
  };

static enum time_type time_type;

/* 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
  {
    sort_none = -1,		/* -U */
    sort_name,			/* default */
    sort_extension,		/* -X */
    sort_size,			/* -S */
    sort_version,		/* -v */
    sort_time,			/* -t */
    sort_numtypes		/* the number of elements of this enum */
  };

static enum sort_type sort_type;

/* 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;

/* True means to display owner information.  -g turns this off.  */

static bool print_owner = true;

/* True means to display author information.  */

static bool print_author;

/* True means to display group information.  -G and -o turn this off.  */

static bool print_group = true;

/* True means print the user and group id's as numbers rather
   than as names.  -n  */

static bool numeric_ids;

/* True means mention the size in blocks of each file.  -s  */

static bool print_block_size;

/* Human-readable options for output.  */
static int human_output_opts;

/* The units to use when printing sizes other than file sizes.  */
static uintmax_t output_block_size;

/* Likewise, but for file sizes.  */
static uintmax_t file_output_block_size = 1;

/* 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;

/* `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
  {
    none,	/*     --indicator-style=none */
    slash,	/* -p, --indicator-style=slash */
    file_type,	/*     --indicator-style=file-type */
    classify	/* -F, --indicator-style=classify */
  };

static enum indicator_style indicator_style;

/* Names of indicator styles.  */
static char const *const indicator_style_args[] =
{
  "none", "slash", "file-type", "classify", NULL
};
static enum indicator_style const indicator_style_types[] =
{
  none, slash, file_type, classify
};
ARGMATCH_VERIFY (indicator_style_args, indicator_style_types);

/* 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;

enum color_type
  {
    color_never,		/* 0: default or --color=never */
    color_always,		/* 1: --color=always */
    color_if_tty		/* 2: --color=tty */
  };

enum Dereference_symlink
  {
    DEREF_UNDEFINED = 1,
    DEREF_NEVER,
    DEREF_COMMAND_LINE_ARGUMENTS,	/* -H */
    DEREF_COMMAND_LINE_SYMLINK_TO_DIR,	/* the default, in certain cases */
    DEREF_ALWAYS			/* -L */
  };

enum indicator_no
  {
    C_LEFT, C_RIGHT, C_END, C_NORM, C_FILE, C_DIR, C_LINK, C_FIFO, C_SOCK,
    C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC, C_DOOR, C_SETUID, C_SETGID,
    C_STICKY, C_OTHER_WRITABLE, C_STICKY_OTHER_WRITABLE
  };

static const char *const indicator_name[]=
  {
    "lc", "rc", "ec", "no", "fi", "di", "ln", "pi", "so",
    "bd", "cd", "mi", "or", "ex", "do", "su", "sg", "st",
    "ow", "tw", NULL
  };

struct color_ext_type
  {
    struct bin_str ext;		/* The extension we're looking for */
    struct bin_str seq;		/* The sequence to output when we do */
    struct color_ext_type *next;	/* Next in list */
  };

static struct bin_str color_indicator[] =
  {
    { LEN_STR_PAIR ("\033[") },		/* lc: Left of color sequence */
    { LEN_STR_PAIR ("m") },		/* rc: Right of color sequence */
    { 0, NULL },			/* ec: End color (replaces lc+no+rc) */
    { LEN_STR_PAIR ("0") },		/* no: Normal */
    { LEN_STR_PAIR ("0") },		/* fi: File: default */
    { LEN_STR_PAIR ("01;34") },		/* di: Directory: bright blue */
    { LEN_STR_PAIR ("01;36") },		/* ln: Symlink: bright cyan */
    { LEN_STR_PAIR ("33") },		/* pi: Pipe: yellow/brown */
    { LEN_STR_PAIR ("01;35") },		/* so: Socket: bright magenta */
    { LEN_STR_PAIR ("01;33") },		/* bd: Block device: bright yellow */
    { LEN_STR_PAIR ("01;33") },		/* cd: Char device: bright yellow */
    { 0, NULL },			/* mi: Missing file: undefined */
    { 0, NULL },			/* or: Orphaned symlink: undefined */
    { LEN_STR_PAIR ("01;32") },		/* ex: Executable: bright green */
    { LEN_STR_PAIR ("01;35") },		/* do: Door: bright magenta */
    { LEN_STR_PAIR ("37;41") },		/* su: setuid: white on red */
    { LEN_STR_PAIR ("30;43") },		/* sg: setgid: black on yellow */
    { LEN_STR_PAIR ("37;44") },		/* st: sticky: black on blue */
    { LEN_STR_PAIR ("34;42") },		/* ow: other-writable: blue on green */
    { LEN_STR_PAIR ("30;42") },		/* tw: ow w/ sticky: black on green */
  };

/* FIXME: comment  */
static struct color_ext_type *color_ext_list = NULL;

/* Buffer for color sequences */
static char *color_buf;

/* True means to check for orphaned symbolic link, for displaying
   colors.  */

static bool check_symlink_color;

/* True means mention the inode number of each file.  -i  */

static bool print_inode;

/* 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;

/* True means when a directory is found, display info on its
   contents.  -R  */

static bool recursive;

/* True means when an argument is a directory name, display info
   on it itself.  -d  */

static bool immediate_dirs;

/* True means that directories are grouped before files. */

static bool directories_first;

/* Which files to ignore.  */

static enum
{
  /* Ignore files whose names start with `.', and files specified by
     --hide and --ignore.  */
  IGNORE_DEFAULT,

  /* Ignore `.', `..', and files specified by --ignore.  */
  IGNORE_DOT_AND_DOTDOT,

  /* Ignore only files specified by --ignore.  */
  IGNORE_MINIMAL
} ignore_mode;

/* 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
  {
    const char *pattern;
    struct ignore_pattern *next;
  };

static struct ignore_pattern *ignore_patterns;

/* Similar to IGNORE_PATTERNS, except that -a or -A causes this
   variable itself to be ignored.  */
static struct ignore_pattern *hide_patterns;

/* 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;

/* Quoting options for file and dir name output.  */

static struct quoting_options *filename_quoting_options;
static struct quoting_options *dirname_quoting_options;

/* 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;

/* True means print each directory name before listing it.  */

static bool print_dir_name;

/* The line length to use for breaking lines in many-per-line format.
   Can be set with -w.  */

static size_t line_length;

/* If true, the file listing format requires that stat be called on
   each file.  */

static bool format_needs_stat;

/* Similar to `format_needs_stat', but set if only the file type is
   needed.  */

static bool format_needs_type;

/* An arbitrary limit on the number of bytes in a printed time stamp.
   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
   time stamp format.  */

enum { TIME_STAMP_LEN_MAXIMUM = MAX (1000, INT_STRLEN_BOUND (time_t)) };

/* strftime formats for non-recent and recent files, respectively, in
   -l output.  */

static char const *long_time_format[2] =
  {
    /* 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.  */
    N_("%b %e  %Y"),
    /* 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.  */
    N_("%b %e %H:%M")
  };

/* The set of signals that are caught.  */

static sigset_t caught_signals;

/* If nonzero, the value of the pending fatal signal.  */

static sig_atomic_t volatile interrupt_signal;

/* A count of the number of pending stop signals that have been received.  */

static sig_atomic_t volatile stop_signal_count;

/* Desired exit status.  */

static int exit_status;

/* Exit statuses.  */
enum
  {
    /* "ls" had a minor problem (e.g., it could not stat a directory
       entry).  */
    LS_MINOR_PROBLEM = 1,

    /* "ls" had more serious trouble.  */
    LS_FAILURE = 2
  };

/* For long options that have no equivalent short option, use a
   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
enum
{
  AUTHOR_OPTION = CHAR_MAX + 1,
  BLOCK_SIZE_OPTION,
  COLOR_OPTION,
  DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION,
  FILE_TYPE_INDICATOR_OPTION,
  FORMAT_OPTION,
  FULL_TIME_OPTION,
  GROUP_DIRECTORIES_FIRST_OPTION,
  HIDE_OPTION,
  INDICATOR_STYLE_OPTION,

  /* FIXME: --kilobytes is deprecated (but not -k); remove in late 2006 */
  KILOBYTES_LONG_OPTION,

  QUOTING_STYLE_OPTION,
  SHOW_CONTROL_CHARS_OPTION,
  SI_OPTION,
  SORT_OPTION,
  TIME_OPTION,
  TIME_STYLE_OPTION
};

static struct option const long_options[] =
{
  {"all", no_argument, NULL, 'a'},
  {"escape", no_argument, NULL, 'b'},
  {"directory", no_argument, NULL, 'd'},
  {"dired", no_argument, NULL, 'D'},
  {"full-time", no_argument, NULL, FULL_TIME_OPTION},
  {"group-directories-first", no_argument, NULL,
   GROUP_DIRECTORIES_FIRST_OPTION},
  {"human-readable", no_argument, NULL, 'h'},
  {"inode", no_argument, NULL, 'i'},
  {"kilobytes", no_argument, NULL, KILOBYTES_LONG_OPTION},
  {"numeric-uid-gid", no_argument, NULL, 'n'},
  {"no-group", no_argument, NULL, 'G'},
  {"hide-control-chars", no_argument, NULL, 'q'},
  {"reverse", no_argument, NULL, 'r'},
  {"size", no_argument, NULL, 's'},
  {"width", required_argument, NULL, 'w'},
  {"almost-all", no_argument, NULL, 'A'},
  {"ignore-backups", no_argument, NULL, 'B'},
  {"classify", no_argument, NULL, 'F'},
  {"file-type", no_argument, NULL, FILE_TYPE_INDICATOR_OPTION},
  {"si", no_argument, NULL, SI_OPTION},
  {"dereference-command-line", no_argument, NULL, 'H'},
  {"dereference-command-line-symlink-to-dir", no_argument, NULL,
   DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION},
  {"hide", required_argument, NULL, HIDE_OPTION},
  {"ignore", required_argument, NULL, 'I'},
  {"indicator-style", required_argument, NULL, INDICATOR_STYLE_OPTION},
  {"dereference", no_argument, NULL, 'L'},
  {"literal", no_argument, NULL, 'N'},
  {"quote-name", no_argument, NULL, 'Q'},
  {"quoting-style", required_argument, NULL, QUOTING_STYLE_OPTION},
  {"recursive", no_argument, NULL, 'R'},
  {"format", required_argument, NULL, FORMAT_OPTION},
  {"show-control-chars", no_argument, NULL, SHOW_CONTROL_CHARS_OPTION},
  {"sort", required_argument, NULL, SORT_OPTION},
  {"tabsize", required_argument, NULL, 'T'},
  {"time", required_argument, NULL, TIME_OPTION},
  {"time-style", required_argument, NULL, TIME_STYLE_OPTION},
  {"color", optional_argument, NULL, COLOR_OPTION},
  {"block-size", required_argument, NULL, BLOCK_SIZE_OPTION},
  {"author", no_argument, NULL, AUTHOR_OPTION},
  {GETOPT_HELP_OPTION_DECL},
  {GETOPT_VERSION_OPTION_DECL},
  {NULL, 0, NULL, 0}
};

static char const *const format_args[] =
{
  "verbose", "long", "commas", "horizontal", "across",
  "vertical", "single-column", NULL
};
static enum format const format_types[] =
{
  long_format, long_format, with_commas, horizontal, horizontal,
  many_per_line, one_per_line
};
ARGMATCH_VERIFY (format_args, format_types);

static char const *const sort_args[] =
{
  "none", "time", "size", "extension", "version", NULL
};
static enum sort_type const sort_types[] =
{
  sort_none, sort_time, sort_size, sort_extension, sort_version
};
ARGMATCH_VERIFY (sort_args, sort_types);

static char const *const time_args[] =
{
  "atime", "access", "use", "ctime", "status", NULL
};
static enum time_type const time_types[] =
{
  time_atime, time_atime, time_atime, time_ctime, time_ctime
};
ARGMATCH_VERIFY (time_args, time_types);

static char const *const color_args[] =
{
  /* force and none are for compatibility with another color-ls version */
  "always", "yes", "force",
  "never", "no", "none",
  "auto", "tty", "if-tty", NULL
};
static enum color_type const color_types[] =
{
  color_always, color_always, color_always,
  color_never, color_never, color_never,
  color_if_tty, color_if_tty, color_if_tty
};
ARGMATCH_VERIFY (color_args, color_types);

/* Information about filling a column.  */
struct column_info
{
  bool valid_len;
  size_t line_len;
  size_t *col_arr;
};

/* Array with information about column filledness.  */
static struct column_info *column_info;

/* Maximum number of columns ever possible for this display.  */
static size_t max_idx;

/* 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


/* 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;

#define DIRED_PUTCHAR(c) do {putchar ((c)); ++dired_pos;} while (0)

/* Write S to STREAM and increment DIRED_POS by S_LEN.  */
#define DIRED_FPUTS(s, stream, s_len) \
    do {fputs (s, stream); dired_pos += s_len;} while (0)

/* Like DIRED_FPUTS, but for use when S is a literal string.  */
#define DIRED_FPUTS_LITERAL(s, stream) \
    do {fputs (s, stream); dired_pos += sizeof (s) - 1;} while (0)

#define DIRED_INDENT()							\
    do									\
      {									\
	if (dired)							\
	  DIRED_FPUTS_LITERAL ("  ", stdout);				\
      }									\
    while (0)

/* With --dired, store pairs of beginning and ending indices of filenames.  */
static struct obstack dired_obstack;

/* 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;

/* Save the current index on the specified obstack, OBS.  */
#define PUSH_CURRENT_DIRED_POS(obs)					\
  do									\
    {									\
      if (dired)							\
	obstack_grow (obs, &dired_pos, sizeof (dired_pos));		\
    }									\
  while (0)

/* 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;

/* Push a pair onto the device/inode stack.  */
#define DEV_INO_PUSH(Dev, Ino)						\
  do									\
    {									\
      struct dev_ino *di;						\
      obstack_blank (&dev_ino_obstack, sizeof (struct dev_ino));	\
      di = -1 + (struct dev_ino *) obstack_next_free (&dev_ino_obstack); \
      di->st_dev = (Dev);						\
      di->st_ino = (Ino);						\
    }									\
  while (0)

/* Pop a dev/ino struct off the global dev_ino_obstack
   and return that struct.  */
static struct dev_ino
dev_ino_pop (void)
{
  assert (sizeof (struct dev_ino) <= obstack_object_size (&dev_ino_obstack));
  obstack_blank (&dev_ino_obstack, -(int) (sizeof (struct dev_ino)));
  return *(struct dev_ino *) obstack_next_free (&dev_ino_obstack);
}

#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
dired_dump_obstack (const char *prefix, struct obstack *os)
{
  size_t n_pos;

  n_pos = obstack_object_size (os) / sizeof (dired_pos);
  if (n_pos > 0)
    {
      size_t i;
      size_t *pos;

      pos = (size_t *) obstack_finish (os);
      fputs (prefix, stdout);
      for (i = 0; i < n_pos; i++)
	printf (" %lu", (unsigned long int) pos[i]);
      putchar ('\n');
    }
}

static size_t
dev_ino_hash (void const *x, size_t table_size)
{
  struct dev_ino const *p = x;
  return (uintmax_t) p->st_ino % table_size;
}

static bool
dev_ino_compare (void const *x, void const *y)
{
  struct dev_ino const *a = x;
  struct dev_ino const *b = y;
  return SAME_INODE (*a, *b) ? true : false;
}

static void
dev_ino_free (void *x)
{
  free (x);
}

/* 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
visit_dir (dev_t dev, ino_t ino)
{
  struct dev_ino *ent;
  struct dev_ino *ent_from_table;
  bool found_match;

  ent = xmalloc (sizeof *ent);
  ent->st_ino = ino;
  ent->st_dev = dev;

  /* Attempt to insert this entry into the table.  */
  ent_from_table = hash_insert (active_dir_set, ent);

  if (ent_from_table == NULL)
    {
      /* Insertion failed due to lack of memory.  */
      xalloc_die ();
    }

  found_match = (ent_from_table != ent);

  if (found_match)
    {
      /* ent was not inserted, so free it.  */
      free (ent);
    }

  return found_match;
}

static void
free_pending_ent (struct pending *p)
{
  free (p->name);
  free (p->realname);
  free (p);
}

static bool
is_colored (enum indicator_no type)
{
  size_t len = color_indicator[type].len;
  char const *s = color_indicator[type].string;
  return ! (len == 0
	    || (len == 1 && strncmp (s, "0", 1) == 0)
	    || (len == 2 && strncmp (s, "00", 2) == 0));
}

static void
restore_default_color (void)
{
  put_indicator (&color_indicator[C_LEFT]);
  put_indicator (&color_indicator[C_RIGHT]);
}

/* An ordinary signal was received; arrange for the program to exit.  */

static void
sighandler (int sig)
{
  if (! SA_NOCLDSTOP)
    signal (sig, SIG_IGN);
  if (! interrupt_signal)
    interrupt_signal = sig;
}

/* A SIGTSTP was received; arrange for the program to suspend itself.  */

static void
stophandler (int sig)
{
  if (! SA_NOCLDSTOP)
    signal (sig, stophandler);
  if (! interrupt_signal)
    stop_signal_count++;
}

/* 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
process_signals (void)
{
  while (interrupt_signal | stop_signal_count)
    {
      int sig;
      int stops;
      sigset_t oldset;

      restore_default_color ();
      fflush (stdout);

      sigprocmask (SIG_BLOCK, &caught_signals, &oldset);

      /* Reload interrupt_signal and stop_signal_count, in case a new
	 signal was handled before sigprocmask took effect.  */
      sig = interrupt_signal;
      stops = stop_signal_count;

      /* 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)
	{
	  stop_signal_count = stops - 1;
	  sig = SIGSTOP;
	}
      else
	signal (sig, SIG_DFL);

      /* Exit or suspend the program.  */
      raise (sig);
      sigprocmask (SIG_SETMASK, &oldset, NULL);

      /* If execution reaches here, then the program has been
	 continued (after being suspended).  */
    }
}

int
main (int argc, char **argv)
{
  int i;
  struct pending *thispend;
  int n_files;

  /* The signals that are trapped, and the number of such signals.  */
  static int const sig[] =
    {
      /* This one is handled specially.  */
      SIGTSTP,

      /* The usual suspects.  */
      SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGTERM,
#ifdef SIGPOLL
      SIGPOLL,
#endif
#ifdef SIGPROF
      SIGPROF,
#endif
#ifdef SIGVTALRM
      SIGVTALRM,
#endif
#ifdef SIGXCPU
      SIGXCPU,
#endif
#ifdef SIGXFSZ
      SIGXFSZ,
#endif
    };
  enum { nsigs = sizeof sig / sizeof sig[0] };

#if ! SA_NOCLDSTOP
  bool caught_sig[nsigs];
#endif

  initialize_main (&argc, &argv);
  program_name = argv[0];
  setlocale (LC_ALL, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);

  initialize_exit_failure (LS_FAILURE);
  atexit (close_stdout);

#define N_ENTRIES(Array) (sizeof Array / sizeof *(Array))
  assert (N_ENTRIES (color_indicator) + 1 == N_ENTRIES (indicator_name));

  exit_status = EXIT_SUCCESS;
  print_dir_name = true;
  pending_dirs = NULL;

  i = decode_switches (argc, argv);

  if (print_with_color)
    parse_ls_color ();

  /* 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)
    {
      /* Avoid following symbolic links when possible.  */
      if (is_colored (C_ORPHAN)
	  || is_colored (C_EXEC)
	  || (is_colored (C_MISSING) && format == long_format))
	check_symlink_color = true;

      /* 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))
	{
	  int j;
#if SA_NOCLDSTOP
	  struct sigaction act;

	  sigemptyset (&caught_signals);
	  for (j = 0; j < nsigs; j++)
	    {
	      sigaction (sig[j], NULL, &act);
	      if (act.sa_handler != SIG_IGN)
		sigaddset (&caught_signals, sig[j]);
	    }

	  act.sa_mask = caught_signals;
	  act.sa_flags = SA_RESTART;

	  for (j = 0; j < nsigs; j++)
	    if (sigismember (&caught_signals, sig[j]))
	      {
		act.sa_handler = sig[j] == SIGTSTP ? stophandler : sighandler;
		sigaction (sig[j], &act, NULL);
	      }
#else
	  for (j = 0; j < nsigs; j++)
	    {
	      caught_sig[j] = (signal (sig[j], SIG_IGN) != SIG_IGN);
	      if (caught_sig[j])
		{
		  signal (sig[j], sig[j] == SIGTSTP ? stophandler : sighandler);
		  siginterrupt (sig[j], 0);
		}
	    }
#endif
	}

      prep_non_filename_text ();
    }

  if (dereference == DEREF_UNDEFINED)
    dereference = ((immediate_dirs
		    || indicator_style == classify
		    || format == long_format)
		   ? DEREF_NEVER
		   : DEREF_COMMAND_LINE_SYMLINK_TO_DIR);

  /* When using -R, initialize a data structure we'll use to
     detect any directory cycles.  */
  if (recursive)
    {
      active_dir_set = hash_initialize (INITIAL_TABLE_SIZE, NULL,
					dev_ino_hash,
					dev_ino_compare,
					dev_ino_free);
      if (active_dir_set == NULL)
	xalloc_die ();

      obstack_init (&dev_ino_obstack);
    }

  format_needs_stat = sort_type == sort_time || sort_type == sort_size
    || format == long_format
    || print_block_size;
  format_needs_type = (! format_needs_stat
		       && (recursive
			   || print_with_color
			   || indicator_style != none
			   || directories_first));

  if (dired)
    {
      obstack_init (&dired_obstack);
      obstack_init (&subdired_obstack);
    }

  cwd_n_alloc = 100;
  cwd_file = xnmalloc (cwd_n_alloc, sizeof *cwd_file);
  cwd_n_used = 0;

  clear_files ();

  n_files = argc - i;

  if (n_files <= 0)
    {
      if (immediate_dirs)
	gobble_file (".", directory, NOT_AN_INODE_NUMBER, true, "");
      else
	queue_directory (".", NULL, true);
    }
  else
    do
      gobble_file (argv[i++], unknown, NOT_AN_INODE_NUMBER, true, "");
    while (i < argc);

  if (cwd_n_used)
    {
      sort_files ();
      if (!immediate_dirs)
	extract_dirs_from_files (NULL, true);
      /* `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)
    {
      print_current_files ();
      if (pending_dirs)
	DIRED_PUTCHAR ('\n');
    }
  else if (n_files <= 1 && pending_dirs && pending_dirs->next == 0)
    print_dir_name = false;

  while (pending_dirs)
    {
      thispend = pending_dirs;
      pending_dirs = pending_dirs->next;

      if (LOOP_DETECT)
	{
	  if (thispend->name == NULL)
	    {
	      /* 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 ();
	      struct dev_ino *found = hash_delete (active_dir_set, &di);
	      /* ASSERT_MATCHING_DEV_INO (thispend->realname, di); */
	      assert (found);
	      dev_ino_free (found);
	      free_pending_ent (thispend);
	      continue;
	    }
	}

      print_dir (thispend->name, thispend->realname,
		 thispend->command_line_arg);

      free_pending_ent (thispend);
      print_dir_name = true;
    }

  if (print_with_color)
    {
      int j;

      restore_default_color ();
      fflush (stdout);

      /* Restore the default signal handling.  */
#if SA_NOCLDSTOP
      for (j = 0; j < nsigs; j++)
	if (sigismember (&caught_signals, sig[j]))
	  signal (sig[j], SIG_DFL);
#else
      for (j = 0; j < nsigs; j++)
	if (caught_sig[j])
	  signal (sig[j], SIG_DFL);
#endif

      /* 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--)
	raise (SIGSTOP);
      j = interrupt_signal;
      if (j)
	raise (j);
    }

  if (dired)
    {
      /* No need to free these since we're about to exit.  */
      dired_dump_obstack ("//DIRED//", &dired_obstack);
      dired_dump_obstack ("//SUBDIRED//", &subdired_obstack);
      printf ("//DIRED-OPTIONS// --quoting-style=%s\n",
	      quoting_style_args[get_quoting_style (filename_quoting_options)]);
    }

  if (LOOP_DETECT)
    {
      assert (hash_get_n_entries (active_dir_set) == 0);
      hash_free (active_dir_set);
    }

  exit (exit_status);
}

/* Set all the option flags according to the switches specified.
   Return the index of the first non-option argument.  */

static int
decode_switches (int argc, char **argv)
{
  int c;
  char *time_style_option = NULL;

  /* Record whether there is an option specifying sort type.  */
  bool sort_type_specified = false;

  qmark_funny_chars = false;

  /* initialize all switches to default settings */

  switch (ls_mode)
    {
    case LS_MULTI_COL:
      /* This is for the `dir' program.  */
      format = many_per_line;
      set_quoting_style (NULL, escape_quoting_style);
      break;

    case LS_LONG_FORMAT:
      /* This is for the `vdir' program.  */
      format = long_format;
      set_quoting_style (NULL, escape_quoting_style);
      break;

    case LS_LS:
      /* This is for the `ls' program.  */
      if (isatty (STDOUT_FILENO))
	{
	  format = many_per_line;
	  /* See description of qmark_funny_chars, above.  */
	  qmark_funny_chars = true;
	}
      else
	{
	  format = one_per_line;
	  qmark_funny_chars = false;
	}
      break;

    default:
      abort ();
    }

  time_type = time_mtime;
  sort_type = sort_name;
  sort_reverse = false;
  numeric_ids = false;
  print_block_size = false;
  indicator_style = none;
  print_inode = false;
  dereference = DEREF_UNDEFINED;
  recursive = false;
  immediate_dirs = false;
  ignore_mode = IGNORE_DEFAULT;
  ignore_patterns = NULL;
  hide_patterns = NULL;

  /* FIXME: put this in a function.  */
  {
    char const *q_style = getenv ("QUOTING_STYLE");
    if (q_style)
      {
	int i = ARGMATCH (q_style, quoting_style_args, quoting_style_vals);
	if (0 <= i)
	  set_quoting_style (NULL, quoting_style_vals[i]);
	else
	  error (0, 0,
	 _("ignoring invalid value of environment variable QUOTING_STYLE: %s"),
		 quotearg (q_style));
      }
  }

  {
    char const *ls_block_size = getenv ("LS_BLOCK_SIZE");
    human_output_opts = human_options (ls_block_size, false,
				       &output_block_size);
    if (ls_block_size || getenv ("BLOCK_SIZE"))
      file_output_block_size = output_block_size;
  }

  line_length = 80;
  {
    char const *p = getenv ("COLUMNS");
    if (p && *p)
      {
	unsigned long int tmp_ulong;
	if (xstrtoul (p, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK
	    && 0 < tmp_ulong && tmp_ulong <= SIZE_MAX)
	  {
	    line_length = tmp_ulong;
	  }
	else
	  {
	    error (0, 0,
	       _("ignoring invalid width in environment variable COLUMNS: %s"),
		   quotearg (p));
	  }
      }
  }

#ifdef TIOCGWINSZ
  {
    struct winsize ws;

    if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1
	&& 0 < ws.ws_col && ws.ws_col == (size_t) ws.ws_col)
      line_length = ws.ws_col;
  }
#endif

  {
    char const *p = getenv ("TABSIZE");
    tabsize = 8;
    if (p)
      {
	unsigned long int tmp_ulong;
	if (xstrtoul (p, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK
	    && tmp_ulong <= SIZE_MAX)
	  {
	    tabsize = tmp_ulong;
	  }
	else
	  {
	    error (0, 0,
	     _("ignoring invalid tab size in environment variable TABSIZE: %s"),
		   quotearg (p));
	  }
      }
  }

  while ((c = getopt_long (argc, argv,
			   "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1",
			   long_options, NULL)) != -1)
    {
      switch (c)
	{
	case 'a':
	  ignore_mode = IGNORE_MINIMAL;
	  break;

	case 'b':
	  set_quoting_style (NULL, escape_quoting_style);
	  break;

	case 'c':
	  time_type = time_ctime;
	  break;

	case 'd':
	  immediate_dirs = true;
	  break;

	case 'f':
	  /* Same as enabling -a -U and disabling -l -s.  */
	  ignore_mode = IGNORE_MINIMAL;
	  sort_type = sort_none;
	  sort_type_specified = true;
	  /* disable -l */
	  if (format == long_format)
	    format = (isatty (STDOUT_FILENO) ? many_per_line : one_per_line);
	  print_block_size = false;	/* disable -s */
	  print_with_color = false;	/* disable --color */
	  break;

	case FILE_TYPE_INDICATOR_OPTION: /* --file-type */
	  indicator_style = file_type;
	  break;

	case 'g':
	  format = long_format;
	  print_owner = false;
	  break;

	case 'h':
	  human_output_opts = human_autoscale | human_SI | human_base_1024;
	  file_output_block_size = output_block_size = 1;
	  break;

	case 'i':
	  print_inode = true;
	  break;

	case KILOBYTES_LONG_OPTION:
	  error (0, 0,
		 _("the --kilobytes option is deprecated; use -k instead"));
	  /* fall through */
	case 'k':
	  human_output_opts = 0;
	  file_output_block_size = output_block_size = 1024;
	  break;

	case 'l':
	  format = long_format;
	  break;

	case 'm':
	  format = with_commas;
	  break;

	case 'n':
	  numeric_ids = true;
	  format = long_format;
	  break;

	case 'o':  /* Just like -l, but don't display group info.  */
	  format = long_format;
	  print_group = false;
	  break;

	case 'p':
	  indicator_style = slash;
	  break;

	case 'q':
	  qmark_funny_chars = true;
	  break;

	case 'r':
	  sort_reverse = true;
	  break;

	case 's':
	  print_block_size = true;
	  break;

	case 't':
	  sort_type = sort_time;
	  sort_type_specified = true;
	  break;

	case 'u':
	  time_type = time_atime;
	  break;

	case 'v':
	  sort_type = sort_version;
	  sort_type_specified = true;
	  break;

	case 'w':
	  {
	    unsigned long int tmp_ulong;
	    if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) != LONGINT_OK
		|| ! (0 < tmp_ulong && tmp_ulong <= SIZE_MAX))
	      error (LS_FAILURE, 0, _("invalid line width: %s"),
		     quotearg (optarg));
	    line_length = tmp_ulong;
	    break;
	  }

	case 'x':
	  format = horizontal;
	  break;

	case 'A':
	  if (ignore_mode == IGNORE_DEFAULT)
	    ignore_mode = IGNORE_DOT_AND_DOTDOT;
	  break;

	case 'B':
	  add_ignore_pattern ("*~");
	  add_ignore_pattern (".*~");
	  break;

	case 'C':
	  format = many_per_line;
	  break;

	case 'D':
	  dired = true;
	  break;

	case 'F':
	  indicator_style = classify;
	  break;

	case 'G':		/* inhibit display of group info */
	  print_group = false;
	  break;

	case 'H':
	  dereference = DEREF_COMMAND_LINE_ARGUMENTS;
	  break;

	case DEREFERENCE_COMMAND_LINE_SYMLINK_TO_DIR_OPTION:
	  dereference = DEREF_COMMAND_LINE_SYMLINK_TO_DIR;
	  break;

	case 'I':
	  add_ignore_pattern (optarg);
	  break;

	case 'L':
	  dereference = DEREF_ALWAYS;
	  break;

	case 'N':
	  set_quoting_style (NULL, literal_quoting_style);
	  break;

	case 'Q':
	  set_quoting_style (NULL, c_quoting_style);
	  break;

	case 'R':
	  recursive = true;
	  break;

	case 'S':
	  sort_type = sort_size;
	  sort_type_specified = true;
	  break;

	case 'T':
	  {
	    unsigned long int tmp_ulong;
	    if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) != LONGINT_OK
		|| SIZE_MAX < tmp_ulong)
	      error (LS_FAILURE, 0, _("invalid tab size: %s"),
		     quotearg (optarg));
	    tabsize = tmp_ulong;
	    break;
	  }

	case 'U':
	  sort_type = sort_none;
	  sort_type_specified = true;
	  break;

	case 'X':
	  sort_type = sort_extension;
	  sort_type_specified = true;
	  break;

	case '1':
	  /* -1 has no effect after -l.  */
	  if (format != long_format)
	    format = one_per_line;
	  break;

        case AUTHOR_OPTION:
          print_author = true;
          break;

	case HIDE_OPTION:
	  {
	    struct ignore_pattern *hide = xmalloc (sizeof *hide);
	    hide->pattern = optarg;
	    hide->next = hide_patterns;
	    hide_patterns = hide;
	  }
	  break;

	case SORT_OPTION:
	  sort_type = XARGMATCH ("--sort", optarg, sort_args, sort_types);
	  sort_type_specified = true;
	  break;

	case GROUP_DIRECTORIES_FIRST_OPTION:
	  directories_first = true;
	  break;

	case TIME_OPTION:
	  time_type = XARGMATCH ("--time", optarg, time_args, time_types);
	  break;

	case FORMAT_OPTION:
	  format = XARGMATCH ("--format", optarg, format_args, format_types);
	  break;

	case FULL_TIME_OPTION:
	  format = long_format;
	  time_style_option = "full-iso";
	  break;

	case COLOR_OPTION:
	  {
	    int i;
	    if (optarg)
	      i = XARGMATCH ("--color", optarg, color_args, color_types);
	    else
	      /* Using --color with no argument is equivalent to using
		 --color=always.  */
	      i = color_always;

	    print_with_color = (i == color_always
				|| (i == color_if_tty
				    && isatty (STDOUT_FILENO)));

	    if (print_with_color)
	      {
		/* 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;
	      }
	    break;
	  }

	case INDICATOR_STYLE_OPTION:
	  indicator_style = XARGMATCH ("--indicator-style", optarg,
				       indicator_style_args,
				       indicator_style_types);
	  break;

	case QUOTING_STYLE_OPTION:
	  set_quoting_style (NULL,
			     XARGMATCH ("--quoting-style", optarg,
					quoting_style_args,
					quoting_style_vals));
	  break;

	case TIME_STYLE_OPTION:
	  time_style_option = optarg;
	  break;

	case SHOW_CONTROL_CHARS_OPTION:
	  qmark_funny_chars = false;
	  break;

	case BLOCK_SIZE_OPTION:
	  human_output_opts = human_options (optarg, true, &output_block_size);
	  file_output_block_size = output_block_size;
	  break;

	case SI_OPTION:
	  human_output_opts = human_autoscale | human_SI;
	  file_output_block_size = output_block_size = 1;
	  break;

	case_GETOPT_HELP_CHAR;

	case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);

	default:
	  usage (LS_FAILURE);
	}
    }

  max_idx = MAX (1, line_length / MIN_COLUMN_WIDTH);

  filename_quoting_options = clone_quoting_options (NULL);
  if (get_quoting_style (filename_quoting_options) == escape_quoting_style)
    set_char_quoting (filename_quoting_options, ' ', 1);
  if (file_type <= indicator_style)
    {
      char const *p;
      for (p = "*=>@|" + indicator_style - file_type; *p; p++)
	set_char_quoting (filename_quoting_options, *p, 1);
    }

  dirname_quoting_options = clone_quoting_options (NULL);
  set_char_quoting (dirname_quoting_options, ':', 1);

  /* --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)
    dired = false;

  /* 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)
      && !sort_type_specified && format != long_format)
    {
      sort_type = sort_time;
    }

  if (format == long_format)
    {
      char *style = time_style_option;
      static char const posix_prefix[] = "posix-";

      if (! style)
	if (! (style = getenv ("TIME_STYLE")))
	  style = "locale";

      while (strncmp (style, posix_prefix, sizeof posix_prefix - 1) == 0)
	{
	  if (! hard_locale (LC_TIME))
	    return optind;
	  style += sizeof posix_prefix - 1;
	}

      if (*style == '+')
	{
	  char *p0 = style + 1;
	  char *p1 = strchr (p0, '\n');
	  if (! p1)
	    p1 = p0;
	  else
	    {
	      if (strchr (p1 + 1, '\n'))
		error (LS_FAILURE, 0, _("invalid time style format %s"),
		       quote (p0));
	      *p1++ = '\0';
	    }
	  long_time_format[0] = p0;
	  long_time_format[1] = p1;
	}
      else
	switch (XARGMATCH ("time style", style,
			   time_style_args,
			   time_style_types))
	  {
	  case full_iso_time_style:
	    long_time_format[0] = long_time_format[1] =
	      "%Y-%m-%d %H:%M:%S.%N %z";
	    break;

	  case long_iso_time_style:
	  case_long_iso_time_style:
	    long_time_format[0] = long_time_format[1] = "%Y-%m-%d %H:%M";
	    break;

	  case iso_time_style:
	    long_time_format[0] = "%Y-%m-%d ";
	    long_time_format[1] = "%m-%d %H:%M";
	    break;

	  case locale_time_style:
	    if (hard_locale (LC_TIME))
	      {
		/* Ensure that the locale has translations for both
		   formats.  If not, fall back on long-iso format.  */
		int i;
		for (i = 0; i < 2; i++)
		  {
		    char const *locale_format =
		      dcgettext (NULL, long_time_format[i], LC_TIME);
		    if (locale_format == long_time_format[i])
		      goto case_long_iso_time_style;
		    long_time_format[i] = locale_format;
		  }
	      }
	  }
    }

  return optind;
}

/* 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
get_funky_string (char **dest, const char **src, bool equals_end,
		  size_t *output_count)
{
  char num;			/* For numerical codes */
  size_t count;			/* Something to count with */
  enum {
    ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR
  } state;
  const char *p;
  char *q;

  p = *src;			/* We don't want to double-indirect */
  q = *dest;			/* the whole darn time.  */

  count = 0;			/* No characters counted in yet.  */
  num = 0;

  state = ST_GND;		/* Start in ground state.  */
// trop longue le et je n'a pas pu l'afficher en totalité ;-))
1
jipicy Messages postés 40842 Date d'inscription jeudi 28 août 2003 Statut Modérateur Dernière intervention 10 août 2020 4 897
20 janv. 2006 à 14:12
Salut,

Crée un "alias".
Par exemple :
alias lst="ls -stat"
et quand tu taperas ta commande "lst", tu auras l'affichage de la commade "ls -stat".
Pour que ton "alias" soit pris en compte définitivement, rajoute son entrée "/etc/profile.d/alias.sh".
0
Je crois que j'ai choisi le mauvais exemple. En fait, je voudrais creer une commande externe qui ressemble à ls du style :
ls -min=valeur qui listerait uniquement les fichiers supérieurs à min.
Je ne sais pas quoi faire : du code en C ou du script bash.
Merci
0
jisisv Messages postés 3645 Date d'inscription dimanche 18 mars 2001 Statut Modérateur Dernière intervention 15 janvier 2017 934
20 janv. 2006 à 15:32
Essayons de cerner ta question:
° soit tu veux réécrire ls
alors tu récupères les sources de ls et tu patches, compiles, installes
Si c'est à usage interne, c"est ton problème.
° sinon les commandes find, stat entre autres
te seront utiles
man stat
man find
Par exemple
johand@horus:~/tmp$ stat -c 'Filename %n Size:%s' *|head -3
Filename eicar.com Size:69
Filename fond-apt.jpg Size:73148
Filename fond-config-base.jpg Size:149076

#####################
johand@horus:~/tmp$ find . -size +100k -ls|head -1
1264997  188 -rw-r--r--   1 johand   johand     188128 jun  8  2005 ./pythondatabase.ps


Quelle est ta distribution?
<troll mode='funky'>
Sous Debian, c'est fastoche
</troll>
0
blueyes666 Messages postés 10 Date d'inscription mercredi 3 octobre 2007 Statut Membre Dernière intervention 29 juin 2009
8 déc. 2007 à 11:33
bonjour voila moi aussi je cherche a recuperer le code source de la commande ls et quelques autres commandes donc si kelk'1 sait comment faire plz help me!!!!!!
j'ai un projet la dessous sur les impementations des commandes shell en c/c++ :p
comme distribution g ubuntu...!
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
gmailjamal Messages postés 10 Date d'inscription dimanche 20 janvier 2008 Statut Membre Dernière intervention 17 mars 2008
20 janv. 2008 à 23:33
svp si tu as deja trouver une solution de modification ou de création d'une commande unix ,plz help me!!!!!!
j'ai un projet la dessous.

merci d'avance
0
blueyes666 Messages postés 10 Date d'inscription mercredi 3 octobre 2007 Statut Membre Dernière intervention 29 juin 2009
21 janv. 2008 à 02:48
ben donne moi ton mail g deja les commandes cd,ls,pwd,history .
mais la t'aura besoin d'un parser etv un lexer et d'un makefile alors je c pas si c'est le meme projet ou pas?
0
gmailjamal Messages postés 10 Date d'inscription dimanche 20 janvier 2008 Statut Membre Dernière intervention 17 mars 2008
23 janv. 2008 à 18:14
voila mn email: dmx-jamal@hotmail.com
mon projet est " modification de programme d'une commande (unix)" càd changer la source d' une commande par exemple ls,grep ou n'import commande pr que cette commande faire autre chose.
dans tt les cas envoyer le plus vite possible ,tt support a une relation avec ce projet.
vrmt merci merci....100000 fois
0
bob031 Messages postés 8158 Date d'inscription samedi 7 août 2004 Statut Membre Dernière intervention 1 septembre 2014 472
23 janv. 2008 à 19:25
bonjour,

moi j'ai pas de messagerie electronique mais je trouve le projet "modification de programme d'une commande (unix)" .....super chouette !
ça doit demander de sacrées compétences en programmation C, non ?

...mais bon ....comme je n'ai trop le temps de chercher, ni trop le temps de m'investir, silteuplééééééééé, si tu peux m'avertir ici dès que tu auras regrouper assez de supports ...enfin comme tu dis quoi :
dans tt les cas envoyer le plus vite possible ,tt support a une relation avec ce projet.
vrmt merci merci....100000 fois


....moi c'est 1 milliard de fois merci.

:-))
0
jipicy Messages postés 40842 Date d'inscription jeudi 28 août 2003 Statut Modérateur Dernière intervention 10 août 2020 4 897 > bob031 Messages postés 8158 Date d'inscription samedi 7 août 2004 Statut Membre Dernière intervention 1 septembre 2014
23 janv. 2008 à 19:28
Oui mais toi t'es riche, pfffffffffffffff c'est pas juste ;-DDDDDDDDDD
0
bob031 Messages postés 8158 Date d'inscription samedi 7 août 2004 Statut Membre Dernière intervention 1 septembre 2014 472 > jipicy Messages postés 40842 Date d'inscription jeudi 28 août 2003 Statut Modérateur Dernière intervention 10 août 2020
23 janv. 2008 à 19:33
Oui mais toi t'es riche .....riche en "merci" oui ! -DDDDDDDDDD

..et comme tout le monde je préfèrerai être riche ....autrement ! :-)

ps : pas forcément "en travaillant plus", .....j'opterai d'ailleurs plutôt pour "en travaillant moins" ce qui me semble bien plus réalisable ....réaliste ?????
0
blueyes666 Messages postés 10 Date d'inscription mercredi 3 octobre 2007 Statut Membre Dernière intervention 29 juin 2009
23 janv. 2008 à 19:29
je pense qu'il ya pa kk1 au monde qui n'a pas de messagerie donc fais toi une sinon........
0
blueyes666 Messages postés 10 Date d'inscription mercredi 3 octobre 2007 Statut Membre Dernière intervention 29 juin 2009
23 janv. 2008 à 19:31
moi je suis riche mais tu parles de koi la ?
putain avoir une boite mail ca coute de l'argent mtn ??????
tu vis ou toi ????
0
gmailjamal Messages postés 10 Date d'inscription dimanche 20 janvier 2008 Statut Membre Dernière intervention 17 mars 2008
24 janv. 2008 à 21:06
slt tt le mond
blueyes666 totalement raison car il n y a pa 1 informaticien ds le mond n 'a pa 1 e-mail
et si tu vx qlq support donne moi ton e-mmmmmmmail
sinon............... (j parl avec toi bob007)
0
Utilisateur anonyme
24 janv. 2008 à 21:19
mdr
que vous etes naifs les jeunes....

EDIT: c'en est touchant, vraiment :-)
0
gmailjamal Messages postés 10 Date d'inscription dimanche 20 janvier 2008 Statut Membre Dernière intervention 17 mars 2008
24 janv. 2008 à 21:21
et toi jipicy vs etes 1 ancien membr ds le forum,vs n'avez pa un ou +eurs docs sur ce sujet ,si vs voulez m'aider
,envoyer moi le +vite possibl (voila mn msn :dmx-jamal@hotmail.com )
vrmt merci merci....100000 fois
bon8
0
gmailjamal Messages postés 10 Date d'inscription dimanche 20 janvier 2008 Statut Membre Dernière intervention 17 mars 2008
24 janv. 2008 à 21:29
ds ce cas j pense vs etes tres tres......vieux sov555555555 ,dnc aide ns par votre experience, et laisse tomber lé critique de rien...et je m'excuse si j 'ai dis qlq chose pa bi1
bon8
et vrmt merci merci....100000 fois
0
bob031 Messages postés 8158 Date d'inscription samedi 7 août 2004 Statut Membre Dernière intervention 1 septembre 2014 472
24 janv. 2008 à 21:48
c'est pas sov555555555, mais sov36

ha ! pour en terminer avec : blueyes666 totalement raison car il n y a pa 1 informaticien ds le mond n 'a pa 1 e-mail

..je ne suis pas informaticien ....

....pour ne pas avoir d'adresse electronique c'est tout simple ...il suffit de ne pas avoir l'internet !


...désolé je ne peux rien pour vous !


ps :moi c'est pas bob007 mais bob031
0
gmailjamal Messages postés 10 Date d'inscription dimanche 20 janvier 2008 Statut Membre Dernière intervention 17 mars 2008
27 janv. 2008 à 17:25
salut tt le monde
n'importe quoi sov... ou bob ...
l'essentiele c'est le partage de l'information et la coopération de tt les membres de forum...
meme je trouve qu'il ya 1 grd manque d'information sur ce projet " modification de pgrm d'1 cmd...unix "
je remerci tt les membres et srtt blueyes666.
vrmt merci merci ....100000 fois
0
jipicy Messages postés 40842 Date d'inscription jeudi 28 août 2003 Statut Modérateur Dernière intervention 10 août 2020 4 897
27 janv. 2008 à 17:34
l'essentiele c'est le partage de l'information et la coopération de tt les membres de forum...
Et te faire envoyer les docs sur ton mail tu trouves que c'est du partage ?
C'en est certes, mais du partage d'égoïste alors ;-((

meme je trouve qu'il ya 1 grd manque d'information sur ce projet " modification de pgrm d'1 cmd...unix "
Ben pour ça on compte désormais sur toi pour combler ce manque, en espérant que tu mettes à la disposition de tous la finalité de ton travail dans ce domaine, merci d'avance ;-))

0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
27 janv. 2008 à 20:14
Salut,

meme je trouve qu'il ya 1 grd manque d'information sur ce projet " modification de pgrm d'1 cmd...unix "
tu crois?!

tu n'as qu'à fouiller dans les sources et chercher ce que tu veux modifier

par exemple sous Debian la commande ls se trouve dans /bin/ls
et /bin/ls fait partie de paquetage coreutils
tu peux télécharger les sources ici http://ftp.gnu.org/gnu/coreutils/
et ensuite te mettre au travail ;-)
0
bob031 Messages postés 8158 Date d'inscription samedi 7 août 2004 Statut Membre Dernière intervention 1 septembre 2014 472
27 janv. 2008 à 20:24
Salut,

tu es sûr qu'il y a tout, là ??? -DDDDD

:-))
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
27 janv. 2008 à 20:26
Hello,

tu n'as pas vu la dernière ligne
// trop longue le et je n'a pas pu l'afficher en totalité ;-))
j'ai voulu dire le code??
;-)
0
jipicy Messages postés 40842 Date d'inscription jeudi 28 août 2003 Statut Modérateur Dernière intervention 10 août 2020 4 897 > lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019
27 janv. 2008 à 20:29
trop longue le ...
j'ai voulu dire le code??

Trop long à dire ? Perlien !!!

;-DD
0
blueyes666 Messages postés 10 Date d'inscription mercredi 3 octobre 2007 Statut Membre Dernière intervention 29 juin 2009
27 janv. 2008 à 20:27
salut tt le monde mais t sur que tout ce code est associé a la commande ls?
moi je pense que c'est trop long et j'ai deja fait un truc pareil et ce n'etait pas comme ca!!!!
je pense la que tu as recuperé le code source de la commande ls depuis /bin/ls ??????
pour ma part c t juste une dizaine ou une vaintaine de ligne combiné avec un makefile, un lexer et un parser.
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
27 janv. 2008 à 20:35
Salut,

c'est peut être trop long, mais c'est comme ça ;-)
c'est le contenu du fichier ls.c qui se trouve dans le paquetage coreutiils
0
bob031 Messages postés 8158 Date d'inscription samedi 7 août 2004 Statut Membre Dernière intervention 1 septembre 2014 472
27 janv. 2008 à 21:09
bon allez ! au boulot tout le monde !

:-))
0