magic pathspec: add ":(icase)path" to match case insensitively
authorJunio C Hamano <gitster@pobox.com>
Thu, 7 Apr 2011 03:56:19 +0000 (20:56 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 8 Apr 2011 23:20:16 +0000 (16:20 -0700)
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/glossary-content.txt
setup.c
index e51d7e60eb841d1a4832641543fbe13cefb6e35e..0ca029b738e516b69202eb5354d2f116f9c80921 100644 (file)
@@ -319,10 +319,13 @@ top `/`;;
        The magic word `top` (mnemonic: `/`) makes the pattern match
        from the root of the working tree, even when you are running
        the command from inside a subdirectory.
+icase;;
+       The magic word `icase` (there is no mnemonic for it) makes the
+       pattern match case insensitively.  E.g. `:(icase)makefile` matches
+       both `Makefile` and `makefile`.
 --
 +
-Currently only the slash `/` is recognized as the "magic signature",
-but it is envisioned that we will support more types of magic in later
+It is envisioned that we will support more types of magic in later
 versions of git.
 
 [[def_parent]]parent::
diff --git a/setup.c b/setup.c
index 5048252d78638c2c6adcf8807442728ef4f37a5e..51e354ca0760d8b6593fe50720b47c160dd8fe59 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -136,12 +136,12 @@ void verify_non_filename(const char *prefix, const char *arg)
  * Possible future magic semantics include stuff like:
  *
  *     { PATHSPEC_NOGLOB, '!', "noglob" },
- *     { PATHSPEC_ICASE, '\0', "icase" },
  *     { PATHSPEC_RECURSIVE, '*', "recursive" },
  *     { PATHSPEC_REGEXP, '\0', "regexp" },
  *
  */
 #define PATHSPEC_FROMTOP    (1<<0)
+#define PATHSPEC_ICASE      (1<<1)
 
 struct pathspec_magic {
        unsigned bit;
@@ -149,6 +149,7 @@ struct pathspec_magic {
        const char *name;
 } pathspec_magic[] = {
        { PATHSPEC_FROMTOP, '/', "top" },
+       { PATHSPEC_ICASE, '\0', "icase" },
 };
 
 /*
@@ -168,7 +169,8 @@ const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)
 {
        unsigned magic = 0;
        const char *copyfrom = elt;
-       int i;
+       const char *retval;
+       int i, free_source = 0;
 
        if (elt[0] != ':') {
                ; /* nothing to do */
@@ -222,10 +224,31 @@ const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)
                        copyfrom++;
        }
 
+       if (magic & PATHSPEC_ICASE) {
+               struct strbuf sb = STRBUF_INIT;
+               for (i = 0; copyfrom[i]; i++) {
+                       int ch = copyfrom[i];
+                       if (('a' <= ch && ch <= 'z') ||
+                           ('A' <= ch && ch <= 'Z')) {
+                               strbuf_addf(&sb, "[%c%c]",
+                                           tolower(ch), toupper(ch));
+                       } else {
+                               strbuf_addch(&sb, ch);
+                       }
+               }
+               if (sb.len) {
+                       free_source = 1;
+                       copyfrom = strbuf_detach(&sb, NULL);
+               }
+       }
+
        if (magic & PATHSPEC_FROMTOP)
-               return xstrdup(copyfrom);
+               retval = xstrdup(copyfrom);
        else
-               return prefix_path(prefix, prefixlen, copyfrom);
+               retval = prefix_path(prefix, prefixlen, copyfrom);
+       if (free_source)
+               free((char *)copyfrom);
+       return retval;
 }
 
 const char **get_pathspec(const char *prefix, const char **pathspec)