+static int countColorControlChars(const char* prompt, int plen)
+{
+ /* ANSI color control sequences have the form:
+ * "\x1b" "[" [0-9;]+ "m"
+ * We parse them with a simple state machine.
+ */
+
+ enum {
+ search_esc,
+ expect_bracket,
+ expect_inner,
+ expect_trail
+ } state = search_esc;
+ int len, found = 0;
+ char ch;
+
+ /* XXX: Strictly we should be checking utf8 chars rather than
+ * bytes in case of the extremely unlikely scenario where
+ * an ANSI sequence is part of a utf8 sequence.
+ */
+ for (; plen ; plen--, prompt++) {
+ ch = *prompt;
+
+ switch (state) {
+ case search_esc:
+ len = 0;
+ if (ch == '\x1b') {
+ state = expect_bracket;
+ len++;
+ }
+ break;
+ case expect_bracket:
+ if (ch == '[') {
+ state = expect_inner;
+ len++;
+ } else {
+ state = search_esc;
+ }
+ break;
+ case expect_inner:
+ if (ch >= '0' && ch <= '9') {
+ len++;
+ state = expect_trail;
+ } else {
+ state = search_esc;
+ }
+ break;
+ case expect_trail:
+ if (ch == 'm') {
+ len++;
+ found += len;
+ state = search_esc;
+ } else if ((ch != ';') && ((ch < '0') || (ch > '9'))) {
+ state = search_esc;
+ }
+ /* 0-9, or semicolon */
+ len++;
+ break;
+ }
+ }
+
+ return found;
+}
+