{"thread":{"id":"6102","subject":"[PATCH 1/5] match_pathspec() -- return how well the spec matched","startedAt":"2006-12-25T11:09:52Z","lastAt":"2006-12-25T11:09:52Z","messageCount":1,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"30264","messageId":"7vk60gmdtr.fsf@assigned-by-dhcp.cox.net","threadId":"6102","inReplyTo":null,"subject":"[PATCH 1/5] match_pathspec() -- return how well the spec matched","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-25T11:09:52Z","receivedAt":"2006-12-25T11:09:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This updates the return value from match_pathspec() so that the\ncaller can tell cases between exact match, leading pathname\nmatch (i.e. file \"foo/bar\" matches a pathspec \"foo\"), or\nfilename glob match.  This can be used to prevent \"rm dir\" from\nremoving \"dir/file\" without explicitly asking for recursive\nbehaviour with -r flag, for example.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n dir.c |   51 +++++++++++++++++++++++++++++++++++----------------\n dir.h |    4 ++++\n 2 files changed, 39 insertions(+), 16 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 16401d8..8477472 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -40,6 +40,18 @@ int common_prefix(const char **pathspec)\n \treturn prefix;\n }\n \n+/*\n+ * Does 'match' matches the given name?\n+ * A match is found if\n+ *\n+ * (1) the 'match' string is leading directory of 'name', or\n+ * (2) the 'match' string is a wildcard and matches 'name', or\n+ * (3) the 'match' string is exactly the same as 'name'.\n+ *\n+ * and the return value tells which case it was.\n+ *\n+ * It returns 0 when there is no match.\n+ */\n static int match_one(const char *match, const char *name, int namelen)\n {\n \tint matchlen;\n@@ -47,27 +59,30 @@ static int match_one(const char *match, const char *name, int namelen)\n \t/* If the match was just the prefix, we matched */\n \tmatchlen = strlen(match);\n \tif (!matchlen)\n-\t\treturn 1;\n+\t\treturn MATCHED_RECURSIVELY;\n \n \t/*\n \t * If we don't match the matchstring exactly,\n \t * we need to match by fnmatch\n \t */\n \tif (strncmp(match, name, matchlen))\n-\t\treturn !fnmatch(match, name, 0);\n+\t\treturn !fnmatch(match, name, 0) ? MATCHED_FNMATCH : 0;\n \n-\t/*\n-\t * If we did match the string exactly, we still\n-\t * need to make sure that it happened on a path\n-\t * component boundary (ie either the last character\n-\t * of the match was '/', or the next character of\n-\t * the name was '/' or the terminating NUL.\n-\t */\n-\treturn\tmatch[matchlen-1] == '/' ||\n-\t\tname[matchlen] == '/' ||\n-\t\t!name[matchlen];\n+\tif (!name[matchlen])\n+\t\treturn MATCHED_EXACTLY;\n+\tif (match[matchlen-1] == '/' || name[matchlen] == '/')\n+\t\treturn MATCHED_RECURSIVELY;\n+\treturn 0;\n }\n \n+/*\n+ * Given a name and a list of pathspecs, see if the name matches\n+ * any of the pathspecs.  The caller is also interested in seeing\n+ * all pathspec matches some names it calls this function with\n+ * (otherwise the user could have mistyped the unmatched pathspec),\n+ * and a mark is left in seen[] array for pathspec element that\n+ * actually matched anything.\n+ */\n int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen)\n {\n \tint retval;\n@@ -77,12 +92,16 @@ int match_pathspec(const char **pathspec, const char *name, int namelen, int pre\n \tnamelen -= prefix;\n \n \tfor (retval = 0; (match = *pathspec++) != NULL; seen++) {\n-\t\tif (retval & *seen)\n+\t\tint how;\n+\t\tif (retval && *seen == MATCHED_EXACTLY)\n \t\t\tcontinue;\n \t\tmatch += prefix;\n-\t\tif (match_one(match, name, namelen)) {\n-\t\t\tretval = 1;\n-\t\t\t*seen = 1;\n+\t\thow = match_one(match, name, namelen);\n+\t\tif (how) {\n+\t\t\tif (retval < how)\n+\t\t\t\tretval = how;\n+\t\t\tif (*seen < how)\n+\t\t\t\t*seen = how;\n \t\t}\n \t}\n \treturn retval;\ndiff --git a/dir.h b/dir.h\nindex 550551a..c919727 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -40,6 +40,10 @@ struct dir_struct {\n };\n \n extern int common_prefix(const char **pathspec);\n+\n+#define MATCHED_RECURSIVELY 1\n+#define MATCHED_FNMATCH 2\n+#define MATCHED_EXACTLY 3\n extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);\n \n extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen);\n-- \n1.4.4.3.g50da\n"}]}