xref: /freebsd-src/contrib/tcsh/tw.color.c (revision 6560ac57ce879857203bc456cdc3849808dc0700)
1c80476e4SDavid E. O'Brien /*
2c80476e4SDavid E. O'Brien  * tw.color.c: builtin color ls-F
3c80476e4SDavid E. O'Brien  */
4c80476e4SDavid E. O'Brien /*-
5c80476e4SDavid E. O'Brien  * Copyright (c) 1998 The Regents of the University of California.
6c80476e4SDavid E. O'Brien  * All rights reserved.
7c80476e4SDavid E. O'Brien  *
8c80476e4SDavid E. O'Brien  * Redistribution and use in source and binary forms, with or without
9c80476e4SDavid E. O'Brien  * modification, are permitted provided that the following conditions
10c80476e4SDavid E. O'Brien  * are met:
11c80476e4SDavid E. O'Brien  * 1. Redistributions of source code must retain the above copyright
12c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer.
13c80476e4SDavid E. O'Brien  * 2. Redistributions in binary form must reproduce the above copyright
14c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer in the
15c80476e4SDavid E. O'Brien  *    documentation and/or other materials provided with the distribution.
1629301572SMark Peek  * 3. Neither the name of the University nor the names of its contributors
17c80476e4SDavid E. O'Brien  *    may be used to endorse or promote products derived from this software
18c80476e4SDavid E. O'Brien  *    without specific prior written permission.
19c80476e4SDavid E. O'Brien  *
20c80476e4SDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21c80476e4SDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22c80476e4SDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23c80476e4SDavid E. O'Brien  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24c80476e4SDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25c80476e4SDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26c80476e4SDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27c80476e4SDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28c80476e4SDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29c80476e4SDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30c80476e4SDavid E. O'Brien  * SUCH DAMAGE.
31c80476e4SDavid E. O'Brien  */
32c80476e4SDavid E. O'Brien #include "sh.h"
33c80476e4SDavid E. O'Brien #include "tw.h"
34c80476e4SDavid E. O'Brien #include "ed.h"
35c80476e4SDavid E. O'Brien #include "tc.h"
36c80476e4SDavid E. O'Brien 
37c80476e4SDavid E. O'Brien #ifdef COLOR_LS_F
38c80476e4SDavid E. O'Brien 
39c80476e4SDavid E. O'Brien typedef struct {
4023338178SMark Peek     const char	 *s;
4145e5710bSMark Peek     size_t len;
42c80476e4SDavid E. O'Brien } Str;
43c80476e4SDavid E. O'Brien 
44c80476e4SDavid E. O'Brien 
45c80476e4SDavid E. O'Brien #define VAR(suffix,variable,defaultcolor) \
46c80476e4SDavid E. O'Brien { \
47c80476e4SDavid E. O'Brien     suffix, variable, { defaultcolor, sizeof(defaultcolor) - 1 }, \
48c80476e4SDavid E. O'Brien       { defaultcolor, sizeof(defaultcolor) - 1 } \
49c80476e4SDavid E. O'Brien }
50c80476e4SDavid E. O'Brien #define NOS '\0' /* no suffix */
51c80476e4SDavid E. O'Brien 
52c80476e4SDavid E. O'Brien typedef struct {
53c80476e4SDavid E. O'Brien     const char suffix;
54c80476e4SDavid E. O'Brien     const char *variable;
55c80476e4SDavid E. O'Brien     Str	    color;
56c80476e4SDavid E. O'Brien     Str	    defaultcolor;
57c80476e4SDavid E. O'Brien } Variable;
58c80476e4SDavid E. O'Brien 
59c80476e4SDavid E. O'Brien static Variable variables[] = {
60c80476e4SDavid E. O'Brien     VAR('/', "di", "01;34"),	/* Directory */
61c80476e4SDavid E. O'Brien     VAR('@', "ln", "01;36"),	/* Symbolic link */
62c80476e4SDavid E. O'Brien     VAR('&', "or", ""),		/* Orphanned symbolic link (defaults to ln) */
63c80476e4SDavid E. O'Brien     VAR('|', "pi", "33"),	/* Named pipe (FIFO) */
64c80476e4SDavid E. O'Brien     VAR('=', "so", "01;35"),	/* Socket */
656767bd61SMark Peek     VAR('>', "do", "01;35"),	/* Door (solaris fast ipc mechanism)  */
66c80476e4SDavid E. O'Brien     VAR('#', "bd", "01;33"),	/* Block device */
67c80476e4SDavid E. O'Brien     VAR('%', "cd", "01;33"),	/* Character device */
68c80476e4SDavid E. O'Brien     VAR('*', "ex", "01;32"),	/* Executable file */
69c80476e4SDavid E. O'Brien     VAR(NOS, "fi", "0"),	/* Regular file */
70c80476e4SDavid E. O'Brien     VAR(NOS, "no", "0"),	/* Normal (non-filename) text */
71c80476e4SDavid E. O'Brien     VAR(NOS, "mi", ""),		/* Missing file (defaults to fi) */
723b6eaa7bSAndrey A. Chernov #ifdef IS_ASCII
733b6eaa7bSAndrey A. Chernov     VAR(NOS, "lc", "\033["),	/* Left code (ASCII) */
743b6eaa7bSAndrey A. Chernov #else
75c80476e4SDavid E. O'Brien     VAR(NOS, "lc", "\x27["),	/* Left code (EBCDIC)*/
763b6eaa7bSAndrey A. Chernov #endif
77c80476e4SDavid E. O'Brien     VAR(NOS, "rc", "m"),	/* Right code */
78c80476e4SDavid E. O'Brien     VAR(NOS, "ec", ""),		/* End code (replaces lc+no+rc) */
7945e5710bSMark Peek     VAR(NOS, "su", ""),		/* Setuid file (u+s) */
8045e5710bSMark Peek     VAR(NOS, "sg", ""),		/* Setgid file (g+s) */
8145e5710bSMark Peek     VAR(NOS, "tw", ""),		/* Sticky and other writable dir (+t,o+w) */
8245e5710bSMark Peek     VAR(NOS, "ow", ""),		/* Other writable dir (o+w) but not sticky */
8345e5710bSMark Peek     VAR(NOS, "st", ""),		/* Sticky dir (+t) but not other writable */
84a15e6f9aSMark Peek     VAR(NOS, "rs", "0"),	/* Reset to normal color */
859ccc37e3SMark Peek     VAR(NOS, "hl", "44;37"),    /* Reg file extra hard links, obsolete? */
869ccc37e3SMark Peek     VAR(NOS, "mh", "44;37"),    /* Reg file extra hard links */
879ccc37e3SMark Peek     VAR(NOS, "ca", "30;41"),    /* File with capability */
88c80476e4SDavid E. O'Brien };
89c80476e4SDavid E. O'Brien 
9019d2e3deSDmitry Chagin #define nvariables (sizeof(variables)/sizeof(variables[0]))
9119d2e3deSDmitry Chagin 
92c80476e4SDavid E. O'Brien enum FileType {
936767bd61SMark Peek     VDir, VSym, VOrph, VPipe, VSock, VDoor, VBlock, VChr, VExe,
9419d2e3deSDmitry Chagin     VFile, VNormal, VMiss, VLeft, VRight, VEnd, VSuid, VSgid, VSticky,
9519d2e3deSDmitry Chagin     VOther, Vstird, VReset, Vhard, Vhard2, VCap
96c80476e4SDavid E. O'Brien };
97c80476e4SDavid E. O'Brien 
9819d2e3deSDmitry Chagin /*
9919d2e3deSDmitry Chagin  * Map from LSCOLORS entry index to Variable array index
10019d2e3deSDmitry Chagin  */
10119d2e3deSDmitry Chagin static const uint8_t map[] = {
10219d2e3deSDmitry Chagin     VDir,	/* Directory */
10319d2e3deSDmitry Chagin     VSym,	/* Symbolic Link */
10419d2e3deSDmitry Chagin     VSock,	/* Socket */
10519d2e3deSDmitry Chagin     VPipe,	/* Named Pipe */
10619d2e3deSDmitry Chagin     VExe,	/* Executable */
10719d2e3deSDmitry Chagin     VBlock,	/* Block Special */
10819d2e3deSDmitry Chagin     VChr,	/* Character Special */
10919d2e3deSDmitry Chagin     VSuid,	/* Setuid Executable */
11019d2e3deSDmitry Chagin     VSgid,	/* Setgid Executable */
11119d2e3deSDmitry Chagin     VSticky,	/* Directory writable to others and sticky */
11219d2e3deSDmitry Chagin     VOther,	/* Directory writable to others but not sticky */
11319d2e3deSDmitry Chagin };
11419d2e3deSDmitry Chagin 
11519d2e3deSDmitry Chagin 
11619d2e3deSDmitry Chagin 
11719d2e3deSDmitry Chagin enum ansi {
11819d2e3deSDmitry Chagin     ANSI_RESET_ON = 0,		/* reset colors/styles (white on black) */
11919d2e3deSDmitry Chagin     ANSI_BOLD_ON = 1,		/* bold on */
12019d2e3deSDmitry Chagin     ANSI_ITALICS_ON = 3,	/* italics on */
12119d2e3deSDmitry Chagin     ANSI_UNDERLINE_ON = 4,	/* underline on */
12219d2e3deSDmitry Chagin     ANSI_INVERSE_ON = 7,	/* inverse on */
12319d2e3deSDmitry Chagin     ANSI_STRIKETHROUGH_ON = 9,	/* strikethrough on */
12419d2e3deSDmitry Chagin     ANSI_BOLD_OFF = 21,		/* bold off */
12519d2e3deSDmitry Chagin     ANSI_ITALICS_OFF = 23,	/* italics off */
12619d2e3deSDmitry Chagin     ANSI_UNDERLINE_OFF = 24,	/* underline off */
12719d2e3deSDmitry Chagin     ANSI_INVERSE_OFF = 27,	/* inverse off */
12819d2e3deSDmitry Chagin     ANSI_STRIKETHROUGH_OFF = 29,/* strikethrough off */
12919d2e3deSDmitry Chagin     ANSI_FG_BLACK = 30,		/* fg black */
13019d2e3deSDmitry Chagin     ANSI_FG_RED = 31,		/* fg red */
13119d2e3deSDmitry Chagin     ANSI_FG_GREEN = 32,		/* fg green */
13219d2e3deSDmitry Chagin     ANSI_FG_YELLOW = 33,	/* fg yellow */
13319d2e3deSDmitry Chagin     ANSI_FG_BLUE = 34,		/* fg blue */
13419d2e3deSDmitry Chagin     ANSI_FG_MAGENTA = 35,	/* fg magenta */
13519d2e3deSDmitry Chagin     ANSI_FG_CYAN = 36,		/* fg cyan */
13619d2e3deSDmitry Chagin     ANSI_FG_WHITE = 37,		/* fg white */
13719d2e3deSDmitry Chagin     ANSI_FG_DEFAULT = 39,	/* fg default (white) */
13819d2e3deSDmitry Chagin     ANSI_BG_BLACK = 40,		/* bg black */
13919d2e3deSDmitry Chagin     ANSI_BG_RED = 41,		/* bg red */
14019d2e3deSDmitry Chagin     ANSI_BG_GREEN = 42,		/* bg green */
14119d2e3deSDmitry Chagin     ANSI_BG_YELLOW = 43,	/* bg yellow */
14219d2e3deSDmitry Chagin     ANSI_BG_BLUE = 44,		/* bg blue */
14319d2e3deSDmitry Chagin     ANSI_BG_MAGENTA = 45,	/* bg magenta */
14419d2e3deSDmitry Chagin     ANSI_BG_CYAN = 46,		/* bg cyan */
14519d2e3deSDmitry Chagin     ANSI_BG_WHITE = 47,		/* bg white */
14619d2e3deSDmitry Chagin     ANSI_BG_DEFAULT = 49,	/* bg default (black) */
14719d2e3deSDmitry Chagin };
14819d2e3deSDmitry Chagin #define TCSH_BOLD	0x80
149c80476e4SDavid E. O'Brien 
150c80476e4SDavid E. O'Brien typedef struct {
151c80476e4SDavid E. O'Brien     Str	    extension;	/* file extension */
152c80476e4SDavid E. O'Brien     Str	    color;	/* color string */
153c80476e4SDavid E. O'Brien } Extension;
154c80476e4SDavid E. O'Brien 
155c80476e4SDavid E. O'Brien static Extension *extensions = NULL;
15623338178SMark Peek static size_t nextensions = 0;
157c80476e4SDavid E. O'Brien 
158c80476e4SDavid E. O'Brien static char *colors = NULL;
15923338178SMark Peek int	     color_context_ls = FALSE;	/* do colored ls */
16023338178SMark Peek static int  color_context_lsmF = FALSE; /* do colored ls-F */
161c80476e4SDavid E. O'Brien 
16245e5710bSMark Peek static int getstring (char **, const Char **, Str *, int);
16345e5710bSMark Peek static void put_color (const Str *);
16445e5710bSMark Peek static void print_color (const Char *, size_t, Char);
165c80476e4SDavid E. O'Brien 
166c80476e4SDavid E. O'Brien /* set_color_context():
167c80476e4SDavid E. O'Brien  */
168c80476e4SDavid E. O'Brien void
set_color_context(void)16945e5710bSMark Peek set_color_context(void)
170c80476e4SDavid E. O'Brien {
171c80476e4SDavid E. O'Brien     struct varent *vp = adrof(STRcolor);
172c80476e4SDavid E. O'Brien 
17329301572SMark Peek     if (vp == NULL || vp->vec == NULL) {
174c80476e4SDavid E. O'Brien 	color_context_ls = FALSE;
175c80476e4SDavid E. O'Brien 	color_context_lsmF = FALSE;
17629301572SMark Peek     } else if (!vp->vec[0] || vp->vec[0][0] == '\0') {
177c80476e4SDavid E. O'Brien 	color_context_ls = TRUE;
178c80476e4SDavid E. O'Brien 	color_context_lsmF = TRUE;
17929301572SMark Peek     } else {
180c80476e4SDavid E. O'Brien 	size_t i;
181c80476e4SDavid E. O'Brien 
182c80476e4SDavid E. O'Brien 	color_context_ls = FALSE;
183c80476e4SDavid E. O'Brien 	color_context_lsmF = FALSE;
184c80476e4SDavid E. O'Brien 	for (i = 0; vp->vec[i]; i++)
185c80476e4SDavid E. O'Brien 	    if (Strcmp(vp->vec[i], STRls) == 0)
186c80476e4SDavid E. O'Brien 		color_context_ls = TRUE;
187c80476e4SDavid E. O'Brien 	    else if (Strcmp(vp->vec[i], STRlsmF) == 0)
188c80476e4SDavid E. O'Brien 		color_context_lsmF = TRUE;
189c80476e4SDavid E. O'Brien     }
190c80476e4SDavid E. O'Brien }
191c80476e4SDavid E. O'Brien 
192c80476e4SDavid E. O'Brien 
193c80476e4SDavid E. O'Brien /* getstring():
194c80476e4SDavid E. O'Brien  */
19523338178SMark Peek static	int
getstring(char ** dp,const Char ** sp,Str * pd,int f)19645e5710bSMark Peek getstring(char **dp, const Char **sp, Str *pd, int f)
197c80476e4SDavid E. O'Brien {
198c80476e4SDavid E. O'Brien     const Char *s = *sp;
199c80476e4SDavid E. O'Brien     char *d = *dp;
20023338178SMark Peek     eChar sc;
201c80476e4SDavid E. O'Brien 
20223338178SMark Peek     while (*s && (*s & CHAR) != (Char)f && (*s & CHAR) != ':') {
203c80476e4SDavid E. O'Brien 	if ((*s & CHAR) == '\\' || (*s & CHAR) == '^') {
20423338178SMark Peek 	    if ((sc = parseescape(&s)) == CHAR_ERR)
205c80476e4SDavid E. O'Brien 		return 0;
206c80476e4SDavid E. O'Brien 	}
207c80476e4SDavid E. O'Brien 	else
20823338178SMark Peek 	    sc = *s++ & CHAR;
20923338178SMark Peek 	d += one_wctomb(d, sc);
210c80476e4SDavid E. O'Brien     }
211c80476e4SDavid E. O'Brien 
212c80476e4SDavid E. O'Brien     pd->s = *dp;
21345e5710bSMark Peek     pd->len = d - *dp;
214c80476e4SDavid E. O'Brien     *sp = s;
215c80476e4SDavid E. O'Brien     *dp = d;
21623338178SMark Peek     return *s == (Char)f;
217c80476e4SDavid E. O'Brien }
218c80476e4SDavid E. O'Brien 
21919d2e3deSDmitry Chagin static void
init(size_t colorlen,size_t extnum)22019d2e3deSDmitry Chagin init(size_t colorlen, size_t extnum)
22119d2e3deSDmitry Chagin {
22219d2e3deSDmitry Chagin     size_t i;
22319d2e3deSDmitry Chagin 
22419d2e3deSDmitry Chagin     xfree(extensions);
22519d2e3deSDmitry Chagin     for (i = 0; i < nvariables; i++)
22619d2e3deSDmitry Chagin 	variables[i].color = variables[i].defaultcolor;
22719d2e3deSDmitry Chagin     if (colorlen == 0 && extnum == 0) {
22819d2e3deSDmitry Chagin 	extensions = NULL;
22919d2e3deSDmitry Chagin 	colors = NULL;
23019d2e3deSDmitry Chagin     } else {
23119d2e3deSDmitry Chagin 	extensions = xmalloc(colorlen + extnum * sizeof(*extensions));
23219d2e3deSDmitry Chagin 	colors = extnum * sizeof(*extensions) + (char *)extensions;
23319d2e3deSDmitry Chagin     }
23419d2e3deSDmitry Chagin     nextensions = 0;
23519d2e3deSDmitry Chagin }
23619d2e3deSDmitry Chagin 
23719d2e3deSDmitry Chagin static int
color(Char x)23819d2e3deSDmitry Chagin color(Char x)
23919d2e3deSDmitry Chagin {
24019d2e3deSDmitry Chagin     static const char ccolors[] = "abcdefghx";
24119d2e3deSDmitry Chagin     char *p;
24219d2e3deSDmitry Chagin     if (Isupper(x)) {
24319d2e3deSDmitry Chagin 	x = Tolower(x);
24419d2e3deSDmitry Chagin     }
24519d2e3deSDmitry Chagin 
24619d2e3deSDmitry Chagin     if (x == '\0' || (p = strchr(ccolors, x)) == NULL)
24719d2e3deSDmitry Chagin 	return -1;
24819d2e3deSDmitry Chagin     return 30 + (p - ccolors);
24919d2e3deSDmitry Chagin }
25019d2e3deSDmitry Chagin 
25119d2e3deSDmitry Chagin static void
makecolor(char ** c,int fg,int bg,Str * v)25219d2e3deSDmitry Chagin makecolor(char **c, int fg, int bg, Str *v)
25319d2e3deSDmitry Chagin {
25419d2e3deSDmitry Chagin     int l;
255*6560ac57SDmitry Chagin     if (fg & 0x80) {
25619d2e3deSDmitry Chagin 	l = xsnprintf(*c, 12, "%.2d;%.2d;%.2d;%.2d", ANSI_BOLD_ON,
25719d2e3deSDmitry Chagin 	    fg & ~TCSH_BOLD, (10 + bg) & ~TCSH_BOLD, ANSI_BOLD_OFF);
258*6560ac57SDmitry Chagin     } else {
25919d2e3deSDmitry Chagin 	l = xsnprintf(*c, 6, "%.2d;%.2d",
26019d2e3deSDmitry Chagin 	    fg & ~TCSH_BOLD, (10 + bg) & ~TCSH_BOLD);
261*6560ac57SDmitry Chagin     }
26219d2e3deSDmitry Chagin 
26319d2e3deSDmitry Chagin     v->s = *c;
26419d2e3deSDmitry Chagin     v->len = l;
26519d2e3deSDmitry Chagin     *c += l + 1;
26619d2e3deSDmitry Chagin }
26719d2e3deSDmitry Chagin 
26819d2e3deSDmitry Chagin /* parseLSCOLORS():
26919d2e3deSDmitry Chagin  * 	Parse the LSCOLORS environment variable
27019d2e3deSDmitry Chagin  */
27119d2e3deSDmitry Chagin static const Char *xv;	/* setjmp clobbering */
27219d2e3deSDmitry Chagin void
parseLSCOLORS(const Char * value)27319d2e3deSDmitry Chagin parseLSCOLORS(const Char *value)
27419d2e3deSDmitry Chagin {
27519d2e3deSDmitry Chagin     size_t i, len, clen;
27619d2e3deSDmitry Chagin     jmp_buf_t osetexit;
27719d2e3deSDmitry Chagin     size_t omark;
27819d2e3deSDmitry Chagin     xv = value;
27919d2e3deSDmitry Chagin 
28019d2e3deSDmitry Chagin     if (xv == NULL) {
28119d2e3deSDmitry Chagin 	init(0, 0);
28219d2e3deSDmitry Chagin 	return;
28319d2e3deSDmitry Chagin     }
28419d2e3deSDmitry Chagin 
28519d2e3deSDmitry Chagin     len = Strlen(xv);
28619d2e3deSDmitry Chagin     len >>= 1;
28719d2e3deSDmitry Chagin     clen = len * 12;	/* "??;??;??;??\0" */
28819d2e3deSDmitry Chagin     init(clen, 0);
28919d2e3deSDmitry Chagin 
29019d2e3deSDmitry Chagin     /* Prevent from crashing if unknown parameters are given. */
29119d2e3deSDmitry Chagin     omark = cleanup_push_mark();
29219d2e3deSDmitry Chagin     getexit(osetexit);
29319d2e3deSDmitry Chagin 
29419d2e3deSDmitry Chagin     /* init pointers */
29519d2e3deSDmitry Chagin 
29619d2e3deSDmitry Chagin     if (setexit() == 0) {
29719d2e3deSDmitry Chagin 	const Char *v = xv;
29819d2e3deSDmitry Chagin 	char *c = colors;
29919d2e3deSDmitry Chagin 
30019d2e3deSDmitry Chagin 	int fg, bg;
30119d2e3deSDmitry Chagin 	for (i = 0; i < len; i++) {
30219d2e3deSDmitry Chagin 	    fg = color(*v++);
30319d2e3deSDmitry Chagin 	    if (fg == -1)
30419d2e3deSDmitry Chagin 		stderror(ERR_BADCOLORVAR, v[-1], '?');
30519d2e3deSDmitry Chagin 
30619d2e3deSDmitry Chagin 	    bg = color(*v++);
30719d2e3deSDmitry Chagin 	    if (bg == -1)
30819d2e3deSDmitry Chagin 		stderror(ERR_BADCOLORVAR, '?', v[-1]);
30919d2e3deSDmitry Chagin 	    makecolor(&c, fg, bg, &variables[map[i]].color);
31019d2e3deSDmitry Chagin 	}
31119d2e3deSDmitry Chagin 
31219d2e3deSDmitry Chagin     }
31319d2e3deSDmitry Chagin     cleanup_pop_mark(omark);
31419d2e3deSDmitry Chagin     resexit(osetexit);
31519d2e3deSDmitry Chagin }
316c80476e4SDavid E. O'Brien 
317c80476e4SDavid E. O'Brien /* parseLS_COLORS():
318c80476e4SDavid E. O'Brien  *	Parse the LS_COLORS environment variable
319c80476e4SDavid E. O'Brien  */
320c80476e4SDavid E. O'Brien void
parseLS_COLORS(const Char * value)32145e5710bSMark Peek parseLS_COLORS(const Char *value)
322c80476e4SDavid E. O'Brien {
32323338178SMark Peek     size_t  i, len;
324c80476e4SDavid E. O'Brien     const Char	 *v;		/* pointer in value */
325c80476e4SDavid E. O'Brien     char   *c;			/* pointer in colors */
32623338178SMark Peek     Extension *volatile e;	/* pointer in extensions */
3278e66bd9eSDavid E. O'Brien     jmp_buf_t osetexit;
32845e5710bSMark Peek     size_t omark;
329c80476e4SDavid E. O'Brien 
33029301572SMark Peek     (void) &e;
33129301572SMark Peek 
332c80476e4SDavid E. O'Brien 
33319d2e3deSDmitry Chagin     if (value == NULL) {
33419d2e3deSDmitry Chagin 	init(0, 0);
335c80476e4SDavid E. O'Brien 	return;
33619d2e3deSDmitry Chagin     }
337c80476e4SDavid E. O'Brien 
338c80476e4SDavid E. O'Brien     len = Strlen(value);
339c80476e4SDavid E. O'Brien     /* allocate memory */
340c80476e4SDavid E. O'Brien     i = 1;
341c80476e4SDavid E. O'Brien     for (v = value; *v; v++)
342c80476e4SDavid E. O'Brien 	if ((*v & CHAR) == ':')
343c80476e4SDavid E. O'Brien 	    i++;
34419d2e3deSDmitry Chagin 
34519d2e3deSDmitry Chagin     init(len, i);
346c80476e4SDavid E. O'Brien 
347c80476e4SDavid E. O'Brien     /* init pointers */
348c80476e4SDavid E. O'Brien     v = value;
349c80476e4SDavid E. O'Brien     c = colors;
35019d2e3deSDmitry Chagin     e = extensions;
351c80476e4SDavid E. O'Brien 
3528e66bd9eSDavid E. O'Brien     /* Prevent from crashing if unknown parameters are given. */
3538e66bd9eSDavid E. O'Brien 
35445e5710bSMark Peek     omark = cleanup_push_mark();
3558e66bd9eSDavid E. O'Brien     getexit(osetexit);
3568e66bd9eSDavid E. O'Brien 
3578e66bd9eSDavid E. O'Brien     if (setexit() == 0) {
3588e66bd9eSDavid E. O'Brien 
359c80476e4SDavid E. O'Brien 	/* parse */
360c80476e4SDavid E. O'Brien 	while (*v) {
361c80476e4SDavid E. O'Brien 	    switch (*v & CHAR) {
362c80476e4SDavid E. O'Brien 	    case ':':
363c80476e4SDavid E. O'Brien 		v++;
364c80476e4SDavid E. O'Brien 		continue;
365c80476e4SDavid E. O'Brien 
366c80476e4SDavid E. O'Brien 	    case '*':		/* :*ext=color: */
367c80476e4SDavid E. O'Brien 		v++;
368c80476e4SDavid E. O'Brien 		if (getstring(&c, &v, &e->extension, '=') &&
369c80476e4SDavid E. O'Brien 		    0 < e->extension.len) {
370c80476e4SDavid E. O'Brien 		    v++;
371c80476e4SDavid E. O'Brien 		    getstring(&c, &v, &e->color, ':');
372c80476e4SDavid E. O'Brien 		    e++;
373c80476e4SDavid E. O'Brien 		    continue;
374c80476e4SDavid E. O'Brien 		}
375c80476e4SDavid E. O'Brien 		break;
376c80476e4SDavid E. O'Brien 
377c80476e4SDavid E. O'Brien 	    default:		/* :vl=color: */
378c80476e4SDavid E. O'Brien 		if (v[0] && v[1] && (v[2] & CHAR) == '=') {
379c80476e4SDavid E. O'Brien 		    for (i = 0; i < nvariables; i++)
38023338178SMark Peek 			if ((Char)variables[i].variable[0] == (v[0] & CHAR) &&
38123338178SMark Peek 			    (Char)variables[i].variable[1] == (v[1] & CHAR))
382c80476e4SDavid E. O'Brien 			    break;
383c80476e4SDavid E. O'Brien 		    if (i < nvariables) {
384c80476e4SDavid E. O'Brien 			v += 3;
385c80476e4SDavid E. O'Brien 			getstring(&c, &v, &variables[i].color, ':');
386c80476e4SDavid E. O'Brien 			continue;
387c80476e4SDavid E. O'Brien 		    }
388c80476e4SDavid E. O'Brien 		    else
389c80476e4SDavid E. O'Brien 			stderror(ERR_BADCOLORVAR, v[0], v[1]);
390c80476e4SDavid E. O'Brien 		}
391c80476e4SDavid E. O'Brien 		break;
392c80476e4SDavid E. O'Brien 	    }
393c80476e4SDavid E. O'Brien 	    while (*v && (*v & CHAR) != ':')
394c80476e4SDavid E. O'Brien 		v++;
395c80476e4SDavid E. O'Brien 	}
3968e66bd9eSDavid E. O'Brien     }
3978e66bd9eSDavid E. O'Brien 
39845e5710bSMark Peek     cleanup_pop_mark(omark);
3998e66bd9eSDavid E. O'Brien     resexit(osetexit);
400c80476e4SDavid E. O'Brien 
40145e5710bSMark Peek     nextensions = e - extensions;
402c80476e4SDavid E. O'Brien }
403c80476e4SDavid E. O'Brien 
404c80476e4SDavid E. O'Brien /* put_color():
405c80476e4SDavid E. O'Brien  */
406c80476e4SDavid E. O'Brien static void
put_color(const Str * colorp)40719d2e3deSDmitry Chagin put_color(const Str *colorp)
408c80476e4SDavid E. O'Brien {
409c80476e4SDavid E. O'Brien     size_t  i;
41019d2e3deSDmitry Chagin     const char	 *c = colorp->s;
41123338178SMark Peek     int	   original_output_raw = output_raw;
412c80476e4SDavid E. O'Brien 
413c80476e4SDavid E. O'Brien     output_raw = TRUE;
41445e5710bSMark Peek     cleanup_push(&original_output_raw, output_raw_restore);
41519d2e3deSDmitry Chagin     for (i = colorp->len; 0 < i; i--)
416c80476e4SDavid E. O'Brien 	xputchar(*c++);
41745e5710bSMark Peek     cleanup_until(&original_output_raw);
418c80476e4SDavid E. O'Brien }
419c80476e4SDavid E. O'Brien 
420c80476e4SDavid E. O'Brien 
421c80476e4SDavid E. O'Brien /* print_color():
422c80476e4SDavid E. O'Brien  */
423c80476e4SDavid E. O'Brien static void
print_color(const Char * fname,size_t len,Char suffix)42445e5710bSMark Peek print_color(const Char *fname, size_t len, Char suffix)
425c80476e4SDavid E. O'Brien {
42623338178SMark Peek     size_t  i;
427c80476e4SDavid E. O'Brien     char   *filename = short2str(fname);
428c80476e4SDavid E. O'Brien     char   *last = filename + len;
42919d2e3deSDmitry Chagin     Str	   *colorp = &variables[VFile].color;
430c80476e4SDavid E. O'Brien 
431c80476e4SDavid E. O'Brien     switch (suffix) {
432c80476e4SDavid E. O'Brien     case '>':			/* File is a symbolic link pointing to
433c80476e4SDavid E. O'Brien 				 * a directory */
43419d2e3deSDmitry Chagin 	colorp = &variables[VDir].color;
435c80476e4SDavid E. O'Brien 	break;
436c80476e4SDavid E. O'Brien     case '+':			/* File is a hidden directory [aix] or
437c80476e4SDavid E. O'Brien 				 * context dependent [hpux] */
438c80476e4SDavid E. O'Brien     case ':':			/* File is network special [hpux] */
439c80476e4SDavid E. O'Brien 	break;
440c80476e4SDavid E. O'Brien     default:
441c80476e4SDavid E. O'Brien 	for (i = 0; i < nvariables; i++)
442c80476e4SDavid E. O'Brien 	    if (variables[i].suffix != NOS &&
44323338178SMark Peek 		(Char)variables[i].suffix == suffix) {
44419d2e3deSDmitry Chagin 		colorp = &variables[i].color;
445c80476e4SDavid E. O'Brien 		break;
446c80476e4SDavid E. O'Brien 	    }
447c80476e4SDavid E. O'Brien 	if (i == nvariables) {
448c80476e4SDavid E. O'Brien 	    for (i = 0; i < nextensions; i++)
44945e5710bSMark Peek 		if (len >= extensions[i].extension.len
45045e5710bSMark Peek 		    && strncmp(last - extensions[i].extension.len,
451c80476e4SDavid E. O'Brien 			       extensions[i].extension.s,
452c80476e4SDavid E. O'Brien 			       extensions[i].extension.len) == 0) {
45319d2e3deSDmitry Chagin 		  colorp = &extensions[i].color;
454c80476e4SDavid E. O'Brien 		break;
455c80476e4SDavid E. O'Brien 	    }
456c80476e4SDavid E. O'Brien 	}
457c80476e4SDavid E. O'Brien 	break;
458c80476e4SDavid E. O'Brien     }
459c80476e4SDavid E. O'Brien 
460c80476e4SDavid E. O'Brien     put_color(&variables[VLeft].color);
46119d2e3deSDmitry Chagin     put_color(colorp);
462c80476e4SDavid E. O'Brien     put_color(&variables[VRight].color);
463c80476e4SDavid E. O'Brien }
464c80476e4SDavid E. O'Brien 
465c80476e4SDavid E. O'Brien 
466c80476e4SDavid E. O'Brien /* print_with_color():
467c80476e4SDavid E. O'Brien  */
468c80476e4SDavid E. O'Brien void
print_with_color(const Char * filename,size_t len,Char suffix)46945e5710bSMark Peek print_with_color(const Char *filename, size_t len, Char suffix)
470c80476e4SDavid E. O'Brien {
471c80476e4SDavid E. O'Brien     if (color_context_lsmF &&
472c80476e4SDavid E. O'Brien 	(haderr ? (didfds ? is2atty : isdiagatty) :
473c80476e4SDavid E. O'Brien 	 (didfds ? is1atty : isoutatty))) {
474c80476e4SDavid E. O'Brien 	print_color(filename, len, suffix);
475c80476e4SDavid E. O'Brien 	xprintf("%S", filename);
476c80476e4SDavid E. O'Brien 	if (0 < variables[VEnd].color.len)
477c80476e4SDavid E. O'Brien 	    put_color(&variables[VEnd].color);
478c80476e4SDavid E. O'Brien 	else {
479c80476e4SDavid E. O'Brien 	    put_color(&variables[VLeft].color);
480c80476e4SDavid E. O'Brien 	    put_color(&variables[VNormal].color);
481c80476e4SDavid E. O'Brien 	    put_color(&variables[VRight].color);
482c80476e4SDavid E. O'Brien 	}
483c80476e4SDavid E. O'Brien     }
484c80476e4SDavid E. O'Brien     else
48523338178SMark Peek 	xprintf("%S", filename);
48623338178SMark Peek     xputwchar(suffix);
487c80476e4SDavid E. O'Brien }
488c80476e4SDavid E. O'Brien 
489c80476e4SDavid E. O'Brien 
490c80476e4SDavid E. O'Brien #endif /* COLOR_LS_F */
491