mirror of
https://github.com/libgit2/libgit2.git
synced 2026-01-25 02:56:17 +00:00
path: support non-ascii drive letters on dos
Windows/DOS only supports drive letters that are alpha characters A-Z. However, you can `subst` any one-character as a drive letter, including numbers or even emoji. Test that we can identify emoji as drive letters.
This commit is contained in:
committed by
Patrick Steinhardt
parent
cf130e6de9
commit
6117dcd34a
38
src/path.c
38
src/path.c
@@ -21,7 +21,29 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define LOOKS_LIKE_DRIVE_PREFIX(S) (git__isalpha((S)[0]) && (S)[1] == ':')
|
||||
static int dos_drive_prefix_length(const char *path)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Does it start with an ASCII letter (i.e. highest bit not set),
|
||||
* followed by a colon?
|
||||
*/
|
||||
if (!(0x80 & (unsigned char)*path))
|
||||
return *path && path[1] == ':' ? 2 : 0;
|
||||
|
||||
/*
|
||||
* While drive letters must be letters of the English alphabet, it is
|
||||
* possible to assign virtually _any_ Unicode character via `subst` as
|
||||
* a drive letter to "virtual drives". Even `1`, or `ä`. Or fun stuff
|
||||
* like this:
|
||||
*
|
||||
* subst ֍: %USERPROFILE%\Desktop
|
||||
*/
|
||||
for (i = 1; i < 4 && (0x80 & (unsigned char)path[i]); i++)
|
||||
; /* skip first UTF-8 character */
|
||||
return path[i] == ':' ? i + 1 : 0;
|
||||
}
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
static bool looks_like_network_computer_name(const char *path, int pos)
|
||||
@@ -123,11 +145,11 @@ static int win32_prefix_length(const char *path, int len)
|
||||
GIT_UNUSED(len);
|
||||
#else
|
||||
/*
|
||||
* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return
|
||||
* 'C:/' here
|
||||
* Mimic unix behavior where '/.git' returns '/': 'C:/.git'
|
||||
* will return 'C:/' here
|
||||
*/
|
||||
if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path))
|
||||
return 2;
|
||||
if (dos_drive_prefix_length(path) == len)
|
||||
return len;
|
||||
|
||||
/*
|
||||
* Similarly checks if we're dealing with a network computer name
|
||||
@@ -260,11 +282,11 @@ const char *git_path_topdir(const char *path)
|
||||
|
||||
int git_path_root(const char *path)
|
||||
{
|
||||
int offset = 0;
|
||||
int offset = 0, prefix_len;
|
||||
|
||||
/* Does the root of the path look like a windows drive ? */
|
||||
if (LOOKS_LIKE_DRIVE_PREFIX(path))
|
||||
offset += 2;
|
||||
if ((prefix_len = dos_drive_prefix_length(path)))
|
||||
offset += prefix_len;
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
/* Are we dealing with a windows network path? */
|
||||
|
||||
@@ -352,3 +352,14 @@ void test_path_core__join_unrooted(void)
|
||||
|
||||
git_buf_free(&out);
|
||||
}
|
||||
|
||||
void test_path_core__join_unrooted_respects_funny_windows_roots(void)
|
||||
{
|
||||
test_join_unrooted("💩:/foo/bar/foobar", 9, "bar/foobar", "💩:/foo");
|
||||
test_join_unrooted("💩:/foo/bar/foobar", 13, "foobar", "💩:/foo/bar");
|
||||
test_join_unrooted("💩:/foo", 5, "💩:/foo", "💩:/asdf");
|
||||
test_join_unrooted("💩:/foo/bar", 5, "💩:/foo/bar", "💩:/asdf");
|
||||
test_join_unrooted("💩:/foo/bar/foobar", 9, "💩:/foo/bar/foobar", "💩:/foo");
|
||||
test_join_unrooted("💩:/foo/bar/foobar", 13, "💩:/foo/bar/foobar", "💩:/foo/bar");
|
||||
test_join_unrooted("💩:/foo/bar/foobar", 9, "💩:/foo/bar/foobar", "💩:/foo/");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user