Browse Source

Merge branch 'j6t/mingw'

* j6t/mingw: (38 commits)
  compat/pread.c: Add a forward declaration to fix a warning
  Windows: Fix ntohl() related warnings about printf formatting
  Windows: TMP and TEMP environment variables specify a temporary directory.
  Windows: Make 'git help -a' work.
  Windows: Work around an oddity when a pipe with no reader is written to.
  Windows: Make the pager work.
  When installing, be prepared that template_dir may be relative.
  Windows: Use a relative default template_dir and ETC_GITCONFIG
  Windows: Compute the fallback for exec_path from the program invocation.
  Turn builtin_exec_path into a function.
  Windows: Use a customized struct stat that also has the st_blocks member.
  Windows: Add a custom implementation for utime().
  Windows: Add a new lstat and fstat implementation based on Win32 API.
  Windows: Implement a custom spawnve().
  Windows: Implement wrappers for gethostbyname(), socket(), and connect().
  Windows: Work around incompatible sort and find.
  Windows: Implement asynchronous functions as threads.
  Windows: Disambiguate DOS style paths from SSH URLs.
  Windows: A rudimentary poll() emulation.
  Windows: Implement start_command().
  ...
maint
Junio C Hamano 17 years ago
parent
commit
bb1ab2db08
  1. 6
      Documentation/git.txt
  2. 46
      Makefile
  3. 2
      cache.h
  4. 488
      compat/fnmatch.c
  5. 84
      compat/fnmatch.h
  6. 1019
      compat/mingw.c
  7. 211
      compat/mingw.h
  8. 4927
      compat/regex.c
  9. 490
      compat/regex.h
  10. 19
      compat/snprintf.c
  11. 2
      connect.c
  12. 13
      date.c
  13. 41
      exec_cmd.c
  14. 36
      git-compat-util.h
  15. 13
      git-sh-setup.sh
  16. 19
      git.c
  17. 33
      help.c
  18. 40
      pager.c
  19. 126
      run-command.c
  20. 5
      run-command.h
  21. 59
      setup.c
  22. 14
      sha1_file.c
  23. 8
      templates/Makefile
  24. 3
      transport.c
  25. 2
      upload-pack.c
  26. 7
      write_or_die.c

6
Documentation/git.txt

@ -410,9 +410,9 @@ git so take care if using Cogito etc. @@ -410,9 +410,9 @@ git so take care if using Cogito etc.
'GIT_ALTERNATE_OBJECT_DIRECTORIES'::
Due to the immutable nature of git objects, old objects can be
archived into shared, read-only directories. This variable
specifies a ":" separated list of git object directories which
can be used to search for git objects. New objects will not be
written to these directories.
specifies a ":" separated (on Windows ";" separated) list
of git object directories which can be used to search for git
objects. New objects will not be written to these directories.

'GIT_DIR'::
If the 'GIT_DIR' environment variable is set then it

46
Makefile

@ -205,7 +205,7 @@ GITWEB_FAVICON = git-favicon.png @@ -205,7 +205,7 @@ GITWEB_FAVICON = git-favicon.png
GITWEB_SITE_HEADER =
GITWEB_SITE_FOOTER =

export prefix bindir gitexecdir sharedir template_dir htmldir sysconfdir
export prefix bindir gitexecdir sharedir htmldir sysconfdir

CC = gcc
AR = ar
@ -273,11 +273,9 @@ EXTRA_PROGRAMS = @@ -273,11 +273,9 @@ EXTRA_PROGRAMS =

# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS += $(EXTRA_PROGRAMS)
PROGRAMS += git-daemon$X
PROGRAMS += git-fast-import$X
PROGRAMS += git-fetch-pack$X
PROGRAMS += git-hash-object$X
PROGRAMS += git-imap-send$X
PROGRAMS += git-index-pack$X
PROGRAMS += git-merge-index$X
PROGRAMS += git-merge-tree$X
@ -337,6 +335,7 @@ LIB_H += builtin.h @@ -337,6 +335,7 @@ LIB_H += builtin.h
LIB_H += cache.h
LIB_H += cache-tree.h
LIB_H += commit.h
LIB_H += compat/mingw.h
LIB_H += csum-file.h
LIB_H += decorate.h
LIB_H += delta.h
@ -717,6 +716,36 @@ ifeq ($(uname_S),HP-UX) @@ -717,6 +716,36 @@ ifeq ($(uname_S),HP-UX)
NO_HSTRERROR = YesPlease
NO_SYS_SELECT_H = YesPlease
endif
ifneq (,$(findstring MINGW,$(uname_S)))
NO_MMAP = YesPlease
NO_PREAD = YesPlease
NO_OPENSSL = YesPlease
NO_CURL = YesPlease
NO_SYMLINK_HEAD = YesPlease
NO_IPV6 = YesPlease
NO_SETENV = YesPlease
NO_UNSETENV = YesPlease
NO_STRCASESTR = YesPlease
NO_STRLCPY = YesPlease
NO_MEMMEM = YesPlease
NEEDS_LIBICONV = YesPlease
OLD_ICONV = YesPlease
NO_C99_FORMAT = YesPlease
NO_STRTOUMAX = YesPlease
NO_MKDTEMP = YesPlease
SNPRINTF_RETURNS_BOGUS = YesPlease
NO_SVN_TESTS = YesPlease
NO_PERL_MAKEMAKER = YesPlease
NO_POSIX_ONLY_PROGRAMS = YesPlease
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat
COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o
EXTLIBS += -lws2_32
X = .exe
template_dir = ../share/git-core/templates/
ETC_GITCONFIG = ../etc/gitconfig
endif
ifneq (,$(findstring arm,$(uname_M)))
ARM_SHA1 = YesPlease
endif
@ -777,6 +806,10 @@ ifdef ZLIB_PATH @@ -777,6 +806,10 @@ ifdef ZLIB_PATH
endif
EXTLIBS += -lz

ifndef NO_POSIX_ONLY_PROGRAMS
PROGRAMS += git-daemon$X
PROGRAMS += git-imap-send$X
endif
ifndef NO_OPENSSL
OPENSSL_LIBSSL = -lssl
ifdef OPENSSLDIR
@ -1268,6 +1301,13 @@ remove-dashes: @@ -1268,6 +1301,13 @@ remove-dashes:

### Installation rules

ifeq ($(firstword $(subst /, ,$(template_dir))),..)
template_instdir = $(gitexecdir)/$(template_dir)
else
template_instdir = $(template_dir)
endif
export template_instdir

install: all
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'

2
cache.h

@ -522,7 +522,7 @@ int safe_create_leading_directories_const(const char *path); @@ -522,7 +522,7 @@ int safe_create_leading_directories_const(const char *path);
char *enter_repo(char *path, int strict);
static inline int is_absolute_path(const char *path)
{
return path[0] == '/';
return path[0] == '/' || has_dos_drive_prefix(path);
}
const char *make_absolute_path(const char *path);
const char *make_nonrelative_path(const char *path);

488
compat/fnmatch.c

@ -0,0 +1,488 @@ @@ -0,0 +1,488 @@
/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
This file is part of the GNU C Library.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */

#if HAVE_CONFIG_H
# include <config.h>
#endif

/* Enable GNU extensions in fnmatch.h. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif

#include <errno.h>
#include <fnmatch.h>
#include <ctype.h>

#if HAVE_STRING_H || defined _LIBC
# include <string.h>
#else
# include <strings.h>
#endif

#if defined STDC_HEADERS || defined _LIBC
# include <stdlib.h>
#endif

/* For platform which support the ISO C amendement 1 functionality we
support user defined character classes. */
#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
# include <wchar.h>
# include <wctype.h>
#endif

/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */

#if defined _LIBC || !defined __GNU_LIBRARY__


# if defined STDC_HEADERS || !defined isascii
# define ISASCII(c) 1
# else
# define ISASCII(c) isascii(c)
# endif

# ifdef isblank
# define ISBLANK(c) (ISASCII (c) && isblank (c))
# else
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
# endif
# ifdef isgraph
# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
# else
# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
# endif

