diff --git a/include/patchelfcrc/reporting.h b/include/patchelfcrc/reporting.h index 73ceef6..1b2b1a9 100644 --- a/include/patchelfcrc/reporting.h +++ b/include/patchelfcrc/reporting.h @@ -21,14 +21,25 @@ #include -#define print_err(fmt, ...) fprintf(stderr, "[ERR] " fmt, ## __VA_ARGS__) +/** + * @brief Setting for reporting to console. + */ +enum reporting_color_mode { + COLOR_MODE_DETECT, /**< @brief Automatically detect if tty. If tty, color is used */ + COLOR_MODE_COLOR, /**< @brief Force color mode on stderr */ + COLOR_MODE_COLOR_OFF, /**< @brief Force no color on stderr */ +}; -#define print_warn(fmt, ...) fprintf(stderr, "[WARN] " fmt, ## __VA_ARGS__) +void print_err(const char *fmt, ...); + +void print_warn(const char *fmt, ...); void print_debug(const char *fmt, ...); -void reporting_enable_verbose(void); +void reporting_enable_verbose(bool state); bool reporting_get_verbosity(void); +void reporting_init(enum reporting_color_mode mode); + #endif /* _REPORTING_H_ */ diff --git a/man/patchelfcrc.1.md b/man/patchelfcrc.1.md index ce2f7a8..2ffabd4 100644 --- a/man/patchelfcrc.1.md +++ b/man/patchelfcrc.1.md @@ -84,6 +84,9 @@ **--usage** : Print usage hints on command line options. +**--no-color** +: Force output on stdout and stderr to be pure text without color codes. + # EXAMPLES **patchelfcrc** --list-crcs diff --git a/src/elfpatch.c b/src/elfpatch.c index 0c82220..eb5a141 100644 --- a/src/elfpatch.c +++ b/src/elfpatch.c @@ -470,12 +470,12 @@ elfpatch_handle_t *elf_patch_open(const char *path, bool readonly, bool expect_l case 1: print_debug("ELF Endianess: little\n"); if (!expect_little_endian) - print_err("Big endian format expected. File is little endian. Double check settings!\n"); + print_warn("Big endian format expected. File is little endian. Double check settings!\n"); break; case 2: print_debug("ELF Endianess: big\n"); if (expect_little_endian) - print_err("Little endian format expected. File is big endian. Double check settings!\n"); + print_warn("Little endian format expected. File is big endian. Double check settings!\n"); break; default: print_err("Cannot determine endianess of ELF file. EI_DATA is: %d\n", ident[5]); diff --git a/src/main.c b/src/main.c index a48ca58..66060c9 100644 --- a/src/main.c +++ b/src/main.c @@ -40,8 +40,10 @@ const char *argp_program_bug_address = "use_vma = true; break; + case ARG_KEY_FORCE_NO_COLOR: + args->force_nocolor = true; + break; case 'p': /* Polyniomial */ args->crc.polynomial = strtoull(arg, &endptr, 0); @@ -195,6 +200,7 @@ static int parse_cmdline_options(int *argc, char ***argv, struct command_line_op {"import", ARG_KEY_IMPORT, "XML", 0, "Do not caclulate CRCs but import them from file", 3}, {"xsd", ARG_KEY_XSD, 0, 0, "Print XSD to stdout", 0}, {"use-vma", ARG_KEY_USE_VMA, 0, 0, "Use the VMA instead of the LMA for struct output", 2}, + {"no-color", ARG_KEY_FORCE_NO_COLOR, 0, 0, "Force the output to be text only without colors", 0}, /* Sentinel */ {NULL, 0, 0, 0, NULL, 0} }; @@ -425,8 +431,11 @@ int main(int argc, char **argv) goto free_cmds; } + /* Initialize console output */ + reporting_init(cmd_opts.force_nocolor ? COLOR_MODE_COLOR_OFF : COLOR_MODE_DETECT); + if (cmd_opts.verbose || cmd_opts.dry_run) - reporting_enable_verbose(); + reporting_enable_verbose(true); print_verbose_start_info(&cmd_opts); @@ -450,7 +459,7 @@ int main(int argc, char **argv) print_warn("--use-vma option only has an effect when exporting as struct output.\n"); if (!cmd_opts.output_section && cmd_opts.export_xml == NULL) - print_err("No output section / XML export specified. Will continue but not create any output\n"); + print_warn("No output section / XML export specified. Will continue but not create any output\n"); /* Prepare libelf for use with the latest ELF version */ elf_version(EV_CURRENT); diff --git a/src/reporting.c b/src/reporting.c index 2ac97c6..540060e 100644 --- a/src/reporting.c +++ b/src/reporting.c @@ -19,9 +19,66 @@ #include #include #include +#include #include +#include +#include static bool global_verbosity_state = false; +static bool reporting_use_color = false; + +#define COLOR_RESET "\e[0m" + +#define COLOR_BOLD_RED "\e[31;1m" +#define COLOR_RED "\e[31m" + +#define COLOR_BOLD_YELLOW "\e[33;1m" +#define COLOR_YELLOW "\e[33m" + + +void print_err(const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + + /* Set color */ + if (reporting_use_color) + fprintf(stderr, COLOR_BOLD_RED "[ERR]" COLOR_RESET " " COLOR_RED); + else + fprintf(stderr, "[ERR] "); + + + vfprintf(stderr, fmt, va); + + /* Reset color */ + if (reporting_use_color) { + fprintf(stderr, COLOR_RESET); + } + + va_end(va); +} + +void print_warn(const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + + /* Set color */ + if (reporting_use_color) + fprintf(stderr, COLOR_BOLD_YELLOW "[WARN]" COLOR_RESET " " COLOR_YELLOW); + else + fprintf(stderr, "[WARN] "); + + + vfprintf(stderr, fmt, va); + + /* Reset color */ + if (reporting_use_color) { + fprintf(stderr, COLOR_RESET); + } + + va_end(va); +} void print_debug(const char *fmt, ...) { @@ -34,12 +91,52 @@ void print_debug(const char *fmt, ...) } } -void reporting_enable_verbose(void) +void reporting_enable_verbose(bool state) { - global_verbosity_state = true; + global_verbosity_state = state; } bool reporting_get_verbosity(void) { return global_verbosity_state; } + +/** + * @brief Check whether stderr supports colors. + * @note This function checks for a tty and the TERM environment variable. It has to contain "xterm". + * @return true if colors are supported + * @return false if no colors should be used + */ +static bool stderr_supports_colors(void) +{ + const char *env_var; + const char *tmp; + + if (isatty(2) != 1) + return false; + + env_var = getenv("TERM"); + if (!env_var) + return false; + + tmp = strstr(env_var, "xterm"); + if (!tmp) + return false; + + return true; +} + +void reporting_init(enum reporting_color_mode mode) +{ + switch (mode) { + case COLOR_MODE_COLOR: + reporting_use_color = true; + break; + case COLOR_MODE_COLOR_OFF: + reporting_use_color = false; + break; + default: /* Auto detect case and invalid settings */ + reporting_use_color = stderr_supports_colors(); + break; + } +}