#define LF 0x01
#define CR 0x02
-#define SKIP_LINE_ENDINGS(flags) (((flags) & CR) && ((flags) & LF) ? 2 : 1)
+#define SKIP_LINE_ENDINGS(flags) ((flags) == (CR|LF) ? 2 : 1)
#define VALID_FILE_TYPE(mode) (S_ISREG (mode) || S_ISLNK (mode) || S_ISFIFO (mode))
# define COLOR_SEP_CHAR '/'
#endif
-#define DEBUG_FILE "debug.txt"
+#if DEBUG
+# define DEBUG_FILE "debug.txt"
+#endif
+
+#define MAX_ATTRIBUTE_CHARS (6 * 2)
-#define MAX_ATTRIBUTE_CHARS (5 * 2)
+#define PROGRAM_NAME "colorize"
-#define VERSION "0.61"
+#define VERSION "0.63"
typedef enum { false, true } bool;
char unit;
};
-enum fmts {
+enum {
FMT_GENERIC,
FMT_STRING,
FMT_QUOTE,
enum { GENERIC, FOREGROUND = 0, BACKGROUND };
static const struct {
- struct color const *entries;
+ const struct color *entries;
unsigned int count;
const char *desc;
} tables[] = {
OPT_CLEAN,
OPT_CLEAN_ALL,
OPT_EXCLUDE_RANDOM,
+ OPT_OMIT_COLOR_EMPTY,
OPT_HELP,
OPT_VERSION
};
static int opt_type;
static const struct option long_opts[] = {
- { "attr", required_argument, &opt_type, OPT_ATTR },
- { "clean", no_argument, &opt_type, OPT_CLEAN },
- { "clean-all", no_argument, &opt_type, OPT_CLEAN_ALL },
- { "exclude-random", required_argument, &opt_type, OPT_EXCLUDE_RANDOM },
- { "help", no_argument, &opt_type, OPT_HELP },
- { "version", no_argument, &opt_type, OPT_VERSION },
- { NULL, 0, NULL, 0 },
+ { "attr", required_argument, &opt_type, OPT_ATTR },
+ { "clean", no_argument, &opt_type, OPT_CLEAN },
+ { "clean-all", no_argument, &opt_type, OPT_CLEAN_ALL },
+ { "exclude-random", required_argument, &opt_type, OPT_EXCLUDE_RANDOM },
+ { "omit-color-empty", no_argument, &opt_type, OPT_OMIT_COLOR_EMPTY },
+ { "help", no_argument, &opt_type, OPT_HELP },
+ { "version", no_argument, &opt_type, OPT_VERSION },
+ { NULL, 0, NULL, 0 },
};
enum attr_type {
ATTR_REVERSE = 0x08,
ATTR_CONCEALED = 0x10
};
+struct attr {
+ const char *name;
+ unsigned int val;
+ enum attr_type type;
+};
static FILE *stream;
#if DEBUG
static bool clean;
static bool clean_all;
+static bool omit_color_empty;
static char attr[MAX_ATTRIBUTE_CHARS + 1];
static char *exclude;
static void process_opts (int, char **);
static void process_opt_attr (const char *);
-static void write_attr (unsigned int, unsigned int *, enum attr_type, const char *);
+static void write_attr (const struct attr *, unsigned int *);
static void print_hint (void);
static void print_help (void);
static void print_version (void);
static void save_char (char, char **, size_t *, size_t *);
static void find_color_entries (struct color_name **, const struct color **);
static void find_color_entry (const struct color_name *, unsigned int, const struct color **);
-static void print_line (const char *, const struct color **, const char * const, unsigned int);
+static void print_line (const char *, const struct color **, const char * const, unsigned int, bool);
static void print_clean (const char *);
static bool is_esc (const char *);
static const char *get_end_of_esc (const char *);
vfprintf_fail (formats[FMT_GENERIC], "--exclude-random switch must be provided a plain color");
break;
}
+ case OPT_OMIT_COLOR_EMPTY:
+ omit_color_empty = true;
+ break;
case OPT_HELP:
PRINT_HELP_EXIT ();
case OPT_VERSION:
process_opt_attr (const char *p)
{
/* If attributes are added to this "list", also increase MAX_ATTRIBUTE_CHARS! */
- const struct attr {
- const char *name;
- unsigned int val;
- enum attr_type type;
- } attrs[] = {
+ const struct attr attrs[] = {
{ "bold", 1, ATTR_BOLD },
{ "underscore", 4, ATTR_UNDERSCORE },
{ "blink", 5, ATTR_BLINK },
const size_t name_len = strlen (attrs[i].name);
if ((size_t)(p - s) == name_len && strneq (s, attrs[i].name, name_len))
{
- write_attr (attrs[i].val, &attr_types, attrs[i].type, attrs[i].name);
+ write_attr (&attrs[i], &attr_types);
valid_attr = true;
break;
}
}
if (!valid_attr)
- vfprintf_fail (formats[FMT_GENERIC], "--attr switch must be provided valid attribute names");
+ {
+ char *attr_invalid = xmalloc ((p - s) + 1);
+ STACK_VAR (attr_invalid);
+ strncpy (attr_invalid, s, p - s);
+ attr_invalid[p - s] = '\0';
+ vfprintf_fail ("--attr switch attribute '%s' is not valid", attr_invalid);
+ RELEASE_VAR (attr_invalid); /* never reached */
+ }
}
if (*p)
p++;
}
static void
-write_attr (unsigned int val, unsigned int *attr_types, enum attr_type attr_type, const char *attr_name)
+write_attr (const struct attr *attr_i, unsigned int *attr_types)
{
+ const unsigned int val = attr_i->val;
+ const enum attr_type attr_type = attr_i->type;
+ const char *attr_name = attr_i->name;
+
if (*attr_types & attr_type)
vfprintf_fail ("--attr switch has attribute '%s' twice or more", attr_name);
snprintf (attr + strlen (attr), 3, "%u;", val);
static void
print_help (void)
{
- struct short_opt {
+ struct opt_data {
const char *name;
const char *short_opt;
+ const char *arg;
};
- const struct short_opt short_opts[] = {
- { "help", "h" },
- { "version", "V" },
+ const struct opt_data opts_data[] = {
+ { "attr", NULL, "=ATTR1,ATTR2,..." },
+ { "exclude-random", NULL, "=COLOR" },
+ { "help", "h", NULL },
+ { "version", "V", NULL },
};
const struct option *opt = long_opts;
unsigned int i;
printf ("\n\tOptions\n");
for (; opt->name; opt++)
{
- const char *short_opt = NULL;
+ const struct opt_data *opt_data = NULL;
unsigned int i;
- for (i = 0; i < sizeof (short_opts) / sizeof (struct short_opt); i++)
+ for (i = 0; i < sizeof (opts_data) / sizeof (struct opt_data); i++)
+ if (streq (opt->name, opts_data[i].name))
+ {
+ opt_data = &opts_data[i];
+ break;
+ }
+ if (opt_data)
{
- if (streq (opt->name, short_opts[i].name))
- {
- short_opt = short_opts[i].short_opt;
- break;
- }
+ if (opt_data->short_opt)
+ printf ("\t\t-%s, --%s\n", opt_data->short_opt, opt->name);
+ else
+ printf ("\t\t --%s%s\n", opt->name, opt_data->arg);
}
- if (short_opt)
- printf ("\t\t-%s, --%s\n", short_opt, opt->name);
else
printf ("\t\t --%s\n", opt->name);
}
#endif
const char *version_prefix, *version_string;
const char *c_flags, *ld_flags, *cpp_flags;
+ const char *const desc_flags_unknown = "unknown";
struct bytes_size bytes_size;
bool debug;
#ifdef CFLAGS
c_flags = to_str (CFLAGS);
#else
- c_flags = "unknown";
+ c_flags = desc_flags_unknown;
#endif
#ifdef LDFLAGS
ld_flags = to_str (LDFLAGS);
#else
- ld_flags = "unknown";
+ ld_flags = desc_flags_unknown;
#endif
#ifdef CPPFLAGS
cpp_flags = to_str (CPPFLAGS);
#else
- cpp_flags = "unknown";
+ cpp_flags = desc_flags_unknown;
#endif
#if DEBUG
debug = true;
#endif
version_prefix = version ? "" : "v";
version_string = version ? version : VERSION;
- printf ("colorize %s%s (compiled at %s, %s)\n", version_prefix, version_string, __DATE__, __TIME__);
+ printf ("%s %s%s (compiled at %s, %s)\n", PROGRAM_NAME, version_prefix, version_string, __DATE__, __TIME__);
printf ("Compiler flags: %s\n", c_flags);
printf ("Linker flags: %s\n", ld_flags);
const char *color_string = arg_cnt >= 1 ? arg_strings[0] : NULL;
const char *file_string = arg_cnt == 2 ? arg_strings[1] : NULL;
- assert (color_string);
+ assert (color_string != NULL);
if (streq (color_string, "-"))
{
gather_color_names (color_string, attr, color_names);
- assert (color_names[FOREGROUND]);
+ assert (color_names[FOREGROUND] != NULL);
if (color_names[BACKGROUND])
{
}
find_color_entries (color_names, colors);
+ assert (colors[FOREGROUND] != NULL);
free_color_names (color_names);
if (!colors[FOREGROUND]->code && colors[BACKGROUND] && colors[BACKGROUND]->code)
color_name.name = color_name.orig = "default";
find_color_entry (&color_name, FOREGROUND, colors);
+ assert (colors[FOREGROUND]->code != NULL);
}
process_file_arg (file_string, file, stream);
*file = "stdin";
}
- assert (*stream);
- assert (*file);
+ assert (*stream != NULL);
+ assert (*file != NULL);
}
static void
}
else
p = color + strlen (color);
- assert (p);
+ assert (p != NULL);
for (ch = color; *ch; ch++)
if (!isalpha (*ch))
line = buf;
while ((eol = strpbrk (line, "\n\r")))
{
+ const bool has_text = (eol > line);
const char *p;
flags &= ~(CR|LF);
if (*eol == '\r')
vfprintf_fail (formats[FMT_FILE], file, "unrecognized line ending");
p = eol + SKIP_LINE_ENDINGS (flags);
*eol = '\0';
- print_line (attr, colors, line, flags);
+ print_line (attr, colors, line, flags,
+ omit_color_empty ? has_text : true);
line = p;
}
if (feof (stream))
{
if (*line != '\0')
- print_line (attr, colors, line, 0);
+ print_line (attr, colors, line, 0, true);
}
else if (*line != '\0')
{
if ((clean || clean_all) && (p = strrchr (line, '\033')))
merge_print_line (line, p, stream);
else
- print_line (attr, colors, line, 0);
+ print_line (attr, colors, line, 0, true);
}
}
}
}
static void
-print_line (const char *attr, const struct color **colors, const char *const line, unsigned int flags)
+print_line (const char *attr, const struct color **colors, const char *const line, unsigned int flags, bool emit_colors)
{
/* --clean[-all] */
if (clean || clean_all)
print_clean (line);
- else
+ /* skip for --omit-color-empty? */
+ else if (emit_colors)
{
/* Foreground color code is guaranteed to be set when background color code is present. */
if (colors[BACKGROUND] && colors[BACKGROUND]->code)
{
char *p;
- assert (strlen (str));
- assert (strlen (name));
+ assert (strlen (str) > 0);
+ assert (strlen (name) > 0);
if (!(*str == *name || *str == toupper (*name)))
return false;
else if (*(name + 1) != '\0'
&& !((p = strstr (str + 1, name + 1)) && p == str + 1))
return false;
-
- return true;
+ else
+ return true;
}
static FILE *