From bacedeb21cd30101b787838d003d686ae3036838 Mon Sep 17 00:00:00 2001
From: Ray Donnelly <mingw.android@gmail.com>
Date: Mon, 23 Feb 2015 21:46:45 +0000
Subject: [PATCH 1/9] lang: Allow both extensions and full filenames

Because many filetypes (e.g. make) are not indicated by the
file extension but instead by the full filename (Makefile).

Renames extension to pattern, but retains the existing format
where each pattern is treated as an extension. Full filenames
are indicated by prefixing the pattern with a '^'.
---
 src/lang.c    | 57 ++++++++++++++++++++++++++++++++++-----------------------
 src/lang.h    | 24 +++++++++++++-----------
 src/options.c | 26 +++++++++++++-------------
 3 files changed, 60 insertions(+), 47 deletions(-)

diff --git a/src/lang.c b/src/lang.c
index 5ccd860..17783ae 100644
--- a/src/lang.c
+++ b/src/lang.c
@@ -115,20 +115,27 @@ size_t get_lang_count() {
     return sizeof(langs) / sizeof(lang_spec_t);
 }
 
-char *make_lang_regex(char *ext_array, size_t num_exts) {
+char *make_lang_regex(char *pat_array, size_t num_pats) {
     int regex_capacity = 100;
     char *regex = ag_malloc(regex_capacity);
-    int regex_length = 3;
+    int regex_length = 1;
     int subsequent = 0;
-    char *extension;
+    char *pattern;
+    const char *dot = "\\.";
+    size_t strlen_dot = strlen(dot);
     size_t i;
 
-    strcpy(regex, "\\.(");
+    strcpy(regex, "(");
 
-    for (i = 0; i < num_exts; ++i) {
-        extension = ext_array + i * SINGLE_EXT_LEN;
-        int extension_length = strlen(extension);
-        while (regex_length + extension_length + 3 + subsequent > regex_capacity) {
+    for (i = 0; i < num_pats; ++i) {
+        pattern = pat_array + i * SINGLE_PAT_LEN;
+        int is_extension = (*pattern == '^') ? 0 : 1;
+        int length = strlen(pattern);
+        if (is_extension == 0) {
+            pattern += 1;
+            length -= 1;
+        }
+        while (regex_length + length + 3 + subsequent > regex_capacity) {
             regex_capacity *= 2;
             regex = ag_realloc(regex, regex_capacity);
         }
@@ -137,8 +144,12 @@ char *make_lang_regex(char *ext_array, size_t num_exts) {
         } else {
             subsequent = 1;
         }
-        strcpy(regex + regex_length, extension);
-        regex_length += extension_length;
+        if (is_extension == 1) {
+            strcpy(regex + regex_length, dot);
+            regex_length += strlen_dot;
+        }
+        strcpy(regex + regex_length, pattern);
+        regex_length += length;
     }
 
     regex[regex_length++] = ')';
@@ -147,29 +158,29 @@ char *make_lang_regex(char *ext_array, size_t num_exts) {
     return regex;
 }
 
-size_t combine_file_extensions(size_t *extension_index, size_t len, char **exts) {
+size_t combine_file_patterns(size_t *pattern_index, size_t len, char **pats) {
     /* Keep it fixed as 100 for the reason that if you have more than 100
      * file types to search, you'd better search all the files.
      * */
-    size_t ext_capacity = 100;
-    (*exts) = (char *)ag_malloc(ext_capacity * SINGLE_EXT_LEN);
-    memset((*exts), 0, ext_capacity * SINGLE_EXT_LEN);
-    size_t num_of_extensions = 0;
+    size_t pat_capacity = 100;
+    (*pats) = (char *)ag_malloc(pat_capacity * SINGLE_PAT_LEN);
+    memset((*pats), 0, pat_capacity * SINGLE_PAT_LEN);
+    size_t num_of_patterns = 0;
 
     size_t i;
     for (i = 0; i < len; ++i) {
         size_t j = 0;
-        const char *ext = langs[extension_index[i]].extensions[j];
+        const char *pat = langs[pattern_index[i]].patterns[j];
         do {
-            if (num_of_extensions == ext_capacity) {
+            if (num_of_patterns == pat_capacity) {
                 break;
             }
-            char *pos = (*exts) + num_of_extensions * SINGLE_EXT_LEN;
-            strncpy(pos, ext, strlen(ext));
-            ++num_of_extensions;
-            ext = langs[extension_index[i]].extensions[++j];
-        } while (ext);
+            char *pos = (*pats) + num_of_patterns * SINGLE_PAT_LEN;
+            strncpy(pos, pat, strlen(pat));
+            ++num_of_patterns;
+            pat = langs[pattern_index[i]].patterns[++j];
+        } while (pat);
     }
 
-    return num_of_extensions;
+    return num_of_patterns;
 }
diff --git a/src/lang.h b/src/lang.h
index d0007f9..202da4b 100644
--- a/src/lang.h
+++ b/src/lang.h
@@ -1,12 +1,12 @@
 #ifndef LANG_H
 #define LANG_H
 
-#define MAX_EXTENSIONS 12
-#define SINGLE_EXT_LEN 20
+#define MAX_PATTERNS 12
+#define SINGLE_PAT_LEN 20
 
 typedef struct {
     const char *name;
-    const char *extensions[MAX_EXTENSIONS];
+    const char *patterns[MAX_PATTERNS];
 } lang_spec_t;
 
 extern lang_spec_t langs[];
@@ -17,20 +17,22 @@ extern lang_spec_t langs[];
 size_t get_lang_count(void);
 
 /**
-Convert a NULL-terminated array of language extensions
-into a regular expression of the form \.(extension1|extension2...)$
+Convert a NULL-terminated array of language patterns
+into a regular expression of the form (\.?pattern1|\.?pattern2...)$
+Patterns that begin with ^ are interpreted as full names, those
+without are interpreted as file extensions.
 
 Caller is responsible for freeing the returned string.
 */
-char *make_lang_regex(char *ext_array, size_t num_exts);
+char *make_lang_regex(char *pat_array, size_t num_pats);
 
 
 /**
-Combine multiple file type extensions into one array.
+Combine multiple file type patterns into one array.
 
-The combined result is returned through *exts*;
-*exts* is one-dimension array, which can contain up to 100 extensions;
-The number of extensions that *exts* actually contain is returned.
+The combined result is returned through *pats*;
+*pats* is one-dimension array, which can contain up to 100 patterns;
+The number of patterns that *pats* actually contain is returned.
 */
-size_t combine_file_extensions(size_t *extension_index, size_t len, char **exts);
+size_t combine_file_patterns(size_t *pattern_index, size_t len, char **pats);
 #endif
diff --git a/src/options.c b/src/options.c
index dbe3e24..b8da938 100644
--- a/src/options.c
+++ b/src/options.c
@@ -224,9 +224,9 @@ void parse_options(int argc, char **argv, char **base_paths[], char **paths[]) {
     size_t longopts_len, full_len;
     option_t *longopts;
     char *lang_regex = NULL;
-    size_t *ext_index = NULL;
-    char *extensions = NULL;
-    size_t num_exts = 0;
+    size_t *pat_index = NULL;
+    char *patterns = NULL;
+    size_t num_pats = 0;
 
     init_options();
 
@@ -332,8 +332,8 @@ void parse_options(int argc, char **argv, char **base_paths[], char **paths[]) {
     full_len = (longopts_len + lang_count + 1);
     longopts = ag_malloc(full_len * sizeof(option_t));
     memcpy(longopts, base_longopts, sizeof(base_longopts));
-    ext_index = (size_t *)ag_malloc(sizeof(size_t) * lang_count);
-    memset(ext_index, 0, sizeof(size_t) * lang_count);
+    pat_index = (size_t *)ag_malloc(sizeof(size_t) * lang_count);
+    memset(pat_index, 0, sizeof(size_t) * lang_count);
 
     for (i = 0; i < lang_count; i++) {
         option_t opt = { langs[i].name, no_argument, NULL, 0 };
@@ -580,7 +580,7 @@ void parse_options(int argc, char **argv, char **base_paths[], char **paths[]) {
                 for (i = 0; i < lang_count; i++) {
                     if (strcmp(longopts[opt_index].name, langs[i].name) == 0) {
                         has_filetype = 1;
-                        ext_index[lang_num++] = i;
+                        pat_index[lang_num++] = i;
                         break;
                     }
                 }
@@ -614,15 +614,15 @@ void parse_options(int argc, char **argv, char **base_paths[], char **paths[]) {
     }
 
     if (has_filetype) {
-        num_exts = combine_file_extensions(ext_index, lang_num, &extensions);
-        lang_regex = make_lang_regex(extensions, num_exts);
+        num_pats = combine_file_patterns(pat_index, lang_num, &patterns);
+        lang_regex = make_lang_regex(patterns, num_pats);
         compile_study(&opts.file_search_regex, &opts.file_search_regex_extra, lang_regex, 0, 0);
     }
 
-    if (extensions) {
-        free(extensions);
+    if (patterns) {
+        free(patterns);
     }
-    free(ext_index);
+    free(pat_index);
     if (lang_regex) {
         free(lang_regex);
     }
@@ -663,8 +663,8 @@ void parse_options(int argc, char **argv, char **base_paths[], char **paths[]) {
         for (lang_index = 0; lang_index < lang_count; lang_index++) {
             printf("  --%s\n    ", langs[lang_index].name);
             int j;
-            for (j = 0; j < MAX_EXTENSIONS && langs[lang_index].extensions[j]; j++) {
-                printf("  .%s", langs[lang_index].extensions[j]);
+            for (j = 0; j < MAX_PATTERNS && langs[lang_index].patterns[j]; j++) {
+                printf("  .%s", langs[lang_index].patterns[j]);
             }
             printf("\n\n");
         }
-- 
2.12.1

