git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 4/7] color: refactor parse_attr

From
Jeff King <peff@peff.net>
Date
Jun 23, 2016, 17:38 UTC
Message-ID
<20160623173812.GD15774@sigill.intra.peff.net>
In-Reply-To
<20160623173048.GA19923@sigill.intra.peff.net>

The list of attributes we recognize is a bit unwieldy, as we actually have two arrays that must be kept in sync. Instead, let's have a single array-of-struct to represent our mapping. That means we can never have an accident that causes us to read off the end of an array, and it makes diffs for adding new attributes much easier to read.

This also makes it easy to handle the "no" cases without having to repeat each attribute (this shortens the list, making it easier to read, but also also cuts the size of our linear search in half). Technically this makes it impossible for us to add an attribute that starts with "no" (we could confuse "nobody" for the negation of "body"), but since this is a constrained set of attributes, that's OK.

Since we can also store the length of each name in the struct, that makes it easy for us to avoid reading past the "len" parameter given to us (though in practice it was not a bug, since all of our current callers are interested in a subset of a NUL-terminated buffer, not a true undelimited range of memory).

Signed-off-by: Jeff King <peff@peff.net>
---
 color.c | 31 +++++++++++++++++++++----------
 1 file changed, 21 insertions(+), 10 deletions(-)
diff --git a/color.c b/color.c
index 8f85153..d787dec 100644
--- a/color.c
+++ b/color.c
@@ -123,19 +123,30 @@ static int parse_color(struct color *out, const char *name, int len)
 	return -1;
 }
 
-static int parse_attr(const char *name, int len)
+static int parse_attr(const char *name, size_t len)
 {
-	static const int attr_values[] = { 1, 2, 4, 5, 7,
-					   22, 22, 24, 25, 27 };
-	static const char * const attr_names[] = {
-		"bold", "dim", "ul", "blink", "reverse",
-		"nobold", "nodim", "noul", "noblink", "noreverse"
+	static const struct {
+		const char *name;
+		size_t len;
+		int val, neg;
+	} attrs[] = {
+#define ATTR(x, val, neg) { (x), sizeof(x)-1, (val), (neg) }
+		ATTR("bold",      1, 22),
+		ATTR("dim",       2, 22),
+		ATTR("ul",        4, 24),
+		ATTR("blink",     5, 25),
+		ATTR("reverse",   7, 27)
+#undef ATTR
 	};
+	int negate = 0;
 	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];
+
+	if (skip_prefix_mem(name, len, "no", &name, &len))
+		negate = 1;
+
+	for (i = 0; i < ARRAY_SIZE(attrs); i++) {
+		if (attrs[i].len == len && !memcmp(attrs[i].name, name, len))
+			return negate ? attrs[i].neg : attrs[i].val;
 	}
 	return -1;
 }
-- 
2.9.0.209.g845fbc1
Previous: Jeff KingNext: Jeff King
Message 12 of 24 in “Italics formatting”
  1. Simon CourtoisJun 23, 2016
  2. 0/2 more ANSI attributesJeff King, Jun 23, 2016
  3. 1/2 color: fix max-size commentJeff King, Jun 23, 2016
  4. 2/2 color: support "italic" attributeJeff King, Jun 23, 2016
  5. Simon CourtoisJun 23, 2016
  6. Junio C HamanoJun 23, 2016
  7. Jeff KingJun 23, 2016
  8. 0/7 more ANSI attributesJeff King, Jun 23, 2016
  9. 1/7 color: fix max-size commentJeff King, Jun 23, 2016
  10. 2/7 doc: refactor description of color formatJeff King, Jun 23, 2016
  11. 3/7 add skip_prefix_mem helperJeff King, Jun 23, 2016
  12. 4/7 color: refactor parse_attrJeff King, Jun 23, 2016
  13. 5/7 color: allow "no-" for negating attributesJeff King, Jun 23, 2016
  14. 6/7 color: support "italic" attributeJeff King, Jun 23, 2016
  15. Junio C HamanoJun 23, 2016
  16. Jeff KingJun 23, 2016
  17. 7/7 color: support strike-through attributeJeff King, Jun 23, 2016
  18. Junio C HamanoJun 23, 2016
  19. Jeff KingJun 23, 2016
  20. Junio C HamanoJun 23, 2016
  21. Junio C HamanoJun 23, 2016
  22. Jeff KingJun 23, 2016
  23. Junio C HamanoJun 23, 2016
  24. Junio C HamanoJun 23, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.