1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/tw.color.c,v 1.27 2010/08/19 05:52:19 christos Exp $ */ 259243Sobrien/* 359243Sobrien * tw.color.c: builtin color ls-F 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1998 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35232633SmpRCSID("$tcsh: tw.color.c,v 1.27 2010/08/19 05:52:19 christos Exp $") 3659243Sobrien 3759243Sobrien#include "tw.h" 3859243Sobrien#include "ed.h" 3959243Sobrien#include "tc.h" 4059243Sobrien 4159243Sobrien#ifdef COLOR_LS_F 4259243Sobrien 4359243Sobrientypedef struct { 44167465Smp const char *s; 45167465Smp size_t len; 4659243Sobrien} Str; 4759243Sobrien 4859243Sobrien 4959243Sobrien#define VAR(suffix,variable,defaultcolor) \ 5059243Sobrien{ \ 5159243Sobrien suffix, variable, { defaultcolor, sizeof(defaultcolor) - 1 }, \ 5259243Sobrien { defaultcolor, sizeof(defaultcolor) - 1 } \ 5359243Sobrien} 5459243Sobrien#define NOS '\0' /* no suffix */ 5559243Sobrien 5659243Sobrientypedef struct { 5759243Sobrien const char suffix; 5859243Sobrien const char *variable; 59167465Smp Str color; 60167465Smp Str defaultcolor; 6159243Sobrien} Variable; 6259243Sobrien 6359243Sobrienstatic Variable variables[] = { 6459243Sobrien VAR('/', "di", "01;34"), /* Directory */ 6559243Sobrien VAR('@', "ln", "01;36"), /* Symbolic link */ 6659243Sobrien VAR('&', "or", ""), /* Orphanned symbolic link (defaults to ln) */ 6759243Sobrien VAR('|', "pi", "33"), /* Named pipe (FIFO) */ 6859243Sobrien VAR('=', "so", "01;35"), /* Socket */ 6983098Smp VAR('>', "do", "01;35"), /* Door (solaris fast ipc mechanism) */ 7059243Sobrien VAR('#', "bd", "01;33"), /* Block device */ 7159243Sobrien VAR('%', "cd", "01;33"), /* Character device */ 7259243Sobrien VAR('*', "ex", "01;32"), /* Executable file */ 7359243Sobrien VAR(NOS, "fi", "0"), /* Regular file */ 7459243Sobrien VAR(NOS, "no", "0"), /* Normal (non-filename) text */ 7559243Sobrien VAR(NOS, "mi", ""), /* Missing file (defaults to fi) */ 7669408Sache#ifdef IS_ASCII 7769408Sache VAR(NOS, "lc", "\033["), /* Left code (ASCII) */ 7869408Sache#else 7959243Sobrien VAR(NOS, "lc", "\x27["), /* Left code (EBCDIC)*/ 8069408Sache#endif 8159243Sobrien VAR(NOS, "rc", "m"), /* Right code */ 8259243Sobrien VAR(NOS, "ec", ""), /* End code (replaces lc+no+rc) */ 83167465Smp VAR(NOS, "su", ""), /* Setuid file (u+s) */ 84167465Smp VAR(NOS, "sg", ""), /* Setgid file (g+s) */ 85167465Smp VAR(NOS, "tw", ""), /* Sticky and other writable dir (+t,o+w) */ 86167465Smp VAR(NOS, "ow", ""), /* Other writable dir (o+w) but not sticky */ 87167465Smp VAR(NOS, "st", ""), /* Sticky dir (+t) but not other writable */ 88195609Smp VAR(NOS, "rs", "0"), /* Reset to normal color */ 89232633Smp VAR(NOS, "hl", "44;37"), /* Reg file extra hard links, obsolete? */ 90232633Smp VAR(NOS, "mh", "44;37"), /* Reg file extra hard links */ 91232633Smp VAR(NOS, "ca", "30;41"), /* File with capability */ 9259243Sobrien}; 9359243Sobrien 9459243Sobrienenum FileType { 9583098Smp VDir, VSym, VOrph, VPipe, VSock, VDoor, VBlock, VChr, VExe, 9659243Sobrien VFile, VNormal, VMiss, VLeft, VRight, VEnd 9759243Sobrien}; 9859243Sobrien 9959243Sobrien#define nvariables (sizeof(variables)/sizeof(variables[0])) 10059243Sobrien 10159243Sobrientypedef struct { 102167465Smp Str extension; /* file extension */ 103167465Smp Str color; /* color string */ 10459243Sobrien} Extension; 10559243Sobrien 10659243Sobrienstatic Extension *extensions = NULL; 107145479Smpstatic size_t nextensions = 0; 10859243Sobrien 10959243Sobrienstatic char *colors = NULL; 110145479Smpint color_context_ls = FALSE; /* do colored ls */ 111167465Smpstatic int color_context_lsmF = FALSE; /* do colored ls-F */ 11259243Sobrien 113167465Smpstatic int getstring (char **, const Char **, Str *, int); 114167465Smpstatic void put_color (const Str *); 115167465Smpstatic void print_color (const Char *, size_t, Char); 11659243Sobrien 11759243Sobrien/* set_color_context(): 11859243Sobrien */ 11959243Sobrienvoid 120167465Smpset_color_context(void) 12159243Sobrien{ 12259243Sobrien struct varent *vp = adrof(STRcolor); 12359243Sobrien 124100616Smp if (vp == NULL || vp->vec == NULL) { 12559243Sobrien color_context_ls = FALSE; 12659243Sobrien color_context_lsmF = FALSE; 127100616Smp } else if (!vp->vec[0] || vp->vec[0][0] == '\0') { 12859243Sobrien color_context_ls = TRUE; 12959243Sobrien color_context_lsmF = TRUE; 130100616Smp } else { 13159243Sobrien size_t i; 13259243Sobrien 13359243Sobrien color_context_ls = FALSE; 13459243Sobrien color_context_lsmF = FALSE; 13559243Sobrien for (i = 0; vp->vec[i]; i++) 13659243Sobrien if (Strcmp(vp->vec[i], STRls) == 0) 13759243Sobrien color_context_ls = TRUE; 13859243Sobrien else if (Strcmp(vp->vec[i], STRlsmF) == 0) 13959243Sobrien color_context_lsmF = TRUE; 14059243Sobrien } 14159243Sobrien} 14259243Sobrien 14359243Sobrien 14459243Sobrien/* getstring(): 14559243Sobrien */ 146167465Smpstatic int 147167465Smpgetstring(char **dp, const Char **sp, Str *pd, int f) 14859243Sobrien{ 14959243Sobrien const Char *s = *sp; 15059243Sobrien char *d = *dp; 151145479Smp eChar sc; 15259243Sobrien 153145479Smp while (*s && (*s & CHAR) != (Char)f && (*s & CHAR) != ':') { 15459243Sobrien if ((*s & CHAR) == '\\' || (*s & CHAR) == '^') { 155145479Smp if ((sc = parseescape(&s)) == CHAR_ERR) 15659243Sobrien return 0; 15759243Sobrien } 15859243Sobrien else 159145479Smp sc = *s++ & CHAR; 160145479Smp d += one_wctomb(d, sc); 16159243Sobrien } 16259243Sobrien 16359243Sobrien pd->s = *dp; 164167465Smp pd->len = d - *dp; 16559243Sobrien *sp = s; 16659243Sobrien *dp = d; 167145479Smp return *s == (Char)f; 16859243Sobrien} 16959243Sobrien 17059243Sobrien 17159243Sobrien/* parseLS_COLORS(): 17259243Sobrien * Parse the LS_COLORS environment variable 17359243Sobrien */ 17459243Sobrienvoid 175167465SmpparseLS_COLORS(const Char *value) 17659243Sobrien{ 177145479Smp size_t i, len; 178167465Smp const Char *v; /* pointer in value */ 17959243Sobrien char *c; /* pointer in colors */ 180145479Smp Extension *volatile e; /* pointer in extensions */ 18159415Sobrien jmp_buf_t osetexit; 182167465Smp size_t omark; 18359243Sobrien 184100616Smp (void) &e; 185100616Smp 18659243Sobrien /* init */ 187167465Smp xfree(extensions); 18859243Sobrien for (i = 0; i < nvariables; i++) 18959243Sobrien variables[i].color = variables[i].defaultcolor; 19059243Sobrien colors = NULL; 19159243Sobrien extensions = NULL; 19259243Sobrien nextensions = 0; 19359243Sobrien 19459243Sobrien if (value == NULL) 19559243Sobrien return; 19659243Sobrien 19759243Sobrien len = Strlen(value); 19859243Sobrien /* allocate memory */ 19959243Sobrien i = 1; 20059243Sobrien for (v = value; *v; v++) 20159243Sobrien if ((*v & CHAR) == ':') 20259243Sobrien i++; 203167465Smp extensions = xmalloc(len + i * sizeof(Extension)); 20459243Sobrien colors = i * sizeof(Extension) + (char *)extensions; 20559243Sobrien nextensions = 0; 20659243Sobrien 20759243Sobrien /* init pointers */ 20859243Sobrien v = value; 20959243Sobrien c = colors; 21059243Sobrien e = &extensions[0]; 21159243Sobrien 21259415Sobrien /* Prevent from crashing if unknown parameters are given. */ 21359415Sobrien 214167465Smp omark = cleanup_push_mark(); 21559415Sobrien getexit(osetexit); 21659415Sobrien 21759415Sobrien if (setexit() == 0) { 218167465Smp 21959243Sobrien /* parse */ 22059243Sobrien while (*v) { 22159243Sobrien switch (*v & CHAR) { 22259243Sobrien case ':': 22359243Sobrien v++; 22459243Sobrien continue; 22559243Sobrien 22659243Sobrien case '*': /* :*ext=color: */ 22759243Sobrien v++; 22859243Sobrien if (getstring(&c, &v, &e->extension, '=') && 22959243Sobrien 0 < e->extension.len) { 23059243Sobrien v++; 23159243Sobrien getstring(&c, &v, &e->color, ':'); 23259243Sobrien e++; 23359243Sobrien continue; 23459243Sobrien } 23559243Sobrien break; 23659243Sobrien 23759243Sobrien default: /* :vl=color: */ 23859243Sobrien if (v[0] && v[1] && (v[2] & CHAR) == '=') { 23959243Sobrien for (i = 0; i < nvariables; i++) 240145479Smp if ((Char)variables[i].variable[0] == (v[0] & CHAR) && 241145479Smp (Char)variables[i].variable[1] == (v[1] & CHAR)) 24259243Sobrien break; 24359243Sobrien if (i < nvariables) { 24459243Sobrien v += 3; 24559243Sobrien getstring(&c, &v, &variables[i].color, ':'); 24659243Sobrien continue; 24759243Sobrien } 24859243Sobrien else 24959243Sobrien stderror(ERR_BADCOLORVAR, v[0], v[1]); 25059243Sobrien } 25159243Sobrien break; 25259243Sobrien } 25359243Sobrien while (*v && (*v & CHAR) != ':') 25459243Sobrien v++; 25559243Sobrien } 25659415Sobrien } 25759243Sobrien 258167465Smp cleanup_pop_mark(omark); 25959415Sobrien resexit(osetexit); 26059415Sobrien 261167465Smp nextensions = e - extensions; 26259243Sobrien} 26359243Sobrien 26459243Sobrien/* put_color(): 26559243Sobrien */ 26659243Sobrienstatic void 267167465Smpput_color(const Str *color) 26859243Sobrien{ 26959243Sobrien size_t i; 270167465Smp const char *c = color->s; 271167465Smp int original_output_raw = output_raw; 27259243Sobrien 27359243Sobrien output_raw = TRUE; 274167465Smp cleanup_push(&original_output_raw, output_raw_restore); 27559243Sobrien for (i = color->len; 0 < i; i--) 27659243Sobrien xputchar(*c++); 277167465Smp cleanup_until(&original_output_raw); 27859243Sobrien} 27959243Sobrien 28059243Sobrien 28159243Sobrien/* print_color(): 28259243Sobrien */ 28359243Sobrienstatic void 284167465Smpprint_color(const Char *fname, size_t len, Char suffix) 28559243Sobrien{ 286145479Smp size_t i; 28759243Sobrien char *filename = short2str(fname); 28859243Sobrien char *last = filename + len; 289167465Smp Str *color = &variables[VFile].color; 29059243Sobrien 29159243Sobrien switch (suffix) { 29259243Sobrien case '>': /* File is a symbolic link pointing to 29359243Sobrien * a directory */ 294167465Smp color = &variables[VDir].color; 295167465Smp break; 29659243Sobrien case '+': /* File is a hidden directory [aix] or 29759243Sobrien * context dependent [hpux] */ 29859243Sobrien case ':': /* File is network special [hpux] */ 299167465Smp break; 30059243Sobrien default: 30159243Sobrien for (i = 0; i < nvariables; i++) 30259243Sobrien if (variables[i].suffix != NOS && 303145479Smp (Char)variables[i].suffix == suffix) { 30459243Sobrien color = &variables[i].color; 30559243Sobrien break; 30659243Sobrien } 30759243Sobrien if (i == nvariables) { 30859243Sobrien for (i = 0; i < nextensions; i++) 309167465Smp if (len >= extensions[i].extension.len 310167465Smp && strncmp(last - extensions[i].extension.len, 311167465Smp extensions[i].extension.s, 312167465Smp extensions[i].extension.len) == 0) { 31359243Sobrien color = &extensions[i].color; 31459243Sobrien break; 31559243Sobrien } 31659243Sobrien } 31759243Sobrien break; 31859243Sobrien } 31959243Sobrien 32059243Sobrien put_color(&variables[VLeft].color); 32159243Sobrien put_color(color); 32259243Sobrien put_color(&variables[VRight].color); 32359243Sobrien} 32459243Sobrien 32559243Sobrien 32659243Sobrien/* print_with_color(): 32759243Sobrien */ 32859243Sobrienvoid 329167465Smpprint_with_color(const Char *filename, size_t len, Char suffix) 33059243Sobrien{ 33159243Sobrien if (color_context_lsmF && 33259243Sobrien (haderr ? (didfds ? is2atty : isdiagatty) : 33359243Sobrien (didfds ? is1atty : isoutatty))) { 33459243Sobrien print_color(filename, len, suffix); 33559243Sobrien xprintf("%S", filename); 33659243Sobrien if (0 < variables[VEnd].color.len) 33759243Sobrien put_color(&variables[VEnd].color); 33859243Sobrien else { 33959243Sobrien put_color(&variables[VLeft].color); 34059243Sobrien put_color(&variables[VNormal].color); 34159243Sobrien put_color(&variables[VRight].color); 34259243Sobrien } 34359243Sobrien } 34459243Sobrien else 345145479Smp xprintf("%S", filename); 346145479Smp xputwchar(suffix); 34759243Sobrien} 34859243Sobrien 34959243Sobrien 35059243Sobrien#endif /* COLOR_LS_F */ 351