summaryrefslogtreecommitdiffstats
path: root/color.c
diff options
context:
space:
mode:
authorThomas Roessler <roessler@does-not-exist.org>1998-06-08 09:16:03 +0000
committerThomas Roessler <roessler@does-not-exist.org>1998-06-08 09:16:03 +0000
commit1a5381e07e97fe482c2b3a7c75f99938f0b105d4 (patch)
treeb4fa4088bbbf5fc9217ee6f87ab60034175e6899 /color.c
Initial revision
Diffstat (limited to 'color.c')
-rw-r--r--color.c731
1 files changed, 731 insertions, 0 deletions
diff --git a/color.c b/color.c
new file mode 100644
index 00000000..6468b2e3
--- /dev/null
+++ b/color.c
@@ -0,0 +1,731 @@
+/*
+ * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "mutt.h"
+#include "mutt_curses.h"
+#include "mapping.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+/* globals */
+int *ColorQuote;
+int ColorQuoteUsed;
+int ColorDefs[MT_COLOR_MAX];
+COLOR_LINE *ColorHdrList = NULL;
+COLOR_LINE *ColorBodyList = NULL;
+COLOR_LINE *ColorIndexList = NULL;
+
+/* local to this file */
+static int ColorQuoteSize;
+
+#ifdef HAVE_COLOR
+
+#define COLOR_DEFAULT (-2)
+
+typedef struct color_list
+{
+ short fg;
+ short bg;
+ short index;
+ short count;
+ struct color_list *next;
+} COLOR_LIST;
+
+static COLOR_LIST *ColorList = NULL;
+static int UserColors = 0;
+
+static struct mapping_t Colors[] =
+{
+ { "black", COLOR_BLACK },
+ { "blue", COLOR_BLUE },
+ { "cyan", COLOR_CYAN },
+ { "green", COLOR_GREEN },
+ { "magenta", COLOR_MAGENTA },
+ { "red", COLOR_RED },
+ { "white", COLOR_WHITE },
+ { "yellow", COLOR_YELLOW },
+#if defined (USE_SLANG_CURSES) || defined (HAVE_USE_DEFAULT_COLORS)
+ { "default", COLOR_DEFAULT },
+#endif
+ { 0, 0 }
+};
+
+#endif /* HAVE_COLOR */
+
+static struct mapping_t Fields[] =
+{
+ { "hdrdefault", MT_COLOR_HDEFAULT },
+ { "quoted", MT_COLOR_QUOTED },
+ { "signature", MT_COLOR_SIGNATURE },
+ { "indicator", MT_COLOR_INDICATOR },
+ { "status", MT_COLOR_STATUS },
+ { "tree", MT_COLOR_TREE },
+ { "error", MT_COLOR_ERROR },
+ { "normal", MT_COLOR_NORMAL },
+ { "tilde", MT_COLOR_TILDE },
+ { "markers", MT_COLOR_MARKERS },
+ { "header", MT_COLOR_HEADER },
+ { "body", MT_COLOR_BODY },
+ { "message", MT_COLOR_MESSAGE },
+ { "attachment", MT_COLOR_ATTACHMENT },
+ { "search", MT_COLOR_SEARCH },
+ { "bold", MT_COLOR_BOLD },
+ { "underline", MT_COLOR_UNDERLINE },
+ { "index", MT_COLOR_INDEX },
+ { NULL, 0 }
+};
+
+#define COLOR_QUOTE_INIT 8
+
+void ci_start_color (void)
+{
+ memset (ColorDefs, A_NORMAL, sizeof (int) * MT_COLOR_MAX);
+ ColorQuote = (int *) safe_malloc (COLOR_QUOTE_INIT * sizeof (int));
+ memset (ColorQuote, A_NORMAL, sizeof (int) * COLOR_QUOTE_INIT);
+ ColorQuoteSize = COLOR_QUOTE_INIT;
+ ColorQuoteUsed = 0;
+
+ /* set some defaults */
+ ColorDefs[MT_COLOR_STATUS] = A_REVERSE;
+ ColorDefs[MT_COLOR_INDICATOR] = A_REVERSE;
+ ColorDefs[MT_COLOR_SEARCH] = A_REVERSE;
+ ColorDefs[MT_COLOR_MARKERS] = A_REVERSE;
+ /* special meaning: toggle the relevant attribute */
+ ColorDefs[MT_COLOR_BOLD] = 0;
+ ColorDefs[MT_COLOR_UNDERLINE] = 0;
+
+#ifdef HAVE_COLOR
+ start_color ();
+#endif
+}
+
+#ifdef HAVE_COLOR
+
+#ifdef USE_SLANG_CURSES
+static char * get_color_name (int val)
+{
+ static char * missing[3] = {"brown", "lightgray", ""};
+ int i;
+
+ switch (val)
+ {
+ case COLOR_YELLOW:
+ return (missing[0]);
+
+ case COLOR_WHITE:
+ return (missing[1]);
+
+ case COLOR_DEFAULT:
+ return (missing[2]);
+ }
+
+ for (i = 0; Colors[i].name; i++)
+ {
+ if (Colors[i].value == val)
+ return (Colors[i].name);
+ }
+ return (Colors[0].name);
+}
+#endif
+
+int mutt_alloc_color (int fg, int bg)
+{
+ COLOR_LIST *p = ColorList;
+ int i;
+
+ /* check to see if this color is already allocated to save space */
+ while (p)
+ {
+ if (p->fg == fg && p->bg == bg)
+ {
+ (p->count)++;
+ return (COLOR_PAIR (p->index));
+ }
+ p = p->next;
+ }
+
+ /* check to see if there are colors left */
+ if (++UserColors > COLOR_PAIRS) return (A_NORMAL);
+
+ /* find the smallest available index (object) */
+ i = 1;
+ FOREVER
+ {
+ p = ColorList;
+ while (p)
+ {
+ if (p->index == i) break;
+ p = p->next;
+ }
+ if (p == NULL) break;
+ i++;
+ }
+
+ p = (COLOR_LIST *) safe_malloc (sizeof (COLOR_LIST));
+ p->next = ColorList;
+ ColorList = p;
+
+ p->index = i;
+ p->count = 1;
+ p->bg = bg;
+ p->fg = fg;
+
+#if defined (USE_SLANG_CURSES)
+ if (fg == COLOR_DEFAULT || bg == COLOR_DEFAULT)
+ SLtt_set_color (i, NULL, get_color_name (fg), get_color_name (bg));
+ else
+#elif defined (HAVE_USE_DEFAULT_COLORS)
+ if (fg == COLOR_DEFAULT)
+ fg = -1;
+ if (bg == COLOR_DEFAULT)
+ bg = -1;
+#endif
+
+ init_pair (i, fg, bg);
+
+ dprint(1,(debugfile,"mutt_alloc_color(): Color pairs used so far: %d\n",
+ UserColors));
+
+ return (COLOR_PAIR (p->index));
+}
+
+void mutt_free_color (int fg, int bg)
+{
+ COLOR_LIST *p, *q;
+
+ p = ColorList;
+ while (p)
+ {
+ if (p->fg == fg && p->bg == bg)
+ {
+ (p->count)--;
+ if (p->count > 0) return;
+
+ UserColors--;
+ dprint(1,(debugfile,"mutt_free_color(): Color pairs used so far: %d\n",
+ UserColors));
+
+ if (p == ColorList)
+ {
+ ColorList = ColorList->next;
+ safe_free ((void **) &p);
+ return;
+ }
+ q = ColorList;
+ while (q)
+ {
+ if (q->next == p)
+ {
+ q->next = p->next;
+ safe_free ((void **) &p);
+ return;
+ }
+ q = q->next;
+ }
+ /* can't get here */
+ }
+ p = p->next;
+ }
+}
+
+#endif /* HAVE_COLOR */
+
+static COLOR_LINE *mutt_new_color_line (void)
+{
+ COLOR_LINE *p = safe_calloc (1, sizeof (COLOR_LINE));
+
+ return (p);
+}
+
+static int add_pattern (COLOR_LINE **top, const char *s, int sensitive,
+ int fg, int bg, int attr, BUFFER *err,
+ /* is_index used to store compiled pattern
+ only for `index' color object
+ when called from mutt_parse_color() */
+ int is_index)
+{
+ COLOR_LINE *tmp = *top;
+
+ while (tmp)
+ {
+ if (sensitive)
+ {
+ if (strcmp (s, tmp->pattern) == 0)
+ break;
+ }
+ else
+ {
+ if (strcasecmp (s, tmp->pattern) == 0)
+ break;
+ }
+ tmp = tmp->next;
+ }
+
+ if (tmp)
+ {
+#ifdef HAVE_COLOR
+ if (fg != -1 && bg != -1)
+ {
+ if (tmp->fg != fg || tmp->bg != bg)
+ {
+ mutt_free_color (tmp->fg, tmp->bg);
+ tmp->fg = fg;
+ tmp->bg = bg;
+ attr |= mutt_alloc_color (fg, bg);
+ }
+ else
+ attr |= (tmp->pair & ~A_BOLD);
+ }
+#endif /* HAVE_COLOR */
+ tmp->pair = attr;
+ }
+ else
+ {
+ int r;
+ char buf[STRING];
+
+ tmp = mutt_new_color_line ();
+ if ((r = REGCOMP (&tmp->rx, s, (sensitive ? mutt_which_case (s) : REG_ICASE))) != 0)
+ {
+ regerror (r, &tmp->rx, err->data, err->dsize);
+ regfree (&tmp->rx);
+ safe_free ((void **) &tmp);
+ return (-1);
+ }
+ tmp->next = *top;
+ tmp->pattern = safe_strdup (s);
+#ifdef HAVE_COLOR
+ tmp->fg = fg;
+ tmp->bg = bg;
+ attr |= mutt_alloc_color (fg, bg);
+ if (is_index)
+ {
+ strcpy(buf,tmp->pattern);
+ mutt_check_simple (buf, sizeof (buf), SimpleSearch);
+ tmp->color_pattern = mutt_pattern_comp (buf, M_FULL_MSG, err);
+ }
+#endif
+ tmp->pair = attr;
+ *top = tmp;
+ }
+
+ return 0;
+}
+
+#ifdef HAVE_COLOR
+
+static int
+parse_color_name (const char *s, int *col, int *attr, int brite, BUFFER *err)
+{
+ char *eptr;
+
+ if (strncasecmp (s, "bright", 6) == 0)
+ {
+ *attr |= brite;
+ s += 6;
+ }
+
+ /* allow aliases for xterm color resources */
+ if (strncasecmp (s, "color", 5) == 0)
+ {
+ s += 5;
+ *col = strtol (s, &eptr, 10);
+ if (!*s || *eptr || *col < 0 || *col >= COLORS)
+ {
+ snprintf (err->data, err->dsize, "%s: color not supported by term", s);
+ return (-1);
+ }
+ }
+ else if ((*col = mutt_getvaluebyname (s, Colors)) == -1)
+ {
+ snprintf (err->data, err->dsize, "%s: no such color", s);
+ return (-1);
+ }
+
+#ifdef HAVE_USE_DEFAULT_COLORS
+ if (*col == COLOR_DEFAULT && use_default_colors () != OK)
+ {
+ strfcpy (err->data, "default colors not supported", err->dsize);
+ return (-1);
+ }
+#endif
+
+ return 0;
+}
+
+/* usage: uncolor index pattern [pattern...] */
+int mutt_parse_uncolor (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
+{
+ int object = 0, do_cache = 0;
+ COLOR_LINE *tmp, *last = NULL;
+
+ mutt_extract_token (buf, s, 0);
+
+ if ((object = mutt_getvaluebyname (buf->data, Fields)) == -1)
+ {
+ snprintf (err->data, err->dsize, "%s: no such object", buf->data);
+ return (-1);
+ }
+
+ if (strncmp (buf->data, "index", 5) != 0)
+ {
+ strfcpy (err->data, "uncolor: command valid only for index object", err->dsize);
+ return (-1);
+ }
+
+ if (!MoreArgs (s))
+ {
+ strfcpy (err->data, "uncolor: too few arguments", err->dsize);
+ return (-1);
+ }
+
+ while (MoreArgs (s))
+ {
+ mutt_extract_token (buf, s, 0);
+ if (!strcmp ("*", buf->data))
+ {
+ for (tmp = ColorIndexList; tmp; )
+ {
+ if (!do_cache)
+ do_cache = 1;
+ last = tmp;
+ tmp = tmp->next;
+ mutt_pattern_free (&last->color_pattern);
+ mutt_free_color(last->fg,last->bg);
+ safe_free ((void **) &last);
+ }
+ ColorIndexList = NULL;
+ }
+ else
+ {
+ for (last = NULL, tmp = ColorIndexList; tmp; last = tmp, tmp = tmp->next)
+ {
+ if (!strcmp (buf->data, tmp->pattern))
+ {
+ if (!do_cache)
+ do_cache = 1;
+ dprint(1,(debugfile,"Freeing pattern \"%s\" from ColorIndexList\n",
+ tmp->pattern));
+ if (last)
+ last->next = tmp->next;
+ else
+ ColorIndexList = tmp->next;
+ mutt_pattern_free (&tmp->color_pattern);
+ mutt_free_color(tmp->fg,tmp->bg);
+ safe_free ((void **) &tmp);
+ break;
+ }
+ }
+ }
+ }
+
+ if (do_cache && !option (OPTNOCURSES) && has_colors ())
+ {
+ mutt_cache_index_colors (Context);
+ set_option (OPTFORCEREDRAWINDEX);
+ }
+
+ return (0);
+}
+
+/* usage: color <object> <fg> <bg> [ <regexp> ] */
+int mutt_parse_color (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
+{
+ int object = 0, bold = 0, fg = 0, bg = 0, q_level = 0;
+ int r = 0;
+ char *eptr;
+
+ mutt_extract_token (buf, s, 0);
+ if (!strncmp (buf->data, "quoted", 6))
+ {
+ if (buf->data[6])
+ {
+ q_level = strtol (buf->data + 6, &eptr, 10);
+ if (*eptr || q_level < 0)
+ {
+ snprintf (err->data, err->dsize, "%s: no such object", buf->data);
+ return (-1);
+ }
+ }
+ object = MT_COLOR_QUOTED;
+ }
+ else if ((object = mutt_getvaluebyname (buf->data, Fields)) == -1)
+ {
+ snprintf (err->data, err->dsize, "%s: no such object", buf->data);
+ return (-1);
+ }
+
+ /* first color */
+ if (! MoreArgs (s))
+ {
+ strfcpy (err->data, "color: too few arguments", err->dsize);
+ return (-1);
+ }
+ mutt_extract_token (buf, s, 0);
+
+ if (parse_color_name (buf->data, &fg, &bold, A_BOLD, err) != 0)
+ return (-1);
+
+ /* second color */
+ if (! MoreArgs (s))
+ {
+ strfcpy (err->data, "color: too few arguments", err->dsize);
+ return (-1);
+ }
+ mutt_extract_token (buf, s, 0);
+
+ /* A_BLINK turns the background color brite on some terms */
+ if (parse_color_name (buf->data, &bg, &bold, A_BLINK, err) != 0)
+ return (-1);
+
+ if (object == MT_COLOR_HEADER || object == MT_COLOR_BODY || object == MT_COLOR_INDEX)
+ {
+ if (! MoreArgs (s))
+ {
+ strfcpy (err->data, "color: too few arguments", err->dsize);
+ return (-1);
+ }
+
+ mutt_extract_token (buf, s, 0);
+ if (MoreArgs (s))
+ {
+ strfcpy (err->data, "color: too many arguments", err->dsize);
+ return (-1);
+ }
+
+ /* don't parse curses command if we're not using the screen */
+ /* ignore color commands if we're running on a mono terminal */
+ if (option (OPTNOCURSES) || !has_colors ())
+ {
+ return 0;
+ }
+
+ if (object == MT_COLOR_HEADER)
+ r = add_pattern (&ColorHdrList, buf->data, 0, fg, bg, bold, err,0);
+ else if (object == MT_COLOR_BODY)
+ r = add_pattern (&ColorBodyList, buf->data, 1, fg, bg, bold, err, 0);
+ else if (object == MT_COLOR_INDEX)
+ {
+ pattern_t *pat;
+ char tempbuf[LONG_STRING];
+
+ strfcpy (tempbuf, buf->data, sizeof (tempbuf));
+ mutt_check_simple (tempbuf, sizeof (tempbuf), SimpleSearch);
+ if ((pat = mutt_pattern_comp (tempbuf, M_FULL_MSG, err)) == NULL)
+ {
+ mutt_pattern_free (&pat);
+ return (-1);
+ }
+ r = add_pattern (&ColorIndexList, buf->data, 1, fg, bg, bold, err, 1);
+ mutt_cache_index_colors(Context);
+ set_option (OPTFORCEREDRAWINDEX);
+ }
+ }
+ else
+ {
+ /* don't parse curses command if we're not using the screen */
+ /* ignore color commands if we're running on a mono terminal */
+ if (option (OPTNOCURSES) || !has_colors ())
+ {
+ return 0;
+ }
+
+ if (object == MT_COLOR_QUOTED)
+ {
+ if (q_level >= ColorQuoteSize)
+ {
+ safe_realloc ((void **) &ColorQuote, (ColorQuoteSize += 2) * sizeof (int));
+ ColorQuote[ColorQuoteSize-2] = ColorDefs[MT_COLOR_QUOTED];
+ ColorQuote[ColorQuoteSize-1] = ColorDefs[MT_COLOR_QUOTED];
+ }
+ if (q_level >= ColorQuoteUsed)
+ ColorQuoteUsed = q_level + 1;
+ if (q_level == 0)
+ {
+ ColorDefs[MT_COLOR_QUOTED] = bold | mutt_alloc_color (fg, bg);
+
+ ColorQuote[0] = ColorDefs[MT_COLOR_QUOTED];
+ for (q_level = 1; q_level < ColorQuoteUsed; q_level++)
+ {
+ if (ColorQuote[q_level] == A_NORMAL)
+ ColorQuote[q_level] = ColorDefs[MT_COLOR_QUOTED];
+ }
+ }
+ else
+ ColorQuote[q_level] = bold | mutt_alloc_color (fg, bg);
+ }
+ else
+ ColorDefs[object] = bold | mutt_alloc_color (fg, bg);
+ }
+
+#ifdef HAVE_BKGDSET
+ if (object == MT_COLOR_NORMAL)
+ BKGDSET (MT_COLOR_NORMAL);
+#endif
+
+ return (r);
+}
+
+#endif /* HAVE_COLOR */
+
+/*
+ * command: mono <object> <attribute>
+ *
+ * set attribute for an object when using a terminal with no color support
+ */
+int mutt_parse_mono (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
+{
+ int r = 0, object, q_level = 0, attr = A_NORMAL;
+ char *eptr;
+
+ mutt_extract_token (buf, s, 0);
+ if (strncmp (buf->data, "quoted", 6) == 0)
+ {
+ if (buf->data[6])
+ {
+ q_level = strtol (buf->data + 6, &eptr, 10);
+ if (*eptr || q_level < 0)
+ {
+ snprintf (err->data, err->dsize, "%s: no such object", buf->data);
+ return (-1);
+ }
+ }
+ object = MT_COLOR_QUOTED;
+ }
+ else if ((object = mutt_getvaluebyname (buf->data, Fields)) == -1)
+ {
+ snprintf (err->data, err->dsize, "%s: no such object", buf->data);
+ return (-1);
+ }
+
+ if (! MoreArgs (s))
+ {
+ strfcpy (err->data, "mono: too few arguments", err->dsize);
+ return (-1);
+ }
+
+ mutt_extract_token (buf, s, 0);
+
+ if (strcasecmp ("bold", buf->data) == 0)
+ attr |= A_BOLD;
+ else if (strcasecmp ("underline", buf->data) == 0)
+ attr |= A_UNDERLINE;
+ else if (strcasecmp ("none", buf->data) == 0)
+ attr = A_NORMAL;
+ else if (strcasecmp ("reverse", buf->data) == 0)
+ attr |= A_REVERSE;
+ else if (strcasecmp ("standout", buf->data) == 0)
+ attr |= A_STANDOUT;
+ else if (strcasecmp ("normal", buf->data) == 0)
+ attr = A_NORMAL; /* needs use = instead of |= to clear other bits */
+ else
+ {
+ snprintf (err->data, err->dsize, "%s: no such attribute", buf->data);
+ return (-1);
+ }
+
+ if (object == MT_COLOR_HEADER || object == MT_COLOR_BODY || object == MT_COLOR_INDEX)
+ {
+ if (! MoreArgs (s))
+ {
+ snprintf (err->data, err->dsize, "mono: missing regexp");
+ return (-1);
+ }
+
+ mutt_extract_token (buf, s, 0);
+ if (MoreArgs (s))
+ {
+ strfcpy (err->data, "mono: too many arguments", err->dsize);
+ return (-1);
+ }
+
+ /* if we have color, ignore the mono commands */
+ if (option (OPTNOCURSES)
+#ifdef HAVE_COLOR
+ || has_colors ()
+#endif
+ )
+ {
+ return 0;
+ }
+
+ if (object == MT_COLOR_HEADER)
+ r = add_pattern (&ColorHdrList, buf->data, 0, -1, -1, attr, err, 0);
+ else if (object == MT_COLOR_BODY)
+ r = add_pattern (&ColorBodyList, buf->data, 1, -1, -1, attr, err, 0);
+ else if (object == MT_COLOR_INDEX)
+ {
+ pattern_t *pat;
+ char tempbuf[LONG_STRING];
+
+ strfcpy (tempbuf, buf->data, sizeof (tempbuf));
+ mutt_check_simple (tempbuf, sizeof (tempbuf), SimpleSearch);
+ if ((pat = mutt_pattern_comp (tempbuf, M_FULL_MSG, err)) == NULL)
+ {
+ mutt_pattern_free (&pat);
+ return (-1);
+ }
+ r = add_pattern (&ColorIndexList, buf->data, 1, -1, -1, attr, err, 1);
+ mutt_cache_index_colors (Context);
+ set_option (OPTFORCEREDRAWINDEX);
+ }
+ }
+ else
+ {
+ /* if we have color, ignore the mono commands */
+ if (option (OPTNOCURSES)
+#ifdef HAVE_COLOR
+ || has_colors ()
+#endif
+ )
+ {
+ return 0;
+ }
+
+ if (object == MT_COLOR_QUOTED)
+ {
+ if (q_level >= ColorQuoteSize)
+ {
+ safe_realloc ((void **) &ColorQuote, (ColorQuoteSize += 2) * sizeof (int));
+ ColorQuote[ColorQuoteSize-2] = ColorDefs[MT_COLOR_QUOTED];
+ ColorQuote[ColorQuoteSize-1] = ColorDefs[MT_COLOR_QUOTED];
+ }
+ if (q_level >= ColorQuoteUsed)
+ ColorQuoteUsed = q_level + 1;
+ if (q_level == 0)
+ {
+ ColorDefs[MT_COLOR_QUOTED] = attr;
+
+ ColorQuote[0] = ColorDefs[MT_COLOR_QUOTED];
+ for (q_level = 1; q_level < ColorQuoteUsed; q_level++)
+ {
+ if (ColorQuote[q_level] == A_NORMAL)
+ ColorQuote[q_level] = ColorDefs[MT_COLOR_QUOTED];
+ }
+ }
+ else
+ ColorQuote[q_level] = attr;
+ }
+ else
+ ColorDefs[object] = attr;
+ }
+
+ return (r);
+}