1 /* `dir', `vdir' and `ls' directory listing programs for GNU.
3 Modified by Chet Ramey for Readline.
5 Copyright (C) 1985, 1988, 1990-1991, 1995-2010, 2012, 2017
6 Free Software Foundation, Inc.
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.
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.
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/>. */
21 /* Written by Richard Stallman and David MacKenzie. */
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>. */
27 #define READLINE_LIBRARY
29 #if defined (HAVE_CONFIG_H)
35 // strdup() / strcpy()
36 #if defined (HAVE_STRING_H)
38 #else /* !HAVE_STRING_H */
40 #endif /* !HAVE_STRING_H */
43 #if defined (HAVE_STDLIB_H)
46 # include "ansi_stdlib.h"
47 #endif /* HAVE_STDLIB_H */
49 #include "rldefs.h" // STREQ, savestring
51 #include "rlprivate.h"
56 #include "parse-colors.h"
58 #if defined (COLOR_SUPPORT)
60 static bool get_funky_string (char **dest
, const char **src
, bool equals_end
, size_t *output_count
);
62 struct bin_str _rl_color_indicator
[] =
64 { LEN_STR_PAIR ("\033[") }, // lc: Left of color sequence
65 { LEN_STR_PAIR ("m") }, // rc: Right of color sequence
66 { 0, NULL
}, // ec: End color (replaces lc+no+rc)
67 { LEN_STR_PAIR ("0") }, // rs: Reset to ordinary colors
68 { 0, NULL
}, // no: Normal
69 { 0, NULL
}, // fi: File: default
70 { LEN_STR_PAIR ("01;34") }, // di: Directory: bright blue
71 { LEN_STR_PAIR ("01;36") }, // ln: Symlink: bright cyan
72 { LEN_STR_PAIR ("33") }, // pi: Pipe: yellow/brown
73 { LEN_STR_PAIR ("01;35") }, // so: Socket: bright magenta
74 { LEN_STR_PAIR ("01;33") }, // bd: Block device: bright yellow
75 { LEN_STR_PAIR ("01;33") }, // cd: Char device: bright yellow
76 { 0, NULL
}, // mi: Missing file: undefined
77 { 0, NULL
}, // or: Orphaned symlink: undefined
78 { LEN_STR_PAIR ("01;32") }, // ex: Executable: bright green
79 { LEN_STR_PAIR ("01;35") }, // do: Door: bright magenta
80 { LEN_STR_PAIR ("37;41") }, // su: setuid: white on red
81 { LEN_STR_PAIR ("30;43") }, // sg: setgid: black on yellow
82 { LEN_STR_PAIR ("37;44") }, // st: sticky: black on blue
83 { LEN_STR_PAIR ("34;42") }, // ow: other-writable: blue on green
84 { LEN_STR_PAIR ("30;42") }, // tw: ow w/ sticky: black on green
85 { LEN_STR_PAIR ("30;41") }, // ca: black on red
86 { 0, NULL
}, // mh: disabled by default
87 { LEN_STR_PAIR ("\033[K") }, // cl: clear to end of line
90 /* Parse a string as part of the LS_COLORS variable; this may involve
91 decoding all kinds of escape characters. If equals_end is set an
92 unescaped equal sign ends the string, otherwise only a : or \0
93 does. Set *OUTPUT_COUNT to the number of bytes output. Return
96 The resulting string is *not* null-terminated, but may contain
99 Note that both dest and src are char **; on return they point to
100 the first free byte after the array and the character that ended
101 the input string, respectively. */
104 get_funky_string (char **dest
, const char **src
, bool equals_end
, size_t *output_count
) {
105 char num
; /* For numerical codes */
106 size_t count
; /* Something to count with */
108 ST_GND
, ST_BACKSLASH
, ST_OCTAL
, ST_HEX
, ST_CARET
, ST_END
, ST_ERROR
113 p
= *src
; /* We don't want to double-indirect */
114 q
= *dest
; /* the whole darn time. */
116 count
= 0; /* No characters counted in yet. */
119 state
= ST_GND
; /* Start in ground state. */
120 while (state
< ST_END
)
124 case ST_GND
: /* Ground state (no escapes) */
129 state
= ST_END
; /* End of string */
132 state
= ST_BACKSLASH
; /* Backslash scape sequence */
136 state
= ST_CARET
; /* Caret escape */
142 state
= ST_END
; /* End */
145 /* else fall through */
153 case ST_BACKSLASH
: /* Backslash escaped character */
164 state
= ST_OCTAL
; /* Octal sequence */
169 state
= ST_HEX
; /* Hex sequence */
175 case 'b': /* Backspace */
178 case 'e': /* Escape */
181 case 'f': /* Form feed */
184 case 'n': /* Newline */
187 case 'r': /* Carriage return */
196 case '?': /* Delete */
199 case '_': /* Space */
202 case '\0': /* End of string */
203 state
= ST_ERROR
; /* Error! */
205 default: /* Escaped character like \ ^ : = */
209 if (state
== ST_BACKSLASH
)
218 case ST_OCTAL
: /* Octal sequence */
219 if (*p
< '0' || *p
> '7')
226 num
= (num
<< 3) + (*(p
++) - '0');
229 case ST_HEX
: /* Hex sequence */
242 num
= (num
<< 4) + (*(p
++) - '0');
250 num
= (num
<< 4) + (*(p
++) - 'a') + 10;
258 num
= (num
<< 4) + (*(p
++) - 'A') + 10;
268 case ST_CARET
: /* Caret escape */
269 state
= ST_GND
; /* Should be the next state... */
270 if (*p
>= '@' && *p
<= '~')
272 *(q
++) = *(p
++) & 037;
286 /* abort (); no, we should not */
294 *output_count
= count
;
296 return state
!= ST_ERROR
;
298 #endif /* COLOR_SUPPORT */
300 void _rl_parse_colors(void)
302 #if defined (COLOR_SUPPORT)
303 const char *p
; /* Pointer to character being parsed */
304 char *buf
; /* color_buf buffer pointer */
305 int state
; /* State of parser */
306 int ind_no
; /* Indicator number */
307 char label
[3]; /* Indicator label */
308 COLOR_EXT_TYPE
*ext
; /* Extension we are working on */
310 p
= sh_get_env_value ("LS_COLORS");
311 if (p
== 0 || *p
== '\0')
313 _rl_color_ext_list
= NULL
;
318 strcpy (label
, "??");
320 /* This is an overly conservative estimate, but any possible
321 LS_COLORS string will *not* generate a color_buf longer than
322 itself, so it is a safe way of allocating a buffer in
324 buf
= color_buf
= savestring (p
);
331 case 1: /* First label character */
339 /* Allocate new extension block and add to head of
340 linked list (this way a later definition will
341 override an earlier one, which can be useful for
342 having terminal-specific defs override global). */
344 ext
= (COLOR_EXT_TYPE
*)xmalloc (sizeof *ext
);
345 ext
->next
= _rl_color_ext_list
;
346 _rl_color_ext_list
= ext
;
349 ext
->ext
.string
= buf
;
351 state
= (get_funky_string (&buf
, &p
, true, &ext
->ext
.len
)
356 state
= 0; /* Done! */
359 default: /* Assume it is file type label */
366 case 2: /* Second label character */
373 state
= -1; /* Error */
376 case 3: /* Equal sign after indicator label */
377 state
= -1; /* Assume failure... */
378 if (*(p
++) == '=')/* It *should* be... */
380 for (ind_no
= 0; indicator_name
[ind_no
] != NULL
; ++ind_no
)
382 if (STREQ (label
, indicator_name
[ind_no
]))
384 _rl_color_indicator
[ind_no
].string
= buf
;
385 state
= (get_funky_string (&buf
, &p
, false,
386 &_rl_color_indicator
[ind_no
].len
)
393 _rl_errmsg ("LS_COLORS: unrecognized prefix: %s", label
);
394 /* recover from an unrecognized prefix */
395 while (p
&& *p
&& *p
!= ':')
399 else if (p
&& *p
== 0)
405 case 4: /* Equal sign after *.ext */
408 ext
->seq
.string
= buf
;
409 state
= (get_funky_string (&buf
, &p
, false, &ext
->seq
.len
)
414 /* XXX - recover here as with an unrecognized prefix? */
415 if (state
== -1 && ext
->ext
.string
)
416 _rl_errmsg ("LS_COLORS: syntax error: %s", ext
->ext
.string
);
426 _rl_errmsg ("unparsable value for LS_COLORS environment variable");
428 for (e
= _rl_color_ext_list
; e
!= NULL
; /* empty */)
434 _rl_color_ext_list
= NULL
;
435 _rl_colored_stats
= 0; /* can't have colored stats without colors */
437 #else /* !COLOR_SUPPORT */
439 #endif /* !COLOR_SUPPORT */