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:
parent
b8e8da45a9
commit
3885812c8c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=61178
@ -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));
|
||||
|
76
bin/ls/ls.1
76
bin/ls/ls.1
@ -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
|
||||
|
16
bin/ls/ls.c
16
bin/ls/ls.c
@ -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;
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
129
bin/ls/print.c
129
bin/ls/print.c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user