>From 1140372cf26385fdbf589941d8c3e6dd3da4c581 Mon Sep 17 00:00:00 2001
From: Colomban Wendling <ban@herbesfolles.org>
Date: Mon, 2 Dec 2013 20:06:11 +0100
Subject: [PATCH] Rename utils_strtod to utils_parse_color and make it more
 robust

Also accept 3-digits input, like allowed in color schemes, as well as
9 and 12 digits input and X11 named colors (using pango_color_parse()).
---
 src/highlighting.c | 32 ++++--------------------------
 src/sciwrappers.c  |  2 +-
 src/utils.c        | 57 ++++++++++++++++++------------------------------------
 src/utils.h        |  2 +-
 src/win32.c        |  2 +-
 5 files changed, 26 insertions(+), 69 deletions(-)

diff --git a/src/highlighting.c b/src/highlighting.c
index de7cd43..ae72cde 100644
--- a/src/highlighting.c
+++ b/src/highlighting.c
@@ -219,9 +219,7 @@ static gboolean read_named_style(const gchar *named_style, GeanyLexerStyle *styl
 static void parse_color(GKeyFile *kf, const gchar *str, gint *clr)
 {
 	gint c;
-	gchar hex_clr[9] = { 0 };
 	gchar *named_color = NULL;
-	const gchar *start;
 
 	g_return_if_fail(clr != NULL);
 
@@ -229,38 +227,16 @@ static void parse_color(GKeyFile *kf, const gchar *str, gint *clr)
 		return;
 
 	named_color = g_key_file_get_string(kf, "named_colors", str, NULL);
-	if  (named_color)
+	if (named_color)
 		str = named_color;
 
-	if (str[0] == '#')
-		start = str + 1;
-	else if (strlen(str) > 1 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
-		start = str + 2;
-	else
-	{
+	c = utils_parse_color(str);
+	if (c == -1)
 		geany_debug("Bad color '%s'", str);
-		g_free(named_color);
-		return;
-	}
-
-	if (strlen(start) == 3)
-	{
-		g_snprintf(hex_clr, 9, "0x%c%c%c%c%c%c", start[0], start[0],
-			start[1], start[1], start[2], start[2]);
-	}
 	else
-		g_snprintf(hex_clr, 9, "0x%s", start);
+		*clr = c;
 
 	g_free(named_color);
-
-	c = utils_strtod(hex_clr, NULL, FALSE);
-
-	if (c > -1)
-	{
-		*clr = c;
-		return;
-	}
-	geany_debug("Bad color '%s'", str);
 }
 
 
diff --git a/src/sciwrappers.c b/src/sciwrappers.c
index 5baa8ed..80a6366 100644
--- a/src/sciwrappers.c
+++ b/src/sciwrappers.c
@@ -69,7 +69,7 @@ void sci_set_line_numbers(ScintillaObject *sci, gboolean set, gint extra_width)
 
 void sci_set_mark_long_lines(ScintillaObject *sci, gint type, gint column, const gchar *colour)
 {
-	glong colour_val = utils_strtod(colour, NULL, TRUE); /* Scintilla uses a "long" value */
+	glong colour_val = utils_parse_color(colour); /* Scintilla uses a "long" value */
 
 	if (column == 0)
 		type = 2;
diff --git a/src/utils.c b/src/utils.c
index 9cb7c7e..0a46761 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -964,50 +964,31 @@ gchar *utils_make_human_readable_str(guint64 size, gulong block_size,
 }
 
 
- static guint utils_get_value_of_hex(const gchar ch)
-{
-	if (ch >= '0' && ch <= '9')
-		return ch - '0';
-	else if (ch >= 'A' && ch <= 'F')
-		return ch - 'A' + 10;
-	else if (ch >= 'a' && ch <= 'f')
-		return ch - 'a' + 10;
-	else
-		return 0;
-}
-
-
-/* utils_strtod() converts a string containing a hex colour ("0x00ff00") into an integer.
- * Basically, it is the same as strtod() would do, but it does not understand hex colour values,
- * before ANSI-C99. With with_route set, it takes strings of the format "#00ff00".
- * Returns -1 on failure. */
-gint utils_strtod(const gchar *source, gchar **end, gboolean with_route)
+/* reads an RGB hex color with from 1 to 4 bytes per channel and a "0x" or "#"
+ * prefix, or an X11 color (see pango_parse_color())
+ * 
+ * @returns the color as an integer in Scintilla's BBGGRR format, or -1 */
+gint utils_parse_color(const gchar *spec)
 {
-	guint red, green, blue, offset = 0;
+	/* max is '#' (2) plus 4 digit on 3 channel (12), so 13;  add 1 for \0
+	 * and 1 to include possible invalid data and fail, plus 1 for good measure. */
+	gchar buf[16] = {0};
+	PangoColor c;
 
-	g_return_val_if_fail(source != NULL, -1);
+	g_return_val_if_fail(spec != NULL, -1);
 
-	if (with_route && (strlen(source) != 7 || source[0] != '#'))
-		return -1;
-	else if (! with_route && (strlen(source) != 8 || source[0] != '0' ||
-		(source[1] != 'x' && source[1] != 'X')))
+	if (spec[0] == '0' && (spec[1] == 'x' || spec[1] == 'X'))
 	{
-		return -1;
+		/* convert to # format for Pango to understand it */
+		buf[0] = '#';
+		strncpy(buf + 1, spec + 2, sizeof(buf) - 2);
+		spec = buf;
 	}
 
-	/* offset is set to 1 when the string starts with 0x, otherwise it starts with #
-	 * and we don't need to increase the index */
-	if (! with_route)
-		offset = 1;
-
-	red = utils_get_value_of_hex(
-					source[1 + offset]) * 16 + utils_get_value_of_hex(source[2 + offset]);
-	green = utils_get_value_of_hex(
-					source[3 + offset]) * 16 + utils_get_value_of_hex(source[4 + offset]);
-	blue = utils_get_value_of_hex(
-					source[5 + offset]) * 16 + utils_get_value_of_hex(source[6 + offset]);
-
-	return (red | (green << 8) | (blue << 16));
+	if (pango_color_parse(&c, spec))
+		return (c.red / 256) | ((c.green / 256) << 8) | ((c.blue / 256) << 16);
+	else
+		return -1;
 }
 
 
diff --git a/src/utils.h b/src/utils.h
index 4219e65..7448884 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -220,7 +220,7 @@ void utils_beep(void);
 gchar *utils_make_human_readable_str(guint64 size, gulong block_size,
 									 gulong display_unit);
 
-gint utils_strtod(const gchar *source, gchar **end, gboolean with_route);
+gint utils_parse_color(const gchar *spec);
 
 gchar *utils_get_current_time_string(void);
 
diff --git a/src/win32.c b/src/win32.c
index b6aa9c4..b5a5142 100644
--- a/src/win32.c
+++ b/src/win32.c
@@ -565,7 +565,7 @@ void win32_show_color_dialog(const gchar *colour)
 	cc.lStructSize = sizeof(cc);
 	cc.hwndOwner = GDK_WINDOW_HWND(gtk_widget_get_window(main_widgets.window));
 	cc.lpCustColors = (LPDWORD) acr_cust_clr;
-	cc.rgbResult = (colour != NULL) ? utils_strtod(colour, NULL, colour[0] == '#') : 0;
+	cc.rgbResult = (colour != NULL) ? utils_parse_color(colour) : 0;
 	cc.Flags = CC_FULLOPEN | CC_RGBINIT;
 
 	if (ChooseColor(&cc))
-- 
1.8.5

