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