1 /* FIXME: accept, but ignore EIGHTBIT option
2 FIXME: embed contents of default mapping file
3 FIXME: add option to print that default mapping?
5 /* dircolors - parse a Slackware-style DIR_COLORS file.
6 Copyright (C) 1994, 1995 H. Peter Anvin
7 Copyright (C) 1996 Free Software Foundation, Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
36 #define USER_FILE ".dir_colors" /* Versus user's home directory */
37 #define SYSTEM_FILE "DIR_COLORS" /* System-wide file in directory SYSTEM_DIR
38 (defined on the cc command line). */
40 #define STRINGLEN 2048 /* Max length of a string */
42 enum modes { MO_SH, MO_CSH, MO_KSH, MO_ZSH, MO_UNKNOWN, MO_ERR };
44 /* FIXME: associate these arrays? */
45 static const char *const shells[] =
46 { "sh", "ash", "csh", "tcsh", "bash", "ksh", "zsh", NULL };
48 static const int shell_mode[] =
49 { MO_SH, MO_SH, MO_CSH, MO_CSH, MO_KSH, MO_KSH, MO_ZSH };
51 /* Parser needs these state variables. */
52 enum states { ST_TERMNO, ST_TERMYES, ST_TERMSURE, ST_GLOBAL };
54 /* FIXME: associate with ls_codes? */
55 static const char *const slack_codes[] =
57 "NORMAL", "NORM", "FILE", "DIR", "LNK", "LINK",
58 "SYMLINK", "ORPHAN", "MISSING", "FIFO", "PIPE", "SOCK", "BLK", "BLOCK",
59 "CHR", "CHAR", "EXEC", "LEFT", "LEFTCODE", "RIGHT", "RIGHTCODE", "END",
63 static const char *const ls_codes[] =
65 "no", "no", "fi", "di", "ln", "ln", "ln", "or", "mi", "pi", "pi",
66 "so", "bd", "bd", "cd", "cd", "ex", "lc", "lc", "rc", "rc", "ec", "ec"
69 enum color_opts { col_yes, col_no, col_tty };
71 static struct option const long_options[] =
73 {"ash", no_argument, NULL, 'a'},
74 {"bash", no_argument, NULL, 'b'},
75 {"csh", no_argument, NULL, 'c'},
76 {"help", no_argument, NULL, 'h'},
77 {"no-path", no_argument, NULL, 'P'},
78 {"sh", no_argument, NULL, 's'},
79 {"tcsh", no_argument, NULL, 't'},
80 {"version", no_argument, NULL, 'v'},
81 {"zsh", no_argument, NULL, 'z'},
90 fprintf (stderr, _("Try `%s --help' for more information.\n"),
94 printf (_("Usage: %s [OPTION]... [FILE]\n"), program_name);
96 -h, --help display this help and exit\n\
97 -P, --no-path do not look for shell in PATH\n\
98 --version output version information and exit\n\
99 Determine format of output:\n\
100 -a, --ash assume ash shell\n\
101 -b, --bash assume bash shell\n\
102 -c, --csh assume csh shell\n\
103 -s, --sh assume Bourne shell\n\
104 -t, --tcsh assume tcsh shell\n\
105 -z, --zsh assume zsh shell\n"));
114 char *shell, *shellv;
117 shellv = getenv ("SHELL");
118 if (shellv == NULL || *shellv == '\0')
120 No SHELL variable, and no mode option specified"));
122 shell = strrchr (shellv, '/');
128 for (i = 0; shells[i]; ++i)
129 if (strcmp (shell, shells[i]) == 0)
130 return shell_mode[i];
132 error (1, 0, _("Unknown shell `%s'\n"), shell);
137 parse_line (char **keyword, char **arg, char *line)
141 *keyword = *arg = "";
143 for (p = line; isspace (*p); ++p)
146 if (*p == '\0' || *p == '#')
151 while (!isspace (*p))
160 if (*p == '\0' || *p == '#')
165 while (*p != '\0' && *p != '#')
167 for (--p; isspace (*p); --p)
174 /* Write a string to standard out, while watching for "dangerous"
175 sequences like unescaped : and = characters. */
178 put_seq (const char *str, char follow)
205 putchar (follow); /* The character that ends the sequence. */
209 main (int argc, char *argv[])
213 int mode = MO_UNKNOWN;
218 char line[STRINGLEN];
219 char useropts[2048] = "";
222 int color_opt = col_no; /* Assume --color=no */
224 int no_path = 0; /* Do not search PATH */
231 program_name = argv[0];
232 setlocale (LC_ALL, "");
233 bindtextdomain (PACKAGE, LOCALEDIR);
234 textdomain (PACKAGE);
236 /* Parse command line. */
238 while ((optc = getopt_long (argc, argv, "abhckPstz", long_options, NULL))
243 case 's': /* Plain sh mode */
279 printf ("%s - %s\n", program_name, PACKAGE_VERSION);
286 /* Use shell to determine mode, if not already done. */
287 if (mode == MO_UNKNOWN)
288 mode = figure_mode ();
290 /* Open dir_colors file */
294 if (p != NULL && *p != '\0')
296 /* Note: deliberate leak. It's not worth freeing this. */
297 input_file = xmalloc (strlen (p) + 1
298 + strlen (USER_FILE) + 1);
299 stpcpy (stpcpy (stpcpy (input_file, p), "/"), USER_FILE);
300 fp = fopen (input_file, "r");
305 /* Note: deliberate leak. It's not worth freeing this. */
306 input_file = xmalloc (strlen (SHAREDIR) + 1
307 + strlen (USER_FILE) + 1);
308 stpcpy (stpcpy (stpcpy (input_file, SHAREDIR), "/"),
310 fp = fopen (input_file, "r");
315 input_file = argv[optind];
316 fp = fopen (input_file, "r");
320 error (1, errno, _("while opening input file `%s'"), input_file);
322 /* Get terminal type */
323 term = getenv ("TERM");
324 if (term == NULL || *term == '\0')
327 /* Write out common start */
331 puts ("set noglob;\n\
332 setenv LS_COLORS \':");
337 fputs ("LS_COLORS=\'", stdout);
343 /* FIXME: use getline */
344 while (fgets (line, STRINGLEN, fp) != NULL )
346 parse_line (&keywd, &arg, line);
349 if (strcasecmp (keywd, "TERM") == 0)
351 if (strcmp (arg, term) == 0)
353 else if (state != ST_TERMSURE)
358 if (state == ST_TERMSURE)
359 state = ST_TERMYES; /* Another TERM can cancel */
361 if (state != ST_TERMNO)
366 put_seq (keywd, '=');
369 else if (keywd[0] == '*')
371 put_seq (keywd, '=');
374 else if (strcasecmp(keywd, "OPTIONS") == 0)
376 strcat (useropts, " ");
377 strcat (useropts, arg);
379 else if (strcasecmp(keywd, "COLOR") == 0)
399 error (0, 0, _("Unknown COLOR option `%s'\n"), arg);
407 for (i = 0; slack_codes[i] != NULL; ++i)
408 if (strcasecmp (keywd, slack_codes[i]) == 0)
411 if (slack_codes[i] != NULL)
413 printf ("%s=", ls_codes[i]);
417 error (0, 0, _("Unknown keyword %s\n"), keywd);
426 /* Decide on the options. */
430 copt = "--color=yes";
438 copt = "--color=tty";
442 /* Find ls in the path. */
445 no_path = 1; /* Assume we won't find one. */
448 if (p != NULL && *p != '\0')
455 if (*p != '/') /* Skip relative path entries. */
456 while (*p != '\0' && *p != ':')
461 while (*p != '\0' && *p != ':')
463 /* Make sure it ends in slash. */
468 if (access (line, X_OK) == 0)
470 no_path = 0; /* Found it. */
485 LS_OPTIONS='%s%s';\n\
486 export LS_OPTIONS;\n\
487 ls () { ( exec ls $LS_OPTIONS \"$@\" ) };\n\
488 dir () { ( exec dir $LS_OPTIONS \"$@\" ) };\n\
489 vdir () { ( exec vdir $LS_OPTIONS \"$@\" ) };\n\
490 d () { dir \"$@\" ; };\n\
491 v () { vdir \"$@\" ; };\n", copt, useropts);
495 LS_OPTIONS='%s%s';\n\
496 ls () { %s $LS_OPTIONS \"$@\" ; };\n\
497 dir () { %s $LS_OPTIONS --format=vertical \"$@\" ; };\n\
498 vdir () { %s $LS_OPTIONS --format=long \"$@\" ; };\n\
499 d () { dir \"$@\" ; };\n\
500 v () { vdir \"$@\" ; };\n", copt, useropts, line, line, line);
506 setenv LS_OPTIONS '%s%s';\n\
507 alias ls \'ls $LS_OPTIONS\';\n\
508 alias dir \'dir $LS_OPTIONS\';\n\
509 alias vdir \'vdir $LS_OPTIONS\';\n\
512 unset noglob;\n", copt, useropts);
515 setenv LS_OPTIONS '%s%s';\n\
516 alias ls \'%s $LS_OPTIONS\';\n\
517 alias dir \'%s $LS_OPTIONS --format=vertical\';\n\
518 alias vdir \'%s $LS_OPTIONS --format=long\';\n\
521 unset noglob;\n", copt, useropts, line, line, line);
528 LS_OPTIONS='%s%s';\n\
529 export LS_OPTIONS;\n\
530 alias ls=\'ls $LS_OPTIONS\';\n\
531 alias dir=\'dir $LS_OPTIONS\';\n\
532 alias vdir=\'vdir $LS_OPTIONS\';\n\
534 alias v=vdir;\n", copt, useropts);
538 LS_OPTIONS='%s%s';\n\
539 export LS_OPTIONS;\n\
540 alias ls=\'%s $LS_OPTIONS\';\n\
541 alias dir=\'%s $LS_OPTIONS --format=vertical\';\n\
542 alias vdir=\'%s $LS_OPTIONS --format=long\';\n\
544 alias v=vdir;\n", copt, useropts, line, line, line);
551 LS_OPTIONS=(%s%s);\n\
552 export LS_OPTIONS;\n\
553 alias ls=\'ls $LS_OPTIONS\';\n\
554 alias dir=\'dir $LS_OPTIONS\';\n\
555 alias vdir=\'vdir $LS_OPTIONS\';\n\
557 alias v=vdir;\n", copt, useropts);
561 LS_OPTIONS=(%s%s);\n\
562 export LS_OPTIONS;\n\
563 alias ls=\'%s $LS_OPTIONS\';\n\
564 alias dir=\'%s $LS_OPTIONS --format=vertical\';\n\
565 alias vdir=\'%s $LS_OPTIONS --format=long\';\n\
567 alias v=vdir;\n", copt, useropts, line, line, line);