diff options
| author | Edward Thomson <ethomson@edwardthomson.com> | 2019-12-03 23:15:47 +1100 |
|---|---|---|
| committer | Edward Thomson <ethomson@edwardthomson.com> | 2019-12-10 18:11:45 +1000 |
| commit | 14ff3516e5f4203838a0edb044c6622b8e3a3755 (patch) | |
| tree | f4105016769743a7dcf987b2bbf10a405df18f95 /src/path.c | |
| parent | 85d4ff77e2b539c525f36d0860f3faa8e68308b7 (diff) | |
| download | libgit2-14ff3516e5f4203838a0edb044c6622b8e3a3755.tar.gz | |
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.
Diffstat (limited to 'src/path.c')
| -rw-r--r-- | src/path.c | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/src/path.c b/src/path.c index 7241a3500..625b95c0d 100644 --- a/src/path.c +++ b/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 @@ -272,11 +294,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? */ |
