+ hash_table[code] = new_index;
+
+ return -1;
+}
+
+//////////////////////////////////////////////////////////////////////
+// A matcher matches either with a collection of substrings, or with a
+// regexp
+
+struct matcher_t {
+ regex_t preg;
+ int regexp_error;
+ int nb_patterns;
+ char *splitted_patterns, **patterns;
+};
+
+int match(char *string, matcher_t *matcher) {
+ if(matcher->nb_patterns >= 0) {
+ for(int n = 0; n < matcher->nb_patterns; n++) {
+ if(strstr(string, matcher->patterns[n]) == 0) return 0;
+ }
+ return 1;
+ } else {
+ return regexec(&matcher->preg, string, 0, 0, 0) == 0;
+ }
+}
+
+void free_matcher(matcher_t *matcher) {
+ if(matcher->nb_patterns >= 0) {
+ delete[] matcher->splitted_patterns;
+ delete[] matcher->patterns;
+ } else {
+ if(!matcher->regexp_error) regfree(&matcher->preg);
+ }
+}
+
+void initialize_matcher(int use_regexp, matcher_t *matcher, const char *pattern) {
+ if(use_regexp) {
+ matcher->nb_patterns = -1;
+ matcher->regexp_error = regcomp(&matcher->preg, pattern, REG_ICASE);
+ } else {
+ matcher->regexp_error = 0;
+ matcher->nb_patterns = 1;
+
+ for(const char *s = pattern; *s; s++) {
+ if(*s == pattern_separator) {
+ matcher->nb_patterns++;
+ }
+ }
+
+ matcher->splitted_patterns = new char[strlen(pattern) + 1];
+ matcher->patterns = new char*[matcher->nb_patterns];
+
+ strcpy(matcher->splitted_patterns, pattern);
+
+ int n = 0;
+ char *last_pattern_start = matcher->splitted_patterns;
+ for(char *s = matcher->splitted_patterns; n < matcher->nb_patterns; s++) {
+ if(*s == pattern_separator || *s == '\0') {
+ *s = '\0';
+ matcher->patterns[n++] = last_pattern_start;
+ last_pattern_start = s + 1;
+ }
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+
+int previous_visible(int current_line, int nb_lines, char **lines, matcher_t *matcher) {