diff options
author | Steven Schubiger <stsc@refcnt.org> | 2015-05-14 21:51:15 +0200 |
---|---|---|
committer | Steven Schubiger <stsc@refcnt.org> | 2015-05-14 21:51:15 +0200 |
commit | 6261571979a8192e1f7f5b719fb058218235331b (patch) | |
tree | c79669f07807cbf36187afbb0f3f51a409c42859 | |
parent | 919406858ea367fbcb328d2d5f29d65b0abd564a (diff) | |
download | colorize-6261571979a8192e1f7f5b719fb058218235331b.tar.gz colorize-6261571979a8192e1f7f5b719fb058218235331b.tar.bz2 |
Refactor print_clean
Avoid allocating memory for escape sequence offsets by printing
text in between directly. Furthermore, divide resulting code
into numerous functions in order to reduce complexity.
Thanks Urs Fässler
-rw-r--r-- | colorize.c | 270 |
1 files changed, 154 insertions, 116 deletions
@@ -213,7 +213,17 @@ 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 (bool, const struct color **, const char * const, unsigned int); static void print_clean (const char *); -static void print_free_offsets (const char *, char ***, unsigned int); +static bool is_esc (const char *); +static const char *get_end_of_esc (const char *); +static const char *get_end_of_text (const char *); +static void print_text (const char *, size_t); +static bool gather_esc_offsets (const char *, const char **, const char **); +static bool validate_esc_clean_all (const char **); +static bool validate_esc_clean (int, unsigned int, const char **, bool *); +static bool is_reset (int, unsigned int, const char **); +static bool is_bold (int, unsigned int, const char **); +static bool is_fg_color (int, const char **); +static bool is_bg_color (int, unsigned int, const char **); #if !DEBUG static void *malloc_wrap (size_t); static void *calloc_wrap (size_t, size_t); @@ -852,136 +862,164 @@ print_line (bool bold, const struct color **colors, const char *const line, unsi static void print_clean (const char *line) { - const char *p; - char ***offsets = NULL; - unsigned int count = 0, i = 0; + const char *p = line; - for (p = line; *p;) + if (is_esc (p)) + p = get_end_of_esc (p); + + while (*p != '\0') { - /* ESC[ */ - if (*p == 27 && *(p + 1) == '[') - { - const char *begin = p; - p += 2; - if (clean_all) - { - while (isdigit (*p) || *p == ';') - p++; - } - else if (clean) - { - bool check_values; - unsigned int iter = 0; - const char *digit; - do { - check_values = false; - iter++; - if (!isdigit (*p)) - goto DISCARD; - digit = p; - while (isdigit (*p)) - p++; - if (p - digit > 2) - goto DISCARD; - else /* check range */ - { - char val[3]; - int value; - unsigned int i; - const unsigned int digits = p - digit; - for (i = 0; i < digits; i++) - val[i] = *digit++; - val[i] = '\0'; - value = atoi (val); - if (value == 0) /* reset */ - { - if (iter > 1) - goto DISCARD; - goto END; - } - else if (value == 1) /* bold */ - { - bool discard = false; - if (iter > 1) - discard = true; - else if (*p != ';') - discard = true; - if (discard) - goto DISCARD; - p++; - check_values = true; - } - else if ((value >= 30 && value <= 37) || value == 39) /* foreground colors */ - goto END; - else if ((value >= 40 && value <= 47) || value == 49) /* background colors */ - { - if (iter > 1) - goto DISCARD; - goto END; - } - else - goto DISCARD; - } - } while (iter == 1 && check_values); - } - END: if (*p == 'm') - { - const char *end = p++; - if (!offsets) - offsets = xmalloc (++count * sizeof (char **)); - else - offsets = xrealloc (offsets, ++count * sizeof (char **)); - offsets[i] = xmalloc (2 * sizeof (char *)); - offsets[i][0] = (char *)begin; /* ESC */ - offsets[i][1] = (char *)end; /* m */ - i++; - continue; - } - DISCARD: - continue; - } - p++; + const char *text_start = p; + const char *text_end = get_end_of_text (p); + print_text (text_start, text_end - text_start); + p = get_end_of_esc (text_end); } +} - if (offsets) - print_free_offsets (line, offsets, count); - else - printf (formats[FMT_GENERIC], line); +static bool +is_esc (const char *p) +{ + return gather_esc_offsets (p, NULL, NULL); } -#define SET_CHAR(offset, new, old) \ - *old = *offset; \ - *offset = new; \ +static const char * +get_end_of_esc (const char *p) +{ + const char *esc; + const char *end = NULL; + while ((esc = strchr (p, '\033'))) + { + if (gather_esc_offsets (esc, NULL, &end)) + break; + p = esc + 1; + } + return end ? end + 1 : p + strlen (p); +} -#define RESTORE_CHAR(offset, old) \ - *offset = old; \ +static const char * +get_end_of_text (const char *p) +{ + const char *esc; + const char *start = NULL; + while ((esc = strchr (p, '\033'))) + { + if (gather_esc_offsets (esc, &start, NULL)) + break; + p = esc + 1; + } + return start ? start : p + strlen (p); +} static void -print_free_offsets (const char *line, char ***offsets, unsigned int count) +print_text (const char *p, size_t len) { - char ch; - unsigned int i; - - SET_CHAR (offsets[0][0], '\0', &ch); - printf (formats[FMT_GENERIC], line); - RESTORE_CHAR (offsets[0][0], ch); + size_t bytes_written; + bytes_written = fwrite (p, 1, len, stdout); + if (bytes_written != len) + vfprintf_fail (formats[FMT_ERROR], len, "written"); +} - for (i = 0; i < count; i++) +static bool +gather_esc_offsets (const char *p, const char **start, const char **end) +{ + /* ESC[ */ + if (*p == 27 && *(p + 1) == '[') { - char ch; - bool next_offset = false; - if (i + 1 < count) + bool valid = false; + const char *begin = p; + p += 2; + if (clean_all) + valid = validate_esc_clean_all (&p); + else if (clean) + { + bool check_values; + unsigned int iter = 0; + const char *digit; + do { + check_values = false; + iter++; + if (!isdigit (*p)) + break; + digit = p; + while (isdigit (*p)) + p++; + if (p - digit > 2) + break; + else /* check range */ + { + char val[3]; + int value; + unsigned int i; + const unsigned int digits = p - digit; + for (i = 0; i < digits; i++) + val[i] = *digit++; + val[i] = '\0'; + value = atoi (val); + valid = validate_esc_clean (value, iter, &p, &check_values); + } + } while (check_values); + } + if (valid) { - SET_CHAR (offsets[i + 1][0], '\0', &ch); - next_offset = true; + if (start) + *start = begin; + if (end) + *end = p; + return true; } - printf (formats[FMT_GENERIC], offsets[i][1] + 1); - if (next_offset) - RESTORE_CHAR (offsets[i + 1][0], ch); } - for (i = 0; i < count; i++) - free (offsets[i]); - free_null (offsets); + return false; +} + +static bool +validate_esc_clean_all (const char **p) +{ + while (isdigit (**p) || **p == ';') + (*p)++; + return (**p == 'm'); +} + +static bool +validate_esc_clean (int value, unsigned int iter, const char **p, bool *check_values) +{ + if (is_reset (value, iter, p)) + return true; + else if (is_bold (value, iter, p)) + { + (*p)++; + *check_values = true; + return false; /* partial escape sequence, need another valid value */ + } + else if (is_fg_color (value, p)) + return true; + else if (is_bg_color (value, iter, p)) + return true; + else + return false; +} + +static bool +is_reset (int value, unsigned int iter, const char **p) +{ + return (value == 0 && iter == 1 && **p == 'm'); +} + +static bool +is_bold (int value, unsigned int iter, const char **p) +{ + return (value == 1 && iter == 1 && **p == ';'); +} + +static bool +is_fg_color (int value, const char **p) +{ + return (((value >= 30 && value <= 37) || value == 39) && **p == 'm'); +} + +static bool +is_bg_color (int value, unsigned int iter, const char **p) +{ + return (((value >= 40 && value <= 47) || value == 49) && iter == 1 && **p == 'm'); } #if !DEBUG |