# define ISPRINT(c) (ISASCII (c) && isprint (c))
# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
# define ISALNUM(c) (ISASCII (c) && isalnum (c))
# define ISALPHA(c) (ISASCII (c) && isalpha (c))
# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
# define ISLOWER(c) (ISASCII (c) && islower (c))
# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
# define ISSPACE(c) (ISASCII (c) && isspace (c))
# define ISUPPER(c) (ISASCII (c) && isupper (c))
# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))

# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))

# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
/* The GNU C library provides support for user-defined character classes
and the functions from ISO C amendement 1. */
# ifdef CHARCLASS_NAME_MAX
# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
# else
/* This shouldn't happen but some implementation might still have this
problem. Use a reasonable default value. */
# define CHAR_CLASS_MAX_LENGTH 256
# endif

# ifdef _LIBC
# define IS_CHAR_CLASS(string) __wctype (string)
# else
# define IS_CHAR_CLASS(string) wctype (string)
# endif
# else
# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */

# define IS_CHAR_CLASS(string) \
(STREQ (string, "alpha") || STREQ (string, "upper") \
|| STREQ (string, "lower") || STREQ (string, "digit") \
|| STREQ (string, "alnum") || STREQ (string, "xdigit") \
|| STREQ (string, "space") || STREQ (string, "print") \
|| STREQ (string, "punct") || STREQ (string, "graph") \
|| STREQ (string, "cntrl") || STREQ (string, "blank"))
# endif

/* Avoid depending on library functions or files
whose names are inconsistent. */

# if !defined _LIBC && !defined getenv
extern char *getenv ();
# endif

# ifndef errno
extern int errno;
# endif

/* This function doesn't exist on most systems. */

# if !defined HAVE___STRCHRNUL && !defined _LIBC
static char *
__strchrnul (s, c)
const char *s;
int c;
{
char *result = strchr (s, c);
if (result == NULL)
result = strchr (s, '\0');
return result;
}
# endif

# ifndef internal_function
/* Inside GNU libc we mark some function in a special way. In other
environments simply ignore the marking. */
# define internal_function
# endif

/* Match STRING against the filename pattern PATTERN, returning zero if
it matches, nonzero if not. */
static int internal_fnmatch __P ((const char *pattern, const char *string,
int no_leading_period, int flags))
internal_function;
static int
internal_function
internal_fnmatch (pattern, string, no_leading_period, flags)
const char *pattern;
const char *string;
int no_leading_period;
int flags;
{
register const char *p = pattern, *n = string;
register unsigned char c;

/* Note that this evaluates C many times. */
# ifdef _LIBC
# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
# else
# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
# endif

while ((c = *p++) != '\0')
{
c = FOLD (c);

switch (c)
{
case '?':
if (*n == '\0')
return FNM_NOMATCH;
else if (*n == '/' && (flags & FNM_FILE_NAME))
return FNM_NOMATCH;
else if (*n == '.' && no_leading_period
&& (n == string
|| (n[-1] == '/' && (flags & FNM_FILE_NAME))))
return FNM_NOMATCH;
break;

case '\\':
if (!(flags & FNM_NOESCAPE))
{
c = *p++;
if (c == '\0')
/* Trailing \ loses. */
return FNM_NOMATCH;
c = FOLD (c);
}
if (FOLD ((unsigned char) *n) != c)
return FNM_NOMATCH;
break;

case '*':
if (*n == '.' && no_leading_period
&& (n == string
|| (n[-1] == '/' && (flags & FNM_FILE_NAME))))
return FNM_NOMATCH;

for (c = *p++; c == '?' || c == '*'; c = *p++)
{
if (*n == '/' && (flags & FNM_FILE_NAME))
/* A slash does not match a wildcard under FNM_FILE_NAME. */
return FNM_NOMATCH;
else if (c == '?')
{
/* A ? needs to match one character. */
if (*n == '\0')
/* There isn't another character; no match. */
return FNM_NOMATCH;
else
/* One character of the string is consumed in matching
this ? wildcard, so *??? won't match if there are
less than three characters. */
++n;
}
}

if (c == '\0')
/* The wildcard(s) is/are the last element of the pattern.
If the name is a file name and contains another slash
this does mean it cannot match. */
return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL
? FNM_NOMATCH : 0);
else
{
const char *endp;

endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0');

if (c == '[')
{
int flags2 = ((flags & FNM_FILE_NAME)
? flags : (flags & ~FNM_PERIOD));

for (--p; n < endp; ++n)
if (internal_fnmatch (p, n,
(no_leading_period
&& (n == string
|| (n[-1] == '/'
&& (flags
& FNM_FILE_NAME)))),
flags2)
== 0)
return 0;
}
else if (c == '/' && (flags & FNM_FILE_NAME))
{
while (*n != '\0' && *n != '/')
++n;
if (*n == '/'
&& (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
flags) == 0))
return 0;
}
else
{
int flags2 = ((flags & FNM_FILE_NAME)
? flags : (flags & ~FNM_PERIOD));

if (c == '\\' && !(flags & FNM_NOESCAPE))
c = *p;
c = FOLD (c);
for (--p; n < endp; ++n)
if (FOLD ((unsigned char) *n) == c
&& (internal_fnmatch (p, n,
(no_leading_period
&& (n == string
|| (n[-1] == '/'
&& (flags
& FNM_FILE_NAME)))),
flags2) == 0))
return 0;
}
}

/* If we come here no match is possible with the wildcard. */
return FNM_NOMATCH;

case '[':
{
/* Nonzero if the sense of the character class is inverted. */
static int posixly_correct;
register int not;
char cold;

if (posixly_correct == 0)
posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;

if (*n == '\0')
return FNM_NOMATCH;

if (*n == '.' && no_leading_period && (n == string
|| (n[-1] == '/'
&& (flags
& FNM_FILE_NAME))))
return FNM_NOMATCH;

if (*n == '/' && (flags & FNM_FILE_NAME))
/* `/' cannot be matched. */
return FNM_NOMATCH;

not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
if (not)
++p;

c = *p++;
for (;;)
{
unsigned char fn = FOLD ((unsigned char) *n);

if (!(flags & FNM_NOESCAPE) && c == '\\')
{
if (*p == '\0')
return FNM_NOMATCH;
c = FOLD ((unsigned char) *p);
++p;

if (c == fn)
goto matched;
}
else if (c == '[' && *p == ':')
{
/* Leave room for the null. */
char str[CHAR_CLASS_MAX_LENGTH + 1];
size_t c1 = 0;
# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
wctype_t wt;
# endif
const char *startp = p;

for (;;)
{
if (c1 == CHAR_CLASS_MAX_LENGTH)
/* The name is too long and therefore the pattern
is ill-formed. */
return FNM_NOMATCH;

c = *++p;
if (c == ':' && p[1] == ']')
{
p += 2;
break;
}
if (c < 'a' || c >= 'z')
{
/* This cannot possibly be a character class name.
Match it as a normal range. */
p = startp;
c = '[';
goto normal_bracket;
}
str[c1++] = c;
}
str[c1] = '\0';

# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
wt = IS_CHAR_CLASS (str);
if (wt == 0)
/* Invalid character class name. */
return FNM_NOMATCH;

if (__iswctype (__btowc ((unsigned char) *n), wt))
goto matched;
# else
if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n))
|| (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n))
|| (STREQ (str, "blank") && ISBLANK ((unsigned char) *n))
|| (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n))
|| (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n))
|| (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n))
|| (STREQ (str, "lower") && ISLOWER ((unsigned char) *n))
|| (STREQ (str, "print") && ISPRINT ((unsigned char) *n))
|| (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n))
|| (STREQ (str, "space") && ISSPACE ((unsigned char) *n))
|| (STREQ (str, "upper") && ISUPPER ((unsigned char) *n))
|| (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n)))
goto matched;
# endif
}
else if (c == '\0')
/* [ (unterminated) loses. */
return FNM_NOMATCH;
else
{
normal_bracket:
if (FOLD (c) == fn)
goto matched;

cold = c;
c = *p++;

if (c == '-' && *p != ']')
{
/* It is a range. */
unsigned char cend = *p++;
if (!(flags & FNM_NOESCAPE) && cend == '\\')
cend = *p++;
if (cend == '\0')
return FNM_NOMATCH;

if (cold <= fn && fn <= FOLD (cend))
goto matched;

c = *p++;
}
}

