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. */
464 if (*(q
- 1) != '/' )
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
);