Add colour support to /bin/ls (at a cost of 1056 bytes on my system).

It is not switched on by default and must be enabled with the -G
flag.  When using ls -G the output behaviour is modified with ANSI
colour sequences wrapped around filenames to help distinguish file
types.  (Colours can be redefined in the LSCOLORS environment
variable as described in the manual page.)

Colour support is silently disabled (if switched on) if stdout
isn't a tty.

Based on:	asami's colorls port.
PR:		bin/18900 && ports/18616.
This commit is contained in:
Josef Karthauser 2000-06-02 14:53:42 +00:00
parent b8e8da45a9
commit 3885812c8c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=61178
5 changed files with 220 additions and 4 deletions

View File

@ -51,3 +51,5 @@ void printscol __P((DISPLAY *));
void usage __P((void));
int len_octal __P((char *, int));
int prn_octal __P((char *));
void parsecolors __P((char *cs));
int colortype __P((mode_t mode));

View File

@ -43,7 +43,7 @@
.Nd list directory contents
.Sh SYNOPSIS
.Nm ls
.Op Fl ABCFHLPRTWabcdfgiklnoqrstu1
.Op Fl ABCFGHLPRTWabcdfgiklnoqrstu1
.Op Ar file ...
.Sh DESCRIPTION
For each operand that names a
@ -90,6 +90,12 @@ an equals sign (=) after each socket,
a percent sign (%) after each whiteout,
and a vertical bar (|) after each that is a
.Tn FIFO .
.It Fl G
Use ANSI color sequences to distinguish file types. (See
.Ev LSCOLORS
below.) In addition to those mentioned above in
.Fl F ,
some extra attributes (setuid bit set, etc.) are also displayed.
.It Fl H
Symbolic links on the command line are followed. This option is assumed if
none of the
@ -386,6 +392,74 @@ The timezone to use when displaying dates.
See
.Xr environ 7
for more information.
.It LSCOLORS
The value of this variable describes what color to use for which
attribute when the color output
.Pq Fl G
is specified. This string is a concatenation of pairs of the format
.Sy fb ,
where
.Sy f
is the foreground color and
.Sy b
is the background color.
.Pp
The color designators are as follows:
.Pp
.Bl -tag -width 4n -offset indent -compact
.It Sy 0
black
.It Sy 1
red
.It Sy 2
green
.It Sy 3
yellow
.It Sy 4
blue
.It Sy 5
magenta
.It Sy 6
cyan
.It Sy 7
white
.It Sy x
default foreground or background
.El
.Pp
(Note: the above are standard ANSI colors. The actual display may
differ depending on the color capabilities of your terminal.)
.Pp
The order of the attributes are as follows:
.Pp
.Bl -enum -offset indent -compact
.It
directory
.It
symbolic link
.It
socket
.It
pipe
.It
executable
.It
block special
.It
character special
.It
executable with setuid bit set
.It
executable with setgid bit set
.It
directory writable to others, with sticky bit
.It
directory writable to others, without sticky bit
.El
.Pp
The default is "4x5x2x3x1x464301060203", i.e., blue foreground and
default background for regular directories, black foreground and red
background for setuid executables, etc.
.It Ev LS_COLWIDTHS
If this variable is set, it is considered to be a
colon-delimited list of minimum column widths. Unreasonable

View File