if (c == ']')
break;
}

if (!not)
return FNM_NOMATCH;
break;

matched:
/* Skip the rest of the [...] that already matched. */
while (c != ']')
{
if (c == '\0')
/* [... (unterminated) loses. */
return FNM_NOMATCH;

c = *p++;
if (!(flags & FNM_NOESCAPE) && c == '\\')
{
if (*p == '\0')
return FNM_NOMATCH;
/* XXX 1003.2d11 is unclear if this is right. */
++p;
}
else if (c == '[' && *p == ':')
{
do
if (*++p == '\0')
return FNM_NOMATCH;
while (*p != ':' || p[1] == ']');
p += 2;
c = *p;
}
}
if (not)
return FNM_NOMATCH;
}
break;

default:
if (c != FOLD ((unsigned char) *n))
return FNM_NOMATCH;
}

++n;
}

if (*n == '\0')
return 0;

if ((flags & FNM_LEADING_DIR) && *n == '/')
/* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
return 0;

return FNM_NOMATCH;

# undef FOLD
}


int
fnmatch (pattern, string, flags)
const char *pattern;
const char *string;
int flags;
{
return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
}

#endif /* _LIBC or not __GNU_LIBRARY__. */

84
compat/fnmatch.h

@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
This file is part of the GNU C Library.

The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */

#ifndef _FNMATCH_H
#define _FNMATCH_H 1

#ifdef __cplusplus
extern "C" {
#endif

#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
# if !defined __GLIBC__ || !defined __P
# undef __P
# define __P(protos) protos
# endif
#else /* Not C++ or ANSI C. */
# undef __P
# define __P(protos) ()
/* We can get away without defining `const' here only because in this file
it is used only inside the prototype for `fnmatch', which is elided in
non-ANSI C where `const' is problematical. */
#endif /* C++ or ANSI C. */

#ifndef const
# if (defined __STDC__ && __STDC__) || defined __cplusplus
# define __const const
# else
# define __const
# endif
#endif

/* We #undef these before defining them because some losing systems
(HP-UX A.08.07 for example) define these in <unistd.h>. */
#undef FNM_PATHNAME
#undef FNM_NOESCAPE
#undef FNM_PERIOD

/* Bits set in the FLAGS argument to `fnmatch'. */
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */

#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
#endif

/* Value returned by `fnmatch' if STRING does not match PATTERN. */
#define FNM_NOMATCH 1

/* This value is returned if the implementation does not support
`fnmatch'. Since this is not the case here it will never be
returned but the conformance test suites still require the symbol
to be defined. */
#ifdef _XOPEN_SOURCE
# define FNM_NOSYS (-1)
#endif

/* Match NAME against the filename pattern PATTERN,
returning zero if it matches, FNM_NOMATCH if not. */
extern int fnmatch __P ((__const char *__pattern, __const char *__name,
int __flags));

#ifdef __cplusplus
}
#endif

#endif /* fnmatch.h */

1019
compat/mingw.c

File diff suppressed because it is too large Load Diff

211
compat/mingw.h

@ -0,0 +1,211 @@ @@ -0,0 +1,211 @@
#include <winsock2.h>

/*
* things that are not available in header files
*/

typedef int pid_t;
#define hstrerror strerror

#define S_IFLNK 0120000 /* Symbolic link */
#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(x) 0
#define S_IRGRP 0
#define S_IWGRP 0
#define S_IXGRP 0
#define S_ISGID 0
#define S_IROTH 0
#define S_IXOTH 0

#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */
#define WEXITSTATUS(x) ((x) & 0xff)
#define WIFSIGNALED(x) ((unsigned)(x) > 259)

#define SIGKILL 0
#define SIGCHLD 0
#define SIGPIPE 0
#define SIGHUP 0
#define SIGQUIT 0
#define SIGALRM 100

#define F_GETFD 1
#define F_SETFD 2
#define FD_CLOEXEC 0x1

struct passwd {
char *pw_name;
char *pw_gecos;
char *pw_dir;
};

struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
#define POLLIN 1
#define POLLHUP 2

typedef void (__cdecl *sig_handler_t)(int);
struct sigaction {
sig_handler_t sa_handler;
unsigned sa_flags;
};
#define sigemptyset(x) (void)0
#define SA_RESTART 0

struct itimerval {
struct timeval it_value, it_interval;
};
#define ITIMER_REAL 0

/*
* trivial stubs
*/

static inline int readlink(const char *path, char *buf, size_t bufsiz)
{ errno = ENOSYS; return -1; }
static inline int symlink(const char *oldpath, const char *newpath)
{ errno = ENOSYS; return -1; }
static inline int link(const char *oldpath, const char *newpath)
{ errno = ENOSYS; return -1; }
static inline int fchmod(int fildes, mode_t mode)
{ errno = ENOSYS; return -1; }
static inline int fork(void)
{ errno = ENOSYS; return -1; }
static inline unsigned int alarm(unsigned int seconds)
{ return 0; }
static inline int fsync(int fd)
{ return 0; }
static inline int getppid(void)
{ return 1; }
static inline void sync(void)
{}
static inline int getuid()
{ return 1; }
static inline struct passwd *getpwnam(const char *name)
{ return NULL; }
static inline int fcntl(int fd, int cmd, long arg)
{
if (cmd == F_GETFD || cmd == F_SETFD)
return 0;
errno = EINVAL;
return -1;
}

/*
* simple adaptors
*/

static inline int mingw_mkdir(const char *path, int mode)
{
return mkdir(path);
}
#define mkdir mingw_mkdir

static inline int mingw_unlink(const char *pathname)
{
/* read-only files cannot be removed */
chmod(pathname, 0666);
return unlink(pathname);
}
#define unlink mingw_unlink

static inline int waitpid(pid_t pid, unsigned *status, unsigned options)
{
if (options == 0)
return _cwait(status, pid, 0);
errno = EINVAL;
return -1;
}

/*
* implementations of missing functions
*/

int pipe(int filedes[2]);
unsigned int sleep (unsigned int seconds);
int mkstemp(char *template);
int gettimeofday(struct timeval *tv, void *tz);
int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
struct tm *gmtime_r(const time_t *timep, struct tm *result);
struct tm *localtime_r(const time_t *timep, struct tm *result);
int getpagesize(void); /* defined in MinGW's libgcc.a */
struct passwd *getpwuid(int uid);
int setitimer(int type, struct itimerval *in, struct itimerval *out);
int sigaction(int sig, struct sigaction *in, struct sigaction *out);

/*
* replacements of existing functions
*/

int mingw_open (const char *filename, int oflags, ...);
#define open mingw_open

char *mingw_getcwd(char *pointer, int len);
#define getcwd mingw_getcwd

char *mingw_getenv(const char *name);
#define getenv mingw_getenv

struct hostent *mingw_gethostbyname(const char *host);
#define gethostbyname mingw_gethostbyname

int mingw_socket(int domain, int type, int protocol);
#define socket mingw_socket

int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
#define connect mingw_connect

int mingw_rename(const char*, const char*);
#define rename mingw_rename

/* Use mingw_lstat() instead of lstat()/stat() and
* mingw_fstat() instead of fstat() on Windows.
* struct stat is redefined because it lacks the st_blocks member.
*/
struct mingw_stat {
unsigned st_mode;
time_t st_mtime, st_atime, st_ctime;
unsigned st_dev, st_ino, st_uid, st_gid;
size_t st_size;
size_t st_blocks;
};
int mingw_lstat(const char *file_name, struct mingw_stat *buf);
int mingw_fstat(int fd, struct mingw_stat *buf);
#define fstat mingw_fstat
#define lstat mingw_lstat
#define stat mingw_stat
static inline int mingw_stat(const char *file_name, struct mingw_stat *buf)
{ return mingw_lstat(file_name, buf); }

int mingw_utime(const char *file_name, const struct utimbuf *times);
#define utime mingw_utime

pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env);
void mingw_execvp(const char *cmd, char *const *argv);
#define execvp mingw_execvp

static inline unsigned int git_ntohl(unsigned int x)
{ return (unsigned int)ntohl(x); }
#define ntohl git_ntohl

sig_handler_t mingw_signal(int sig, sig_handler_t handler);
#define signal mingw_signal

/*
* git specific compatibility
*/

#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
#define is_dir_sep(c) ((c) == '/' || (c) == '\\')
#define PATH_SEP ';'
#define PRIuMAX "I64u"

/*
* helpers
*/

char **copy_environ(void);
void free_environ(char **env);
char **env_setenv(char **env, const char *name);

4927
compat/regex.c

File diff suppressed because it is too large Load Diff

490
compat/regex.h

@ -0,0 +1,490 @@ @@ -0,0 +1,490 @@
/* Definitions for data structures and routines for the regular
expression library, version 0.12.

Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

#ifndef __REGEXP_LIBRARY_H__
#define __REGEXP_LIBRARY_H__

/* POSIX says that <sys/types.h> must be included (by the caller) before
<regex.h>. */

#ifdef VMS
/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
should be there. */
#include <stddef.h>
#endif


/* The following bits are used to determine the regexp syntax we
recognize. The set/not-set meanings are chosen so that Emacs syntax
remains the value 0. The bits are given in alphabetical order, and
the definitions shifted by one from the previous bit; thus, when we
add or remove a bit, only one other definition need change. */
typedef unsigned reg_syntax_t;

/* If this bit is not set, then \ inside a bracket expression is literal.
If set, then such a \ quotes the following character. */
#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)

/* If this bit is not set, then + and ? are operators, and \+ and \? are
literals.
If set, then \+ and \? are operators and + and ? are literals. */
#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)

/* If this bit is set, then character classes are supported. They are:
[:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
[:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
If not set, then character classes are not supported. */
#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)

/* If this bit is set, then ^ and $ are always anchors (outside bracket
expressions, of course).
If this bit is not set, then it depends:
^ is an anchor if it is at the beginning of a regular
expression or after an open-group or an alternation operator;
$ is an anchor if it is at the end of a regular expression, or
before a close-group or an alternation operator.

This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
POSIX draft 11.2 says that * etc. in leading positions is undefined.
We already implemented a previous draft which made those constructs
invalid, though, so we haven't changed the code back. */
#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)

/* If this bit is set, then special characters are always special
regardless of where they are in the pattern.
If this bit is not set, then special characters are special only in
some contexts; otherwise they are ordinary. Specifically,
* + ? and intervals are only special when not after the beginning,
open-group, or alternation operator. */
#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)

/* If this bit is set, then *, +, ?, and { cannot be first in an re or
immediately after an alternation or begin-group operator. */
#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)

/* If this bit is set, then . matches newline.
If not set, then it doesn't. */
#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)

/* If this bit is set, then . doesn't match NUL.
If not set, then it does. */
#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)

/* If this bit is set, nonmatching lists [^...] do not match newline.
If not set, they do. */
#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)

/* If this bit is set, either \{...\} or {...} defines an
interval, depending on RE_NO_BK_BRACES.
If not set, \{, \}, {, and } are literals. */
#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)

/* If this bit is set, +, ? and | aren't recognized as operators.
If not set, they are. */
#define RE_LIMITED_OPS (RE_INTERVALS << 1)

/* If this bit is set, newline is an alternation operator.
If not set, newline is literal. */
#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)

/* If this bit is set, then `{...}' defines an interval, and \{ and \}
are literals.
If not set, then `\{...\}' defines an interval. */
#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)

/* If this bit is set, (...) defines a group, and \( and \) are literals.
If not set, \(...\) defines a group, and ( and ) are literals. */
#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)

/* If this bit is set, then \<digit> matches <digit>.
If not set, then \<digit> is a back-reference. */
#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)

/* If this bit is set, then | is an alternation operator, and \| is literal.
If not set, then \| is an alternation operator, and | is literal. */
#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)

/* If this bit is set, then an ending range point collating higher
than the starting range point, as in [z-a], is invalid.
If not set, then when ending range point collates higher than the
starting range point, the range is ignored. */
#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)

/* If this bit is set, then an unmatched ) is ordinary.
If not set, then an unmatched ) is invalid. */
#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)

/* This global variable defines the particular regexp syntax to use (for
some interfaces). When a regexp is compiled, the syntax used is
stored in the pattern buffer, so changing this does not affect
already-compiled regexps. */
extern reg_syntax_t re_syntax_options;
/* Define combinations of the above bits for the standard possibilities.
(The [[[ comments delimit what gets put into the Texinfo file, so
don't delete them!) */
/* [[[begin syntaxes]]] */
#define RE_SYNTAX_EMACS 0

#define RE_SYNTAX_AWK \
(RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
| RE_NO_BK_PARENS | RE_NO_BK_REFS \
| RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
| RE_UNMATCHED_RIGHT_PAREN_ORD)

#define RE_SYNTAX_POSIX_AWK \
(RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)

#define RE_SYNTAX_GREP \
(RE_BK_PLUS_QM | RE_CHAR_CLASSES \
| RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
| RE_NEWLINE_ALT)

#define RE_SYNTAX_EGREP \
(RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
| RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
| RE_NEWLINE_ALT | RE_NO_BK_PARENS \
| RE_NO_BK_VBAR)

#define RE_SYNTAX_POSIX_EGREP \
(RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)

/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC

#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC

/* Syntax bits common to both basic and extended POSIX regex syntax. */
#define _RE_SYNTAX_POSIX_COMMON \
(RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
| RE_INTERVALS | RE_NO_EMPTY_RANGES)

#define RE_SYNTAX_POSIX_BASIC \
(_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)

/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
isn't minimal, since other operators, such as \`, aren't disabled. */
#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
(_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)

#define RE_SYNTAX_POSIX_EXTENDED \
(_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
| RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
| RE_NO_BK_PARENS | RE_NO_BK_VBAR \
| RE_UNMATCHED_RIGHT_PAREN_ORD)

