Automatic date update in version.in
[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, 2017
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 #ifndef S_ISDIR
41 #  define       S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
42 #endif
43
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
73 _rl_put_indicator (const struct bin_str *ind)
74 {
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;
178   else if (linkok == 0 && _rl_color_indicator[C_ORPHAN].string != NULL)
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
191 #if defined (S_ISUID)
192           if ((mode & S_ISUID) != 0 && is_colored (C_SETUID))
193             colored_filetype = C_SETUID;
194           else
195 #endif
196 #if defined (S_ISGID)
197           if ((mode & S_ISGID) != 0 && is_colored (C_SETGID))
198             colored_filetype = C_SETGID;
199           else
200 #endif
201           if (is_colored (C_CAP) && 0) //f->has_capability)
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         }
225 #if defined (S_ISLNK)
226       else if (S_ISLNK (mode))
227         colored_filetype = C_LINK;
228 #endif
229       else if (S_ISFIFO (mode))
230         colored_filetype = C_FIFO;
231 #if defined (S_ISSOCK)
232       else if (S_ISSOCK (mode))
233         colored_filetype = C_SOCK;
234 #endif
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 */