Commit | Line | Data |
---|---|---|
775e241e TT |
1 | /* `dir', `vdir' and `ls' directory listing programs for GNU. |
2 | ||
3 | Modified by Chet Ramey for Readline. | |
4 | ||
b4f26d54 | 5 | Copyright (C) 1985, 1988, 1990-1991, 1995-2010, 2012, 2015, 2017, 2019 |
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 | ||
b4f26d54 TT |
35 | #if defined __TANDEM |
36 | # define _XOPEN_SOURCE_EXTENDED 1 | |
37 | # define _TANDEM_SOURCE 1 | |
38 | # include <sys/types.h> | |
39 | # include <sys/stat.h> | |
40 | #endif | |
41 | ||
775e241e TT |
42 | #include <stdio.h> |
43 | ||
44 | #include "posixstat.h" // stat related macros (S_ISREG, ...) | |
45 | #include <fcntl.h> // S_ISUID | |
46 | ||
cb41b9e7 TT |
47 | #ifndef S_ISDIR |
48 | # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) | |
49 | #endif | |
50 | ||
775e241e TT |
51 | // strlen() |
52 | #if defined (HAVE_STRING_H) | |
53 | # include <string.h> | |
54 | #else /* !HAVE_STRING_H */ | |
55 | # include <strings.h> | |
56 | #endif /* !HAVE_STRING_H */ | |
57 | ||
58 | // abort() | |
59 | #if defined (HAVE_STDLIB_H) | |
60 | # include <stdlib.h> | |
61 | #else | |
62 | # include "ansi_stdlib.h" | |
63 | #endif /* HAVE_STDLIB_H */ | |
64 | ||
65 | #include "readline.h" | |
66 | #include "rldefs.h" | |
67 | ||
68 | #ifdef COLOR_SUPPORT | |
69 | ||
70 | #include "xmalloc.h" | |
71 | #include "colors.h" | |
72 | ||
73 | static bool is_colored (enum indicator_no type); | |
74 | static void restore_default_color (void); | |
75 | ||
76 | COLOR_EXT_TYPE *_rl_color_ext_list = 0; | |
77 | ||
78 | /* Output a color indicator (which may contain nulls). */ | |
79 | void | |
cb41b9e7 TT |
80 | _rl_put_indicator (const struct bin_str *ind) |
81 | { | |
775e241e TT |
82 | fwrite (ind->string, ind->len, 1, rl_outstream); |
83 | } | |
84 | ||
85 | static bool | |
86 | is_colored (enum indicator_no colored_filetype) | |
87 | { | |
88 | size_t len = _rl_color_indicator[colored_filetype].len; | |
89 | char const *s = _rl_color_indicator[colored_filetype].string; | |
90 | return ! (len == 0 | |
91 | || (len == 1 && strncmp (s, "0", 1) == 0) | |
92 | || (len == 2 && strncmp (s, "00", 2) == 0)); | |
93 | } | |
94 | ||
95 | static void | |
96 | restore_default_color (void) | |
97 | { | |
98 | _rl_put_indicator (&_rl_color_indicator[C_LEFT]); | |
99 | _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); | |
100 | } | |
101 | ||
102 | void | |
103 | _rl_set_normal_color (void) | |
104 | { | |
105 | if (is_colored (C_NORM)) | |
106 | { | |
107 | _rl_put_indicator (&_rl_color_indicator[C_LEFT]); | |
108 | _rl_put_indicator (&_rl_color_indicator[C_NORM]); | |
109 | _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); | |
110 | } | |
111 | } | |
112 | ||
113 | bool | |
114 | _rl_print_prefix_color (void) | |
115 | { | |
116 | struct bin_str *s; | |
117 | ||
118 | /* What do we want to use for the prefix? Let's try cyan first, see colors.h */ | |
119 | s = &_rl_color_indicator[C_PREFIX]; | |
120 | if (s->string != NULL) | |
121 | { | |
122 | if (is_colored (C_NORM)) | |
123 | restore_default_color (); | |
124 | _rl_put_indicator (&_rl_color_indicator[C_LEFT]); | |
125 | _rl_put_indicator (s); | |
126 | _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); | |
127 | return 0; | |
128 | } | |
129 | else | |
130 | return 1; | |
131 | } | |
132 | ||
133 | /* Returns whether any color sequence was printed. */ | |
134 | bool | |
135 | _rl_print_color_indicator (const char *f) | |
136 | { | |
137 | enum indicator_no colored_filetype; | |
138 | COLOR_EXT_TYPE *ext; /* Color extension */ | |
139 | size_t len; /* Length of name */ | |
140 | ||
141 | const char* name; | |
142 | char *filename; | |
143 | struct stat astat, linkstat; | |
144 | mode_t mode; | |
145 | int linkok; /* 1 == ok, 0 == dangling symlink, -1 == missing */ | |
146 | int stat_ok; | |
147 | ||
148 | name = f; | |
149 | ||
150 | /* This should already have undergone tilde expansion */ | |
151 | filename = 0; | |
152 | if (rl_filename_stat_hook) | |
153 | { | |
154 | filename = savestring (f); | |
155 | (*rl_filename_stat_hook) (&filename); | |
156 | name = filename; | |
157 | } | |
158 | ||
159 | #if defined (HAVE_LSTAT) | |
160 | stat_ok = lstat(name, &astat); | |
161 | #else | |
162 | stat_ok = stat(name, &astat); | |
163 | #endif | |
164 | if (stat_ok == 0) | |
165 | { | |
166 | mode = astat.st_mode; | |
167 | #if defined (HAVE_LSTAT) | |
168 | if (S_ISLNK (mode)) | |
169 | { | |
170 | linkok = stat (name, &linkstat) == 0; | |
171 | if (linkok && strncmp (_rl_color_indicator[C_LINK].string, "target", 6) == 0) | |
172 | mode = linkstat.st_mode; | |
173 | } | |
174 | else | |
175 | #endif | |
176 | linkok = 1; | |
177 | } | |
178 | else | |
179 | linkok = -1; | |
180 | ||
181 | /* Is this a nonexistent file? If so, linkok == -1. */ | |
182 | ||
183 | if (linkok == -1 && _rl_color_indicator[C_MISSING].string != NULL) | |
184 | colored_filetype = C_MISSING; | |
01116842 | 185 | else if (linkok == 0 && _rl_color_indicator[C_ORPHAN].string != NULL) |
775e241e TT |
186 | colored_filetype = C_ORPHAN; /* dangling symlink */ |
187 | else if(stat_ok != 0) | |
188 | { | |
189 | static enum indicator_no filetype_indicator[] = FILETYPE_INDICATORS; | |
190 | colored_filetype = filetype_indicator[normal]; //f->filetype]; | |
191 | } | |
192 | else | |
193 | { | |
194 | if (S_ISREG (mode)) | |
195 | { | |
196 | colored_filetype = C_FILE; | |
197 | ||
cb41b9e7 | 198 | #if defined (S_ISUID) |
775e241e TT |
199 | if ((mode & S_ISUID) != 0 && is_colored (C_SETUID)) |
200 | colored_filetype = C_SETUID; | |
cb41b9e7 TT |
201 | else |
202 | #endif | |
203 | #if defined (S_ISGID) | |
204 | if ((mode & S_ISGID) != 0 && is_colored (C_SETGID)) | |
775e241e | 205 | colored_filetype = C_SETGID; |
cb41b9e7 TT |
206 | else |
207 | #endif | |
208 | if (is_colored (C_CAP) && 0) //f->has_capability) | |
775e241e TT |
209 | colored_filetype = C_CAP; |
210 | else if ((mode & S_IXUGO) != 0 && is_colored (C_EXEC)) | |
211 | colored_filetype = C_EXEC; | |
212 | else if ((1 < astat.st_nlink) && is_colored (C_MULTIHARDLINK)) | |
213 | colored_filetype = C_MULTIHARDLINK; | |
214 | } | |
215 | else if (S_ISDIR (mode)) | |
216 | { | |
217 | colored_filetype = C_DIR; | |
218 | ||
219 | #if defined (S_ISVTX) | |
220 | if ((mode & S_ISVTX) && (mode & S_IWOTH) | |
221 | && is_colored (C_STICKY_OTHER_WRITABLE)) | |
222 | colored_filetype = C_STICKY_OTHER_WRITABLE; | |
223 | else | |
224 | #endif | |
225 | if ((mode & S_IWOTH) != 0 && is_colored (C_OTHER_WRITABLE)) | |
226 | colored_filetype = C_OTHER_WRITABLE; | |
227 | #if defined (S_ISVTX) | |
228 | else if ((mode & S_ISVTX) != 0 && is_colored (C_STICKY)) | |
229 | colored_filetype = C_STICKY; | |
230 | #endif | |
231 | } | |
cb41b9e7 | 232 | #if defined (S_ISLNK) |
775e241e TT |
233 | else if (S_ISLNK (mode)) |
234 | colored_filetype = C_LINK; | |
cb41b9e7 | 235 | #endif |
775e241e TT |
236 | else if (S_ISFIFO (mode)) |
237 | colored_filetype = C_FIFO; | |
cb41b9e7 | 238 | #if defined (S_ISSOCK) |
775e241e TT |
239 | else if (S_ISSOCK (mode)) |
240 | colored_filetype = C_SOCK; | |
cb41b9e7 | 241 | #endif |
775e241e TT |
242 | else if (S_ISBLK (mode)) |
243 | colored_filetype = C_BLK; | |
244 | else if (S_ISCHR (mode)) | |
245 | colored_filetype = C_CHR; | |
246 | else | |
247 | { | |
248 | /* Classify a file of some other type as C_ORPHAN. */ | |
249 | colored_filetype = C_ORPHAN; | |
250 | } | |
251 | } | |
252 | ||
253 | /* Check the file's suffix only if still classified as C_FILE. */ | |
254 | ext = NULL; | |
255 | if (colored_filetype == C_FILE) | |
256 | { | |
257 | /* Test if NAME has a recognized suffix. */ | |
258 | len = strlen (name); | |
259 | name += len; /* Pointer to final \0. */ | |
260 | for (ext = _rl_color_ext_list; ext != NULL; ext = ext->next) | |
261 | { | |
262 | if (ext->ext.len <= len | |
263 | && strncmp (name - ext->ext.len, ext->ext.string, | |
264 | ext->ext.len) == 0) | |
265 | break; | |
266 | } | |
267 | } | |
268 | ||
269 | free (filename); /* NULL or savestring return value */ | |
270 | ||
271 | { | |
272 | const struct bin_str *const s | |
273 | = ext ? &(ext->seq) : &_rl_color_indicator[colored_filetype]; | |
274 | if (s->string != NULL) | |
275 | { | |
276 | /* Need to reset so not dealing with attribute combinations */ | |
277 | if (is_colored (C_NORM)) | |
278 | restore_default_color (); | |
279 | _rl_put_indicator (&_rl_color_indicator[C_LEFT]); | |
280 | _rl_put_indicator (s); | |
281 | _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); | |
282 | return 0; | |
283 | } | |
284 | else | |
285 | return 1; | |
286 | } | |
287 | } | |
288 | ||
289 | void | |
290 | _rl_prep_non_filename_text (void) | |
291 | { | |
292 | if (_rl_color_indicator[C_END].string != NULL) | |
293 | _rl_put_indicator (&_rl_color_indicator[C_END]); | |
294 | else | |
295 | { | |
296 | _rl_put_indicator (&_rl_color_indicator[C_LEFT]); | |
297 | _rl_put_indicator (&_rl_color_indicator[C_RESET]); | |
298 | _rl_put_indicator (&_rl_color_indicator[C_RIGHT]); | |
299 | } | |
300 | } | |
301 | #endif /* COLOR_SUPPORT */ |