tw.color.c revision 145479
11590Srgrimes/* $Header: /src/pub/tcsh/tw.color.c,v 1.18 2005/03/03 16:40:53 kim Exp $ */
21590Srgrimes/*
31590Srgrimes * tw.color.c: builtin color ls-F
41590Srgrimes */
51590Srgrimes/*-
61590Srgrimes * Copyright (c) 1998 The Regents of the University of California.
71590Srgrimes * All rights reserved.
81590Srgrimes *
91590Srgrimes * Redistribution and use in source and binary forms, with or without
101590Srgrimes * modification, are permitted provided that the following conditions
111590Srgrimes * are met:
121590Srgrimes * 1. Redistributions of source code must retain the above copyright
131590Srgrimes *    notice, this list of conditions and the following disclaimer.
141590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151590Srgrimes *    notice, this list of conditions and the following disclaimer in the
161590Srgrimes *    documentation and/or other materials provided with the distribution.
171590Srgrimes * 3. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes#include "sh.h"
341590Srgrimes
3528454ScharnierRCSID("$Id: tw.color.c,v 1.18 2005/03/03 16:40:53 kim Exp $")
361590Srgrimes
371590Srgrimes#include "tw.h"
381590Srgrimes#include "ed.h"
391590Srgrimes#include "tc.h"
401590Srgrimes
4128454Scharnier#ifdef COLOR_LS_F
421590Srgrimes
4328454Scharniertypedef struct {
4428454Scharnier    const char   *s;
4550477Speter    int     len;
461590Srgrimes} Str;
471590Srgrimes
4828454Scharnier
49132858Stjr#define VAR(suffix,variable,defaultcolor) \
501590Srgrimes{ \
5128454Scharnier    suffix, variable, { defaultcolor, sizeof(defaultcolor) - 1 }, \
5228454Scharnier      { defaultcolor, sizeof(defaultcolor) - 1 } \
5328454Scharnier}
5428454Scharnier#define NOS '\0' /* no suffix */
55132858Stjr
56132858Stjrtypedef struct {
571590Srgrimes    const char suffix;
581590Srgrimes    const char *variable;
591590Srgrimes    Str     color;
601590Srgrimes    Str     defaultcolor;
611590Srgrimes} Variable;
621590Srgrimes
631590Srgrimesstatic Variable variables[] = {
641590Srgrimes    VAR('/', "di", "01;34"),	/* Directory */
651590Srgrimes    VAR('@', "ln", "01;36"),	/* Symbolic link */
661590Srgrimes    VAR('&', "or", ""),		/* Orphanned symbolic link (defaults to ln) */
671590Srgrimes    VAR('|', "pi", "33"),	/* Named pipe (FIFO) */
681590Srgrimes    VAR('=', "so", "01;35"),	/* Socket */
691590Srgrimes    VAR('>', "do", "01;35"),	/* Door (solaris fast ipc mechanism)  */
701590Srgrimes    VAR('#', "bd", "01;33"),	/* Block device */
711590Srgrimes    VAR('%', "cd", "01;33"),	/* Character device */
721590Srgrimes    VAR('*', "ex", "01;32"),	/* Executable file */
731590Srgrimes    VAR(NOS, "fi", "0"),	/* Regular file */
7487303Sdwmalone    VAR(NOS, "no", "0"),	/* Normal (non-filename) text */
7587303Sdwmalone    VAR(NOS, "mi", ""),		/* Missing file (defaults to fi) */
761590Srgrimes#ifdef IS_ASCII
771590Srgrimes    VAR(NOS, "lc", "\033["),	/* Left code (ASCII) */
781590Srgrimes#else
791590Srgrimes    VAR(NOS, "lc", "\x27["),	/* Left code (EBCDIC)*/
801590Srgrimes#endif
81132858Stjr    VAR(NOS, "rc", "m"),	/* Right code */
82132858Stjr    VAR(NOS, "ec", ""),		/* End code (replaces lc+no+rc) */
831590Srgrimes};
841590Srgrimes
851590Srgrimesenum FileType {
861590Srgrimes    VDir, VSym, VOrph, VPipe, VSock, VDoor, VBlock, VChr, VExe,
871590Srgrimes    VFile, VNormal, VMiss, VLeft, VRight, VEnd
881590Srgrimes};
891590Srgrimes
901590Srgrimes#define nvariables (sizeof(variables)/sizeof(variables[0]))
911590Srgrimes
9292922Simptypedef struct {
9392922Simp    Str     extension;	/* file extension */
9492922Simp    Str     color;	/* color string */
9592922Simp} Extension;
9692922Simp
9792922Simpstatic Extension *extensions = NULL;
9892922Simpstatic size_t nextensions = 0;
9992922Simp
10092922Simpstatic char *colors = NULL;
10192922Simpint	     color_context_ls = FALSE;	/* do colored ls */
10292922Simpstatic int  color_context_lsmF = FALSE;	/* do colored ls-F */
103132858Stjr
10428454Scharnierstatic int getstring __P((char **, const Char **, Str *, int));
1051590Srgrimesstatic void put_color __P((Str *));
1061590Srgrimesstatic void print_color __P((Char *, size_t, Char));
10728789Scharnier
108102944Sdwmalone/* set_color_context():
1091590Srgrimes */
1101590Srgrimesvoid
11187303Sdwmaloneset_color_context()
1121590Srgrimes{
1131590Srgrimes    struct varent *vp = adrof(STRcolor);
1141590Srgrimes
115132858Stjr    if (vp == NULL || vp->vec == NULL) {
116132858Stjr	color_context_ls = FALSE;
1171590Srgrimes	color_context_lsmF = FALSE;
1181590Srgrimes    } else if (!vp->vec[0] || vp->vec[0][0] == '\0') {
1191590Srgrimes	color_context_ls = TRUE;
12024360Simp	color_context_lsmF = TRUE;
1211590Srgrimes    } else {
1221590Srgrimes	size_t i;
1231590Srgrimes
1241590Srgrimes	color_context_ls = FALSE;
12587303Sdwmalone	color_context_lsmF = FALSE;
1261590Srgrimes	for (i = 0; vp->vec[i]; i++)
1271590Srgrimes	    if (Strcmp(vp->vec[i], STRls) == 0)
1281590Srgrimes		color_context_ls = TRUE;
1291590Srgrimes	    else if (Strcmp(vp->vec[i], STRlsmF) == 0)
1301590Srgrimes		color_context_lsmF = TRUE;
13128454Scharnier    }
1321590Srgrimes}
1331590Srgrimes
1341590Srgrimes
1351590Srgrimes/* getstring():
1361590Srgrimes */
1371590Srgrimesstatic  int
1381590Srgrimesgetstring(dp, sp, pd, f)
1391590Srgrimes    char        **dp;		/* dest buffer */
14028454Scharnier    const Char  **sp;		/* source buffer */
141102412Scharnier    Str          *pd;		/* pointer to dest buffer */
1421590Srgrimes    int           f;		/* final character */
1431590Srgrimes{
1441590Srgrimes    const Char *s = *sp;
1451590Srgrimes    char *d = *dp;
1461590Srgrimes    eChar sc;
1471590Srgrimes
1481590Srgrimes    while (*s && (*s & CHAR) != (Char)f && (*s & CHAR) != ':') {
1491590Srgrimes	if ((*s & CHAR) == '\\' || (*s & CHAR) == '^') {
1501590Srgrimes	    if ((sc = parseescape(&s)) == CHAR_ERR)
1511590Srgrimes		return 0;
1521590Srgrimes	}
1531590Srgrimes	else
1541590Srgrimes	    sc = *s++ & CHAR;
1551590Srgrimes	d += one_wctomb(d, sc);
1561590Srgrimes    }
15728454Scharnier
15828454Scharnier    pd->s = *dp;
15928454Scharnier    pd->len = (int) (d - *dp);
1601590Srgrimes    *sp = s;
1611590Srgrimes    *dp = d;
1621590Srgrimes    return *s == (Char)f;
1631590Srgrimes}
1641590Srgrimes
16528454Scharnier
166102944Sdwmalone/* parseLS_COLORS():
16728454Scharnier *	Parse the LS_COLORS environment variable
168146466Sru */
16928454Scharniervoid
17028454ScharnierparseLS_COLORS(value)
17128454Scharnier    Char   *value;		/* LS_COLOR variable's value */
17228454Scharnier{
173102944Sdwmalone    size_t  i, len;
1741590Srgrimes    const Char   *v;		/* pointer in value */
175132858Stjr    char   *c;			/* pointer in colors */
176132858Stjr    Extension *volatile e;	/* pointer in extensions */
1771590Srgrimes    jmp_buf_t osetexit;
178132858Stjr
1791590Srgrimes    (void) &e;
1801590Srgrimes
1811590Srgrimes    /* init */
1821590Srgrimes    if (extensions)
1831590Srgrimes        xfree((ptr_t) extensions);
1841590Srgrimes    for (i = 0; i < nvariables; i++)
1851590Srgrimes	variables[i].color = variables[i].defaultcolor;
1861590Srgrimes    colors = NULL;
1871590Srgrimes    extensions = NULL;
1881590Srgrimes    nextensions = 0;
1891590Srgrimes
1901590Srgrimes    if (value == NULL)
1911590Srgrimes	return;
1921590Srgrimes
1931590Srgrimes    len = Strlen(value);
1941590Srgrimes    /* allocate memory */
1951590Srgrimes    i = 1;
1961590Srgrimes    for (v = value; *v; v++)
1971590Srgrimes	if ((*v & CHAR) == ':')
1981590Srgrimes	    i++;
1991590Srgrimes    extensions = (Extension *) xmalloc((size_t) (len + i * sizeof(Extension)));
2001590Srgrimes    colors = i * sizeof(Extension) + (char *)extensions;
2011590Srgrimes    nextensions = 0;
2021590Srgrimes
2031590Srgrimes    /* init pointers */
204132858Stjr    v = value;
2051590Srgrimes    c = colors;
2061590Srgrimes    e = &extensions[0];
2071590Srgrimes
2081590Srgrimes    /* Prevent from crashing if unknown parameters are given. */
2091590Srgrimes
2101590Srgrimes    getexit(osetexit);
2111590Srgrimes
2121590Srgrimes    if (setexit() == 0) {
2131590Srgrimes
2141590Srgrimes    /* parse */
2151590Srgrimes    while (*v) {
2161590Srgrimes	switch (*v & CHAR) {
2171590Srgrimes	case ':':
2181590Srgrimes	    v++;
2191590Srgrimes	    continue;
2201590Srgrimes
2211590Srgrimes	case '*':		/* :*ext=color: */
2221590Srgrimes	    v++;
2231590Srgrimes	    if (getstring(&c, &v, &e->extension, '=') &&
2241590Srgrimes		0 < e->extension.len) {
2251590Srgrimes		v++;
2261590Srgrimes		getstring(&c, &v, &e->color, ':');
2271590Srgrimes		e++;
2281590Srgrimes		continue;
2291590Srgrimes	    }
2301590Srgrimes	    break;
2311590Srgrimes
2321590Srgrimes	default:		/* :vl=color: */
2331590Srgrimes	    if (v[0] && v[1] && (v[2] & CHAR) == '=') {
2341590Srgrimes		for (i = 0; i < nvariables; i++)
2351590Srgrimes		    if ((Char)variables[i].variable[0] == (v[0] & CHAR) &&
2361590Srgrimes			(Char)variables[i].variable[1] == (v[1] & CHAR))
23728454Scharnier			break;
2381590Srgrimes		if (i < nvariables) {
2391590Srgrimes		    v += 3;
2401590Srgrimes		    getstring(&c, &v, &variables[i].color, ':');
2411590Srgrimes		    continue;
242132858Stjr		}
243132858Stjr		else
244132858Stjr		    stderror(ERR_BADCOLORVAR, v[0], v[1]);
245132858Stjr	    }
246132858Stjr	    break;
247132858Stjr	}
248132858Stjr	while (*v && (*v & CHAR) != ':')
249132858Stjr	    v++;
250132858Stjr    }
251132858Stjr    }
252132858Stjr
253132858Stjr    resexit(osetexit);
254132858Stjr
2551590Srgrimes    nextensions = (int) (e - extensions);
2561590Srgrimes}
2571590Srgrimes
2581590Srgrimes
2591590Srgrimes/* put_color():
2601590Srgrimes */
2611590Srgrimesstatic void
2621590Srgrimesput_color(color)
2631590Srgrimes    Str    *color;
2641590Srgrimes{
2651590Srgrimes    size_t  i;
2661590Srgrimes    const char   *c = color->s;
267132858Stjr    int    original_output_raw = output_raw;
2681590Srgrimes
2691590Srgrimes    output_raw = TRUE;
2701590Srgrimes    for (i = color->len; 0 < i; i--)
271132858Stjr	xputchar(*c++);
2721590Srgrimes    output_raw = original_output_raw;
2731590Srgrimes}
2741590Srgrimes
275132858Stjr
276132858Stjr/* print_color():
277132858Stjr */
278132858Stjrstatic void
279132858Stjrprint_color(fname, len, suffix)
2801590Srgrimes    Char   *fname;
2811590Srgrimes    size_t  len;
282132858Stjr    Char    suffix;
283132858Stjr{
284132858Stjr    size_t  i;
285132858Stjr    char   *filename = short2str(fname);
286132858Stjr    char   *last = filename + len;
287132858Stjr    Str    *color = &variables[VFile].color;
288132858Stjr
289132858Stjr    switch (suffix) {
290132858Stjr    case '>':			/* File is a symbolic link pointing to
291132858Stjr				 * a directory */
292132858Stjr        color = &variables[VDir].color;
293132858Stjr	    break;
294132858Stjr    case '+':			/* File is a hidden directory [aix] or
295132858Stjr				 * context dependent [hpux] */
2961590Srgrimes    case ':':			/* File is network special [hpux] */
2971590Srgrimes        break;
2981590Srgrimes    default:
2991590Srgrimes	for (i = 0; i < nvariables; i++)
300132882Stjr	    if (variables[i].suffix != NOS &&
301132882Stjr		(Char)variables[i].suffix == suffix) {
3021590Srgrimes		color = &variables[i].color;
3031590Srgrimes		break;
3041590Srgrimes	    }
3051590Srgrimes	if (i == nvariables) {
30628454Scharnier	    for (i = 0; i < nextensions; i++)
307102944Sdwmalone	        if (strncmp(last - extensions[i].extension.len,
3081590Srgrimes			    extensions[i].extension.s,
30987303Sdwmalone			    extensions[i].extension.len) == 0) {
31087303Sdwmalone		  color = &extensions[i].color;
3111590Srgrimes		break;
3121590Srgrimes	    }
3131590Srgrimes	}
3141590Srgrimes	break;
3151590Srgrimes    }
3161590Srgrimes
31728454Scharnier    put_color(&variables[VLeft].color);
3181590Srgrimes    put_color(color);
3191590Srgrimes    put_color(&variables[VRight].color);
3201590Srgrimes}
3211590Srgrimes
3221590Srgrimes
3231590Srgrimes/* print_with_color():
324132858Stjr */
3251590Srgrimesvoid
326132858Stjrprint_with_color(filename, len, suffix)
327132858Stjr    Char   *filename;
328132858Stjr    size_t  len;
3291590Srgrimes    Char    suffix;
3301590Srgrimes{
33128454Scharnier    if (color_context_lsmF &&
3321590Srgrimes	(haderr ? (didfds ? is2atty : isdiagatty) :
3331590Srgrimes	 (didfds ? is1atty : isoutatty))) {
3341590Srgrimes	print_color(filename, len, suffix);
335132858Stjr	xprintf("%S", filename);
3361590Srgrimes	if (0 < variables[VEnd].color.len)
3371590Srgrimes	    put_color(&variables[VEnd].color);
3381590Srgrimes	else {
3391590Srgrimes	    put_color(&variables[VLeft].color);
3401590Srgrimes	    put_color(&variables[VNormal].color);
3411590Srgrimes	    put_color(&variables[VRight].color);
3421590Srgrimes	}
3431590Srgrimes    }
3441590Srgrimes    else
3451590Srgrimes	xprintf("%S", filename);
3461590Srgrimes    xputwchar(suffix);
3471590Srgrimes}
34828454Scharnier
349102944Sdwmalone
3501590Srgrimes#endif /* COLOR_LS_F */
351102944Sdwmalone