]> git.refcnt.org Git - colorize.git/blobdiff - colorize.c
Add COPYING
[colorize.git] / colorize.c
index 26eaa2f5ee9092ac7d11862cf3e9b4ae741af604..902e189f27a261fb0e32882b26da1bd0d9d5c7e2 100644 (file)
@@ -2,7 +2,7 @@
  * colorize - Read text from standard input stream or file and print
  *            it colorized through use of ANSI escape sequences
  *
- * Copyright (c) 2011-2014 Steven Schubiger
+ * Copyright (c) 2011-2015 Steven Schubiger
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@
 
 #define _BSD_SOURCE
 #define _XOPEN_SOURCE 700
+#define _FILE_OFFSET_BITS 64
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #define streq(s1, s2) (strcmp (s1, s2) == 0)
 
 #if !DEBUG
-# define xmalloc(size)        malloc_wrap(size)
-# define xcalloc(nmemb, size) calloc_wrap(nmemb, size)
-# define xrealloc(ptr, size)  realloc_wrap(ptr, size)
+# define xmalloc(size)          malloc_wrap(size)
+# define xcalloc(nmemb, size)   calloc_wrap(nmemb, size)
+# define xrealloc(ptr, size)    realloc_wrap(ptr, size)
+# define xstrdup(str)           strdup_wrap(str,            NULL, 0)
+# define str_concat(str1, str2) str_concat_wrap(str1, str2, NULL, 0)
 #else
-# define xmalloc(size)        malloc_wrap_debug(size,        __FILE__, __LINE__)
-# define xcalloc(nmemb, size) calloc_wrap_debug(nmemb, size, __FILE__, __LINE__)
-# define xrealloc(ptr, size)  realloc_wrap_debug(ptr, size,  __FILE__, __LINE__)
+# define xmalloc(size)          malloc_wrap_debug(size,        __FILE__, __LINE__)
+# define xcalloc(nmemb, size)   calloc_wrap_debug(nmemb, size, __FILE__, __LINE__)
+# define xrealloc(ptr, size)    realloc_wrap_debug(ptr, size,  __FILE__, __LINE__)
+# define xstrdup(str)           strdup_wrap(str,               __FILE__, __LINE__)
+# define str_concat(str1, str2) str_concat_wrap(str1, str2,    __FILE__, __LINE__)
 #endif
 
 #define free_null(ptr) free_wrap((void **)&ptr)
-#define xstrdup(str)   strdup_wrap(str)
 
-#if BUF_SIZE <= 0
+#if defined(BUF_SIZE) && (BUF_SIZE <= 0 || BUF_SIZE > 65536)
 # undef BUF_SIZE
 #endif
 #ifndef BUF_SIZE
 #if !DEBUG
 # define MEM_ALLOC_FAIL() do {                                         \
     fprintf (stderr, "%s: memory allocation failure\n", program_name); \
-    exit (2);                                                          \
+    exit (EXIT_FAILURE);                                               \
 } while (false)
 #else
 # define MEM_ALLOC_FAIL_DEBUG(file, line) do {                                              \
     fprintf (stderr, "Memory allocation failure in source file %s, line %u\n", file, line); \
-    exit (2);                                                                               \
+    exit (EXIT_FAILURE);                                                                    \
 } while (false)
 #endif
 
 
 #define COLOR_SEP_CHAR '/'
 
-#define VERSION "0.54"
+#define DEBUG_FILE "debug.txt"
+
+#define VERSION "0.55"
 
 typedef enum { false, true } bool;
 
@@ -143,6 +149,11 @@ static const struct color bg_colors[] = {
     { "default", "49m" },
 };
 
