commit:     c660ce430d11238f35dce8620f3cd5de9a9c483f
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Wed Jun 25 15:36:05 2025 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Wed Jun 25 15:36:05 2025 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=c660ce43

libq/colors: fix up color.map support

Somehow the colour variables, and their names, mappings, were completely
off.  Stashed everything in a single struct such that assignments are
direct, and it is much less likely a var would be added without handling
it.

While handling input from color.map, trim spaces around keys and values
and match case-insensitive, such that we don't get unexpected weird or
non-functional results.

Bonus, created a list of colours Portage uses, and added support for the
RGB ANSI ones, as Portage also uses.

Bug: https://bugs.gentoo.org/958487
Suggested-by: C.Blake <charlechaud <AT> gmail.com>
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>

 libq/colors.c | 231 ++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 137 insertions(+), 94 deletions(-)

diff --git a/libq/colors.c b/libq/colors.c
index 6f3d7f1..18dbaf7 100644
--- a/libq/colors.c
+++ b/libq/colors.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005-2021 Gentoo Foundation
+ * Copyright 2005-2025 Gentoo Foundation
  * Distributed under the terms of the GNU General Public License v2
  *
  * Copyright 2005-2010 Ned Ludd        - <[email protected]>
@@ -11,12 +11,47 @@
 #include "colors.h"
 #include "rmspace.h"
 
+#define COLOR_MAP CONFIG_EPREFIX "etc/portage/color.map"
+
+#define CPAIR_VALUE_LEN 16
+typedef struct {
+       const char  *name;
+       const char  *origval;
+       const char **var;
+       char         tmpbuf[CPAIR_VALUE_LEN];
+} colourpair;
+
+typedef struct {
+       const char *name;
+       const char *value;
+} colourmap;
+
 /* color constants */
 #ifdef OPTIMIZE_FOR_SIZE
-# define _MAKE_COLOR(c,b) ""
+# define _MAKE_COLOUR1(c)   ""
+# define _MAKE_COLOUR2(c,b) ""
 #else
-# define _MAKE_COLOR(c,b) "\e[" c ";" b "m"
+# define _MAKE_COLOUR1(c)   "\e[" #c "m"
+# define _MAKE_COLOUR2(c,b) "\e[" #c ";" #b "m"
 #endif
+#define LQC_BLACK      _MAKE_COLOUR1(30)
+#define LQC_DARKGREY   _MAKE_COLOUR2(30,01)
+#define LQC_RED        _MAKE_COLOUR1(31)
+#define LQC_DARKRED    _MAKE_COLOUR2(31,01)
+#define LQC_GREEN      _MAKE_COLOUR1(32)
+#define LQC_DARKGREEN  _MAKE_COLOUR2(32,01)
+#define LQC_YELLOW     _MAKE_COLOUR1(33)
+#define LQC_BROWN      _MAKE_COLOUR2(33,01)
+#define LQC_BLUE       _MAKE_COLOUR1(34)
+#define LQC_DARKBLUE   _MAKE_COLOUR2(34,01)
+#define LQC_FUCHSIA    _MAKE_COLOUR1(35)
+#define LQC_PURPLE     _MAKE_COLOUR2(35,01)
+#define LQC_TURQUOISE  _MAKE_COLOUR1(36)
+#define LQC_TEAL       _MAKE_COLOUR2(36,01)
+#define LQC_WHITE      _MAKE_COLOUR1(37)
+#define LQC_LIGHTGREY  _MAKE_COLOUR2(37,01)
+
+/* symbols that are used by the code and hold the active colour escapes */
 const char *NORM;
 const char *BLUE;
 const char *BOLD;
@@ -30,35 +65,69 @@ const char *RED;
 const char *WHITE;
 const char *YELLOW;
 
-static const char *COLOR_MAP = CONFIG_EPREFIX "etc/portage/color.map";
+/* all of the above need to be in the list below */
+static colourpair colour_pairs[] = {
+       {"norm",      _MAKE_COLOUR2(0,0),   &NORM,      ""},
+       {"blue",      LQC_TEAL,             &BLUE,      ""},
+       {"bold",      _MAKE_COLOUR2(0,1),   &BOLD,      ""},
+       {"bryellow",  LQC_BROWN,            &BRYELLOW,  ""},
+       {"cyan",      LQC_TURQUOISE,        &CYAN,      ""},
+       {"dkblue",    LQC_DARKBLUE,         &DKBLUE,    ""},
+       {"dkgreen",   LQC_GREEN,            &DKGREEN,   ""},
+       {"green",     LQC_DARKGREEN,        &GREEN,     ""},
+       {"magenta",   LQC_FUCHSIA,          &MAGENTA,   ""},
+       {"red",       LQC_DARKRED,          &RED,       ""},
+       {"white",     _MAKE_COLOUR2(1,38),  &WHITE,     ""},
+       {"yellow",    LQC_BROWN,            &YELLOW,    ""}
+};
 
