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