]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/readline/colors.c
bash-4.4 beta release
[thirdparty/bash.git] / lib / readline / colors.c
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 (const 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 */