Index: src/table.c
===================================================================
--- src/table.c	(revision 1524)
+++ src/table.c	(working copy)
@@ -30,16 +30,13 @@
 #include "table.h"
 
 /* Table info. */
-#ifdef TABLE_MAIN
-#define VTE_TABLE_MAX_NUMERIC_DEPTH 5
-#else
-#define VTE_TABLE_MAX_NUMERIC_DEPTH 16
-#endif
 #define VTE_TABLE_MAX_LITERAL (128 + 32)
 #define _vte_table_map_literal(__c) \
 	(((__c) < (VTE_TABLE_MAX_LITERAL)) ? (__c) : 0)
 #define _vte_table_is_numeric(__c) \
 	(((__c) >= '0') && ((__c) <= '9'))
+#define _vte_table_is_numeric_list(__c) \
+	((((__c) >= '0') && ((__c) <= '9')) || (__c) == ';')
 
 struct _vte_table {
 	struct _vte_matcher_impl impl;
@@ -50,6 +47,7 @@
 	int increment;
 	struct _vte_table *table_string;
 	struct _vte_table *table_number;
+	struct _vte_table *table_number_list;
 	struct _vte_table **table;
 };
 
@@ -182,16 +180,17 @@
 		/* Handle variable-length parameters. */
 		if ((pattern[1] == 'm') ||
 		    (pattern[1] == 'M')) {
-			int i, j, initial;
-			GByteArray *b;
 			/* Build the "new" original using the initial portion
 			 * of the original string and what's left after this
 			 * specifier. */
-			initial = original_length - length;
-			b = g_byte_array_new();
 			if (pattern[1] == 'm') {
+				int initial;
+				GByteArray *b;
+
+				initial = original_length - length;
 				/* 0 args; we use 'M' to signal that zero is
 				 * not allowed.  */
+				b = g_byte_array_new();
 				g_byte_array_set_size(b, 0);
 				g_byte_array_append(b, original, initial);
 				g_byte_array_append(b, pattern + 2, length - 2);
@@ -199,25 +198,19 @@
 						b->data + initial,
 						b->len - initial,
 						result, quark, inc);
+				g_byte_array_free(b, TRUE);
 			}
-			for (i = 1;
-			     i <= VTE_TABLE_MAX_NUMERIC_DEPTH;
-			     i++) {
-				g_byte_array_set_size(b, 0);
-				g_byte_array_append(b, original, initial);
-				for (j = 1; j <= i; j++) {
-					if (j > 1) {
-						g_byte_array_append(b, ";", 1);
-					}
-					g_byte_array_append(b, "%d", 2);
-				}
-				g_byte_array_append(b, pattern + 2, length - 2);
-				_vte_table_addi(table,
-						b->data, b->len,
-						b->data + initial, b->len - initial,
-						result, quark, inc);
+			/* Create a new subtable. */
+			if (table->table_number_list == NULL) {
+				subtable = _vte_table_new();
+				table->table_number_list = subtable;
+			} else {
+				subtable = table->table_number_list;
 			}
-			g_byte_array_free(b, TRUE);
+			/* Add the rest of the string to the subtable. */
+			_vte_table_addi(subtable, original, original_length,
+					pattern + 2, length - 2,
+					result, quark, inc);
 			return;
 		}
 
@@ -343,7 +336,7 @@
 		  const gunichar *candidate, gssize length,
 		  const char **res, const gunichar **consumed, GQuark *quark,
 		  unsigned char **original, gssize *original_length,
