summaryrefslogtreecommitdiff
path: root/compat
diff options
context:
space:
mode:
Diffstat (limited to 'compat')
-rw-r--r--compat/bswap.h38
-rw-r--r--compat/cygwin.c19
-rw-r--r--compat/cygwin.h2
-rw-r--r--compat/fopen.c4
-rw-r--r--compat/mingw.c93
-rw-r--r--compat/mingw.h9
-rw-r--r--compat/precompose_utf8.c1
-rw-r--r--compat/qsort_s.c69
-rw-r--r--compat/regex/regexec.c2
-rw-r--r--compat/winansi.c192
10 files changed, 255 insertions, 174 deletions
diff --git a/compat/bswap.h b/compat/bswap.h
index d47c003544..7d063e9e40 100644
--- a/compat/bswap.h
+++ b/compat/bswap.h
@@ -162,19 +162,29 @@ static inline uint64_t git_bswap64(uint64_t x)
#else
-#define get_be16(p) ( \
- (*((unsigned char *)(p) + 0) << 8) | \
- (*((unsigned char *)(p) + 1) << 0) )
-#define get_be32(p) ( \
- (*((unsigned char *)(p) + 0) << 24) | \
- (*((unsigned char *)(p) + 1) << 16) | \
- (*((unsigned char *)(p) + 2) << 8) | \
- (*((unsigned char *)(p) + 3) << 0) )
-#define put_be32(p, v) do { \
- unsigned int __v = (v); \
- *((unsigned char *)(p) + 0) = __v >> 24; \
- *((unsigned char *)(p) + 1) = __v >> 16; \
- *((unsigned char *)(p) + 2) = __v >> 8; \
- *((unsigned char *)(p) + 3) = __v >> 0; } while (0)
+static inline uint16_t get_be16(const void *ptr)
+{
+ const unsigned char *p = ptr;
+ return (uint16_t)p[0] << 8 |
+ (uint16_t)p[1] << 0;
+}
+
+static inline uint32_t get_be32(const void *ptr)
+{
+ const unsigned char *p = ptr;
+ return (uint32_t)p[0] << 24 |
+ (uint32_t)p[1] << 16 |
+ (uint32_t)p[2] << 8 |
+ (uint32_t)p[3] << 0;
+}
+
+static inline void put_be32(void *ptr, uint32_t value)
+{
+ unsigned char *p = ptr;
+ p[0] = value >> 24;
+ p[1] = value >> 16;
+ p[2] = value >> 8;
+ p[3] = value >> 0;
+}
#endif
diff --git a/compat/cygwin.c b/compat/cygwin.c
new file mode 100644
index 0000000000..b9862d606d
--- /dev/null
+++ b/compat/cygwin.c
@@ -0,0 +1,19 @@
+#include "../git-compat-util.h"
+#include "../cache.h"
+
+int cygwin_offset_1st_component(const char *path)
+{
+ const char *pos = path;
+ /* unc paths */
+ if (is_dir_sep(pos[0]) && is_dir_sep(pos[1])) {
+ /* skip server name */
+ pos = strchr(pos + 2, '/');
+ if (!pos)
+ return 0; /* Error: malformed unc path */
+
+ do {
+ pos++;
+ } while (*pos && pos[0] != '/');
+ }
+ return pos + is_dir_sep(*pos) - path;
+}
diff --git a/compat/cygwin.h b/compat/cygwin.h
new file mode 100644
index 0000000000..8e52de4644
--- /dev/null
+++ b/compat/cygwin.h
@@ -0,0 +1,2 @@
+int cygwin_offset_1st_component(const char *path);
+#define offset_1st_component cygwin_offset_1st_component
diff --git a/compat/fopen.c b/compat/fopen.c
index b5ca142fed..107b3e8182 100644
--- a/compat/fopen.c
+++ b/compat/fopen.c
@@ -1,14 +1,14 @@
/*
* The order of the following two lines is important.
*
- * FREAD_READS_DIRECTORIES is undefined before including git-compat-util.h
+ * SUPPRESS_FOPEN_REDEFINITION is defined before including git-compat-util.h
* to avoid the redefinition of fopen within git-compat-util.h. This is
* necessary since fopen is a macro on some platforms which may be set
* based on compiler options. For example, on AIX fopen is set to fopen64
* when _LARGE_FILES is defined. The previous technique of merely undefining
* fopen after including git-compat-util.h is inadequate in this case.
*/
-#undef FREAD_READS_DIRECTORIES
+#define SUPPRESS_FOPEN_REDEFINITION
#include "../git-compat-util.h"
FILE *git_fopen(const char *path, const char *mode)
diff --git a/compat/mingw.c b/compat/mingw.c
index 3fbfda5978..8b6fa0db44 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -423,6 +423,8 @@ FILE *mingw_fopen (const char *filename, const char *otype)
return NULL;
}
file = _wfopen(wfilename, wotype);
+ if (!file && GetLastError() == ERROR_INVALID_NAME)
+ errno = ENOENT;
if (file && hide && set_hidden_flag(wfilename, 1))
warning("could not mark '%s' as hidden.", filename);
return file;
@@ -941,64 +943,14 @@ static const char *parse_interpreter(const char *cmd)
}
/*
- * Splits the PATH into parts.
- */
-static char **get_path_split(void)
-{
- char *p, **path, *envpath = mingw_getenv("PATH");
- int i, n = 0;
-
- if (!envpath || !*envpath)
- return NULL;
-
- envpath = xstrdup(envpath);
- p = envpath;
- while (p) {
- char *dir = p;
- p = strchr(p, ';');
- if (p) *p++ = '\0';
- if (*dir) { /* not earlier, catches series of ; */
- ++n;
- }
- }
- if (!n)
- return NULL;
-
- ALLOC_ARRAY(path, n + 1);
- p = envpath;
- i = 0;
- do {
- if (*p)
- path[i++] = xstrdup(p);
- p = p+strlen(p)+1;
- } while (i < n);
- path[i] = NULL;
-
- free(envpath);
-
- return path;
-}
-
-static void free_path_split(char **path)
-{
- char **p = path;
-
- if (!path)
- return;
-
- while (*p)
- free(*p++);
- free(path);
-}
-
-/*
* exe_only means that we only want to detect .exe files, but not scripts
* (which do not have an extension)
*/
-static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
+static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
+ int isexe, int exe_only)
{
char path[MAX_PATH];
- snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+ snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd);
if (!isexe && access(path, F_OK) == 0)
return xstrdup(path);
@@ -1013,17 +965,29 @@ static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_on
* Determines the absolute path of cmd using the split path in path.
* If cmd contains a slash or backslash, no lookup is performed.
*/
-static char *path_lookup(const char *cmd, char **path, int exe_only)
+static char *path_lookup(const char *cmd, int exe_only)
{
+ const char *path;
char *prog = NULL;
int len = strlen(cmd);
int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
if (strchr(cmd, '/') || strchr(cmd, '\\'))
- prog = xstrdup(cmd);
+ return xstrdup(cmd);
+
+ path = mingw_getenv("PATH");
+ if (!path)
+ return NULL;
- while (!prog && *path)
- prog = lookup_prog(*path++, cmd, isexe, exe_only);
+ while (!prog) {
+ const char *sep = strchrnul(path, ';');
+ int dirlen = sep - path;
+ if (dirlen)
+ prog = lookup_prog(path, dirlen, cmd, isexe, exe_only);
+ if (!*sep)
+ break;
+ path = sep + 1;
+ }
return prog;
}
@@ -1190,8 +1154,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
int fhin, int fhout, int fherr)
{
pid_t pid;
- char **path = get_path_split();
- char *prog = path_lookup(cmd, path, 0);
+ char *prog = path_lookup(cmd, 0);
if (!prog) {
errno = ENOENT;
@@ -1202,7 +1165,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
if (interpr) {
const char *argv0 = argv[0];
- char *iprog = path_lookup(interpr, path, 1);
+ char *iprog = path_lookup(interpr, 1);
argv[0] = prog;
if (!iprog) {
errno = ENOENT;
@@ -1220,21 +1183,18 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
fhin, fhout, fherr);
free(prog);
}
- free_path_split(path);
return pid;
}
static int try_shell_exec(const char *cmd, char *const *argv)
{
const char *interpr = parse_interpreter(cmd);
- char **path;
char *prog;
int pid = 0;
if (!interpr)
return 0;
- path = get_path_split();
- prog = path_lookup(interpr, path, 1);
+ prog = path_lookup(interpr, 1);
if (prog) {
int argc = 0;
const char **argv2;
@@ -1253,7 +1213,6 @@ static int try_shell_exec(const char *cmd, char *const *argv)
free(prog);
free(argv2);
}
- free_path_split(path);
return pid;
}
@@ -1275,8 +1234,7 @@ int mingw_execv(const char *cmd, char *const *argv)
int mingw_execvp(const char *cmd, char *const *argv)
{
- char **path = get_path_split();
- char *prog = path_lookup(cmd, path, 0);
+ char *prog = path_lookup(cmd, 0);
if (prog) {
mingw_execv(prog, argv);
@@ -1284,7 +1242,6 @@ int mingw_execvp(const char *cmd, char *const *argv)
} else
errno = ENOENT;
- free_path_split(path);
return -1;
}
diff --git a/compat/mingw.h b/compat/mingw.h
index 034fff9479..e03aecfe2e 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -384,6 +384,9 @@ int mingw_raise(int sig);
* ANSI emulation wrappers
*/
+int winansi_isatty(int fd);
+#define isatty winansi_isatty
+
void winansi_init(void);
HANDLE winansi_get_osfhandle(int fd);
@@ -395,7 +398,11 @@ HANDLE winansi_get_osfhandle(int fd);
(isalpha(*(path)) && (path)[1] == ':' ? 2 : 0)
int mingw_skip_dos_drive_prefix(char **path);
#define skip_dos_drive_prefix mingw_skip_dos_drive_prefix
-#define is_dir_sep(c) ((c) == '/' || (c) == '\\')
+static inline int mingw_is_dir_sep(int c)
+{
+ return c == '/' || c == '\\';
+}
+#define is_dir_sep mingw_is_dir_sep
static inline char *mingw_find_last_dir_sep(const char *path)
{
char *ret = NULL;
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index 4293b53b17..de61c15d34 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -6,6 +6,7 @@
#define PRECOMPOSE_UNICODE_C
#include "cache.h"
+#include "config.h"
#include "utf8.h"
#include "precompose_utf8.h"
diff --git a/compat/qsort_s.c b/compat/qsort_s.c
new file mode 100644
index 0000000000..52d1f0a73d
--- /dev/null
+++ b/compat/qsort_s.c
@@ -0,0 +1,69 @@
+#include "../git-compat-util.h"
+
+/*
+ * A merge sort implementation, simplified from the qsort implementation
+ * by Mike Haertel, which is a part of the GNU C Library.
+ * Added context pointer, safety checks and return value.
+ */
+
+static void msort_with_tmp(void *b, size_t n, size_t s,
+ int (*cmp)(const void *, const void *, void *),
+ char *t, void *ctx)
+{
+ char *tmp;
+ char *b1, *b2;
+ size_t n1, n2;
+
+ if (n <= 1)
+ return;
+
+ n1 = n / 2;
+ n2 = n - n1;
+ b1 = b;
+ b2 = (char *)b + (n1 * s);
+
+ msort_with_tmp(b1, n1, s, cmp, t, ctx);
+ msort_with_tmp(b2, n2, s, cmp, t, ctx);
+
+ tmp = t;
+
+ while (n1 > 0 && n2 > 0) {
+ if (cmp(b1, b2, ctx) <= 0) {
+ memcpy(tmp, b1, s);
+ tmp += s;
+ b1 += s;
+ --n1;
+ } else {
+ memcpy(tmp, b2, s);
+ tmp += s;
+ b2 += s;
+ --n2;
+ }
+ }
+ if (n1 > 0)
+ memcpy(tmp, b1, n1 * s);
+ memcpy(b, t, (n - n2) * s);
+}
+
+int git_qsort_s(void *b, size_t n, size_t s,
+ int (*cmp)(const void *, const void *, void *), void *ctx)
+{
+ const size_t size = st_mult(n, s);
+ char buf[1024];
+
+ if (!n)
+ return 0;
+ if (!b || !cmp)
+ return -1;
+
+ if (size < sizeof(buf)) {
+ /* The temporary array fits on the small on-stack buffer. */
+ msort_with_tmp(b, n, s, cmp, buf, ctx);
+ } else {
+ /* It's somewhat large, so malloc it. */
+ char *tmp = xmalloc(size);
+ msort_with_tmp(b, n, s, cmp, tmp, ctx);
+ free(tmp);
+ }
+ return 0;
+}
diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c
index eb5e1d4439..0a745d9c3b 100644
--- a/compat/regex/regexec.c
+++ b/compat/regex/regexec.c
@@ -4102,7 +4102,7 @@ extend_buffers (re_match_context_t *mctx)
if (BE (INT_MAX / 2 / sizeof (re_dfastate_t *) <= pstr->bufs_len, 0))
return REG_ESPACE;
- /* Double the lengthes of the buffers. */
+ /* Double the lengths of the buffers. */
ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
if (BE (ret != REG_NOERROR, 0))
return ret;
diff --git a/compat/winansi.c b/compat/winansi.c
index db4a5b0a37..a11a0f16d2 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -6,6 +6,12 @@
#include "../git-compat-util.h"
#include <wingdi.h>
#include <winreg.h>
+#include "win32.h"
+
+static int fd_is_interactive[3] = { 0, 0, 0 };
+#define FD_CONSOLE 0x1
+#define FD_SWAPPED 0x2
+#define FD_MSYS 0x4
/*
ANSI codes used by git: m, K
@@ -81,6 +87,7 @@ static void warn_if_raster_font(void)
static int is_console(int fd)
{
CONSOLE_SCREEN_BUFFER_INFO sbi;
+ DWORD mode;
HANDLE hcon;
static int initialized = 0;
@@ -95,9 +102,22 @@ static int is_console(int fd)
return 0;
/* check if its a handle to a console output screen buffer */
- if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+ if (!fd) {
+ if (!GetConsoleMode(hcon, &mode))
+ return 0;
+ /*
+ * This code path is only reached if there is no console
+ * attached to stdout/stderr, i.e. we will not need to output
+ * any text to any console, therefore we might just as well
+ * use black as foreground color.
+ */
+ sbi.wAttributes = 0;
+ } else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
return 0;
+ if (fd >= 0 && fd <= 2)
+ fd_is_interactive[fd] |= FD_CONSOLE;
+
/* initialize attributes */
if (!initialized) {
console = hcon;
@@ -120,6 +140,11 @@ static void write_console(unsigned char *str, size_t len)
/* convert utf-8 to utf-16 */
int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
+ if (wlen < 0) {
+ wchar_t *err = L"[invalid]";
+ WriteConsoleW(console, err, wcslen(err), &dummy, NULL);
+ return;
+ }
/* write directly to console */
WriteConsoleW(console, wbuf, wlen, &dummy, NULL);
@@ -459,76 +484,49 @@ static HANDLE duplicate_handle(HANDLE hnd)
return hresult;
}
-
-/*
- * Make MSVCRT's internal file descriptor control structure accessible
- * so that we can tweak OS handles and flags directly (we need MSVCRT
- * to treat our pipe handle as if it were a console).
- *
- * We assume that the ioinfo structure (exposed by MSVCRT.dll via
- * __pioinfo) starts with the OS handle and the flags. The exact size
- * varies between MSVCRT versions, so we try different sizes until
- * toggling the FDEV bit of _pioinfo(1)->osflags is reflected in
- * isatty(1).
- */
-typedef struct {
- HANDLE osfhnd;
- char osflags;
-} ioinfo;
-
-extern __declspec(dllimport) ioinfo *__pioinfo[];
-
-static size_t sizeof_ioinfo = 0;
-
-#define IOINFO_L2E 5
-#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
-
-#define FPIPE 0x08
-#define FDEV 0x40
-
-static inline ioinfo* _pioinfo(int fd)
-{
- return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] +
- (fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo);
-}
-
-static int init_sizeof_ioinfo(void)
-{
- int istty, wastty;
- /* don't init twice */
- if (sizeof_ioinfo)
- return sizeof_ioinfo >= 256;
-
- sizeof_ioinfo = sizeof(ioinfo);
- wastty = isatty(1);
- while (sizeof_ioinfo < 256) {
- /* toggle FDEV flag, check isatty, then toggle back */
- _pioinfo(1)->osflags ^= FDEV;
- istty = isatty(1);
- _pioinfo(1)->osflags ^= FDEV;
- /* return if we found the correct size */
- if (istty != wastty)
- return 0;
- sizeof_ioinfo += sizeof(void*);
- }
- error("Tweaking file descriptors doesn't work with this MSVCRT.dll");
- return 1;
-}
-
static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
{
- ioinfo *pioinfo;
- HANDLE old_handle;
-
- /* init ioinfo size if we haven't done so */
- if (init_sizeof_ioinfo())
- return INVALID_HANDLE_VALUE;
-
- /* get ioinfo pointer and change the handles */
- pioinfo = _pioinfo(fd);
- old_handle = pioinfo->osfhnd;
- pioinfo->osfhnd = new_handle;
- return old_handle;
+ /*
+ * Create a copy of the original handle associated with fd
+ * because the original will get closed when we dup2().
+ */
+ HANDLE handle = (HANDLE)_get_osfhandle(fd);
+ HANDLE duplicate = duplicate_handle(handle);
+
+ /* Create a temp fd associated with the already open "new_handle". */
+ int new_fd = _open_osfhandle((intptr_t)new_handle, O_BINARY);
+
+ assert((fd == 1) || (fd == 2));
+
+ /*
+ * Use stock dup2() to re-bind fd to the new handle. Note that
+ * this will implicitly close(1) and close both fd=1 and the
+ * originally associated handle. It will open a new fd=1 and
+ * call DuplicateHandle() on the handle associated with new_fd.
+ * It is because of this implicit close() that we created the
+ * copy of the original.
+ *
+ * Note that we need to update the cached console handle to the
+ * duplicated one because the dup2() call will implicitly close
+ * the original one.
+ *
+ * Note that dup2() when given target := {0,1,2} will also
+ * call SetStdHandle(), so we don't need to worry about that.
+ */
+ if (console == handle)
+ console = duplicate;
+ dup2(new_fd, fd);
+
+ /* Close the temp fd. This explicitly closes "new_handle"
+ * (because it has been associated with it).
+ */
+ close(new_fd);
+
+ if (fd == 2)
+ setvbuf(stderr, NULL, _IONBF, BUFSIZ);
+ fd_is_interactive[fd] |= FD_SWAPPED;
+
+ return duplicate;
}
#ifdef DETECT_MSYS_TTY
@@ -553,23 +551,39 @@ static void detect_msys_tty(int fd)
buffer, sizeof(buffer) - 2, &result)))
return;
name = nameinfo->Name.Buffer;
- name[nameinfo->Name.Length] = 0;
-
- /* check if this could be a MSYS2 pty pipe ('msys-XXXX-ptyN-XX') */
- if (!wcsstr(name, L"msys-") || !wcsstr(name, L"-pty"))
- return;
-
- /* init ioinfo size if we haven't done so */
- if (init_sizeof_ioinfo())
+ name[nameinfo->Name.Length / sizeof(*name)] = 0;
+
+ /*
+ * Check if this could be a MSYS2 pty pipe ('msys-XXXX-ptyN-XX')
+ * or a cygwin pty pipe ('cygwin-XXXX-ptyN-XX')
+ */
+ if ((!wcsstr(name, L"msys-") && !wcsstr(name, L"cygwin-")) ||
+ !wcsstr(name, L"-pty"))
return;
- /* set FDEV flag, reset FPIPE flag */
- _pioinfo(fd)->osflags &= ~FPIPE;
- _pioinfo(fd)->osflags |= FDEV;
+ if (fd == 2)
+ setvbuf(stderr, NULL, _IONBF, BUFSIZ);
+ fd_is_interactive[fd] |= FD_MSYS;
}
#endif
+/*
+ * Wrapper for isatty(). Most calls in the main git code
+ * call isatty(1 or 2) to see if the instance is interactive
+ * and should: be colored, show progress, paginate output.
+ * We lie and give results for what the descriptor WAS at
+ * startup (and ignore any pipe redirection we internally
+ * do).
+ */
+#undef isatty
+int winansi_isatty(int fd)
+{
+ if (fd >= 0 && fd <= 2)
+ return fd_is_interactive[fd] != 0;
+ return isatty(fd);
+}
+
void winansi_init(void)
{
int con1, con2;
@@ -578,6 +592,10 @@ void winansi_init(void)
/* check if either stdout or stderr is a console output screen buffer */
con1 = is_console(1);
con2 = is_console(2);
+
+ /* Also compute console bit for fd 0 even though we don't need the result here. */
+ is_console(0);
+
if (!con1 && !con2) {
#ifdef DETECT_MSYS_TTY
/* check if stdin / stdout / stderr are MSYS2 pty pipes */
@@ -621,12 +639,10 @@ void winansi_init(void)
*/
HANDLE winansi_get_osfhandle(int fd)
{
- HANDLE hnd = (HANDLE) _get_osfhandle(fd);
- if (isatty(fd) && GetFileType(hnd) == FILE_TYPE_PIPE) {
- if (fd == 1 && hconsole1)
- return hconsole1;
- else if (fd == 2 && hconsole2)
- return hconsole2;
- }
- return hnd;
+ if (fd == 1 && (fd_is_interactive[1] & FD_SWAPPED))
+ return hconsole1;
+ if (fd == 2 && (fd_is_interactive[2] & FD_SWAPPED))
+ return hconsole2;
+
+ return (HANDLE)_get_osfhandle(fd);
}