| /* `dir', `vdir' and `ls' directory listing programs for GNU. |
| |
| Modified by Chet Ramey for Readline. |
| |
| Copyright (C) 1985, 1988, 1990-1991, 1995-2010, 2012, 2015, 2017, 2019 |
| 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 <http://www.gnu.org/licenses/>. */ |
| |
| /* 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>. */ |
| |
| #define READLINE_LIBRARY |
| |
| #if defined (HAVE_CONFIG_H) |
| # include <config.h> |
| #endif |
| |
| #include "rlconf.h" |
| |
| #if defined __TANDEM |
| # define _XOPEN_SOURCE_EXTENDED 1 |
| # define _TANDEM_SOURCE 1 |
| # include <sys/types.h> |
| # include <sys/stat.h> |
| #endif |
| |
| #include <stdio.h> |
| |
| #include "posixstat.h" // stat related macros (S_ISREG, ...) |
| #include <fcntl.h> // S_ISUID |
| |
| #ifndef S_ISDIR |
| # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
| #endif |
| |
| // strlen() |
| #if defined (HAVE_STRING_H) |
| # include <string.h> |
| #else /* !HAVE_STRING_H */ |
| # include <strings.h> |
| #endif /* !HAVE_STRING_H */ |
| |
| // abort() |
| #if defined (HAVE_STDLIB_H) |
| # include <stdlib.h> |
| #else |
| # include "ansi_stdlib.h" |
| #endif /* HAVE_STDLIB_H */ |
| |
| #include "readline.h" |
| #include "rldefs.h" |
| |
| #ifdef COLOR_SUPPORT |
| |
| #include "xmalloc.h" |
| #include "colors.h" |
| |
| static bool is_colored (enum indicator_no type); |
| static void restore_default_color (void); |
| |
| COLOR_EXT_TYPE *_rl_color_ext_list = 0; |
| |
| /* Output a color indicator (which may contain nulls). */ |
| void |
| _rl_put_indicator (const struct bin_str *ind) |
| { |
| fwrite (ind->string, ind->len, 1, rl_outstream); |
| } |
| |
| static bool |
| is_colored (enum indicator_no colored_filetype) |
| { |
| size_t len = _rl_color_indicator[colored_filetype].len; |
| char const *s = _rl_color_indicator[colored_filetype].string; |
| return ! (len == 0 |
| || (len == 1 && strncmp (s, "0", 1) == 0) |
| || (len == 2 && strncmp (s, "00", 2) == 0)); |
| } |
| |
| static void |
| restore_default_color (void) |
| { |
| _rl_put_indicator (&_rl_color_indicator[C_LEFT]); |
| _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); |
| } |
| |
| void |
| _rl_set_normal_color (void) |
| { |
| if (is_colored (C_NORM)) |
| { |
| _rl_put_indicator (&_rl_color_indicator[C_LEFT]); |
| _rl_put_indicator (&_rl_color_indicator[C_NORM]); |
| _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); |
| } |
| } |
| |
| bool |
| _rl_print_prefix_color (void) |
| { |
| struct bin_str *s; |
| |
| /* What do we want to use for the prefix? Let's try cyan first, see colors.h */ |
| s = &_rl_color_indicator[C_PREFIX]; |
| if (s->string != NULL) |
| { |
| if (is_colored (C_NORM)) |
| restore_default_color (); |
| _rl_put_indicator (&_rl_color_indicator[C_LEFT]); |
| _rl_put_indicator (s); |
| _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); |
| return 0; |
| } |
| else |
| return 1; |
| } |
| |
| /* Returns whether any color sequence was printed. */ |
| bool |
| _rl_print_color_indicator (const char *f) |
| { |
| enum indicator_no colored_filetype; |
| COLOR_EXT_TYPE *ext; /* Color extension */ |
| size_t len; /* Length of name */ |
| |
| const char* name; |
| char *filename; |
| struct stat astat, linkstat; |
| mode_t mode; |
| int linkok; /* 1 == ok, 0 == dangling symlink, -1 == missing */ |
| int stat_ok; |
| |
| name = f; |
| |
| /* This should already have undergone tilde expansion */ |
| filename = 0; |
| if (rl_filename_stat_hook) |
| { |
| filename = savestring (f); |
| (*rl_filename_stat_hook) (&filename); |
| name = filename; |
| } |
| |
| #if defined (HAVE_LSTAT) |
| stat_ok = lstat(name, &astat); |
| #else |
| stat_ok = stat(name, &astat); |
| #endif |
| if (stat_ok == 0) |
| { |
| mode = astat.st_mode; |
| #if defined (HAVE_LSTAT) |
| if (S_ISLNK (mode)) |
| { |
| linkok = stat (name, &linkstat) == 0; |
| if (linkok && strncmp (_rl_color_indicator[C_LINK].string, "target", 6) == 0) |
| mode = linkstat.st_mode; |
| } |
| else |
| #endif |
| linkok = 1; |
| } |
| else |
| linkok = -1; |
| |
| /* Is this a nonexistent file? If so, linkok == -1. */ |
| |
| if (linkok == -1 && _rl_color_indicator[C_MISSING].string != NULL) |
| colored_filetype = C_MISSING; |
| else if (linkok == 0 && _rl_color_indicator[C_ORPHAN].string != NULL) |
| colored_filetype = C_ORPHAN; /* dangling symlink */ |
| else if(stat_ok != 0) |
| { |
| static enum indicator_no filetype_indicator[] = FILETYPE_INDICATORS; |
| colored_filetype = filetype_indicator[normal]; //f->filetype]; |
| } |
| else |
| { |
| if (S_ISREG (mode)) |
| { |
| colored_filetype = C_FILE; |
| |
| #if defined (S_ISUID) |
| if ((mode & S_ISUID) != 0 && is_colored (C_SETUID)) |
| colored_filetype = C_SETUID; |
| else |
| #endif |
| #if defined (S_ISGID) |
| if ((mode & S_ISGID) != 0 && is_colored (C_SETGID)) |
| colored_filetype = C_SETGID; |
| else |
| #endif |
| if (is_colored (C_CAP) && 0) //f->has_capability) |
| colored_filetype = C_CAP; |
| else if ((mode & S_IXUGO) != 0 && is_colored (C_EXEC)) |
| colored_filetype = C_EXEC; |
| else if ((1 < astat.st_nlink) && is_colored (C_MULTIHARDLINK)) |
| colored_filetype = C_MULTIHARDLINK; |
| } |
| else if (S_ISDIR (mode)) |
| { |
| colored_filetype = C_DIR; |
| |
| #if defined (S_ISVTX) |
| if ((mode & S_ISVTX) && (mode & S_IWOTH) |
| && is_colored (C_STICKY_OTHER_WRITABLE)) |
| colored_filetype = C_STICKY_OTHER_WRITABLE; |
| else |
| #endif |
| if ((mode & S_IWOTH) != 0 && is_colored (C_OTHER_WRITABLE)) |
| colored_filetype = C_OTHER_WRITABLE; |
| #if defined (S_ISVTX) |
| else if ((mode & S_ISVTX) != 0 && is_colored (C_STICKY)) |
| colored_filetype = C_STICKY; |
| #endif |
| } |
| #if defined (S_ISLNK) |
| else if (S_ISLNK (mode)) |
| colored_filetype = C_LINK; |
| #endif |
| else if (S_ISFIFO (mode)) |
| colored_filetype = C_FIFO; |
| #if defined (S_ISSOCK) |
| else if (S_ISSOCK (mode)) |
| colored_filetype = C_SOCK; |
| #endif |
| else if (S_ISBLK (mode)) |
| colored_filetype = C_BLK; |
| else if (S_ISCHR (mode)) |
| colored_filetype = C_CHR; |
| else |
| { |
| /* Classify a file of some other type as C_ORPHAN. */ |
| colored_filetype = C_ORPHAN; |
| } |
| } |
| |
| /* Check the file's suffix only if still classified as C_FILE. */ |
| ext = NULL; |
| if (colored_filetype == C_FILE) |
| { |
| /* Test if NAME has a recognized suffix. */ |
| len = strlen (name); |
| name += len; /* Pointer to final \0. */ |
| for (ext = _rl_color_ext_list; ext != NULL; ext = ext->next) |
| { |
| if (ext->ext.len <= len |
| && strncmp (name - ext->ext.len, ext->ext.string, |
| ext->ext.len) == 0) |
| break; |
| } |
| } |
| |
| free (filename); /* NULL or savestring return value */ |
| |
| { |
| const struct bin_str *const s |
| = ext ? &(ext->seq) : &_rl_color_indicator[colored_filetype]; |
| if (s->string != NULL) |
| { |
| /* Need to reset so not dealing with attribute combinations */ |
| if (is_colored (C_NORM)) |
| restore_default_color (); |
| _rl_put_indicator (&_rl_color_indicator[C_LEFT]); |
| _rl_put_indicator (s); |
| _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); |
| return 0; |
| } |
| else |
| return 1; |
| } |
| } |
| |
| void |
| _rl_prep_non_filename_text (void) |
| { |
| if (_rl_color_indicator[C_END].string != NULL) |
| _rl_put_indicator (&_rl_color_indicator[C_END]); |
| else |
| { |
| _rl_put_indicator (&_rl_color_indicator[C_LEFT]); |
| _rl_put_indicator (&_rl_color_indicator[C_RESET]); |
| _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); |
| } |
| } |
| #endif /* COLOR_SUPPORT */ |