+struct bytes_size {
+    unsigned int size;
+    char unit;
+};
+
 enum fmts {
     FMT_GENERIC,
     FMT_STRING,
@@ -176,6 +187,9 @@ static const struct {
 };
 
 static FILE *stream = NULL;
+#if DEBUG
+static FILE *log = NULL;
+#endif
 
 static unsigned int stacked_vars = 0;
 static void **vars_list = NULL;
@@ -210,10 +224,12 @@ static void *calloc_wrap_debug (size_t, size_t, const char *, unsigned int);
 static void *realloc_wrap_debug (void *, size_t, const char *, unsigned int);
 #endif
 static void free_wrap (void **);
-static char *strdup_wrap (const char *);
-static char *str_concat (const char *, const char *);
+static char *strdup_wrap (const char *, const char *, unsigned int);
+static char *str_concat_wrap (const char *, const char *, const char *, unsigned int);
+static bool get_bytes_size (unsigned long, struct bytes_size *);
 static char *get_file_type (mode_t);
 static bool has_color_name (const char *, const char *);
+static FILE *open_file (const char *, const char *);
 static void vfprintf_diag (const char *, ...);
 static void vfprintf_fail (const char *, ...);
 static void stack_var (void ***, unsigned int *, unsigned int, void *);
@@ -266,7 +282,11 @@ main (int argc, char **argv)
 
     setvbuf (stdout, NULL, _IOLBF, 0);
 
-    while ((opt = getopt_long (argc, argv, "hv", long_opts, NULL)) != -1)
+#if DEBUG
+    log = open_file (DEBUG_FILE, "w");
+#endif
+
+    while ((opt = getopt_long (argc, argv, "hV", long_opts, NULL)) != -1)
       {
         PARSE_OPT:
         switch (opt)
@@ -310,7 +330,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 ();
@@ -391,13 +411,20 @@ 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
 print_version (void)
 {
+#ifdef HAVE_VERSION
+# include "version.h"
+#else
+    const char *version = NULL;
+#endif
+    const char *version_prefix, *version_string;
     const char *c_flags;
+    struct bytes_size bytes_size;
     bool debug;
 #ifdef CFLAGS
     c_flags = to_str (CFLAGS);
@@ -409,9 +436,21 @@ print_version (void)
 #else
     debug = false;
 #endif
-    printf ("%s v%s (compiled at %s, %s)\n", "colorize", VERSION, __DATE__, __TIME__);
+    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 ("Compiler flags: %s\n", c_flags);
-    printf ("Buffer size: %u bytes\n", BUF_SIZE);
+    if (get_bytes_size (BUF_SIZE, &bytes_size))
+      {
+        if (BUF_SIZE % 1024 == 0)
+          printf ("Buffer size: %u%c\n", bytes_size.size, bytes_size.unit);
+        else
+          printf ("Buffer size: %u%c, %u byte%s\n", bytes_size.size, bytes_size.unit,
+                   BUF_SIZE % 1024, BUF_SIZE % 1024 > 1 ? "s" : "");
+      }
+    else
+      printf ("Buffer size: %lu byte%s\n", (unsigned long)BUF_SIZE, BUF_SIZE > 1 ? "s" : "");
     printf ("Debugging: %s\n", debug ? "yes" : "no");
 }
 
@@ -422,13 +461,17 @@ cleanup (void)
 
     if (stream && fileno (stream) != STDIN_FILENO)
       fclose (stream);
+#if DEBUG
+    if (log)
+      fclose (log);
+#endif
 
     if (vars_list)
       {
         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);
       }
@@ -440,8 +483,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]);
       }
 }
@@ -471,7 +514,7 @@ process_args (unsigned int arg_cnt, char **arg_strings, bool *bold, const struct
 
     /* Ensure that we don't fail if there's a file with one or more
        color names in its path.  */
-    if (ret != -1)
+    if (ret == 0) /* success */
       {
         bool have_file;
         unsigned int c;
@@ -567,7 +610,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 ();
               }
@@ -590,11 +632,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);
           }
@@ -623,13 +665,12 @@ process_file_arg (const char *file_string, const char **file, FILE **stream)
           *stream = stdin;
         else
           {
-            FILE *s;
             const char *file = file_string;
             struct stat sb;
             int ret;
 
             errno = 0;
-            ret = lstat (file, &sb);
+            ret = stat (file, &sb);
 
             if (ret == -1)
               vfprintf_fail (formats[FMT_FILE], file, strerror (errno));
@@ -637,12 +678,7 @@ process_file_arg (const char *file_string, const char **file, FILE **stream)
             if (!VALID_FILE_TYPE (sb.st_mode))
               vfprintf_fail (formats[FMT_TYPE], file, "unrecognized type", get_file_type (sb.st_mode));
 
-            errno = 0;
-
-            s = fopen (file, "r");
-            if (!s)
-              vfprintf_fail (formats[FMT_FILE], file, strerror (errno));
-            *stream = s;
+            *stream = open_file (file, "r");
           }
         *file = file_string;
       }
