Commit | Line | Data |
---|---|---|
775e241e TT |
1 | /* `dir', `vdir' and `ls' directory listing programs for GNU. |
2 | ||
3 | Modified by Chet Ramey for Readline. | |
4 | ||
cb41b9e7 | 5 | Copyright (C) 1985, 1988, 1990-1991, 1995-2010, 2012, 2015, 2017 |
775e241e TT |
6 | Free Software Foundation, Inc. |
7 | ||
8 | This program is free software: you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation, either version 3 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | This program is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
20 | ||
21 | /* Written by Richard Stallman and David MacKenzie. */ | |
22 | ||
23 | /* Color support by Peter Anvin <Peter.Anvin@linux.org> and Dennis | |
24 | Flaherty <dennisf@denix.elk.miles.com> based on original patches by | |
25 | Greg Lee <lee@uhunix.uhcc.hawaii.edu>. */ | |
26 | ||
27 | #define READLINE_LIBRARY | |
28 | ||
29 | #if defined (HAVE_CONFIG_H) | |
30 | # include <config.h> | |
31 | #endif | |
32 | ||
33 | #include "rlconf.h" | |
34 | ||
35 | #include <stdio.h> | |
36 | ||
37 | #include "posixstat.h" // stat related macros (S_ISREG, ...) | |
38 | #include <fcntl.h> // S_ISUID | |
39 | ||
cb41b9e7 TT |
40 | #ifndef S_ISDIR |
41 | # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) | |
42 | #endif | |
43 | ||
775e241e TT |
44 | // strlen() |
45 | #if defined (HAVE_STRING_H) | |
46 | # include <string.h> | |
47 | #else /* !HAVE_STRING_H */ | |
48 | # include <strings.h> | |
49 | #endif /* !HAVE_STRING_H */ | |
50 | ||
51 | // abort() | |
52 | #if defined (HAVE_STDLIB_H) | |
53 | # include <stdlib.h> | |
54 | #else | |
55 | # include "ansi_stdlib.h" | |
56 | #endif /* HAVE_STDLIB_H */ | |
57 | ||
58 | #include "readline.h" | |
59 | #include "rldefs.h" | |
60 | ||
61 | #ifdef COLOR_SUPPORT | |
62 | ||
63 | #include "xmalloc.h" | |
64 | #include "colors.h" | |
65 | ||
66 | static bool is_colored (enum indicator_no type); | |
67 | static void restore_default_color (void); | |
68 | ||
69 | COLOR_EXT_TYPE *_rl_color_ext_list = 0; | |
70 | ||
71 | /* Output a color indicator (which may contain nulls). */ | |
72 | void | |
cb41b9e7 TT |
73 | _rl_put_indicator (const struct bin_str *ind) |
74 | { | |
775e241e TT |
75 | fwrite (ind->string, ind->len, 1, rl_outstream); |
76 | } | |
77 | ||
78 | static bool | |
79 | is_colored (enum indicator_no colored_filetype) | |
80 | { | |
81 | size_t len = _rl_color_indicator[colored_filetype].len; | |
82 | char const *s = _rl_color_indicator[colored_filetype].string; | |
83 | return ! (len == 0 | |
84 | || (len == 1 && strncmp (s, "0", 1) == 0) | |
85 | || (len == 2 && strncmp (s, "00", 2) == 0)); | |
86 | } | |
87 | ||
88 | static void | |
89 | restore_default_color (void) | |
90 | { | |
91 | _rl_put_indicator (&_rl_color_indicator[C_LEFT]); | |
92 | _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); | |
93 | } | |
94 | ||
95 | void | |
96 | _rl_set_normal_color (void) | |
97 | { | |
98 | if (is_colored (C_NORM)) | |
99 | { | |
100 | _rl_put_indicator (&_rl_color_indicator[C_LEFT]); | |
101 | _rl_put_indicator (&_rl_color_indicator[C_NORM]); | |
102 | _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); | |
103 | } | |
104 | } | |
105 | ||
106 | bool | |
107 | _rl_print_prefix_color (void) | |
108 | { | |
109 | struct bin_str *s; | |
110 | ||
111 | /* What do we want to use for the prefix? Let's try cyan first, see colors.h */ | |
112 | s = &_rl_color_indicator[C_PREFIX]; | |
113 | if (s->string != NULL) | |
114 | { | |
115 | if (is_colored (C_NORM)) | |
116 | restore_default_color (); | |
117 | _rl_put_indicator (&_rl_color_indicator[C_LEFT]); | |
118 | _rl_put_indicator (s); | |
119 | _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); | |
120 | return 0; | |
121 | } | |
122 | else | |
123 | return 1; | |
124 | } | |
125 | ||
126 | /* Returns whether any color sequence was printed. */ | |
127 | bool | |
128 | _rl_print_color_indicator (const char *f) | |
129 | { | |
130 | enum indicator_no colored_filetype; | |
131 | COLOR_EXT_TYPE *ext; /* Color extension */ | |
132 | size_t len; /* Length of name */ | |
133 | ||
134 | const char* name; | |
135 | char *filename; | |
136 | struct stat astat, linkstat; | |
137 | mode_t mode; | |
138 | int linkok; /* 1 == ok, 0 == dangling symlink, -1 == missing */ | |
139 | int stat_ok; | |
140 | ||
141 | name = f; | |
142 | ||
143 | /* This should already have undergone tilde expansion */ | |
144 | filename = 0; | |
145 | if (rl_filename_stat_hook) | |
146 | { | |
147 | filename = savestring (f); | |
148 | (*rl_filename_stat_hook) (&filename); | |
149 | name = filename; | |
150 | } | |
151 | ||
152 | #if defined (HAVE_LSTAT) | |
153 | stat_ok = lstat(name, &astat); | |
154 | #else | |
155 | stat_ok = stat(name, &astat); | |
156 | #endif | |
157 | if (stat_ok == 0) | |
158 | { | |
159 | mode = astat.st_mode; | |
160 | #if defined (HAVE_LSTAT) | |
161 | if (S_ISLNK (mode)) | |
162 | { | |
163 | linkok = stat (name, &linkstat) == 0; | |
164 | if (linkok && strncmp (_rl_color_indicator[C_LINK].string, "target", 6) == 0) | |
165 | mode = linkstat.st_mode; | |
166 | } | |
167 | else | |
168 | #endif | |
169 | linkok = 1; | |
170 | } | |
171 | else | |
172 | linkok = -1; | |
173 | ||
174 | /* Is this a nonexistent file? If so, linkok == -1. */ | |
175 | ||
176 | if (linkok == -1 && _rl_color_indicator[C_MISSING].string != NULL) | |
177 | colored_filetype = C_MISSING; | |
01116842 | 178 | else if (linkok == 0 && _rl_color_indicator[C_ORPHAN].string != NULL) |
775e241e TT |
179 | colored_filetype = C_ORPHAN; /* dangling symlink */ |
180 | else if(stat_ok != 0) | |
181 | { | |
182 | static enum indicator_no filetype_indicator[] = FILETYPE_INDICATORS; | |
183 | colored_filetype = filetype_indicator[normal]; //f->filetype]; | |
184 | } | |
185 | else | |
186 | { | |
187 | if (S_ISREG (mode)) | |
188 | { | |
189 | colored_filetype = C_FILE; | |
190 | ||
cb41b9e7 | 191 | #if defined (S_ISUID) |
775e241e TT |
192 | if ((mode & S_ISUID) != 0 && is_colored (C_SETUID)) |
193 | colored_filetype = C_SETUID; | |
cb41b9e7 TT |
194 | else |
195 | #endif | |
196 | #if defined (S_ISGID) | |
197 | if ((mode & S_ISGID) != 0 && is_colored (C_SETGID)) | |
775e241e | 198 | colored_filetype = C_SETGID; |
cb41b9e7 TT |
199 | else |
200 | #endif | |
201 | if (is_colored (C_CAP) && 0) //f->has_capability) | |
775e241e TT |
202 | colored_filetype = C_CAP; |
203 | else if ((mode & S_IXUGO) != 0 && is_colored (C_EXEC)) | |
204 | colored_filetype = C_EXEC; | |
205 | else if ((1 < astat.st_nlink) && is_colored (C_MULTIHARDLINK)) | |
206 | colored_filetype = C_MULTIHARDLINK; | |
207 | } | |
208 | else if (S_ISDIR (mode)) | |
209 | { | |
210 | colored_filetype = C_DIR; | |
211 | ||
212 | #if defined (S_ISVTX) | |
213 | if ((mode & S_ISVTX) && (mode & S_IWOTH) | |
214 | && is_colored (C_STICKY_OTHER_WRITABLE)) | |
215 | colored_filetype = C_STICKY_OTHER_WRITABLE; | |
216 | else | |
217 | #endif | |
218 | if ((mode & S_IWOTH) != 0 && is_colored (C_OTHER_WRITABLE)) | |
219 | colored_filetype = C_OTHER_WRITABLE; | |
220 | #if defined (S_ISVTX) | |
221 | else if ((mode & S_ISVTX) != 0 && is_colored (C_STICKY)) | |
222 | colored_filetype = C_STICKY; | |
223 | #endif | |
224 | } | |
cb41b9e7 | 225 | #if defined (S_ISLNK) |
775e241e TT |
226 | else if (S_ISLNK (mode)) |
227 | colored_filetype = C_LINK; | |
cb41b9e7 | 228 | #endif |
775e241e TT |
229 | else if (S_ISFIFO (mode)) |
230 | colored_filetype = C_FIFO; | |
cb41b9e7 | 231 | #if defined (S_ISSOCK) |
775e241e TT |
232 | else if (S_ISSOCK (mode)) |
233 | colored_filetype = C_SOCK; | |
cb41b9e7 | 234 | #endif |
775e241e TT |
235 | else if (S_ISBLK (mode)) |
236 | colored_filetype = C_BLK; | |
237 | else if (S_ISCHR (mode)) | |
238 | colored_filetype = C_CHR; | |
239 | else | |
240 | { | |
241 | /* Classify a file of some other type as C_ORPHAN. */ | |
242 | colored_filetype = C_ORPHAN; | |
243 | } | |
244 | } | |
245 | ||
246 | /* Check the file's suffix only if still classified as C_FILE. */ | |
247 | ext = NULL; | |
248 | if (colored_filetype == C_FILE) | |
249 | { | |
250 | /* Test if NAME has a recognized suffix. */ | |
251 | len = strlen (name); | |
252 | name += len; /* Pointer to final \0. */ | |
253 | for (ext = _rl_color_ext_list; ext != NULL; ext = ext->next) | |
254 | { | |
255 | if (ext->ext.len <= len | |
256 | && strncmp (name - ext->ext.len, ext->ext.string, | |
257 | ext->ext.len) == 0) | |
258 | break; | |
259 | } | |
260 | } | |
261 | ||
262 | free (filename); /* NULL or savestring return value */ | |
263 | ||
264 | { | |
265 | const struct bin_str *const s | |
266 | = ext ? &(ext->seq) : &_rl_color_indicator[colored_filetype]; | |
267 | if (s->string != NULL) | |
268 | { | |
269 | /* Need to reset so not dealing with attribute combinations */ | |
270 | if (is_colored (C_NORM)) | |
271 | restore_default_color (); | |
272 | _rl_put_indicator (&_rl_color_indicator[C_LEFT]); | |
273 | _rl_put_indicator (s); | |
274 | _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); | |
275 | return 0; | |
276 | } | |
277 | else | |
278 | return 1; | |
279 | } | |
280 | } | |
281 | ||
282 | void | |
283 | _rl_prep_non_filename_text (void) | |
284 | { | |
285 | if (_rl_color_indicator[C_END].string != NULL) | |
286 | _rl_put_indicator (&_rl_color_indicator[C_END]); | |
287 | else | |
288 | { | |
289 | _rl_put_indicator (&_rl_color_indicator[C_LEFT]); | |
290 | _rl_put_indicator (&_rl_color_indicator[C_RESET]); | |
291 | _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); | |
292 | } | |
293 | } | |
294 | #endif /* COLOR_SUPPORT */ |