]> git.refcnt.org Git - colorize.git/blobdiff - colorize.c
colorize 0.56
[colorize.git] / colorize.c
index 2637dab05fbab987abd0395dfd202b874a3e3ad9..abeb665f474bf2de57789a3b784686cadafbc543 100644 (file)
 
 #define DEBUG_FILE "debug.txt"
 
-#define VERSION "0.55"
+#define VERSION "0.56"
 
 typedef enum { false, true } bool;
 
@@ -165,14 +165,14 @@ enum fmts {
     FMT_TYPE
 };
 static const char *formats[] = {
-    "%s",                    /* generic */
-    "%s '%s'",               /* string  */
-    "%s `%s' %s",            /* quote   */
-    "%s color '%s' %s",      /* color   */
-    "%s color '%s' %s '%s'", /* random  */
-    "less than %u bytes %s", /* error   */
-    "%s: %s",                /* file    */
-    "%s: %s: %s",            /* type    */
+    "%s",                     /* generic */
+    "%s '%s'",                /* string  */
+    "%s `%s' %s",             /* quote   */
+    "%s color '%s' %s",       /* color   */
+    "%s color '%s' %s '%s'",  /* random  */
+    "less than %lu bytes %s", /* error   */
+    "%s: %s",                 /* file    */
+    "%s: %s: %s",             /* type    */
 };
 
 enum { FOREGROUND, BACKGROUND };
@@ -186,18 +186,18 @@ static const struct {
     { bg_colors, sizeof (bg_colors) / sizeof (struct color), "background" },
 };
 
-static FILE *stream = NULL;
+static FILE *stream;
 #if DEBUG
-static FILE *log = NULL;
+static FILE *log;
 #endif
 
-static unsigned int stacked_vars = 0;
-static void **vars_list = NULL;
+static unsigned int stacked_vars;
+static void **vars_list;
 
-static bool clean = false;
-static bool clean_all = false;
+static bool clean;
+static bool clean_all;
 
-static char *exclude = NULL;
+static char *exclude;
 
 static const char *program_name;
 
@@ -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);
@@ -243,7 +253,7 @@ static void release_var (void **, unsigned int, void **);
 extern char *optarg;
 extern int optind;
 
-static int opt_type = 0;
+static int opt_type;
 
 int
 main (int argc, char **argv)
@@ -286,7 +296,7 @@ main (int argc, char **argv)
     log = open_file (DEBUG_FILE, "w");
 #endif
 
-    while ((opt = getopt_long (argc, argv, "hv", long_opts, NULL)) != -1)
+    while ((opt = getopt_long (argc, argv, "hV", long_opts, NULL)) != -1)
       {
         PARSE_OPT:
         switch (opt)
@@ -330,7 +340,7 @@ main (int argc, char **argv)
               break;
             case 'h':
               SET_OPT_TYPE (OPT_HELP);
-            case 'v':
+            case 'V':
               SET_OPT_TYPE (OPT_VERSION);
             case '?':
               print_hint ();
@@ -411,7 +421,7 @@ print_help (void)
     printf ("\t\t    --clean-all\n");
     printf ("\t\t    --exclude-random\n");
     printf ("\t\t-h, --help\n");
-    printf ("\t\t-v, --version\n\n");
+    printf ("\t\t-V, --version\n\n");
 }
 
 static void
@@ -471,7 +481,7 @@ cleanup (void)
         unsigned int i;
         for (i = 0; i < stacked_vars; i++)
           if (vars_list[i])
-            free_null (vars_list[i]);
+            free (vars_list[i]);
 
         free_null (vars_list);
       }
@@ -483,8 +493,8 @@ free_color_names (struct color_name **color_names)
     unsigned int i;
     for (i = 0; color_names[i]; i++)
       {
-        free_null (color_names[i]->name);
-        free_null (color_names[i]->orig);
+        free (color_names[i]->name);
+        free (color_names[i]->orig);
         free_null (color_names[i]);
       }
 }
@@ -610,7 +620,6 @@ process_args (unsigned int arg_cnt, char **arg_strings, bool *bold, const struct
                   break;
                 case BACKGROUND:
                   vfprintf_fail (formats[FMT_COLOR], tables[BACKGROUND].desc, color, "cannot be bold");
-                  break;
                 default: /* never reached */
                   ABORT_TRACE ();
               }
@@ -633,11 +642,11 @@ process_args (unsigned int arg_cnt, char **arg_strings, bool *bold, const struct
     if (color_names[BACKGROUND])
       {
         unsigned int i;
-        unsigned int color_sets[2][2] = { { FOREGROUND, BACKGROUND }, { BACKGROUND, FOREGROUND } };
+        const unsigned int color_sets[2][2] = { { FOREGROUND, BACKGROUND }, { BACKGROUND, FOREGROUND } };
         for (i = 0; i < 2; i++)
           {
-            unsigned int color1 = color_sets[i][0];
-            unsigned int color2 = color_sets[i][1];
+            const unsigned int color1 = color_sets[i][0];
+            const unsigned int color2 = color_sets[i][1];
             if (CHECK_COLORS_RANDOM (color1, color2))
               vfprintf_fail (formats[FMT_RANDOM], tables[color1].desc, color_names[color1]->orig, "cannot be combined with", color_names[color2]->orig);
           }
@@ -853,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;
+
+    if (is_esc (p))
+      p = get_end_of_esc (p);
 
-    for (p = line; *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], (unsigned long)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)
           {
-            SET_CHAR (offsets[i + 1][0], '\0', &ch);
-            next_offset = true;
+            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)
+          {
+            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_null (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