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(). ...
This commit is contained in:
commit
bb1ab2db08
@ -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
46
Makefile
@ -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 =
|
||||
|
||||
# ... 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
|
||||
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)
|
||||
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
|
||||
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:
|
||||
|
||||
### 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
2
cache.h
@ -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
Normal file
488
compat/fnmatch.c
Normal file
@ -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
Normal file
84
compat/fnmatch.h
Normal file
@ -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
Normal file
1019
compat/mingw.c
Normal file
File diff suppressed because it is too large
Load Diff
211
compat/mingw.h
Normal file
211
compat/mingw.h
Normal file
@ -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
Normal file
4927
compat/regex.c
Normal file
File diff suppressed because it is too large
Load Diff
490
compat/regex.h
Normal file
490
compat/regex.h
Normal file
@ -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:
|
||||
*/
|
@ -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)
|
||||
if (! str)
|
||||
break;
|
||||
s = str;
|
||||
ret = vsnprintf(str, maxsize, format, ap);
|
||||
ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
|
||||
}
|
||||
free(s);
|
||||
return ret;
|
||||
|
@ -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
13
date.c
@ -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)
|
||||
|
||||
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,
|
||||
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)
|
||||
}
|
||||
|
||||
/* 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)
|
||||
|
||||
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
41
exec_cmd.c
@ -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)
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
|
@ -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 @@
|
||||
#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 @@
|
||||
#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));
|
||||
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);
|
||||
#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
|
||||
|
@ -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
19
git.c
@ -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)
|
||||
|
||||
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)
|
||||
* 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
33
help.c
@ -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,
|
||||
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)
|
||||
|
||||
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
40
pager.c
@ -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)
|
||||
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)
|
||||
|
||||
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)
|
||||
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
126
run-command.c
@ -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)
|
||||
}
|
||||
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
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
@ -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
59
setup.c
@ -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)
|
||||
* (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)
|
||||
}
|
||||
|
||||
/* 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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
die("Not a git repository");
|
||||
}
|
||||
} while (cwd[--offset] != '/');
|
||||
} while (offset > minoffset && cwd[--offset] != '/');
|
||||
}
|
||||
|
||||
inside_git_dir = 0;
|
||||
|
14
sha1_file.c
14
sha1_file.c
@ -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)
|
||||
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,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:
|
||||
$(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 -)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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…
Reference in New Issue
Block a user