@@ -944,7 +980,7 @@ print_free_offsets (const char *line, char ***offsets, unsigned int count)
           RESTORE_CHAR (offsets[i + 1][0], ch);
       }
     for (i = 0; i < count; i++)
-      free_null (offsets[i]);
+      free (offsets[i]);
     free_null (offsets);
 }
 
@@ -982,6 +1018,7 @@ malloc_wrap_debug (size_t size, const char *file, unsigned int line)
     void *p = malloc (size);
     if (!p)
       MEM_ALLOC_FAIL_DEBUG (file, line);
+    fprintf (log, "%s: malloc'ed %lu bytes [source file %s, line %u]\n", program_name, (unsigned long)size, file, line);
     return p;
 }
 
@@ -991,6 +1028,7 @@ calloc_wrap_debug (size_t nmemb, size_t size, const char *file, unsigned int lin
     void *p = calloc (nmemb, size);
     if (!p)
       MEM_ALLOC_FAIL_DEBUG (file, line);
+    fprintf (log, "%s: calloc'ed %lu bytes [source file %s, line %u]\n", program_name, (unsigned long)(nmemb * size), file, line);
     return p;
 }
 
@@ -1000,9 +1038,10 @@ realloc_wrap_debug (void *ptr, size_t size, const char *file, unsigned int line)
     void *p = realloc (ptr, size);
     if (!p)
       MEM_ALLOC_FAIL_DEBUG (file, line);
+    fprintf (log, "%s: realloc'ed %lu bytes [source file %s, line %u]\n", program_name, (unsigned long)size, file, line);
     return p;
 }
-#endif
+#endif /* !DEBUG */
 
 static void
 free_wrap (void **ptr)
@@ -1011,22 +1050,28 @@ free_wrap (void **ptr)
     *ptr = NULL;
 }
 
+#if !DEBUG
+# define do_malloc(len, file, line) malloc_wrap(len)
+#else
+# define do_malloc(len, file, line) malloc_wrap_debug(len, file, line)
+#endif
+
 static char *
-strdup_wrap (const char *str)
+strdup_wrap (const char *str, const char *file, unsigned int line)
 {
     const size_t len = strlen (str) + 1;
-    char *p = xmalloc (len);
+    char *p = do_malloc (len, file, line);
     strncpy (p, str, len);
     return p;
 }
 
 static char *
-str_concat (const char *str1, const char *str2)
+str_concat_wrap (const char *str1, const char *str2, const char *file, unsigned int line)
 {
     const size_t len = strlen (str1) + strlen (str2) + 1;
     char *p, *str;
 
-    p = str = xmalloc (len);
+    p = str = do_malloc (len, file, line);
     strncpy (p, str1, strlen (str1));
     p += strlen (str1);
     strncpy (p, str2, strlen (str2));
@@ -1036,6 +1081,24 @@ str_concat (const char *str1, const char *str2)
     return str;
 }
 
+static bool
+get_bytes_size (unsigned long bytes, struct bytes_size *bytes_size)
+{
+    const char *unit, units[] = { '0', 'K', 'M', 'G', '\0' };
+    unsigned long size = bytes;
+    if (bytes < 1024)
+      return false;
+    unit = units;
+    while (size >= 1024 && *(unit + 1))
+      {
+        size /= 1024;
+        unit++;
+      }
+    bytes_size->size = (unsigned int)size;
+    bytes_size->unit = *unit;
+    return true;
+}
+
 static char *
 get_file_type (mode_t mode)
 {
@@ -1074,6 +1137,19 @@ has_color_name (const char *str, const char *name)
     return true;
 }
 
+static FILE *
+open_file (const char *file, const char *mode)
+{
+    FILE *stream;
+
+    errno = 0;
+    stream = fopen (file, mode);
+    if (!stream)
+      vfprintf_fail (formats[FMT_FILE], file, strerror (errno));
+
+    return stream;
+}
+
 #define DO_VFPRINTF(fmt)                    \
     va_list ap;                             \
     fprintf (stderr, "%s: ", program_name); \