-#define CPAIR_VALUE_LEN 16
-typedef struct {
-       const char *name;
-       char value[CPAIR_VALUE_LEN];
-       char origval[CPAIR_VALUE_LEN];
-} cpairtype;
-
-#define X2(X) X, X
-static cpairtype color_pairs[] = {
-       {"blue",      X2(_MAKE_COLOR("34", "01")) },
-       {"brown",     X2(_MAKE_COLOR("00", "33")) },
-       {"darkblue",  X2(_MAKE_COLOR("00", "34")) },
-       {"darkgreen", X2(_MAKE_COLOR("00", "32")) },
-       {"darkred",   X2(_MAKE_COLOR("00", "31")) },
-       {"faint",     X2(_MAKE_COLOR("00", "02")) },
-       {"fuchsia",   X2(_MAKE_COLOR("35", "01")) },
-       {"green",     X2(_MAKE_COLOR("32", "01")) },
-       {"lightgray", X2(_MAKE_COLOR("00", "37")) },
-       {"purple",    X2(_MAKE_COLOR("00", "35")) },
-       {"red",       X2(_MAKE_COLOR("31", "01")) },
-       {"teal",      X2(_MAKE_COLOR("00", "36")) },
-       {"turquoise", X2(_MAKE_COLOR("36", "01")) },
-       {"white",     X2(_MAKE_COLOR("01", "38")) },
-       {"yellow",    X2(_MAKE_COLOR("01", "33")) },
-       {"eol",       X2(_MAKE_COLOR("00", "00")) },
+static colourmap colour_map[] = {
+       /* Portage's list of names */
+       {"black",      LQC_BLACK    },
+       {"darkgrey",   LQC_DARKGREY },
+       {"darkgray",   LQC_DARKGREY },
+       {"red",        LQC_RED      },
+       {"darkred",    LQC_DARKRED  },
+       {"green",      LQC_GREEN    },
+       {"darkgreen",  LQC_DARKGREEN},
+       {"yellow",     LQC_YELLOW   },
+       {"brown",      LQC_BROWN    },
+       {"darkyellow", LQC_BROWN    },
+       {"blue",       LQC_BLUE     },
+       {"darkblue",   LQC_DARKBLUE },
+       {"fuchsia",    LQC_FUCHSIA  },
+       {"purple",     LQC_PURPLE   },
+       {"turquoise",  LQC_TURQUOISE},
+       {"darkteal",   LQC_TURQUOISE},
+       {"teal",       LQC_TEAL     },
+       /* portage-utils historical colour names */
+       {"bryellow",   LQC_BROWN    },
+       {"cyan",       LQC_TURQUOISE},
+       {"dkblue",     LQC_DARKBLUE },
+       {"dkgreen",    LQC_GREEN    },
+       {"magenta",    LQC_FUCHSIA  }
+};
+static colourmap rgb_map[] = {
+       /* RGB ANSI codes */
+       {"0x000000",   LQC_BLACK    },
+       {"0x555555",   LQC_DARKGREY },
+       {"0xAA0000",   LQC_RED      },
+       {"0xFF5555",   LQC_DARKRED  },
+       {"0x00AA00",   LQC_GREEN    },
+       {"0x55FF55",   LQC_DARKGREEN},
+       {"0xAA5500",   LQC_YELLOW   },
+       {"0xFFFF55",   LQC_BROWN    },
+       {"0x0000AA",   LQC_BLUE     },
+       {"0x5555FF",   LQC_DARKBLUE },
+       {"0xAA00AA",   LQC_FUCHSIA  },
+       {"0xFF55FF",   LQC_PURPLE   },
+       {"0x00AAAA",   LQC_TURQUOISE},
+       {"0x55FFFF",   LQC_TEAL     },
+       {"0xAAAAAA",   LQC_WHITE    },
+       {"0xFFFFFF",   LQC_LIGHTGREY},
+       /* some terminals have darkyellow instead of brown */
+       {"0xAAAA00",   LQC_BROWN    }
 };
-#undef X2
 
 void
 color_remap(void)
@@ -71,24 +140,13 @@ color_remap(void)
        char *p;
        unsigned int lineno = 0;
 
-       /* set q's defaults, if there's no colormap, or the file is empty,
-        * or it doesn't match things, we at least got some defaults */
-       NORM     = _MAKE_COLOR("00", "00");
-       BLUE     = _MAKE_COLOR("36", "01");
-       BOLD     = _MAKE_COLOR("00", "01");
-       BRYELLOW = _MAKE_COLOR("01", "33");
-       CYAN     = _MAKE_COLOR("00", "36");
-       DKBLUE   = _MAKE_COLOR("34", "01");
-       DKGREEN  = _MAKE_COLOR("00", "32");
-       GREEN    = _MAKE_COLOR("32", "01");
-       MAGENTA  = _MAKE_COLOR("00", "35");
-       RED      = _MAKE_COLOR("31", "01");
-       WHITE    = _MAKE_COLOR("01", "38");
-       YELLOW   = _MAKE_COLOR("33", "01");
-
        if ((fp = fopen(COLOR_MAP, "r")) == NULL)
                return;
 
+       /* (re)set to defaults */
+       for (i = 0; i < ARRAY_SIZE(colour_pairs); i++)
+               *(colour_pairs[i].var) = colour_pairs[i].origval;
+
        buf = NULL;
        while ((linelen = getline(&buf, &buflen, fp)) >= 0) {
                lineno++;
@@ -96,78 +154,63 @@ color_remap(void)
                if ((p = strchr(buf, '#')) != NULL)
                        *p = '\0';
 
-               rmspace_len(buf, (size_t)linelen);
-
                p = strchr(buf, '=');
                if (p == NULL)
                        continue;
 
-               *p++ = 0; /* split the pair */
-               for (i = 0; i < ARRAY_SIZE(color_pairs); ++i) {
-                       if (strcmp(buf, color_pairs[i].name) == 0) {
+               *p++ = '\0'; /* split the pair */
+               rmspace(buf);
+               rmspace(p);
+
+               for (i = 0; i < ARRAY_SIZE(colour_pairs); i++) {
+                       int found = 0;
+                       if (strcmp(buf, colour_pairs[i].name) == 0) {
                                if (strncmp(p, "0x", 2) == 0) {
-                                       warn("[%s=%s] RGB values in color map 
are not "
-                                                       "supported on line %d 
of %s",
-                                                       buf, p, lineno, 
COLOR_MAP);
+                                       size_t n;
+                                       for (n = 0; n < ARRAY_SIZE(rgb_map); 
n++) {
+                                               if (strcasecmp(rgb_map[n].name, 
p) == 0) {
+                                                       found = 1;
+                                                       *(colour_pairs[i].var) 
= rgb_map[n].value;
+                                                       break;
+                                               }
+                                       }
+                                       if (found == 0)
+                                               warn("[%s=%s] arbitrary RGB 
values in color map "
+                                                        "are not supported on 
line %d of %s",
+                                                        buf, p, lineno, 
COLOR_MAP);
                                } else {
                                        /* color=color format support */
                                        size_t n;
-                                       int found = 0;
-                                       for (n = 0; n < 
ARRAY_SIZE(color_pairs); n++) {
-                                               if (strcmp(color_pairs[n].name, 
p) == 0) {
-                                                       
snprintf(color_pairs[i].value,
-                                                                       
sizeof(color_pairs[i].value),
-                                                                       "%s", 
color_pairs[n].origval);
+                                       for (n = 0; n < ARRAY_SIZE(colour_map); 
n++) {
+                                               if 
(strcasecmp(colour_map[n].name, p) == 0) {
                                                        found = 1;
+                                                       *(colour_pairs[i].var) 
= colour_map[n].value;
                                                        break;
                                                }
                                        }
 
-                                       if (!found)
-                                               snprintf(color_pairs[i].value,
-                                                               
sizeof(color_pairs[i].value), "\e[%s", p);
+                                       if (found == 0) {
+                                               snprintf(colour_pairs[i].tmpbuf,
+                                                                
sizeof(colour_pairs[i].tmpbuf),
+                                                                "\e[%s", p);
+                                               *(colour_pairs[i].var) = 
colour_pairs[i].tmpbuf;
+                                       }
                                }
+
+                               break;
                        }
                }
        }
 
        free(buf);
        fclose(fp);
-
-       for (i = 0; i < ARRAY_SIZE(color_pairs); ++i) {
-               /* unmapped: MAGENTA YELLOW */
-               if (strcmp(color_pairs[i].name, "white") == 0)
-                       WHITE = color_pairs[i].value;
-               else if (strcmp(color_pairs[i].name, "green") == 0)
-                       GREEN = color_pairs[i].value;
-               else if (strcmp(color_pairs[i].name, "darkgreen") == 0)
-                       DKGREEN = color_pairs[i].value;
-               else if (strcmp(color_pairs[i].name, "red") == 0)
-                       RED = color_pairs[i].value;
-               else if (strcmp(color_pairs[i].name, "blue") == 0)
-                       DKBLUE = color_pairs[i].value;
-               else if (strcmp(color_pairs[i].name, "turquoise") == 0)
-                       BLUE = color_pairs[i].value;
-               else if (strcmp(color_pairs[i].name, "yellow") == 0)
-                       BRYELLOW = color_pairs[i].value;
-               else if (strcmp(color_pairs[i].name, "teal") == 0)
-                       CYAN = color_pairs[i].value;
-       }
 }
 
 void
 color_clear(void)
 {
-       NORM     = "";
-       BLUE     = "";
-       BOLD     = "";
-       BRYELLOW = "";
-       CYAN     = "";
-       DKBLUE   = "";
-       DKGREEN  = "";
-       GREEN    = "";
-       MAGENTA  = "";
-       RED      = "";
-       WHITE    = "";
-       YELLOW   = "";
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(colour_pairs); i++)
+               *(colour_pairs[i].var) = "";
 }

Reply via email to