1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-07-25 10:16:53 +02:00
This commit is contained in:
Jim Meyering
1996-04-29 04:04:59 +00:00
parent ea11fd8868
commit 6ea9602009
+563
View File
@@ -0,0 +1,563 @@
/* dircolors - parse a Slackware-style DIR_COLORS file.
Copyright (C) 1994, 1995 H. Peter Anvin
Copyright (C) 1996 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include "system.h"
#include "error.h"
#define USER_FILE ".dir_colors" /* Versus user's home directory */
#define SYSTEM_FILE "/DIR_COLORS" /* System-wide file in directory SYSTEM_DIR
(defined on the cc command line). */
#define STRINGLEN 2048 /* Max length of a string */
enum modes { mo_sh, mo_csh, mo_ksh, mo_zsh, mo_unknown, mo_err };
const char *shells[] = { "sh", "ash", "csh", "tcsh", "bash", "ksh",
"zsh", NULL };
const int shell_mode[] = { mo_sh, mo_sh, mo_csh, mo_csh,
mo_ksh, mo_ksh, mo_zsh };
char *program_name;
static void usage __P ((int status));
static int
figure_mode (void)
{
char *shell, *shellv;
int i;
shellv = getenv ("SHELL");
if (shellv == NULL || *shellv == '\0')
error (1, 0, _("\
No SHELL variable, and no mode option specified"));
shell = strrchr (shellv, '/');
if (shell != NULL)
++shell;
else
shell = shellv;
for (i = 0; shells[i]; ++i)
if (strcmp (shell, shells[i]) == 0)
return shell_mode[i];
error (1, 0, _("Unknown shell `%s'\n"), shell);
/* NOTREACHED */
}
static void
parse_line (char **keyword, char **arg, char *line)
{
char *p;
*keyword = *arg = "";
for (p = line; isspace (*p); ++p)
;
if (*p == '\0' || *p == '#')
return;
*keyword = p;
while (!isspace (*p))
if (*p++ == '\0')
return;
*p++ = '\0';
while (isspace (*p))
++p;
if (*p == '\0' || *p == '#')
return;
*arg = p;
while (*p != '\0' && *p != '#')
++p;
for (--p; isspace (*p); --p)
;
++p;
*p = '\0';
}
/* Write a string to standard out, while watching for "dangerous"
sequences like unescaped : and = characters. */
static void
put_seq (char *str, char follow)
{
int danger = 1;
while (*str != '\0')
{
switch (*str)
{
case '\\':
case '^':
danger = !danger;
break;
case ':':
case '=':
if (danger)
putchar ('\\');
/* Fall through */
default:
danger = 1;
break;
}
putchar (*str++);
}
putchar (follow); /* The character that ends the sequence. */
}
/* Parser needs these state variables. */
enum states { st_termno, st_termyes, st_termsure, st_global };
const char *slack_codes[] = {"NORMAL", "NORM", "FILE", "DIR", "LNK", "LINK",
"SYMLINK", "ORPHAN", "MISSING", "FIFO", "PIPE", "SOCK", "BLK", "BLOCK",
"CHR", "CHAR", "EXEC", "LEFT", "LEFTCODE", "RIGHT", "RIGHTCODE", "END",
"ENDCODE", NULL};
const char *ls_codes[] = {"no", "no", "fi", "di", "ln", "ln", "ln",
"or", "mi", "pi", "pi", "so", "bd", "bd", "cd", "cd", "ex", "lc", "lc", "rc",
"rc", "ec", "ec"};
enum color_opts { col_yes, col_no, col_tty };
static struct option long_options[] =
{
{"ash", no_argument, NULL, 'a'},
{"bash", no_argument, NULL, 'b'},
{"csh", no_argument, NULL, 'c'},
{"help", no_argument, NULL, 'h'},
{"no-path", no_argument, NULL, 'P'},
{"sh", no_argument, NULL, 's'},
{"tcsh", no_argument, NULL, 't'},
{"version", no_argument, NULL, 'v'},
{"zsh", no_argument, NULL, 'z'},
};
int
main (int argc, char *argv[])
{
char *p, *q;
char *file = NULL;
int optc;
int mode = mo_unknown;
FILE *fp = NULL;
char *term;
int state;
char line[STRINGLEN];
char useropts[2048] = "";
char *keywd, *arg;
int color_opt = col_no; /* Assume --color=no */
int no_path = 0; /* Do not search PATH */
int do_help = 0;
int do_version = 0;
char *copt;
char *input_file;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
/* Parse command line. */
while ((optc = getopt_long (argc, argv, "abhckPstz", long_options, NULL))
!= EOF)
switch (optc)
{
case 'a':
case 's': /* Plain sh mode */
mode = mo_sh;
break;
case 'c':
case 't':
mode = mo_csh;
break;
case 'b':
case 'k':
mode = mo_ksh;
break;
case 'h':
do_help = 1;
break;
case 'z':
mode = mo_zsh;
break;
case 'P':
no_path = 1;
break;
case 'v':
do_version = 1;
break;
default:
usage (1);
}
/* If version information is wanted show it. */
if (do_version)
{
printf ("%s - %s\n", program_name, PACKAGE_VERSION);
exit (0);
}
/* If help is wanted show the screen. */
if (do_help)
usage (0);
/* Use shell to determine mode, if not already done. */
if (mode == mo_unknown)
mode = figure_mode ();
/* Open dir_colors file */
if (optind == argc)
{
p = getenv ("HOME");
if (p != NULL && *p != '\0')
{
chdir (p);
input_file = USER_FILE;
fp = fopen (input_file, "r");
}
if (fp == NULL)
{
input_file = SHAREDIR SYSTEM_FILE;
fp = fopen (input_file, "r");
}
}
else
{
input_file = argv[optind];
fp = fopen (input_file, "r");
}
if (fp == NULL)
error (1, errno, _("while opening input file `%s'"), input_file);
/* Get terminal type */
term = getenv ("TERM");
if (term == NULL || *term == '\0')
term = "none";
/* Write out common start */
switch (mode)
{
case mo_csh:
puts ("set noglob;\n\
setenv LS_COLORS \':");
break;
case mo_sh:
case mo_ksh:
case mo_zsh:
puts ("LS_COLORS=\'");
break;
}
/* Start parsing that sucker */
state = st_global;
while (fgets (line, STRINGLEN, fp) != NULL )
{
parse_line (&keywd, &arg, line);
if (*keywd != '\0')
{
if (strcasecmp (keywd, "TERM") == 0)
{
if (strcmp (arg, term) == 0)
state = st_termsure;
else if (state != st_termsure)
state = st_termno;
}
else
{
if (state == st_termsure)
state = st_termyes; /* Another TERM can cancel */
if (state != st_termno)
{
if (keywd[0] == '.')
{
putchar ('*');
put_seq (keywd, '=');
put_seq (arg, ':');
}
else if (keywd[0] == '*')
{
put_seq (keywd, '=');
put_seq (arg, ':');
}
else if (strcasecmp(keywd, "OPTIONS") == 0)
{
strcat (useropts, " ");
strcat (useropts, arg);
}
else if (strcasecmp(keywd, "COLOR") == 0)
{
switch (arg[0])
{
case 'a':
case 'y':
case '1':
color_opt = col_yes;
break;
case 'n':
case '0':
color_opt = col_no;
break;
case 't':
color_opt = col_tty;
break;
default:
error (0, 0, _("Unknown COLOR option `%s'\n"), arg);
break;
}
}
else
{
int i;
for (i = 0; slack_codes[i] != NULL; ++i)
if (strcasecmp (keywd, slack_codes[i]) == 0)
break;
if (slack_codes[i] != NULL)
{
printf ("%s=", ls_codes[i]);
put_seq (arg, ':');
}
else
error (0, 0, _("Unknown keyword %s\n"), keywd);
}
}
}
}
}
fclose (fp);
/* Decide on the options. */
switch (color_opt)
{
case col_yes:
copt = "--color=yes";
break;
case col_no:
copt = "--color=no";
break;
case col_tty:
copt = "--color=tty";
break;
}
/* Find ls in the path. */
if (no_path == NULL)
{
no_path = 1; /* Assume we won't find one. */
p = getenv ("PATH");
if (p != NULL && *p != '\0')
{
while (*p != '\0')
{
while (*p == ':')
++p;
if (*p != '/') /* Skip relative path entries. */
while (*p != '\0' && *p != ':')
++p;
else
{
q = line;
while (*p != '\0' && *p != ':')
*q++ = *p++;
/* Make sure it ends in slash. */
if (*(q-1) != '/' )
*q++ = '/';
strcpy (q, "ls");
if (access (line, X_OK) == 0)
{
no_path = 0; /* Found it. */
break;
}
}
}
}
}
/* Write it out. */
switch (mode)
{
case mo_sh:
if (no_path)
printf ("\';\n\
export LS_COLORS;\n\
LS_OPTIONS='%s%s';\n\
export LS_OPTIONS;\n\
ls () { ( exec ls $LS_OPTIONS \"$@\" ) };\n\
dir () { ( exec dir $LS_OPTIONS \"$@\" ) };\n\
vdir () { ( exec vdir $LS_OPTIONS \"$@\" ) };\n\
d () { dir \"$@\" ; };\n\
v () { vdir \"$@\" ; };\n", copt, useropts);
else
printf ("\';\n\
export LS_COLORS;\n\
LS_OPTIONS='%s%s';\n\
ls () { %s $LS_OPTIONS \"$@\" ; };\n\
dir () { %s $LS_OPTIONS --format=vertical \"$@\" ; };\n\
vdir () { %s $LS_OPTIONS --format=long \"$@\" ; };\n\
d () { dir \"$@\" ; };\n\
v () { vdir \"$@\" ; };\n", copt, useropts, line, line, line);
break;
case mo_csh:
if (no_path)
printf ("\';\n\
setenv LS_OPTIONS '%s%s';\n\
alias ls \'ls $LS_OPTIONS\';\n\
alias dir \'dir $LS_OPTIONS\';\n\
alias vdir \'vdir $LS_OPTIONS\';\n\
alias d dir;\n\
alias v vdir;\n\
unset noglob;\n", copt, useropts);
else
printf ("\';\n\
setenv LS_OPTIONS '%s%s';\n\
alias ls \'%s $LS_OPTIONS\';\n\
alias dir \'%s $LS_OPTIONS --format=vertical\';\n\
alias vdir \'%s $LS_OPTIONS --format=long\';\n\
alias d dir;\n\
alias v vdir;\n\
unset noglob;\n", copt, useropts, line, line, line);
break;
case mo_ksh:
if (no_path)
printf ("\';\n\
export LS_COLORS;\n\
LS_OPTIONS='%s%s';\n\
export LS_OPTIONS;\n\
alias ls=\'ls $LS_OPTIONS\';\n\
alias dir=\'dir $LS_OPTIONS\';\n\
alias vdir=\'vdir $LS_OPTIONS\';\n\
alias d=dir;\n\
alias v=vdir;\n", copt, useropts);
else
printf ("\';\n\
export LS_COLORS;\n\
LS_OPTIONS='%s%s';\n\
export LS_OPTIONS;\n\
alias ls=\'%s $LS_OPTIONS\';\n\
alias dir=\'%s $LS_OPTIONS --format=vertical\';\n\
alias vdir=\'%s $LS_OPTIONS --format=long\';\n\
alias d=dir;\n\
alias v=vdir;\n", copt, useropts, line, line, line);
break;
case mo_zsh:
if (no_path)
printf ("\';\n\
export LS_COLORS;\n\
LS_OPTIONS=(%s%s);\n\
export LS_OPTIONS;\n\
alias ls=\'ls $LS_OPTIONS\';\n\
alias dir=\'dir $LS_OPTIONS\';\n\
alias vdir=\'vdir $LS_OPTIONS\';\n\
alias d=dir;\n\
alias v=vdir;\n", copt, useropts);
else
printf ("\';\n\
export LS_COLORS;\n\
LS_OPTIONS=(%s%s);\n\
export LS_OPTIONS;\n\
alias ls=\'%s $LS_OPTIONS\';\n\
alias dir=\'%s $LS_OPTIONS --format=vertical\';\n\
alias vdir=\'%s $LS_OPTIONS --format=long\';\n\
alias d=dir;\n\
alias v=vdir;\n", copt, useropts, line, line, line);
break;
}
exit (0);
}
static void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION]... [FILE]\n"), program_name);
printf (_("\
-h, --help display this help and exit\n\
-P, --no-path do not look for shell in PATH\n\
--version output version information and exit\n\
Determine format of output:\n\
-a, --ash assume ash shell\n\
-b, --bash assume bash shell\n\
-c, --csh assume csh shell\n\
-s, --sh assume Bourne shell\n\
-t, --tcsh assume tcsh shell\n\
-z, --zsh assume zsh shell\n"));
}
exit (status);
}