Browse Source

Lazy regexp compilation

Serj Kalichev 5 years ago
parent
commit
01eaff6403
3 changed files with 32 additions and 27 deletions
  1. 2 2
      clish/ptype.h
  2. 7 1
      clish/ptype/private.h
  3. 23 24
      clish/ptype/ptype.c

+ 2 - 2
clish/ptype.h

@@ -99,7 +99,7 @@ void clish_ptype_delete(clish_ptype_t * instance);
  *   may not be identical to that passed in. e.g. it may have been
  *   a case-modified "select" or a preprocessed value.
  */
-char *clish_ptype_validate(const clish_ptype_t * instance, const char *text);
+char *clish_ptype_validate(clish_ptype_t * instance, const char *text);
 /**
  * This is the translation method for the specified type. The text is
  * first validated then translated into the form which should be used
@@ -110,7 +110,7 @@ char *clish_ptype_validate(const clish_ptype_t * instance, const char *text);
  *   may not be identical to that passed in. e.g. it may have been
  *   a translated "select" value.
  */
-char *clish_ptype_translate(const clish_ptype_t * instance, const char *text);
+char *clish_ptype_translate(clish_ptype_t * instance, const char *text);
 /**
  * This is used to perform parameter auto-completion
  */

+ 7 - 1
clish/ptype/private.h

@@ -19,6 +19,12 @@ struct clish_ptype_select_s {
 	lub_argv_t *items;
 };
 
+typedef struct clish_ptype_regex_s clish_ptype_regex_t;
+struct clish_ptype_regex_s {
+	bool_t is_compiled;
+	regex_t re;
+};
+
 struct clish_ptype_s {
 	lub_bintree_node_t bt_node;
 	char *name;
@@ -29,7 +35,7 @@ struct clish_ptype_s {
 	clish_ptype_preprocess_e preprocess;
 	unsigned last_name;	/* index used for auto-completion */
 	union {
-		regex_t regexp;
+		clish_ptype_regex_t regex;
 		clish_ptype_integer_t integer;
 		clish_ptype_select_t select;
 	} u;

+ 23 - 24
clish/ptype/ptype.c

@@ -151,7 +151,7 @@ clish_ptype_method_e clish_ptype_method_resolve(const char *name)
 {
 	clish_ptype_method_e result = CLISH_PTYPE_REGEXP;
 	if (NULL != name) {
-		unsigned i;
+		unsigned int i;
 		for (i = 0; i < CLISH_PTYPE_SELECT + 1; i++) {
 			if (0 == strcmp(name, method_names[i])) {
 				result = (clish_ptype_method_e) i;
@@ -205,7 +205,7 @@ void clish_ptype_word_generator(clish_ptype_t * this,
 	lub_argv_t *matches, const char *text)
 {
 	char *result = NULL;
-	unsigned i = 0;
+	unsigned int i = 0;
 
 	/* Another ptypes has no completions */
 	if (this->method != CLISH_PTYPE_SELECT)
@@ -229,7 +229,7 @@ void clish_ptype_word_generator(clish_ptype_t * this,
 }
 
 /*--------------------------------------------------------- */
-static char *clish_ptype_validate_or_translate(const clish_ptype_t * this,
+static char *clish_ptype_validate_or_translate(clish_ptype_t *this,
 	const char *text, bool_t translate)
 {
 	char *result = lub_string_dup(text);
@@ -265,22 +265,26 @@ static char *clish_ptype_validate_or_translate(const clish_ptype_t * this,
 	}
 	/*----------------------------------------- */
 	}
-	/*
-	 * now validate according the specified method 
-	 */
+
+	/* Now validate according the specified method */
 	switch (this->method) {
 	/*------------------------------------------------- */
 	case CLISH_PTYPE_REGEXP:
-		/* test the regular expression against the string */
-		/*lint -e64 Type mismatch (arg. no. 4) */
-		/*
-		 * lint seems to equate regmatch_t[] as being of type regmatch_t !
-		 */
-		if (0 != regexec(&this->u.regexp, result, 0, NULL, 0)) {
+		/* Lazy compilation of the regular expression */
+		if (!this->u.regex.is_compiled) {
+			if (regcomp(&this->u.regex.re, this->pattern,
+				REG_NOSUB | REG_EXTENDED)) {
+				lub_string_free(result);
+				result = NULL;
+				break;
+			}
+			this->u.regex.is_compiled = BOOL_TRUE;
+		}
+
+		if (regexec(&this->u.regex.re, result, 0, NULL, 0)) {
 			lub_string_free(result);
 			result = NULL;
 		}
-		/*lint +e64 */
 		break;
 	/*------------------------------------------------- */
 	case CLISH_PTYPE_INTEGER:
@@ -401,13 +405,13 @@ static void clish_ptype_init(clish_ptype_t * this,
 }
 
 /*--------------------------------------------------------- */
-char *clish_ptype_validate(const clish_ptype_t * this, const char *text)
+char *clish_ptype_validate(clish_ptype_t * this, const char *text)
 {
 	return clish_ptype_validate_or_translate(this, text, BOOL_FALSE);
 }
 
 /*--------------------------------------------------------- */
-char *clish_ptype_translate(const clish_ptype_t * this, const char *text)
+char *clish_ptype_translate(clish_ptype_t * this, const char *text)
 {
 	return clish_ptype_validate_or_translate(this, text, BOOL_TRUE);
 }
@@ -430,7 +434,8 @@ static void clish_ptype_fini(clish_ptype_t * this)
 	if (this->pattern) {
 		switch (this->method) {
 		case CLISH_PTYPE_REGEXP:
-			regfree(&this->u.regexp);
+			if (this->u.regex.is_compiled)
+				regfree(&this->u.regex.re);
 			break;
 		case CLISH_PTYPE_INTEGER:
 		case CLISH_PTYPE_UNSIGNEDINTEGER:
@@ -482,17 +487,11 @@ clish_ptype__set_pattern(clish_ptype_t * this,
 	/*------------------------------------------------- */
 	case CLISH_PTYPE_REGEXP:
 	{
-		int result;
-
-		/* only the expression is allowed */
 		lub_string_cat(&this->pattern, "^");
 		lub_string_cat(&this->pattern, pattern);
 		lub_string_cat(&this->pattern, "$");
-
-		/* compile the regular expression for later use */
-		result = regcomp(&this->u.regexp, this->pattern,
-			REG_NOSUB | REG_EXTENDED);
-		assert(0 == result);
+		/* Use lazy mechanism to compile regular expressions */
+		this->u.regex.is_compiled = BOOL_FALSE;
 		break;
 	}
 	/*------------------------------------------------- */