-		  GList **params)
+		  GSList **params)
 {
 	int i = 0;
 	struct _vte_table *subtable = NULL;
@@ -361,7 +354,7 @@
 
 	/* If we're out of data, but we still have children, return the empty
 	 * string. */
-	if ((length == 0) && (table != NULL)) {
+	if (length == 0) {
 		*consumed = candidate;
 		return "";
 	}
@@ -381,13 +374,51 @@
 		arginfo->type = _vte_table_arg_string;
 		arginfo->start = candidate;
 		arginfo->length = i;
-		*params = g_list_append(*params, arginfo);
+		*params = g_slist_prepend(*params, arginfo);
 		/* Continue. */
 		return _vte_table_matchi(subtable, candidate + i, length - i,
 					 res, consumed, quark,
 					 original, original_length, params);
 	}
 
+	/* Check if this could be a list. */
+	if ((_vte_table_is_numeric_list(candidate[0])) &&
+	    (table->table_number_list != NULL)) {
+		GSList *l, *local_params;
+		const char *res;
+
+		subtable = table->table_number_list;
+		/* Iterate over all numeric characters and ';'. */
+		for (i = 0; i < length; i++) {
+			if (!_vte_table_is_numeric_list(candidate[i])) {
+				break;
+			}
+		}
+		/* Save the parameter info. */
+		arginfo = g_slice_new(struct _vte_table_arginfo);
+		arginfo->type = _vte_table_arg_number;
+		arginfo->start = candidate;
+		arginfo->length = i;
+		l = local_params = g_slist_prepend(NULL, arginfo);
+
+		/* Try and continue. */
+		res = _vte_table_matchi(subtable, candidate + i, length - i,
+					 res, consumed, quark,
+					 original, original_length,
+					 &local_params);
+		if (res != NULL) {
+			l->next = *params;
+			*params = l;
+			return res;
+		}
+		for (l = local_params; l != NULL; l = g_slist_next (l)) {
+			g_slice_free(struct _vte_table_arginfo, l->data);
+		}
+		g_slist_free(local_params);
+
+		/* try again */
+	}
+
 	/* Check if this could be a number. */
 	if ((_vte_table_is_numeric(candidate[0])) &&
 	    (table->table_number != NULL)) {
@@ -403,7 +434,7 @@
 		arginfo->type = _vte_table_arg_number;
 		arginfo->start = candidate;
 		arginfo->length = i;
-		*params = g_list_append(*params, arginfo);
+		*params = g_slist_prepend(*params, arginfo);
 		/* Continue. */
 		return _vte_table_matchi(subtable, candidate + i, length - i,
 					 res, consumed, quark,
@@ -419,7 +450,7 @@
 		arginfo->type = _vte_table_arg_char;
 		arginfo->start = candidate;
 		arginfo->length = 1;
-		*params = g_list_append(*params, arginfo);
+		*params = g_slist_prepend(*params, arginfo);
 		/* Continue. */
 		return _vte_table_matchi(subtable, candidate + 1, length - 1,
 					 res, consumed, quark,
@@ -438,39 +469,32 @@
 {
 	GValue value = {0,};
 	GString *tmp;
-	char **vals;
-	int i, j;
+	char *str;
+	int i;
 	long total;
 
 	tmp = g_string_new(NULL);
 	for (i = 0; i < arginfo->length; i++) {
 		tmp = g_string_append_unichar(tmp, arginfo->start[i]);
 	}
+	str = g_string_free(tmp, FALSE);
 
-	vals = g_strsplit(tmp->str, ";", -1);
-
-	if (vals != NULL) {
-		g_value_init(&value, G_TYPE_LONG);
-
-		for (i = 0; vals[i] != NULL; i++) {
-			if (*array == NULL) {
-				*array = g_value_array_new(1);
-			}
-			for (total = 0, j = 0; vals[i][j] != '\0'; j++) {
-				total *= 10;
-				total += g_unichar_digit_value(vals[i][j]) == -1 ?
-					 0 : g_unichar_digit_value(vals[i][j]);
-			}
-			g_value_set_long(&value, total);
-			g_value_array_append(*array, &value);
+	g_value_init(&value, G_TYPE_LONG);
+	i = 0;
+	do {
+		for (total = 0; !(str[i] == '\0' || str[i] == ';'); i++) {
+			total *= 10;
+			total += g_unichar_digit_value(str[i]) == -1 ?
+				0 : g_unichar_digit_value(str[i]);
 		}
-
-		g_strfreev(vals);
-
-		g_value_unset(&value);
-	}
-
-	g_string_free(tmp, TRUE);
+		if (*array == NULL) {
+			*array = g_value_array_new(1);
+		}
+		g_value_set_long(&value, total);
+		g_value_array_append(*array, &value);
+	} while (str[i++] != '\0');
+	g_value_unset(&value);
+	g_free (str);
 }
 
 static void
@@ -528,7 +552,7 @@
 	const char *ret = NULL;
 	unsigned char *original = NULL, *p = NULL;
 	gssize original_length;
-	GList *params = NULL, *tmp;
+	GSList *params = NULL, *tmp;
 	long increment = 0;
 	int i;
 	struct _vte_table_arginfo *arginfo;
@@ -552,12 +576,9 @@
 	*array = NULL;
 
 	/* Provide a fast path for the usual "not a sequence" cases. */
-	if (length == 0) {
+	if (G_LIKELY (length == 0 || candidate == NULL)) {
 		return NULL;
 	}
-	if (candidate == NULL) {
-		return NULL;
-	}
 
 	/* If there's no literal path, and no generic path, and the numeric
 	 * path isn't available, then it's not a sequence, either. */
@@ -597,7 +618,7 @@
 
 	/* If we got a match, extract the parameters. */
 	if ((ret != NULL) && (strlen(ret) > 0) && (array != &dummy_array)) {
-		tmp = params;
+		tmp = params = g_slist_reverse (params);
 		g_assert(original != NULL);
 		p = original;
 		while (p < original + original_length) {
@@ -611,7 +632,7 @@
 				}
 				/* Handle an escaped '%'. */
 				if (p[1] == '%') {
-					tmp = g_list_next(tmp);
+					tmp = g_slist_next(tmp);
 					p += 2;
 					continue;
 				}
@@ -625,7 +646,7 @@
 					_vte_table_extract_numbers(array,
 								   arginfo,
 								   increment);
-					tmp = g_list_next(tmp);
+					tmp = g_slist_next(tmp);
 					p += 2;
 					continue;
 				}
@@ -634,7 +655,7 @@
 					arginfo = tmp->data;
 					_vte_table_extract_string(array,
 								  arginfo);
-					tmp = g_list_next(tmp);
+					tmp = g_slist_next(tmp);
 					p += 2;
 					continue;
 				}
@@ -644,14 +665,14 @@
 					_vte_table_extract_char(array,
 								arginfo,
 								p[2]);
-					tmp = g_list_next(tmp);
+					tmp = g_slist_next(tmp);
 					p += 3;
 					continue;
 				}
 				g_assert_not_reached();
 			} else {
 				/* Literal. */
-				tmp = g_list_next(tmp);
+				tmp = g_slist_next(tmp);
 				p++;
 				continue;
 			}
@@ -660,10 +681,10 @@
 
 	/* Clean up extracted parameters. */
 	if (params != NULL) {
-		for (tmp = params; tmp != NULL; tmp = g_list_next(tmp)) {
+		for (tmp = params; tmp != NULL; tmp = g_slist_next(tmp)) {
 			g_slice_free(struct _vte_table_arginfo, tmp->data);
 		}
-		g_list_free(params);
+		g_slist_free(params);
 	}
 
 	return ret;
