--- /dev/null
+/** \file color.c Functions for printing colored messages. */
+
+/*
+ * Mostly taken from the git source tree, version 1.6.1.76, January 2008.
+ */
+
+#include "para.h"
+#include "color.h"
+
+static int parse_color(const char *name, int len)
+{
+ static const char * const color_names[] = {
+ "normal", "black", "red", "green", "yellow",
+ "blue", "magenta", "cyan", "white"
+ };
+ char *end;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(color_names); i++) {
+ const char *str = color_names[i];
+ if (!strncasecmp(name, str, len) && !str[len])
+ return i - 1;
+ }
+ i = strtol(name, &end, 10);
+ if (end - name == len && i >= -1 && i <= 255)
+ return i;
+ return -2;
+}
+
+static int parse_attr(const char *name, int len)
+{
+ static const int attr_values[] = { 1, 2, 4, 5, 7 };
+ static const char * const attr_names[] = {
+ "bold", "dim", "ul", "blink", "reverse"
+ };
+ int i;
+ for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
+ const char *str = attr_names[i];
+ if (!strncasecmp(name, str, len) && !str[len])
+ return attr_values[i];
+ }
+ return -1;
+}
+
+/**
+ * Create an escape sequence for colored output.
+ *
+ * \param value Human-readable color spec.
+ * \param dst Result pointer for the escape sequence.
+ *
+ * \return -1 on errors, 1 on success.
+ *
+ * Format of \a value: [fg [bg]] [attr].
+ */
+int color_parse(const char *value, char *dst)
+{
+ const char *ptr = value;
+ int attr = -1;
+ int fg = -2;
+ int bg = -2;
+
+ if (!strcasecmp(value, "reset")) {
+ strcpy(dst, COLOR_RESET);
+ return 1;
+ }
+
+ /* [fg [bg]] [attr] */
+ while (*ptr) {
+ const char *word = ptr;
+ int val, len = 0;
+
+ while (word[len] && !isspace(word[len]))
+ len++;
+
+ ptr = word + len;
+ while (*ptr && isspace(*ptr))
+ ptr++;
+
+ val = parse_color(word, len);
+ if (val >= -1) {
+ if (fg == -2) {
+ fg = val;
+ continue;
+ }
+ if (bg == -2) {
+ bg = val;
+ continue;
+ }
+ goto bad;
+ }
+ val = parse_attr(word, len);
+ if (val < 0 || attr != -1)
+ goto bad;
+ attr = val;
+ }
+
+ if (attr >= 0 || fg >= 0 || bg >= 0) {
+ int sep = 0;
+
+ *dst++ = '\033';
+ *dst++ = '[';
+ if (attr >= 0) {
+ *dst++ = '0' + attr;
+ sep++;
+ }
+ if (fg >= 0) {
+ if (sep++)
+ *dst++ = ';';
+ if (fg < 8) {
+ *dst++ = '3';
+ *dst++ = '0' + fg;
+ } else {
+ dst += sprintf(dst, "38;5;%d", fg);
+ }
+ }
+ if (bg >= 0) {
+ if (sep++)
+ *dst++ = ';';
+ if (bg < 8) {
+ *dst++ = '4';
+ *dst++ = '0' + bg;
+ } else {
+ dst += sprintf(dst, "48;5;%d", bg);
+ }
+ }
+ *dst++ = 'm';
+ }
+ *dst = 0;
+ return 1;
+bad:
+ PARA_ERROR_LOG("bad color value '%s'\n", value);
+ return -1;
+}
#include "sched.h"
#include "signal.h"
#include "user_list.h"
+#include "color.h"
/** Define the array of error lists needed by para_server. */
INIT_SERVER_ERRLISTS;
struct task task;
};
+static int want_colors(void)
+{
+ if (conf.color_arg == color_arg_no)
+ return 0;
+ if (conf.color_arg == color_arg_yes)
+ return 1;
+ if (logfile)
+ return 0;
+ return isatty(STDERR_FILENO);
+}
+
+static int get_loglevel_by_name(const char *txt, size_t n)
+{
+ if (!strncasecmp(txt, "debug", n))
+ return LL_DEBUG;
+ if (!strncasecmp(txt, "info", n))
+ return LL_INFO;
+ if (!strncasecmp(txt, "notice", n))
+ return LL_NOTICE;
+ if (!strncasecmp(txt, "warning", n))
+ return LL_WARNING;
+ if (!strncasecmp(txt, "error", n))
+ return LL_ERROR;
+ if (!strncasecmp(txt, "crit", n))
+ return LL_CRIT;
+ if (!strncasecmp(txt, "emerg", n))
+ return LL_EMERG;
+ return -1;
+}
+
+static char log_colors[NUM_LOGLEVELS][COLOR_MAXLEN];
+
+static void init_colors_or_die(void)
+{
+ int ret, i;
+ static const char *default_log_colors[NUM_LOGLEVELS] = {
+ [LL_DEBUG] = "normal",
+ [LL_INFO] = "white bold",
+ [LL_NOTICE] = "cyan bold",
+ [LL_WARNING] = "green bold",
+ [LL_ERROR] = "yellow bold",
+ [LL_CRIT] = "magenta bold",
+ [LL_EMERG] = "red bold",
+ };
+
+ for (i = 0; i < NUM_LOGLEVELS; i++) {
+ ret = color_parse(default_log_colors[i], log_colors[i]);
+ assert(ret >= 0);
+ }
+
+ for (i = 0; i < conf.log_color_given; i++) {
+ char *arg = conf.log_color_arg[i], *p = strchr(arg, ':');
+ int ll;
+ if (!p)
+ goto err;
+ ret = get_loglevel_by_name(arg, p - arg);
+ if (ret < 0)
+ goto err;
+ ll = ret;
+ p++;
+ ret = color_parse(p, log_colors[ll]);
+ if (ret < 0)
+ goto err;
+ }
+ return;
+err:
+ PARA_EMERG_LOG("color syntax error, arg %d (%s)\n", i,
+ conf.log_color_arg[i]);
+ exit(EXIT_FAILURE);
+}
+
/**
* Para_server's log function.
*
__printf_2_3 void para_log(int ll, const char* fmt,...)
{
va_list argp;
- FILE *outfd;
+ FILE *fp;
struct tm *tm;
time_t t1;
- char str[MAXLINE] = "";
- pid_t mypid;
+ char *color, str[MAXLINE] = "";
+ ll = PARA_MIN(ll, NUM_LOGLEVELS - 1);
+ ll = PARA_MAX(ll, LL_DEBUG);
if (ll < conf.loglevel_arg)
return;
- outfd = logfile? logfile : stderr;
+
+ fp = logfile? logfile : stderr;
+ color = want_colors()? log_colors[ll] : NULL;
+
+ if (color)
+ fprintf(fp, "%s", color);
+ /* date and time */
time(&t1);
tm = localtime(&t1);
strftime(str, MAXLINE, "%b %d %H:%M:%S", tm);
- fprintf(outfd, "%s ", str);
+ fprintf(fp, "%s ", str);
+ /* loglevel */
if (conf.loglevel_arg <= LL_INFO)
- fprintf(outfd, "%i: ", ll);
- mypid = getpid();
- if (conf.loglevel_arg <= LL_INFO)
- fprintf(outfd, "(%d) ", (int)mypid);
+ fprintf(fp, "%i: ", ll);
+ if (conf.loglevel_arg <= LL_INFO) { /* log pid */
+ pid_t mypid = getpid();
+ fprintf(fp, "(%d) ", (int)mypid);
+ }
va_start(argp, fmt);
- vfprintf(outfd, fmt, argp);
+ vfprintf(fp, fmt, argp);
va_end(argp);
+ if (color)
+ fprintf(fp, "%s", COLOR_RESET);
}
/*
}
if (conf.logfile_given)
logfile = open_log(conf.logfile_arg);
+ if (want_colors())
+ init_colors_or_die();
ret = 1;
out:
free(cf);