/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
(_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
| RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
| RE_NO_BK_PARENS | RE_NO_BK_REFS \
| RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
/* [[[end syntaxes]]] */
/* Maximum number of duplicates an interval can allow. Some systems
(erroneously) define this in other header files, but we want our
value, so remove any previous define. */
#ifdef RE_DUP_MAX
#undef RE_DUP_MAX
#endif
#define RE_DUP_MAX ((1 << 15) - 1)


/* POSIX `cflags' bits (i.e., information for `regcomp'). */

/* If this bit is set, then use extended regular expression syntax.
If not set, then use basic regular expression syntax. */
#define REG_EXTENDED 1

/* If this bit is set, then ignore case when matching.
If not set, then case is significant. */
#define REG_ICASE (REG_EXTENDED << 1)

/* If this bit is set, then anchors do not match at newline
characters in the string.
If not set, then anchors do match at newlines. */
#define REG_NEWLINE (REG_ICASE << 1)

/* If this bit is set, then report only success or fail in regexec.
If not set, then returns differ between not matching and errors. */
#define REG_NOSUB (REG_NEWLINE << 1)


/* POSIX `eflags' bits (i.e., information for regexec). */

/* If this bit is set, then the beginning-of-line operator doesn't match
the beginning of the string (presumably because it's not the
beginning of a line).
If not set, then the beginning-of-line operator does match the
beginning of the string. */
#define REG_NOTBOL 1

/* Like REG_NOTBOL, except for the end-of-line. */
#define REG_NOTEOL (1 << 1)


/* If any error codes are removed, changed, or added, update the
`re_error_msg' table in regex.c. */
typedef enum
{
REG_NOERROR = 0, /* Success. */
REG_NOMATCH, /* Didn't find a match (for regexec). */

/* POSIX regcomp return error codes. (In the order listed in the
standard.) */
REG_BADPAT, /* Invalid pattern. */
REG_ECOLLATE, /* Not implemented. */
REG_ECTYPE, /* Invalid character class name. */
REG_EESCAPE, /* Trailing backslash. */
REG_ESUBREG, /* Invalid back reference. */
REG_EBRACK, /* Unmatched left bracket. */
REG_EPAREN, /* Parenthesis imbalance. */
REG_EBRACE, /* Unmatched \{. */
REG_BADBR, /* Invalid contents of \{\}. */
REG_ERANGE, /* Invalid range end. */
REG_ESPACE, /* Ran out of memory. */
REG_BADRPT, /* No preceding re for repetition op. */

/* Error codes we've added. */
REG_EEND, /* Premature end. */
REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
} reg_errcode_t;
/* This data structure represents a compiled pattern. Before calling
the pattern compiler, the fields `buffer', `allocated', `fastmap',
`translate', and `no_sub' can be set. After the pattern has been
compiled, the `re_nsub' field is available. All other fields are
private to the regex routines. */

struct re_pattern_buffer
{
/* [[[begin pattern_buffer]]] */
/* Space that holds the compiled pattern. It is declared as
`unsigned char *' because its elements are
sometimes used as array indexes. */
unsigned char *buffer;

/* Number of bytes to which `buffer' points. */
unsigned long allocated;

/* Number of bytes actually used in `buffer'. */
unsigned long used;

/* Syntax setting with which the pattern was compiled. */
reg_syntax_t syntax;

/* Pointer to a fastmap, if any, otherwise zero. re_search uses
the fastmap, if there is one, to skip over impossible
starting points for matches. */
char *fastmap;

/* Either a translate table to apply to all characters before
comparing them, or zero for no translation. The translation
is applied to a pattern when it is compiled and to a string
when it is matched. */
char *translate;

/* Number of subexpressions found by the compiler. */
size_t re_nsub;

/* Zero if this pattern cannot match the empty string, one else.
Well, in truth it's used only in `re_search_2', to see
whether or not we should use the fastmap, so we don't set
this absolutely perfectly; see `re_compile_fastmap' (the
`duplicate' case). */
unsigned can_be_null : 1;

/* If REGS_UNALLOCATED, allocate space in the `regs' structure
for `max (RE_NREGS, re_nsub + 1)' groups.
If REGS_REALLOCATE, reallocate space if necessary.
If REGS_FIXED, use what's there. */
#define REGS_UNALLOCATED 0
#define REGS_REALLOCATE 1
#define REGS_FIXED 2
unsigned regs_allocated : 2;

/* Set to zero when `regex_compile' compiles a pattern; set to one
by `re_compile_fastmap' if it updates the fastmap. */
unsigned fastmap_accurate : 1;

/* If set, `re_match_2' does not return information about
subexpressions. */
unsigned no_sub : 1;

/* If set, a beginning-of-line anchor doesn't match at the
beginning of the string. */
unsigned not_bol : 1;

/* Similarly for an end-of-line anchor. */
unsigned not_eol : 1;

/* If true, an anchor at a newline matches. */
unsigned newline_anchor : 1;

/* [[[end pattern_buffer]]] */
};

typedef struct re_pattern_buffer regex_t;


/* search.c (search_buffer) in Emacs needs this one opcode value. It is
defined both in `regex.c' and here. */
#define RE_EXACTN_VALUE 1
/* Type for byte offsets within the string. POSIX mandates this. */
typedef int regoff_t;


/* This is the structure we store register match data in. See
regex.texinfo for a full description of what registers match. */
struct re_registers
{
unsigned num_regs;
regoff_t *start;
regoff_t *end;
};


/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
`re_match_2' returns information about at least this many registers
the first time a `regs' structure is passed. */
#ifndef RE_NREGS
#define RE_NREGS 30
#endif


/* POSIX specification for registers. Aside from the different names than
`re_registers', POSIX uses an array of structures, instead of a
structure of arrays. */
typedef struct
{
regoff_t rm_so; /* Byte offset from string's start to substring's start. */
regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
} regmatch_t;
/* Declarations for routines. */

/* To avoid duplicating every routine declaration -- once with a
prototype (if we are ANSI), and once without (if we aren't) -- we
use the following macro to declare argument types. This
unfortunately clutters up the declarations a bit, but I think it's
worth it. */

#if __STDC__

#define _RE_ARGS(args) args

#else /* not __STDC__ */

#define _RE_ARGS(args) ()

#endif /* not __STDC__ */

/* Sets the current default syntax to SYNTAX, and return the old syntax.
You can also simply assign to the `re_syntax_options' variable. */
extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));

/* Compile the regular expression PATTERN, with length LENGTH
and syntax given by the global `re_syntax_options', into the buffer
BUFFER. Return NULL if successful, and an error string if not. */
extern const char *re_compile_pattern
_RE_ARGS ((const char *pattern, int length,
struct re_pattern_buffer *buffer));


/* Compile a fastmap for the compiled pattern in BUFFER; used to
accelerate searches. Return 0 if successful and -2 if was an
internal error. */
extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));


/* Search in the string STRING (with length LENGTH) for the pattern
compiled into BUFFER. Start searching at position START, for RANGE
characters. Return the starting position of the match, -1 for no
match, or -2 for an internal error. Also return register
information in REGS (if REGS and BUFFER->no_sub are nonzero). */
extern int re_search
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
int length, int start, int range, struct re_registers *regs));


/* Like `re_search', but search in the concatenation of STRING1 and
STRING2. Also, stop searching at index START + STOP. */
extern int re_search_2
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
int length1, const char *string2, int length2,
int start, int range, struct re_registers *regs, int stop));


/* Like `re_search', but return how many characters in STRING the regexp
in BUFFER matched, starting at position START. */
extern int re_match
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
int length, int start, struct re_registers *regs));


/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
extern int re_match_2
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
int length1, const char *string2, int length2,
int start, struct re_registers *regs, int stop));


