1 /* $Header: /p/tcsh/cvsroot/tcsh/tw.color.c,v 1.32 2014/07/07 19:53:51 christos Exp $ */
3 * tw.color.c: builtin color ls-F
6 * Copyright (c) 1998 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 RCSID("$tcsh: tw.color.c,v 1.32 2014/07/07 19:53:51 christos Exp $")
49 #define VAR(suffix,variable,defaultcolor) \
51 suffix, variable, { defaultcolor, sizeof(defaultcolor) - 1 }, \
52 { defaultcolor, sizeof(defaultcolor) - 1 } \
54 #define NOS '\0' /* no suffix */
63 static Variable variables
[] = {
64 VAR('/', "di", "01;34"), /* Directory */
65 VAR('@', "ln", "01;36"), /* Symbolic link */
66 VAR('&', "or", ""), /* Orphanned symbolic link (defaults to ln) */
67 VAR('|', "pi", "33"), /* Named pipe (FIFO) */
68 VAR('=', "so", "01;35"), /* Socket */
69 VAR('>', "do", "01;35"), /* Door (solaris fast ipc mechanism) */
70 VAR('#', "bd", "01;33"), /* Block device */
71 VAR('%', "cd", "01;33"), /* Character device */
72 VAR('*', "ex", "01;32"), /* Executable file */
73 VAR(NOS
, "fi", "0"), /* Regular file */
74 VAR(NOS
, "no", "0"), /* Normal (non-filename) text */
75 VAR(NOS
, "mi", ""), /* Missing file (defaults to fi) */
77 VAR(NOS
, "lc", "\033["), /* Left code (ASCII) */
79 VAR(NOS
, "lc", "\x27["), /* Left code (EBCDIC)*/
81 VAR(NOS
, "rc", "m"), /* Right code */
82 VAR(NOS
, "ec", ""), /* End code (replaces lc+no+rc) */
83 VAR(NOS
, "su", ""), /* Setuid file (u+s) */
84 VAR(NOS
, "sg", ""), /* Setgid file (g+s) */
85 VAR(NOS
, "tw", ""), /* Sticky and other writable dir (+t,o+w) */
86 VAR(NOS
, "ow", ""), /* Other writable dir (o+w) but not sticky */
87 VAR(NOS
, "st", ""), /* Sticky dir (+t) but not other writable */
88 VAR(NOS
, "rs", "0"), /* Reset to normal color */
89 VAR(NOS
, "hl", "44;37"), /* Reg file extra hard links, obsolete? */
90 VAR(NOS
, "mh", "44;37"), /* Reg file extra hard links */
91 VAR(NOS
, "ca", "30;41"), /* File with capability */
94 #define nvariables (sizeof(variables)/sizeof(variables[0]))
97 VDir
, VSym
, VOrph
, VPipe
, VSock
, VDoor
, VBlock
, VChr
, VExe
,
98 VFile
, VNormal
, VMiss
, VLeft
, VRight
, VEnd
, VSuid
, VSgid
, VSticky
,
99 VOther
, Vstird
, VReset
, Vhard
, Vhard2
, VCap
103 * Map from LSCOLORS entry index to Variable array index
105 static const uint8_t map
[] = {
106 VDir
, /* Directory */
107 VSym
, /* Symbolic Link */
109 VPipe
, /* Named Pipe */
110 VExe
, /* Executable */
111 VBlock
, /* Block Special */
112 VChr
, /* Character Special */
113 VSuid
, /* Setuid Executable */
114 VSgid
, /* Setgid Executable */
115 VSticky
, /* Directory writable to others and sticky */
116 VOther
, /* Directory writable to others but not sticky */
122 ANSI_RESET_ON
= 0, /* reset colors/styles (white on black) */
123 ANSI_BOLD_ON
= 1, /* bold on */
124 ANSI_ITALICS_ON
= 3, /* italics on */
125 ANSI_UNDERLINE_ON
= 4, /* underline on */
126 ANSI_INVERSE_ON
= 7, /* inverse on */
127 ANSI_STRIKETHROUGH_ON
= 9, /* strikethrough on */
128 ANSI_BOLD_OFF
= 21, /* bold off */
129 ANSI_ITALICS_OFF
= 23, /* italics off */
130 ANSI_UNDERLINE_OFF
= 24, /* underline off */
131 ANSI_INVERSE_OFF
= 27, /* inverse off */
132 ANSI_STRIKETHROUGH_OFF
= 29,/* strikethrough off */
133 ANSI_FG_BLACK
= 30, /* fg black */
134 ANSI_FG_RED
= 31, /* fg red */
135 ANSI_FG_GREEN
= 32, /* fg green */
136 ANSI_FG_YELLOW
= 33, /* fg yellow */
137 ANSI_FG_BLUE
= 34, /* fg blue */
138 ANSI_FG_MAGENTA
= 35, /* fg magenta */
139 ANSI_FG_CYAN
= 36, /* fg cyan */
140 ANSI_FG_WHITE
= 37, /* fg white */
141 ANSI_FG_DEFAULT
= 39, /* fg default (white) */
142 ANSI_BG_BLACK
= 40, /* bg black */
143 ANSI_BG_RED
= 41, /* bg red */
144 ANSI_BG_GREEN
= 42, /* bg green */
145 ANSI_BG_YELLOW
= 43, /* bg yellow */
146 ANSI_BG_BLUE
= 44, /* bg blue */
147 ANSI_BG_MAGENTA
= 45, /* bg magenta */
148 ANSI_BG_CYAN
= 46, /* bg cyan */
149 ANSI_BG_WHITE
= 47, /* bg white */
150 ANSI_BG_DEFAULT
= 49, /* bg default (black) */
152 #define TCSH_BOLD 0x80
155 Str extension
; /* file extension */
156 Str color
; /* color string */
159 static Extension
*extensions
= NULL
;
160 static size_t nextensions
= 0;
162 static char *colors
= NULL
;
163 int color_context_ls
= FALSE
; /* do colored ls */
164 static int color_context_lsmF
= FALSE
; /* do colored ls-F */
166 static int getstring (char **, const Char
**, Str
*, int);
167 static void put_color (const Str
*);
168 static void print_color (const Char
*, size_t, Char
);
170 /* set_color_context():
173 set_color_context(void)
175 struct varent
*vp
= adrof(STRcolor
);
177 if (vp
== NULL
|| vp
->vec
== NULL
) {
178 color_context_ls
= FALSE
;
179 color_context_lsmF
= FALSE
;
180 } else if (!vp
->vec
[0] || vp
->vec
[0][0] == '\0') {
181 color_context_ls
= TRUE
;
182 color_context_lsmF
= TRUE
;
186 color_context_ls
= FALSE
;
187 color_context_lsmF
= FALSE
;
188 for (i
= 0; vp
->vec
[i
]; i
++)
189 if (Strcmp(vp
->vec
[i
], STRls
) == 0)
190 color_context_ls
= TRUE
;
191 else if (Strcmp(vp
->vec
[i
], STRlsmF
) == 0)
192 color_context_lsmF
= TRUE
;
200 getstring(char **dp
, const Char
**sp
, Str
*pd
, int f
)
206 while (*s
&& (*s
& CHAR
) != (Char
)f
&& (*s
& CHAR
) != ':') {
207 if ((*s
& CHAR
) == '\\' || (*s
& CHAR
) == '^') {
208 if ((sc
= parseescape(&s
)) == CHAR_ERR
)
213 d
+= one_wctomb(d
, sc
);
220 return *s
== (Char
)f
;
224 init(size_t colorlen
, size_t extnum
)
229 for (i
= 0; i
< nvariables
; i
++)
230 variables
[i
].color
= variables
[i
].defaultcolor
;
231 if (colorlen
== 0 && extnum
== 0) {
235 extensions
= xmalloc(colorlen
+ extnum
* sizeof(*extensions
));
236 colors
= extnum
* sizeof(*extensions
) + (char *)extensions
;
245 static const char ccolors
[] = "abcdefghx";
253 if (x
== '\0' || (p
= strchr(ccolors
, x
)) == NULL
)
255 return 30 + (p
- ccolors
);
259 makecolor(char **c
, int fg
, int bg
, Str
*v
)
263 l
= xsnprintf(*c
, 12, "%.2d;%.2d;%.2d;%.2d", ANSI_BOLD_ON
,
264 fg
& ~TCSH_BOLD
, (10 + bg
) & ~TCSH_BOLD
, ANSI_BOLD_OFF
);
265 l
= xsnprintf(*c
, 6, "%.2d;%.2d",
266 fg
& ~TCSH_BOLD
, (10 + bg
) & ~TCSH_BOLD
);
274 * Parse the LSCOLORS environment variable
276 static const Char
*xv
; /* setjmp clobbering */
278 parseLSCOLORS(const Char
*value
)
292 clen
= len
* 12; /* "??;??;??;??\0" */
295 /* Prevent from crashing if unknown parameters are given. */
296 omark
= cleanup_push_mark();
301 if (setexit() == 0) {
306 for (i
= 0; i
< len
; i
++) {
309 stderror(ERR_BADCOLORVAR
, v
[-1], '?');
313 stderror(ERR_BADCOLORVAR
, '?', v
[-1]);
314 makecolor(&c
, fg
, bg
, &variables
[map
[i
]].color
);
318 cleanup_pop_mark(omark
);
323 * Parse the LS_COLORS environment variable
326 parseLS_COLORS(const Char
*value
)
329 const Char
*v
; /* pointer in value */
330 char *c
; /* pointer in colors */
331 Extension
*volatile e
; /* pointer in extensions */
344 /* allocate memory */
346 for (v
= value
; *v
; v
++)
347 if ((*v
& CHAR
) == ':')
357 /* Prevent from crashing if unknown parameters are given. */
359 omark
= cleanup_push_mark();
362 if (setexit() == 0) {
371 case '*': /* :*ext=color: */
373 if (getstring(&c
, &v
, &e
->extension
, '=') &&
374 0 < e
->extension
.len
) {
376 getstring(&c
, &v
, &e
->color
, ':');
382 default: /* :vl=color: */
383 if (v
[0] && v
[1] && (v
[2] & CHAR
) == '=') {
384 for (i
= 0; i
< nvariables
; i
++)
385 if ((Char
)variables
[i
].variable
[0] == (v
[0] & CHAR
) &&
386 (Char
)variables
[i
].variable
[1] == (v
[1] & CHAR
))
388 if (i
< nvariables
) {
390 getstring(&c
, &v
, &variables
[i
].color
, ':');
394 stderror(ERR_BADCOLORVAR
, v
[0], v
[1]);
398 while (*v
&& (*v
& CHAR
) != ':')
403 cleanup_pop_mark(omark
);
406 nextensions
= e
- extensions
;
412 put_color(const Str
*colorp
)
415 const char *c
= colorp
->s
;
416 int original_output_raw
= output_raw
;
419 cleanup_push(&original_output_raw
, output_raw_restore
);
420 for (i
= colorp
->len
; 0 < i
; i
--)
422 cleanup_until(&original_output_raw
);
429 print_color(const Char
*fname
, size_t len
, Char suffix
)
432 char *filename
= short2str(fname
);
433 char *last
= filename
+ len
;
434 Str
*colorp
= &variables
[VFile
].color
;
437 case '>': /* File is a symbolic link pointing to
439 colorp
= &variables
[VDir
].color
;
441 case '+': /* File is a hidden directory [aix] or
442 * context dependent [hpux] */
443 case ':': /* File is network special [hpux] */
446 for (i
= 0; i
< nvariables
; i
++)
447 if (variables
[i
].suffix
!= NOS
&&
448 (Char
)variables
[i
].suffix
== suffix
) {
449 colorp
= &variables
[i
].color
;
452 if (i
== nvariables
) {
453 for (i
= 0; i
< nextensions
; i
++)
454 if (len
>= extensions
[i
].extension
.len
455 && strncmp(last
- extensions
[i
].extension
.len
,
456 extensions
[i
].extension
.s
,
457 extensions
[i
].extension
.len
) == 0) {
458 colorp
= &extensions
[i
].color
;
465 put_color(&variables
[VLeft
].color
);
467 put_color(&variables
[VRight
].color
);
471 /* print_with_color():
474 print_with_color(const Char
*filename
, size_t len
, Char suffix
)
476 if (color_context_lsmF
&&
477 (haderr
? (didfds
? is2atty
: isdiagatty
) :
478 (didfds
? is1atty
: isoutatty
))) {
479 print_color(filename
, len
, suffix
);
480 xprintf("%S", filename
);
481 if (0 < variables
[VEnd
].color
.len
)
482 put_color(&variables
[VEnd
].color
);
484 put_color(&variables
[VLeft
].color
);
485 put_color(&variables
[VNormal
].color
);
486 put_color(&variables
[VRight
].color
);
490 xprintf("%S", filename
);
495 #endif /* COLOR_LS_F */