No specific user configuration
[platform/upstream/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 /* Returns whether any color sequence was printed. */
102 bool
103 _rl_print_color_indicator (char *f)
104 {
105   enum indicator_no colored_filetype;
106   COLOR_EXT_TYPE *ext;  /* Color extension */
107   size_t len;           /* Length of name */
108
109   const char* name;
110   char *filename;
111   struct stat astat;
112   mode_t mode;
113   int linkok;
114
115   int stat_ok;
116
117   name = f;
118
119   /* This should already have undergone tilde expansion */
120   filename = 0;
121   if (rl_filename_stat_hook)
122     {
123       filename = savestring (f);
124       (*rl_filename_stat_hook) (&filename);
125       name = filename;
126     }
127
128 #if defined (HAVE_LSTAT)
129   stat_ok = lstat(name, &astat);
130 #else
131   stat_ok = stat(name, &astat);
132 #endif
133   if( stat_ok == 0 ) {
134     mode = astat.st_mode;
135     linkok = 1; //f->linkok;
136   }
137   else
138     linkok = -1;
139
140   /* Is this a nonexistent file?  If so, linkok == -1.  */
141
142   if (linkok == -1 && _rl_color_indicator[C_MISSING].string != NULL)
143     colored_filetype = C_MISSING;
144   else if(stat_ok != 0)
145     {
146       static enum indicator_no filetype_indicator[] = FILETYPE_INDICATORS;
147       colored_filetype = filetype_indicator[normal]; //f->filetype];
148     }
149   else
150     {
151       if (S_ISREG (mode))
152         {
153           colored_filetype = C_FILE;
154
155           if ((mode & S_ISUID) != 0 && is_colored (C_SETUID))
156             colored_filetype = C_SETUID;
157           else if ((mode & S_ISGID) != 0 && is_colored (C_SETGID))
158             colored_filetype = C_SETGID;
159           else if (is_colored (C_CAP) && 0) //f->has_capability)
160             colored_filetype = C_CAP;
161           else if ((mode & S_IXUGO) != 0 && is_colored (C_EXEC))
162             colored_filetype = C_EXEC;
163           else if ((1 < astat.st_nlink) && is_colored (C_MULTIHARDLINK))
164             colored_filetype = C_MULTIHARDLINK;
165         }
166       else if (S_ISDIR (mode))
167         {
168           colored_filetype = C_DIR;
169
170 #if defined (S_ISVTX)
171           if ((mode & S_ISVTX) && (mode & S_IWOTH)
172               && is_colored (C_STICKY_OTHER_WRITABLE))
173             colored_filetype = C_STICKY_OTHER_WRITABLE;
174           else
175 #endif
176           if ((mode & S_IWOTH) != 0 && is_colored (C_OTHER_WRITABLE))
177             colored_filetype = C_OTHER_WRITABLE;
178 #if defined (S_ISVTX)
179           else if ((mode & S_ISVTX) != 0 && is_colored (C_STICKY))
180             colored_filetype = C_STICKY;
181 #endif
182         }
183       else if (S_ISLNK (mode))
184         colored_filetype = ((linkok == 0
185                  && (!strncmp (_rl_color_indicator[C_LINK].string, "target", 6)
186                      || _rl_color_indicator[C_ORPHAN].string))
187                 ? C_ORPHAN : C_LINK);
188       else if (S_ISFIFO (mode))
189         colored_filetype = C_FIFO;
190       else if (S_ISSOCK (mode))
191         colored_filetype = C_SOCK;
192       else if (S_ISBLK (mode))
193         colored_filetype = C_BLK;
194       else if (S_ISCHR (mode))
195         colored_filetype = C_CHR;
196       else
197         {
198           /* Classify a file of some other type as C_ORPHAN.  */
199           colored_filetype = C_ORPHAN;
200         }
201     }
202
203   /* Check the file's suffix only if still classified as C_FILE.  */
204   ext = NULL;
205   if (colored_filetype == C_FILE)
206     {
207       /* Test if NAME has a recognized suffix.  */
208       len = strlen (name);
209       name += len;              /* Pointer to final \0.  */
210       for (ext = _rl_color_ext_list; ext != NULL; ext = ext->next)
211         {
212           if (ext->ext.len <= len
213               && strncmp (name - ext->ext.len, ext->ext.string,
214                           ext->ext.len) == 0)
215             break;
216         }
217     }
218
219   free (filename);      /* NULL or savestring return value */
220
221   {
222     const struct bin_str *const s
223       = ext ? &(ext->seq) : &_rl_color_indicator[colored_filetype];
224     if (s->string != NULL)
225       {
226         /* Need to reset so not dealing with attribute combinations */
227         if (is_colored (C_NORM))
228           restore_default_color ();
229         _rl_put_indicator (&_rl_color_indicator[C_LEFT]);
230         _rl_put_indicator (s);
231         _rl_put_indicator (&_rl_color_indicator[C_RIGHT]);
232         return 0;
233       }
234     else
235       return 1;
236   }
237 }
238
239 void
240 _rl_prep_non_filename_text (void)
241 {
242   if (_rl_color_indicator[C_END].string != NULL)
243     _rl_put_indicator (&_rl_color_indicator[C_END]);
244   else
245     {
246       _rl_put_indicator (&_rl_color_indicator[C_LEFT]);
247       _rl_put_indicator (&_rl_color_indicator[C_RESET]);
248       _rl_put_indicator (&_rl_color_indicator[C_RIGHT]);
249     }
250 }
251 #endif /* COLOR_SUPPORT */