summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--utf8.c64
-rw-r--r--utf8.h8
2 files changed, 72 insertions, 0 deletions
diff --git a/utf8.c b/utf8.c
index 0d20e0acb2..2c6442cc11 100644
--- a/utf8.c
+++ b/utf8.c
@@ -628,3 +628,67 @@ int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding)
return chrlen;
}
+
+/*
+ * Pick the next char from the stream, folding as an HFS+ filename comparison
+ * would. Note that this is _not_ complete by any means. It's just enough
+ * to make is_hfs_dotgit() work, and should not be used otherwise.
+ */
+static ucs_char_t next_hfs_char(const char **in)
+{
+ while (1) {
+ ucs_char_t out = pick_one_utf8_char(in, NULL);
+ /*
+ * check for malformed utf8. Technically this
+ * gets converted to a percent-sequence, but
+ * returning 0 is good enough for is_hfs_dotgit
+ * to realize it cannot be .git
+ */
+ if (!*in)
+ return 0;
+
+ /* these code points are ignored completely */
+ switch (out) {
+ case 0x200c: /* ZERO WIDTH NON-JOINER */
+ case 0x200d: /* ZERO WIDTH JOINER */
+ case 0x200e: /* LEFT-TO-RIGHT MARK */
+ case 0x200f: /* RIGHT-TO-LEFT MARK */
+ case 0x202a: /* LEFT-TO-RIGHT EMBEDDING */
+ case 0x202b: /* RIGHT-TO-LEFT EMBEDDING */
+ case 0x202c: /* POP DIRECTIONAL FORMATTING */
+ case 0x202d: /* LEFT-TO-RIGHT OVERRIDE */
+ case 0x202e: /* RIGHT-TO-LEFT OVERRIDE */
+ case 0x206a: /* INHIBIT SYMMETRIC SWAPPING */
+ case 0x206b: /* ACTIVATE SYMMETRIC SWAPPING */
+ case 0x206c: /* INHIBIT ARABIC FORM SHAPING */
+ case 0x206d: /* ACTIVATE ARABIC FORM SHAPING */
+ case 0x206e: /* NATIONAL DIGIT SHAPES */
+ case 0x206f: /* NOMINAL DIGIT SHAPES */
+ case 0xfeff: /* ZERO WIDTH NO-BREAK SPACE */
+ continue;
+ }
+
+ /*
+ * there's a great deal of other case-folding that occurs,
+ * but this is enough to catch anything that will convert
+ * to ".git"
+ */
+ return tolower(out);
+ }
+}
+
+int is_hfs_dotgit(const char *path)
+{
+ ucs_char_t c;
+
+ if (next_hfs_char(&path) != '.' ||
+ next_hfs_char(&path) != 'g' ||
+ next_hfs_char(&path) != 'i' ||
+ next_hfs_char(&path) != 't')
+ return 0;
+ c = next_hfs_char(&path);
+ if (c && !is_dir_sep(c))
+ return 0;
+
+ return 1;
+}
diff --git a/utf8.h b/utf8.h
index 65d0e42b96..e4d9183c5f 100644
--- a/utf8.h
+++ b/utf8.h
@@ -42,4 +42,12 @@ static inline char *reencode_string(const char *in,
int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding);
+/*
+ * Returns true if the the path would match ".git" after HFS case-folding.
+ * The path should be NUL-terminated, but we will match variants of both ".git\0"
+ * and ".git/..." (but _not_ ".../.git"). This makes it suitable for both fsck
+ * and verify_path().
+ */
+int is_hfs_dotgit(const char *path);
+
#endif