/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
ENDS. Subsequent matches using BUFFER and REGS will use this memory
for recording register information. STARTS and ENDS must be
allocated with malloc, and must each be at least `NUM_REGS * sizeof
(regoff_t)' bytes long.

If NUM_REGS == 0, then subsequent matches should allocate their own
register data.

Unless this function is called, the first search or match using
PATTERN_BUFFER will allocate its own register data, without
freeing the old data. */
extern void re_set_registers
_RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
unsigned num_regs, regoff_t *starts, regoff_t *ends));

/* 4.2 bsd compatibility. */
extern char *re_comp _RE_ARGS ((const char *));
extern int re_exec _RE_ARGS ((const char *));

/* POSIX compatibility. */
extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
extern int regexec
_RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
regmatch_t pmatch[], int eflags));
extern size_t regerror
_RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
size_t errbuf_size));
extern void regfree _RE_ARGS ((regex_t *preg));

#endif /* not __REGEXP_LIBRARY_H__ */
/*
Local variables:
make-backup-files: t
version-control: t
trim-versions-without-asking: nil
End:
*/

19
compat/snprintf.c

@ -1,12 +1,25 @@ @@ -1,12 +1,25 @@
#include "../git-compat-util.h"

/*
* The size parameter specifies the available space, i.e. includes
* the trailing NUL byte; but Windows's vsnprintf expects the
* number of characters to write without the trailing NUL.
*/
#ifndef SNPRINTF_SIZE_CORR
#define SNPRINTF_SIZE_CORR 0
#endif

#undef vsnprintf
int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
{
char *s;
int ret;
int ret = -1;

ret = vsnprintf(str, maxsize, format, ap);
if (maxsize > 0) {
ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
/* Windows does not NUL-terminate if result fills buffer */
str[maxsize-1] = 0;
}
if (ret != -1)
return ret;

@ -20,7 +33,7 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) @@ -20,7 +33,7 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
if (! str)
break;
s = str;
ret = vsnprintf(str, maxsize, format, ap);
ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
}
free(s);
return ret;

2
connect.c

@ -529,7 +529,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig, @@ -529,7 +529,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
end = host;

path = strchr(end, c);
if (path) {
if (path && !has_dos_drive_prefix(end)) {
if (c == ':') {
protocol = PROTO_SSH;
*path++ = '\0';

13
date.c

@ -6,7 +6,10 @@ @@ -6,7 +6,10 @@

#include "cache.h"

static time_t my_mktime(struct tm *tm)
/*
* This is like mktime, but without normalization of tm_wday and tm_yday.
*/
time_t tm_to_time_t(const struct tm *tm)
{
static const int mdays[] = {
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
@ -67,7 +70,7 @@ static int local_tzoffset(unsigned long time) @@ -67,7 +70,7 @@ static int local_tzoffset(unsigned long time)

t = time;
localtime_r(&t, &tm);
t_local = my_mktime(&tm);
t_local = tm_to_time_t(&tm);

if (t_local < t) {
eastwest = -1;
@ -322,7 +325,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now, @@ -322,7 +325,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,
if (!now_tm)
return 1;

specified = my_mktime(r);
specified = tm_to_time_t(r);

/* Be it commit time or author time, it does not make
* sense to specify timestamp way into the future. Make
@ -572,7 +575,7 @@ int parse_date(const char *date, char *result, int maxlen) @@ -572,7 +575,7 @@ int parse_date(const char *date, char *result, int maxlen)
}

/* mktime uses local timezone */
then = my_mktime(&tm);
then = tm_to_time_t(&tm);
if (offset == -1)
offset = (then - mktime(&tm)) / 60;

@ -611,7 +614,7 @@ void datestamp(char *buf, int bufsize) @@ -611,7 +614,7 @@ void datestamp(char *buf, int bufsize)

time(&now);

offset = my_mktime(localtime(&now)) - now;
offset = tm_to_time_t(localtime(&now)) - now;
offset /= 60;

date_string(now, offset, buf, bufsize);

41
exec_cmd.c

@ -4,9 +4,42 @@ @@ -4,9 +4,42 @@
#define MAX_ARGS 32

extern char **environ;
static const char *builtin_exec_path = GIT_EXEC_PATH;
static const char *argv_exec_path;

static const char *builtin_exec_path(void)
{
#ifndef __MINGW32__
return GIT_EXEC_PATH;
#else
int len;
char *p, *q, *sl;
static char *ep;
if (ep)
return ep;

len = strlen(_pgmptr);
if (len < 2)
return ep = ".";

p = ep = xmalloc(len+1);
q = _pgmptr;
sl = NULL;
/* copy program name, turn '\\' into '/', skip last part */
while ((*p = *q)) {
if (*q == '\\' || *q == '/') {
*p = '/';
sl = p;
}
p++, q++;
}
if (sl)
*sl = '\0';
else
ep[0] = '.', ep[1] = '\0';
return ep;
#endif
}

void git_set_argv_exec_path(const char *exec_path)
{
argv_exec_path = exec_path;
@ -26,7 +59,7 @@ const char *git_exec_path(void) @@ -26,7 +59,7 @@ const char *git_exec_path(void)
return env;
}

return builtin_exec_path;
return builtin_exec_path();
}

static void add_path(struct strbuf *out, const char *path)
@ -37,7 +70,7 @@ static void add_path(struct strbuf *out, const char *path) @@ -37,7 +70,7 @@ static void add_path(struct strbuf *out, const char *path)
else
strbuf_addstr(out, make_absolute_path(path));

strbuf_addch(out, ':');
strbuf_addch(out, PATH_SEP);
}
}

@ -50,7 +83,7 @@ void setup_path(const char *cmd_path) @@ -50,7 +83,7 @@ void setup_path(const char *cmd_path)

add_path(&new_path, argv_exec_path);
add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT));
add_path(&new_path, builtin_exec_path);
add_path(&new_path, builtin_exec_path());
add_path(&new_path, cmd_path);

if (old_path)

36
git-compat-util.h

@ -63,17 +63,18 @@ @@ -63,17 +63,18 @@
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <fnmatch.h>
#include <assert.h>
#include <regex.h>
#include <utime.h>
#ifndef __MINGW32__
#include <sys/wait.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <utime.h>
#ifndef NO_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <assert.h>
#include <regex.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
@ -89,6 +90,10 @@ @@ -89,6 +90,10 @@
#include <grp.h>
#define _ALL_SOURCE 1
#endif
#else /* __MINGW32__ */
/* pull in Windows compatibility stuff */
#include "compat/mingw.h"
#endif /* __MINGW32__ */

#ifndef NO_ICONV
#include <iconv.h>
@ -105,6 +110,22 @@ @@ -105,6 +110,22 @@
#define PRIuMAX "llu"
#endif

#ifndef PATH_SEP
#define PATH_SEP ':'
#endif

#ifndef STRIP_EXTENSION
#define STRIP_EXTENSION ""
#endif

#ifndef has_dos_drive_prefix
#define has_dos_drive_prefix(path) 0
#endif

#ifndef is_dir_sep
#define is_dir_sep(c) ((c) == '/')
#endif

#ifdef __GNUC__
#define NORETURN __attribute__((__noreturn__))
#else
@ -126,6 +147,7 @@ extern void set_error_routine(void (*routine)(const char *err, va_list params)); @@ -126,6 +147,7 @@ extern void set_error_routine(void (*routine)(const char *err, va_list params));
extern void set_warn_routine(void (*routine)(const char *warn, va_list params));

extern int prefixcmp(const char *str, const char *prefix);
extern time_t tm_to_time_t(const struct tm *tm);

#ifdef NO_MMAP

@ -163,6 +185,12 @@ extern int git_munmap(void *start, size_t length); @@ -163,6 +185,12 @@ extern int git_munmap(void *start, size_t length);
#define pread git_pread
extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
#endif
/*
* Forward decl that will remind us if its twin in cache.h changes.
* This function is used in compat/pread.c. But we can't include
* cache.h there.
*/
extern ssize_t read_in_full(int fd, void *buf, size_t count);

#ifdef NO_SETENV
#define setenv gitsetenv

13
git-sh-setup.sh

@ -142,3 +142,16 @@ then @@ -142,3 +142,16 @@ then
}
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
fi

# Fix some commands on Windows
case $(uname -s) in
*MINGW*)
# Windows has its own (incompatible) sort and find
sort () {
/usr/bin/sort "$@"
}
find () {
/usr/bin/find "$@"
}
;;
esac

19
git.c

@ -369,6 +369,16 @@ static void handle_internal_command(int argc, const char **argv) @@ -369,6 +369,16 @@ static void handle_internal_command(int argc, const char **argv)
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
};
int i;
static const char ext[] = STRIP_EXTENSION;

if (sizeof(ext) > 1) {
i = strlen(argv[0]) - strlen(ext);
if (i > 0 && !strcmp(argv[0] + i, ext)) {
char *argv0 = strdup(argv[0]);
argv[0] = cmd = argv0;
argv0[i] = '\0';
}
}

/* Turn "git cmd --help" into "git help cmd" */
if (argc > 1 && !strcmp(argv[1], "--help")) {
@ -416,8 +426,8 @@ static void execv_dashed_external(const char **argv) @@ -416,8 +426,8 @@ static void execv_dashed_external(const char **argv)

int main(int argc, const char **argv)
{
const char *cmd = argv[0] ? argv[0] : "git-help";
char *slash = strrchr(cmd, '/');
const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help";
char *slash = (char *)cmd + strlen(cmd);
const char *cmd_path = NULL;
int done_alias = 0;

@ -426,7 +436,10 @@ int main(int argc, const char **argv) @@ -426,7 +436,10 @@ int main(int argc, const char **argv)
* name, and the dirname as the default exec_path
* if we don't have anything better.
*/
if (slash) {
do
--slash;
while (cmd <= slash && !is_dir_sep(*slash));
if (cmd <= slash) {
*slash++ = 0;
cmd_path = cmd;
cmd = slash;

33
help.c

@ -391,6 +391,32 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest) @@ -391,6 +391,32 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest)
}
}

static int is_executable(const char *name)
{
struct stat st;

if (stat(name, &st) || /* stat, not lstat */
!S_ISREG(st.st_mode))
return 0;

#ifdef __MINGW32__
/* cannot trust the executable bit, peek into the file instead */
char buf[3] = { 0 };
int n;
int fd = open(name, O_RDONLY);
st.st_mode &= ~S_IXUSR;
if (fd >= 0) {
n = read(fd, buf, 2);
if (n == 2)
/* DOS executables start with "MZ" */
if (!strcmp(buf, "#!") || !strcmp(buf, "MZ"))
st.st_mode |= S_IXUSR;
close(fd);
}
#endif
return st.st_mode & S_IXUSR;
}

static unsigned int list_commands_in_dir(struct cmdnames *cmds,
const char *path)
{
@ -404,15 +430,12 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds, @@ -404,15 +430,12 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,
return 0;

while ((de = readdir(dir)) != NULL) {
struct stat st;
int entlen;

if (prefixcmp(de->d_name, prefix))
continue;

if (stat(de->d_name, &st) || /* stat, not lstat */
!S_ISREG(st.st_mode) ||
!(st.st_mode & S_IXUSR))
if (!is_executable(de->d_name))
continue;

entlen = strlen(de->d_name) - prefix_len;
@ -447,7 +470,7 @@ static unsigned int load_command_list(void) @@ -447,7 +470,7 @@ static unsigned int load_command_list(void)

path = paths = xstrdup(env_path);
while (1) {
if ((colon = strchr(path, ':')))
if ((colon = strchr(path, PATH_SEP)))
*colon = 0;

len = list_commands_in_dir(&other_cmds, path);

40
pager.c

@ -1,12 +1,13 @@ @@ -1,12 +1,13 @@
#include "cache.h"

/*
* This is split up from the rest of git so that we might do
* something different on Windows, for example.
* This is split up from the rest of git so that we can do
* something different on Windows.
*/

static int spawned_pager;

#ifndef __MINGW32__
static void run_pager(const char *pager)
{
/*
@ -22,11 +23,31 @@ static void run_pager(const char *pager) @@ -22,11 +23,31 @@ static void run_pager(const char *pager)
execlp(pager, pager, NULL);
execl("/bin/sh", "sh", "-c", pager, NULL);
}
#else
#include "run-command.h"

static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
static struct child_process pager_process = {
.argv = pager_argv,
.in = -1
};
static void wait_for_pager(void)
{
fflush(stdout);
fflush(stderr);
/* signal EOF to pager */
close(1);
close(2);
finish_command(&pager_process);
}
#endif

void setup_pager(void)
{
#ifndef __MINGW32__
pid_t pid;
int fd[2];
#endif
const char *pager = getenv("GIT_PAGER");

if (!isatty(1))
@ -45,6 +66,7 @@ void setup_pager(void) @@ -45,6 +66,7 @@ void setup_pager(void)

spawned_pager = 1; /* means we are emitting to terminal */

#ifndef __MINGW32__
if (pipe(fd) < 0)
return;
pid = fork();
@ -72,6 +94,20 @@ void setup_pager(void) @@ -72,6 +94,20 @@ void setup_pager(void)
run_pager(pager);
die("unable to execute pager '%s'", pager);
exit(255);
#else
/* spawn the pager */
pager_argv[2] = pager;
if (start_command(&pager_process))
return;

/* original process continues, but writes to the pipe */
dup2(pager_process.in, 1);
dup2(pager_process.in, 2);
close(pager_process.in);

/* this makes sure that the parent terminates after the pager */
atexit(wait_for_pager);
#endif
}

int pager_in_use(void)

126
run-command.c

@ -65,21 +65,8 @@ int start_command(struct child_process *cmd) @@ -65,21 +65,8 @@ int start_command(struct child_process *cmd)
cmd->err = fderr[0];
}

#ifndef __MINGW32__
cmd->pid = fork();
if (cmd->pid < 0) {
if (need_in)
close_pair(fdin);
else if (cmd->in)
close(cmd->in);
if (need_out)
close_pair(fdout);
else if (cmd->out)
close(cmd->out);
if (need_err)
close_pair(fderr);
return -ERR_RUN_COMMAND_FORK;
}

if (!cmd->pid) {
if (cmd->no_stdin)
dup_devnull(0);
@ -128,6 +115,88 @@ int start_command(struct child_process *cmd) @@ -128,6 +115,88 @@ int start_command(struct child_process *cmd)
}
die("exec %s failed.", cmd->argv[0]);
}
#else
int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */
const char *sargv0 = cmd->argv[0];
char **env = environ;
struct strbuf git_cmd;

if (cmd->no_stdin) {
s0 = dup(0);
dup_devnull(0);
} else if (need_in) {
s0 = dup(0);
dup2(fdin[0], 0);
} else if (cmd->in) {
s0 = dup(0);
dup2(cmd->in, 0);
}

if (cmd->no_stderr) {
s2 = dup(2);
dup_devnull(2);
} else if (need_err) {
s2 = dup(2);
dup2(fderr[1], 2);
}

if (cmd->no_stdout) {
s1 = dup(1);
dup_devnull(1);
} else if (cmd->stdout_to_stderr) {
s1 = dup(1);
dup2(2, 1);
} else if (need_out) {
s1 = dup(1);
dup2(fdout[1], 1);
} else if (cmd->out > 1) {
s1 = dup(1);
dup2(cmd->out, 1);
}

if (cmd->dir)
die("chdir in start_command() not implemented");
if (cmd->env) {
env = copy_environ();
for (; *cmd->env; cmd->env++)
env = env_setenv(env, *cmd->env);
}

if (cmd->git_cmd) {
strbuf_init(&git_cmd, 0);
strbuf_addf(&git_cmd, "git-%s", cmd->argv[0]);
cmd->argv[0] = git_cmd.buf;
}

cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);

if (cmd->env)
free_environ(env);
if (cmd->git_cmd)
strbuf_release(&git_cmd);

cmd->argv[0] = sargv0;
if (s0 >= 0)
dup2(s0, 0), close(s0);
if (s1 >= 0)
dup2(s1, 1), close(s1);
if (s2 >= 0)
dup2(s2, 2), close(s2);
#endif

if (cmd->pid < 0) {
if (need_in)
close_pair(fdin);
else if (cmd->in)
close(cmd->in);
if (need_out)
close_pair(fdout);
else if (cmd->out)
close(cmd->out);
if (need_err)
close_pair(fderr);
return -ERR_RUN_COMMAND_FORK;
}

if (need_in)
close(fdin[0]);
@ -219,13 +288,23 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const @@ -219,13 +288,23 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
return run_command(&cmd);
}

#ifdef __MINGW32__
static __stdcall unsigned run_thread(void *data)
{
struct async *async = data;
return async->proc(async->fd_for_proc, async->data);
}
#endif

int start_async(struct async *async)
{
int pipe_out[2];

if (pipe(pipe_out) < 0)
return error("cannot create pipe: %s", strerror(errno));
async->out = pipe_out[0];

#ifndef __MINGW32__
async->pid = fork();
if (async->pid < 0) {
error("fork (async) failed: %s", strerror(errno));
@ -236,16 +315,33 @@ int start_async(struct async *async) @@ -236,16 +315,33 @@ int start_async(struct async *async)
close(pipe_out[0]);
exit(!!async->proc(pipe_out[1], async->data));
}
async->out = pipe_out[0];
close(pipe_out[1]);
#else
async->fd_for_proc = pipe_out[1];
async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
if (!async->tid) {
error("cannot create thread: %s", strerror(errno));
close_pair(pipe_out);
return -1;
}
#endif
return 0;
}

int finish_async(struct async *async)
{
#ifndef __MINGW32__
int ret = 0;

if (wait_or_whine(async->pid))
ret = error("waitpid (async) failed");
#else
DWORD ret = 0;
if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0)
ret = error("waiting for thread failed: %lu", GetLastError());
else if (!GetExitCodeThread(async->tid, &ret))
ret = error("cannot get thread exit code: %lu", GetLastError());
CloseHandle(async->tid);
#endif
return ret;
}

5
run-command.h

@ -76,7 +76,12 @@ struct async { @@ -76,7 +76,12 @@ struct async {
int (*proc)(int fd, void *data);
void *data;
int out; /* caller reads from here and closes it */
#ifndef __MINGW32__
pid_t pid;
#else
HANDLE tid;
int fd_for_proc;
#endif
};

int start_async(struct async *async);

59
setup.c

@ -6,11 +6,17 @@ static int inside_work_tree = -1; @@ -6,11 +6,17 @@ static int inside_work_tree = -1;

static int sanitary_path_copy(char *dst, const char *src)
{
char *dst0 = dst;
char *dst0;

if (*src == '/') {
if (has_dos_drive_prefix(src)) {
*dst++ = *src++;
*dst++ = *src++;
}
dst0 = dst;

if (is_dir_sep(*src)) {
*dst++ = '/';
while (*src == '/')
while (is_dir_sep(*src))
src++;
}

@ -26,27 +32,24 @@ static int sanitary_path_copy(char *dst, const char *src) @@ -26,27 +32,24 @@ static int sanitary_path_copy(char *dst, const char *src)
* (4) "../" -- strip one, eat slash and continue.
*/
if (c == '.') {
switch (src[1]) {
case '\0':
if (!src[1]) {
/* (1) */
src++;
break;
case '/':
} else if (is_dir_sep(src[1])) {
/* (2) */
src += 2;
while (*src == '/')
while (is_dir_sep(*src))
src++;
continue;
case '.':
switch (src[2]) {
case '\0':
} else if (src[1] == '.') {
if (!src[2]) {
/* (3) */
src += 2;
goto up_one;
case '/':
} else if (is_dir_sep(src[2])) {
/* (4) */
src += 3;
while (*src == '/')
while (is_dir_sep(*src))
src++;
goto up_one;
}
@ -54,11 +57,11 @@ static int sanitary_path_copy(char *dst, const char *src) @@ -54,11 +57,11 @@ static int sanitary_path_copy(char *dst, const char *src)
}

/* copy up to the next '/', and eat all '/' */
while ((c = *src++) != '\0' && c != '/')
while ((c = *src++) != '\0' && !is_dir_sep(c))
*dst++ = c;
if (c == '/') {
*dst++ = c;
while (c == '/')
if (is_dir_sep(c)) {
*dst++ = '/';
while (is_dir_sep(c))
c = *src++;
src--;
} else if (!c)
@ -77,7 +80,7 @@ static int sanitary_path_copy(char *dst, const char *src) @@ -77,7 +80,7 @@ static int sanitary_path_copy(char *dst, const char *src)
if (dst <= dst0)
break;
c = *dst--;
if (c == '/') {
if (c == '/') { /* MinGW: cannot be '\\' anymore */
dst += 2;
break;
}
@ -126,10 +129,23 @@ const char *prefix_path(const char *prefix, int len, const char *path) @@ -126,10 +129,23 @@ const char *prefix_path(const char *prefix, int len, const char *path)
const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
{
static char path[PATH_MAX];
#ifndef __MINGW32__
if (!pfx || !*pfx || is_absolute_path(arg))
return arg;
memcpy(path, pfx, pfx_len);
strcpy(path + pfx_len, arg);
#else
char *p;
/* don't add prefix to absolute paths, but still replace '\' by '/' */
if (is_absolute_path(arg))
pfx_len = 0;
else
memcpy(path, pfx, pfx_len);
strcpy(path + pfx_len, arg);
for (p = path + pfx_len; *p; p++)
if (*p == '\\')
*p = '/';
#endif
return path;
}

@ -364,6 +380,7 @@ const char *setup_git_directory_gently(int *nongit_ok) @@ -364,6 +380,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
const char *gitdirenv;
const char *gitfile_dir;
int len, offset;
int minoffset = 0;

/*
* Let's assume that we are in a git repository.
@ -414,6 +431,8 @@ const char *setup_git_directory_gently(int *nongit_ok) @@ -414,6 +431,8 @@ const char *setup_git_directory_gently(int *nongit_ok)

if (!getcwd(cwd, sizeof(cwd)-1))
die("Unable to read current working directory");
if (has_dos_drive_prefix(cwd))
minoffset = 2;

/*
* Test in the following order (relative to the cwd):
@ -446,7 +465,7 @@ const char *setup_git_directory_gently(int *nongit_ok) @@ -446,7 +465,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
}
chdir("..");
do {
if (!offset) {
if (offset <= minoffset) {
if (nongit_ok) {
if (chdir(cwd))
die("Cannot come back to cwd");
@ -455,7 +474,7 @@ const char *setup_git_directory_gently(int *nongit_ok) @@ -455,7 +474,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
}
die("Not a git repository");
}
} while (cwd[--offset] != '/');
} while (offset > minoffset && cwd[--offset] != '/');
}

inside_git_dir = 0;

14
sha1_file.c

@ -83,14 +83,18 @@ int get_sha1_hex(const char *hex, unsigned char *sha1) @@ -83,14 +83,18 @@ int get_sha1_hex(const char *hex, unsigned char *sha1)
return 0;
}

static inline int offset_1st_component(const char *path)
{
if (has_dos_drive_prefix(path))
return 2 + (path[2] == '/');
return *path == '/';
}

int safe_create_leading_directories(char *path)
{
char *pos = path;
char *pos = path + offset_1st_component(path);
struct stat st;

if (is_absolute_path(path))
pos++;

while (pos) {
pos = strchr(pos, '/');
if (!pos)
@ -401,7 +405,7 @@ void prepare_alt_odb(void) @@ -401,7 +405,7 @@ void prepare_alt_odb(void)
if (!alt) alt = "";

alt_odb_tail = &alt_odb_list;
link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0);
link_alt_odb_entries(alt, alt + strlen(alt), PATH_SEP, NULL, 0);

read_info_alternates(get_object_directory(), 0);
}

8
templates/Makefile

@ -8,12 +8,12 @@ INSTALL ?= install @@ -8,12 +8,12 @@ INSTALL ?= install
TAR ?= tar
RM ?= rm -f
prefix ?= $(HOME)
template_dir ?= $(prefix)/share/git-core/templates
template_instdir ?= $(prefix)/share/git-core/templates
# DESTDIR=

# Shell quote (do not use $(call) to accommodate ancient setups);
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
template_dir_SQ = $(subst ','\'',$(template_dir))
template_instdir_SQ = $(subst ','\'',$(template_instdir))

all: boilerplates.made custom

@ -46,6 +46,6 @@ clean: @@ -46,6 +46,6 @@ clean:
$(RM) -r blt boilerplates.made

install: all
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(template_dir_SQ)'
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(template_instdir_SQ)'
(cd blt && $(TAR) cf - .) | \
(cd '$(DESTDIR_SQ)$(template_dir_SQ)' && umask 022 && $(TAR) xf -)
(cd '$(DESTDIR_SQ)$(template_instdir_SQ)' && umask 022 && $(TAR) xf -)

3
transport.c

@ -709,7 +709,8 @@ static int is_local(const char *url) @@ -709,7 +709,8 @@ static int is_local(const char *url)
{
const char *colon = strchr(url, ':');
const char *slash = strchr(url, '/');
return !colon || (slash && slash < colon);
return !colon || (slash && slash < colon) ||
has_dos_drive_prefix(url);
}

static int is_file(const char *url)

2
upload-pack.c

@ -135,6 +135,8 @@ static int do_rev_list(int fd, void *create_full_pack) @@ -135,6 +135,8 @@ static int do_rev_list(int fd, void *create_full_pack)
die("revision walk setup failed");
mark_edges_uninteresting(revs.commits, &revs, show_edge);
traverse_commit_list(&revs, show_commit, show_object);
fflush(pack_pipe);
fclose(pack_pipe);
return 0;
}


7
write_or_die.c

@ -34,7 +34,12 @@ void maybe_flush_or_die(FILE *f, const char *desc) @@ -34,7 +34,12 @@ void maybe_flush_or_die(FILE *f, const char *desc)
return;
}
if (fflush(f)) {
if (errno == EPIPE)
/*
* On Windows, EPIPE is returned only by the first write()
* after the reading end has closed its handle; subsequent
* write()s return EINVAL.
*/
if (errno == EPIPE || errno == EINVAL)
exit(0);
die("write failure on %s: %s", desc, strerror(errno));
}

Loading…
Cancel
Save