xref: /netbsd-src/external/gpl3/gdb/dist/readline/readline/colors.c (revision 4b169a6ba595ae283ca507b26b15fdff40495b1c)
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, 2019
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 #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 
42 #include <stdio.h>
43 
44 #include "posixstat.h" // stat related macros (S_ISREG, ...)
45 #include <fcntl.h> // S_ISUID
46 
47 #ifndef S_ISDIR
48 #  define	S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
49 #endif
50 
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
_rl_put_indicator(const struct bin_str * ind)80 _rl_put_indicator (const struct bin_str *ind)
81 {
82   fwrite (ind->string, ind->len, 1, rl_outstream);
83 }
84 
85 static bool
is_colored(enum indicator_no colored_filetype)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
restore_default_color(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
_rl_set_normal_color(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
_rl_print_prefix_color(void)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
_rl_print_color_indicator(const char * f)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;
185   else if (linkok == 0 && _rl_color_indicator[C_ORPHAN].string != NULL)
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 
198 #if defined (S_ISUID)
199           if ((mode & S_ISUID) != 0 && is_colored (C_SETUID))
200             colored_filetype = C_SETUID;
201           else
202 #endif
203 #if defined (S_ISGID)
204           if ((mode & S_ISGID) != 0 && is_colored (C_SETGID))
205             colored_filetype = C_SETGID;
206           else
207 #endif
208           if (is_colored (C_CAP) && 0) //f->has_capability)
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         }
232 #if defined (S_ISLNK)
233       else if (S_ISLNK (mode))
234         colored_filetype = C_LINK;
235 #endif
236       else if (S_ISFIFO (mode))
237         colored_filetype = C_FIFO;
238 #if defined (S_ISSOCK)
239       else if (S_ISSOCK (mode))
240         colored_filetype = C_SOCK;
241 #endif
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
_rl_prep_non_filename_text(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 */
302