* 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
*
*/
-#define _POSIX_C_SOURCE 200809L
+#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_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__)
+#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 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(size)
-# define xcalloc(nmemb, size) calloc_wrap(nmemb, size)
-# define xrealloc(ptr, size) realloc_wrap(ptr, size)
+# 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
release_var (vars_list, stacked_vars, (void **)&ptr); \
} while (false)
-#define MEM_ALLOC_FAIL_DEBUG(file, line) do { \
- fprintf (stderr, "Memory allocation failure in source file %s, line %u\n", file, line); \
- exit (2); \
-} while (false)
-#define MEM_ALLOC_FAIL() do { \
+#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 (EXIT_FAILURE); \
} while (false)
+#endif
#define ABORT_TRACE() \
fprintf (stderr, "Aborting in source file %s, line %u\n", __FILE__, __LINE__); \
#define COLOR_SEP_CHAR '/'
-#define VERSION "0.53"
+#define DEBUG_FILE "debug.txt"
+
+#define VERSION "0.55"
typedef enum { false, true } bool;
{ "default", "49m" },
};
+struct bytes_size {
+ unsigned int size;
+ char unit;
+};
+
enum fmts {
FMT_GENERIC,
+ FMT_STRING,
FMT_QUOTE,
FMT_COLOR,
FMT_RANDOM,
};
static const char *formats[] = {
"%s", /* generic */
+ "%s '%s'", /* string */
"%s `%s' %s", /* quote */
"%s color '%s' %s", /* color */
"%s color '%s' %s '%s'", /* random */
};
static FILE *stream = NULL;
+#if DEBUG
+static FILE *log = NULL;
+#endif
static unsigned int stacked_vars = 0;
static void **vars_list = NULL;
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);
+#if !DEBUG
static void *malloc_wrap (size_t);
static void *calloc_wrap (size_t, size_t);
static void *realloc_wrap (void *, size_t);
+#else
static void *malloc_wrap_debug (size_t, const char *, unsigned int);
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 *);
setvbuf (stdout, NULL, _IOLBF, 0);
+#if DEBUG
+ log = open_file (DEBUG_FILE, "w");
+#endif
+
while ((opt = getopt_long (argc, argv, "hv", long_opts, NULL)) != -1)
{
PARSE_OPT:
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);
#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");
}
if (stream && fileno (stream) != STDIN_FILENO)
fclose (stream);
+#if DEBUG
+ if (log)
+ fclose (log);
+#endif
if (vars_list)
{
/* 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;
if (have_file)
{
+ const char *file_exists = color_string;
if (file_string)
- vfprintf_fail (formats[FMT_QUOTE], get_file_type (mode), color_string, "cannot be used as color string");
+ vfprintf_fail (formats[FMT_QUOTE], get_file_type (mode), file_exists, "cannot be used as color string");
else
{
if (VALID_FILE_TYPE (mode))
- vfprintf_fail (formats[FMT_QUOTE], get_file_type (mode), color_string, "must be preceeded by color string");
+ vfprintf_fail (formats[FMT_QUOTE], get_file_type (mode), file_exists, "must be preceeded by color string");
else
- vfprintf_fail (formats[FMT_QUOTE], get_file_type (mode), color_string, "is not a valid file type");
+ vfprintf_fail (formats[FMT_QUOTE], get_file_type (mode), file_exists, "is not a valid file type");
}
}
}
if ((p = strchr (color_string, COLOR_SEP_CHAR)))
{
if (p == color_string)
- vfprintf_fail (formats[FMT_GENERIC], "foreground color missing");
+ vfprintf_fail (formats[FMT_STRING], "foreground color missing in string", color_string);
else if (p == color_string + strlen (color_string) - 1)
- vfprintf_fail (formats[FMT_GENERIC], "background color missing");
+ vfprintf_fail (formats[FMT_STRING], "background color missing in string", color_string);
else if (strchr (++p, COLOR_SEP_CHAR))
- vfprintf_fail (formats[FMT_GENERIC], "one color pair allowed only");
+ vfprintf_fail (formats[FMT_STRING], "one color pair allowed only for string", color_string);
}
str = xstrdup (color_string);
FILE *s;
const char *file = file_string;
struct stat sb;
- int errno, ret;
+ int ret;
errno = 0;
ret = lstat (file, &sb);
free_null (offsets);
}
+#if !DEBUG
static void *
malloc_wrap (size_t size)
{
MEM_ALLOC_FAIL ();
return p;
}
-
+#else
static void *
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;
}
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;
}
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 /* !DEBUG */
static void
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));
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)
{
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); \