@ -111,6 +111,7 @@ int f_statustime; /* use time of last mode change */
int f_timesort; /* sort by time vice name */
int f_type; /* add type character for non-regular files */
int f_whiteout; /* show whiteout entries */
int f_color; /* add type in color for non-regular files */
int rval;
@ -148,7 +149,7 @@ main(argc, argv)
f_listdot = 1;
fts_options = FTS_PHYSICAL;
while ((ch = getopt(argc, argv, "1ABCFHLPRTWabcdfgiklnoqrstu")) != -1) {
while ((ch = getopt(argc, argv, "1ABCFGHLPRTWabcdfgiklnoqrstu")) != -1) {
switch (ch) {
/*
* The -1, -C and -l options all override each other so shell
@ -186,6 +187,10 @@ main(argc, argv)
case 'H':
fts_options |= FTS_COMFOLLOW;
break;
case 'G':
if (isatty(STDOUT_FILENO))
f_color = 1;
break;
case 'L':
fts_options &= ~FTS_PHYSICAL;
fts_options |= FTS_LOGICAL;
@ -259,11 +264,16 @@ main(argc, argv)
argc -= optind;
argv += optind;
if (f_color)
parsecolors(getenv("LSCOLORS"));
/*
* If not -F, -i, -l, -s or -t options, don't require stat
* information.
* information, unless in color mode in which case we do
* need this to determine which colors to display.
*/
if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type)
if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type
&& !f_color)
fts_options |= FTS_NOSTAT;
/*

View File

@ -53,6 +53,7 @@ extern int f_size; /* list size in short listing */
extern int f_statustime; /* use time of last mode change */
extern int f_notabs; /* don't use tab-separated multi-col output */
extern int f_type; /* add type character for non-regular files */
extern int f_color; /* add type in color for non-regular files */
typedef struct {
FTSENT *list;

View File

@ -56,6 +56,7 @@ static const char rcsid[] =
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <ctype.h>
#include "ls.h"
#include "extern.h"
@ -67,6 +68,26 @@ static int printtype __P((u_int));
#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT)
/* Most of these are taken from <sys/stat.h> */
typedef enum Colors {
C_DIR, /* directory */
C_LNK, /* symbolic link */
C_SOCK, /* socket */
C_FIFO, /* pipe */
C_EXEC, /* executable */
C_BLK, /* block special */
C_CHR, /* character special */
C_SUID, /* setuid executable */
C_SGID, /* setgid executable */
C_WSDIR, /* directory writeble to others, with sticky bit */
C_WDIR, /* directory writeble to others, without sticky bit */
C_NUMCOLORS /* just a place-holder */
} Colors ;
char *defcolors = "4x5x2x3x1x464301060203";
static int colors[C_NUMCOLORS][2];
void
printscol(dp)
DISPLAY *dp;
@ -128,8 +149,12 @@ printlong(dp)
printtime(sp->st_ctime);
else
printtime(sp->st_mtime);
if (f_color)
(void)colortype(sp->st_mode);
if (f_octal || f_octal_escape) (void)prn_octal(p->fts_name);
else (void)printf("%s", p->fts_name);
if (f_color)
(void)printf("\033[m");
if (f_type)
(void)printtype(sp->st_mode);
if (S_ISLNK(sp->st_mode))
@ -199,6 +224,16 @@ printcol(dp)
dp->s_block);
if ((base += numrows) >= num)
break;
/*
* some terminals get confused if we mix tabs
* with color sequences
*/
if (f_color)
while ((cnt = (chcnt + 1)) <= endcol) {
(void)putchar(' ');
chcnt = cnt;
}
else
while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
<= endcol){
(void)putchar(f_notabs ? ' ' : '\t');
@ -229,8 +264,12 @@ printaname(p, inodefield, sizefield)
if (f_size)
chcnt += printf("%*qd ",
(int)sizefield, howmany(sp->st_blocks, blocksize));
if (f_color)
(void)colortype(sp->st_mode);
chcnt += (f_octal || f_octal_escape) ? prn_octal(p->fts_name)
: printf("%s", p->fts_name);
if (f_color)
printf("\033[m");
if (f_type)
chcnt += printtype(sp->st_mode);
return (chcnt);
@ -294,6 +333,96 @@ printtype(mode)
return (0);
}
void
printcolor(c)
Colors c;
{
printf("\033[");
if (colors[c][0] != -1) {
printf("3%d", colors[c][0]);
if (colors[c][1] != -1)
printf(";");
}
if (colors[c][1] != -1)
printf("4%d", colors[c][1]);
printf("m");
}
int
colortype(mode)
mode_t mode;
{
switch(mode & S_IFMT) {
case S_IFDIR:
if (mode & S_IWOTH)
if (mode & S_ISTXT)
printcolor(C_WSDIR);
else
printcolor(C_WDIR);
else
printcolor(C_DIR);
return(1);
case S_IFLNK:
printcolor(C_LNK);
return(1);
case S_IFSOCK:
printcolor(C_SOCK);
return(1);
case S_IFIFO:
printcolor(C_FIFO);
return(1);
case S_IFBLK:
printcolor(C_BLK);
return(1);
case S_IFCHR:
printcolor(C_CHR);
return(1);
}
if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
if (mode & S_ISUID)
printcolor(C_SUID);
else if (mode & S_ISGID)
printcolor(C_SGID);
else
printcolor(C_EXEC);
return(1);
}
return(0);
}
void
parsecolors(cs)
char *cs;
{
int i, j, len;
char c[2];
if (cs == NULL) cs = ""; /* LSCOLORS not set */
len = strlen(cs);
for (i = 0 ; i < C_NUMCOLORS ; i++) {
if (len <= 2*i) {
c[0] = defcolors[2*i];
c[1] = defcolors[2*i+1];
}
else {
c[0] = cs[2*i];
c[1] = cs[2*i+1];
}
for (j = 0 ; j < 2 ; j++) {
if ((c[j] < '0' || c[j] > '7') &&
tolower(c[j]) != 'x') {
fprintf(stderr,
"error: invalid character '%c' in LSCOLORS env var\n",
c[j]);
c[j] = defcolors[2*i+j];
}
if (c[j] == 'x')
colors[i][j] = -1;
else
colors[i][j] = c[j]-'0';
}
}
}
static void
printlink(p)
FTSENT *p;