Import readline 7.0 (patch 5)
[external/binutils.git] / 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, 2015
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
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 */