merge(third_party/git): Merge squashed git subtree at v2.23.0

Merge commit '1b593e1ea4' as 'third_party/git'
This commit is contained in:
Vincent Ambo 2020-01-11 23:36:56 +00:00
commit 7ef0d62730
3629 changed files with 1139935 additions and 0 deletions

31
third_party/git/compat/access.c vendored Normal file
View file

@ -0,0 +1,31 @@
#define COMPAT_CODE_ACCESS
#include "../git-compat-util.h"
/* Do the same thing access(2) does, but use the effective uid,
* and don't make the mistake of telling root that any file is
* executable. This version uses stat(2).
*/
int git_access(const char *path, int mode)
{
struct stat st;
/* do not interfere a normal user */
if (geteuid())
return access(path, mode);
if (stat(path, &st) < 0)
return -1;
/* Root can read or write any file. */
if (!(mode & X_OK))
return 0;
/* Root can execute any file that has any one of the execute
* bits set.
*/
if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
return 0;
errno = EACCES;
return -1;
}

View file

@ -0,0 +1,96 @@
/* suppress inclusion of conflicting openssl functions */
#define OPENSSL_NO_MD5
#define HEADER_HMAC_H
#define HEADER_SHA_H
#include <CommonCrypto/CommonHMAC.h>
#define EVP_md5(...) kCCHmacAlgMD5
/* CCHmac doesn't take md_len and the return type is void */
#define HMAC git_CC_HMAC
static inline unsigned char *git_CC_HMAC(CCHmacAlgorithm alg,
const void *key, int key_len,
const unsigned char *data, size_t data_len,
unsigned char *md, unsigned int *md_len)
{
CCHmac(alg, key, key_len, data, data_len, md);
return md;
}
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
#define APPLE_LION_OR_NEWER
#include <Security/Security.h>
/* Apple's TYPE_BOOL conflicts with config.c */
#undef TYPE_BOOL
#endif
#ifndef SHA1_MAX_BLOCK_SIZE
#error Using Apple Common Crypto library requires setting SHA1_MAX_BLOCK_SIZE
#endif
#ifdef APPLE_LION_OR_NEWER
#define git_CC_error_check(pattern, err) \
do { \
if (err) { \
die(pattern, (long)CFErrorGetCode(err)); \
} \
} while(0)
#define EVP_EncodeBlock git_CC_EVP_EncodeBlock
static inline int git_CC_EVP_EncodeBlock(unsigned char *out,
const unsigned char *in, int inlen)
{
CFErrorRef err;
SecTransformRef encoder;
CFDataRef input, output;
CFIndex length;
encoder = SecEncodeTransformCreate(kSecBase64Encoding, &err);
git_CC_error_check("SecEncodeTransformCreate failed: %ld", err);
input = CFDataCreate(kCFAllocatorDefault, in, inlen);
SecTransformSetAttribute(encoder, kSecTransformInputAttributeName,
input, &err);
git_CC_error_check("SecTransformSetAttribute failed: %ld", err);
output = SecTransformExecute(encoder, &err);
git_CC_error_check("SecTransformExecute failed: %ld", err);
length = CFDataGetLength(output);
CFDataGetBytes(output, CFRangeMake(0, length), out);
CFRelease(output);
CFRelease(input);
CFRelease(encoder);
return (int)strlen((const char *)out);
}
#define EVP_DecodeBlock git_CC_EVP_DecodeBlock
static int inline git_CC_EVP_DecodeBlock(unsigned char *out,
const unsigned char *in, int inlen)
{
CFErrorRef err;
SecTransformRef decoder;
CFDataRef input, output;
CFIndex length;
decoder = SecDecodeTransformCreate(kSecBase64Encoding, &err);
git_CC_error_check("SecEncodeTransformCreate failed: %ld", err);
input = CFDataCreate(kCFAllocatorDefault, in, inlen);
SecTransformSetAttribute(decoder, kSecTransformInputAttributeName,
input, &err);
git_CC_error_check("SecTransformSetAttribute failed: %ld", err);
output = SecTransformExecute(decoder, &err);
git_CC_error_check("SecTransformExecute failed: %ld", err);
length = CFDataGetLength(output);
CFDataGetBytes(output, CFRangeMake(0, length), out);
CFRelease(output);
CFRelease(input);
CFRelease(decoder);
return (int)strlen((const char *)out);
}
#endif /* APPLE_LION_OR_NEWER */

71
third_party/git/compat/basename.c vendored Normal file
View file

@ -0,0 +1,71 @@
#include "../git-compat-util.h"
#include "../strbuf.h"
/* Adapted from libiberty's basename.c. */
char *gitbasename (char *path)
{
const char *base;
if (path)
skip_dos_drive_prefix(&path);
if (!path || !*path)
return ".";
for (base = path; *path; path++) {
if (!is_dir_sep(*path))
continue;
do {
path++;
} while (is_dir_sep(*path));
if (*path)
base = path;
else
while (--path != base && is_dir_sep(*path))
*path = '\0';
}
return (char *)base;
}
char *gitdirname(char *path)
{
static struct strbuf buf = STRBUF_INIT;
char *p = path, *slash = NULL, c;
int dos_drive_prefix;
if (!p)
return ".";
if ((dos_drive_prefix = skip_dos_drive_prefix(&p)) && !*p)
goto dot;
/*
* POSIX.1-2001 says dirname("/") should return "/", and dirname("//")
* should return "//", but dirname("///") should return "/" again.
*/
if (is_dir_sep(*p)) {
if (!p[1] || (is_dir_sep(p[1]) && !p[2]))
return path;
slash = ++p;
}
while ((c = *(p++)))
if (is_dir_sep(c)) {
char *tentative = p - 1;
/* POSIX.1-2001 says to ignore trailing slashes */
while (is_dir_sep(*p))
p++;
if (*p)
slash = tentative;
}
if (slash) {
*slash = '\0';
return path;
}
dot:
strbuf_reset(&buf);
strbuf_addf(&buf, "%.*s.", dos_drive_prefix, path);
return buf.buf;
}

217
third_party/git/compat/bswap.h vendored Normal file
View file

@ -0,0 +1,217 @@
#ifndef COMPAT_BSWAP_H
#define COMPAT_BSWAP_H
/*
* Let's make sure we always have a sane definition for ntohl()/htonl().
* Some libraries define those as a function call, just to perform byte
* shifting, bringing significant overhead to what should be a simple
* operation.
*/
/*
* Default version that the compiler ought to optimize properly with
* constant values.
*/
static inline uint32_t default_swab32(uint32_t val)
{
return (((val & 0xff000000) >> 24) |
((val & 0x00ff0000) >> 8) |
((val & 0x0000ff00) << 8) |
((val & 0x000000ff) << 24));
}
static inline uint64_t default_bswap64(uint64_t val)
{
return (((val & (uint64_t)0x00000000000000ffULL) << 56) |
((val & (uint64_t)0x000000000000ff00ULL) << 40) |
((val & (uint64_t)0x0000000000ff0000ULL) << 24) |
((val & (uint64_t)0x00000000ff000000ULL) << 8) |
((val & (uint64_t)0x000000ff00000000ULL) >> 8) |
((val & (uint64_t)0x0000ff0000000000ULL) >> 24) |
((val & (uint64_t)0x00ff000000000000ULL) >> 40) |
((val & (uint64_t)0xff00000000000000ULL) >> 56));
}
#undef bswap32
#undef bswap64
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
#define bswap32 git_bswap32
static inline uint32_t git_bswap32(uint32_t x)
{
uint32_t result;
if (__builtin_constant_p(x))
result = default_swab32(x);
else
__asm__("bswap %0" : "=r" (result) : "0" (x));
return result;
}
#define bswap64 git_bswap64
#if defined(__x86_64__)
static inline uint64_t git_bswap64(uint64_t x)
{
uint64_t result;
if (__builtin_constant_p(x))
result = default_bswap64(x);
else
__asm__("bswap %q0" : "=r" (result) : "0" (x));
return result;
}
#else
static inline uint64_t git_bswap64(uint64_t x)
{
union { uint64_t i64; uint32_t i32[2]; } tmp, result;
if (__builtin_constant_p(x))
result.i64 = default_bswap64(x);
else {
tmp.i64 = x;
result.i32[0] = git_bswap32(tmp.i32[1]);
result.i32[1] = git_bswap32(tmp.i32[0]);
}
return result.i64;
}
#endif
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
#include <stdlib.h>
#define bswap32(x) _byteswap_ulong(x)
#define bswap64(x) _byteswap_uint64(x)
#endif
#if defined(bswap32)
#undef ntohl
#undef htonl
#define ntohl(x) bswap32(x)
#define htonl(x) bswap32(x)
#endif
#if defined(bswap64)
#undef ntohll
#undef htonll
#define ntohll(x) bswap64(x)
#define htonll(x) bswap64(x)
#else
#undef ntohll
#undef htonll
#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
# define GIT_BYTE_ORDER __BYTE_ORDER
# define GIT_LITTLE_ENDIAN __LITTLE_ENDIAN
# define GIT_BIG_ENDIAN __BIG_ENDIAN
#elif defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
# define GIT_BYTE_ORDER BYTE_ORDER
# define GIT_LITTLE_ENDIAN LITTLE_ENDIAN
# define GIT_BIG_ENDIAN BIG_ENDIAN
#else
# define GIT_BIG_ENDIAN 4321
# define GIT_LITTLE_ENDIAN 1234
# if defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
# define GIT_BYTE_ORDER GIT_BIG_ENDIAN
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
# define GIT_BYTE_ORDER GIT_LITTLE_ENDIAN
# elif defined(__THW_BIG_ENDIAN__) && !defined(__THW_LITTLE_ENDIAN__)
# define GIT_BYTE_ORDER GIT_BIG_ENDIAN
# elif defined(__THW_LITTLE_ENDIAN__) && !defined(__THW_BIG_ENDIAN__)
# define GIT_BYTE_ORDER GIT_LITTLE_ENDIAN
# else
# error "Cannot determine endianness"
# endif
#endif
#if GIT_BYTE_ORDER == GIT_BIG_ENDIAN
# define ntohll(n) (n)
# define htonll(n) (n)
#else
# define ntohll(n) default_bswap64(n)
# define htonll(n) default_bswap64(n)
#endif
#endif
/*
* Performance might be improved if the CPU architecture is OK with
* unaligned 32-bit loads and a fast ntohl() is available.
* Otherwise fall back to byte loads and shifts which is portable,
* and is faster on architectures with memory alignment issues.
*/
#if !defined(NO_UNALIGNED_LOADS) && ( \
defined(__i386__) || defined(__x86_64__) || \
defined(_M_IX86) || defined(_M_X64) || \
defined(__ppc__) || defined(__ppc64__) || \
defined(__powerpc__) || defined(__powerpc64__) || \
defined(__s390__) || defined(__s390x__))
#define get_be16(p) ntohs(*(unsigned short *)(p))
#define get_be32(p) ntohl(*(unsigned int *)(p))
#define get_be64(p) ntohll(*(uint64_t *)(p))
#define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0)
#define put_be64(p, v) do { *(uint64_t *)(p) = htonll(v); } while (0)
#else
static inline uint16_t get_be16(const void *ptr)
{
const unsigned char *p = ptr;
return (uint16_t)p[0] << 8 |
(uint16_t)p[1] << 0;
}
static inline uint32_t get_be32(const void *ptr)
{
const unsigned char *p = ptr;
return (uint32_t)p[0] << 24 |
(uint32_t)p[1] << 16 |
(uint32_t)p[2] << 8 |
(uint32_t)p[3] << 0;
}
static inline uint64_t get_be64(const void *ptr)
{
const unsigned char *p = ptr;
return (uint64_t)get_be32(&p[0]) << 32 |
(uint64_t)get_be32(&p[4]) << 0;
}
static inline void put_be32(void *ptr, uint32_t value)
{
unsigned char *p = ptr;
p[0] = value >> 24;
p[1] = value >> 16;
p[2] = value >> 8;
p[3] = value >> 0;
}
static inline void put_be64(void *ptr, uint64_t value)
{
unsigned char *p = ptr;
p[0] = value >> 56;
p[1] = value >> 48;
p[2] = value >> 40;
p[3] = value >> 32;
p[4] = value >> 24;
p[5] = value >> 16;
p[6] = value >> 8;
p[7] = value >> 0;
}
#endif
#endif /* COMPAT_BSWAP_H */

7
third_party/git/compat/fileno.c vendored Normal file
View file

@ -0,0 +1,7 @@
#define COMPAT_CODE_FILENO
#include "../git-compat-util.h"
int git_fileno(FILE *stream)
{
return fileno(stream);
}

37
third_party/git/compat/fopen.c vendored Normal file
View file

@ -0,0 +1,37 @@
/*
* The order of the following two lines is important.
*
* SUPPRESS_FOPEN_REDEFINITION is defined before including git-compat-util.h
* to avoid the redefinition of fopen within git-compat-util.h. This is
* necessary since fopen is a macro on some platforms which may be set
* based on compiler options. For example, on AIX fopen is set to fopen64
* when _LARGE_FILES is defined. The previous technique of merely undefining
* fopen after including git-compat-util.h is inadequate in this case.
*/
#define SUPPRESS_FOPEN_REDEFINITION
#include "../git-compat-util.h"
FILE *git_fopen(const char *path, const char *mode)
{
FILE *fp;
struct stat st;
if (mode[0] == 'w' || mode[0] == 'a')
return fopen(path, mode);
if (!(fp = fopen(path, mode)))
return NULL;
if (fstat(fileno(fp), &st)) {
fclose(fp);
return NULL;
}
if (S_ISDIR(st.st_mode)) {
fclose(fp);
errno = EISDIR;
return NULL;
}
return fp;
}

29
third_party/git/compat/gmtime.c vendored Normal file
View file

@ -0,0 +1,29 @@
#include "../git-compat-util.h"
#undef gmtime
#undef gmtime_r
struct tm *git_gmtime(const time_t *timep)
{
static struct tm result;
return git_gmtime_r(timep, &result);
}
struct tm *git_gmtime_r(const time_t *timep, struct tm *result)
{
struct tm *ret;
memset(result, 0, sizeof(*result));
ret = gmtime_r(timep, result);
/*
* Rather than NULL, FreeBSD gmtime simply leaves the "struct tm"
* untouched when it encounters overflow. Since "mday" cannot otherwise
* be zero, we can test this very quickly.
*/
if (ret && !ret->tm_mday) {
ret = NULL;
errno = EOVERFLOW;
}
return ret;
}

21
third_party/git/compat/hstrerror.c vendored Normal file
View file

@ -0,0 +1,21 @@
#include <string.h>
#include <stdio.h>
#include <netdb.h>
const char *githstrerror(int err)
{
static char buffer[48];
switch (err)
{
case HOST_NOT_FOUND:
return "Authoritative answer: host not found";
case NO_DATA:
return "Valid name, no data record of requested type";
case NO_RECOVERY:
return "Non recoverable errors, FORMERR, REFUSED, NOTIMP";
case TRY_AGAIN:
return "Non-authoritative \"host not found\", or SERVERFAIL";
}
snprintf(buffer, sizeof(buffer), "Name resolution error %d", err);
return buffer;
}

185
third_party/git/compat/inet_ntop.c vendored Normal file
View file

@ -0,0 +1,185 @@
/*
* Copyright (c) 1996-1999 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#include "../git-compat-util.h"
#ifndef NS_INADDRSZ
#define NS_INADDRSZ 4
#endif
#ifndef NS_IN6ADDRSZ
#define NS_IN6ADDRSZ 16
#endif
#ifndef NS_INT16SZ
#define NS_INT16SZ 2
#endif
/*
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
/* const char *
* inet_ntop4(src, dst, size)
* format an IPv4 address
* return:
* `dst' (as a const)
* notes:
* (1) uses no statics
* (2) takes a u_char* not an in_addr as input
* author:
* Paul Vixie, 1996.
*/
static const char *
inet_ntop4(const u_char *src, char *dst, size_t size)
{
static const char fmt[] = "%u.%u.%u.%u";
char tmp[sizeof "255.255.255.255"];
int nprinted;
nprinted = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
if (nprinted < 0)
return (NULL); /* we assume "errno" was set by "snprintf()" */
if ((size_t)nprinted >= size) {
errno = ENOSPC;
return (NULL);
}
strlcpy(dst, tmp, size);
return (dst);
}
#ifndef NO_IPV6
/* const char *
* inet_ntop6(src, dst, size)
* convert IPv6 binary address into presentation (printable) format
* author:
* Paul Vixie, 1996.
*/
static const char *
inet_ntop6(const u_char *src, char *dst, size_t size)
{
/*
* Note that int32_t and int16_t need only be "at least" large enough
* to contain a value of the specified size. On some systems, like
* Crays, there is no such thing as an integer variable with 16 bits.
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
struct { int base, len; } best, cur;
unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
int i;
/*
* Preprocess:
* Copy the input (bytewise) array into a wordwise array.
* Find the longest run of 0x00's in src[] for :: shorthanding.
*/
memset(words, '\0', sizeof words);
for (i = 0; i < NS_IN6ADDRSZ; i++)
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
best.base = -1;
best.len = 0;
cur.base = -1;
cur.len = 0;
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
if (words[i] == 0) {
if (cur.base == -1)
cur.base = i, cur.len = 1;
else
cur.len++;
} else {
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
cur.base = -1;
}
}
}
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
}
if (best.base != -1 && best.len < 2)
best.base = -1;
/*
* Format the result.
*/
tp = tmp;
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
/* Are we inside the best run of 0x00's? */
if (best.base != -1 && i >= best.base &&
i < (best.base + best.len)) {
if (i == best.base)
*tp++ = ':';
continue;
}
/* Are we following an initial run of 0x00s or any real hex? */
if (i != 0)
*tp++ = ':';
/* Is this address an encapsulated IPv4? */
if (i == 6 && best.base == 0 &&
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
return (NULL);
tp += strlen(tp);
break;
}
tp += snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]);
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) ==
(NS_IN6ADDRSZ / NS_INT16SZ))
*tp++ = ':';
*tp++ = '\0';
/*
* Check for overflow, copy, and we're done.
*/
if ((size_t)(tp - tmp) > size) {
errno = ENOSPC;
return (NULL);
}
strlcpy(dst, tmp, size);
return (dst);
}
#endif
/* char *
* inet_ntop(af, src, dst, size)
* convert a network format address to presentation format.
* return:
* pointer to presentation format address (`dst'), or NULL (see errno).
* author:
* Paul Vixie, 1996.
*/
const char *
inet_ntop(int af, const void *src, char *dst, size_t size)
{
switch (af) {
case AF_INET:
return (inet_ntop4(src, dst, size));
#ifndef NO_IPV6
case AF_INET6:
return (inet_ntop6(src, dst, size));
#endif
default:
errno = EAFNOSUPPORT;
return (NULL);
}
/* NOTREACHED */
}

215
third_party/git/compat/inet_pton.c vendored Normal file
View file

@ -0,0 +1,215 @@
/*
* Copyright (C) 1996-2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "../git-compat-util.h"
#ifndef NS_INT16SZ
#define NS_INT16SZ 2
#endif
#ifndef NS_INADDRSZ
#define NS_INADDRSZ 4
#endif
#ifndef NS_IN6ADDRSZ
#define NS_IN6ADDRSZ 16
#endif
/*
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
static int inet_pton4(const char *src, unsigned char *dst);
#ifndef NO_IPV6
static int inet_pton6(const char *src, unsigned char *dst);
#endif
/* int
* inet_pton4(src, dst)
* like inet_aton() but without all the hexadecimal and shorthand.
* return:
* 1 if `src' is a valid dotted quad, else 0.
* notice:
* does not touch `dst' unless it's returning 1.
* author:
* Paul Vixie, 1996.
*/
static int
inet_pton4(const char *src, unsigned char *dst)
{
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
unsigned char tmp[NS_INADDRSZ], *tp;
saw_digit = 0;
octets = 0;
*(tp = tmp) = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr(digits, ch)) != NULL) {
unsigned int new = *tp * 10 + (pch - digits);
if (new > 255)
return (0);
*tp = new;
if (! saw_digit) {
if (++octets > 4)
return (0);
saw_digit = 1;
}
} else if (ch == '.' && saw_digit) {
if (octets == 4)
return (0);
*++tp = 0;
saw_digit = 0;
} else
return (0);
}
if (octets < 4)
return (0);
memcpy(dst, tmp, NS_INADDRSZ);
return (1);
}
/* int
* inet_pton6(src, dst)
* convert presentation level address to network order binary form.
* return:
* 1 if `src' is a valid [RFC1884 2.2] address, else 0.
* notice:
* (1) does not touch `dst' unless it's returning 1.
* (2) :: in a full address is silently ignored.
* credit:
* inspired by Mark Andrews.
* author:
* Paul Vixie, 1996.
*/
#ifndef NO_IPV6
static int
inet_pton6(const char *src, unsigned char *dst)
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, saw_xdigit;
unsigned int val;
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
endp = tp + NS_IN6ADDRSZ;
colonp = NULL;
/* Leading :: requires some special handling. */
if (*src == ':')
if (*++src != ':')
return (0);
curtok = src;
saw_xdigit = 0;
val = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
val <<= 4;
val |= (pch - xdigits);
if (val > 0xffff)
return (0);
saw_xdigit = 1;
continue;
}
if (ch == ':') {
curtok = src;
if (!saw_xdigit) {
if (colonp)
return (0);
colonp = tp;
continue;
}
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (unsigned char) (val >> 8) & 0xff;
*tp++ = (unsigned char) val & 0xff;
saw_xdigit = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
inet_pton4(curtok, tp) > 0) {
tp += NS_INADDRSZ;
saw_xdigit = 0;
break; /* '\0' was seen by inet_pton4(). */
}
return (0);
}
if (saw_xdigit) {
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (unsigned char) (val >> 8) & 0xff;
*tp++ = (unsigned char) val & 0xff;
}
if (colonp != NULL) {
/*
* Since some memmove()'s erroneously fail to handle
* overlapping regions, we'll do the shift by hand.
*/
const int n = tp - colonp;
int i;
for (i = 1; i <= n; i++) {
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp)
return (0);
memcpy(dst, tmp, NS_IN6ADDRSZ);
return (1);
}
#endif
/* int
* isc_net_pton(af, src, dst)
* convert from presentation format (which usually means ASCII printable)
* to network format (which is usually some kind of binary format).
* return:
* 1 if the address was valid for the specified address family
* 0 if the address wasn't valid (`dst' is untouched in this case)
* -1 if some other error occurred (`dst' is untouched in this case, too)
* author:
* Paul Vixie, 1996.
*/
int
inet_pton(int af, const char *src, void *dst)
{
switch (af) {
case AF_INET:
return (inet_pton4(src, dst));
#ifndef NO_IPV6
case AF_INET6:
return (inet_pton6(src, dst));
#endif
default:
errno = EAFNOSUPPORT;
return (-1);
}
/* NOTREACHED */
}

32
third_party/git/compat/memmem.c vendored Normal file
View file

@ -0,0 +1,32 @@
#include "../git-compat-util.h"
void *gitmemmem(const void *haystack, size_t haystack_len,
const void *needle, size_t needle_len)
{
const char *begin = haystack;
const char *last_possible = begin + haystack_len - needle_len;
const char *tail = needle;
char point;
/*
* The first occurrence of the empty string is deemed to occur at
* the beginning of the string.
*/
if (needle_len == 0)
return (void *)begin;
/*
* Sanity check, otherwise the loop might search through the whole
* memory.
*/
if (haystack_len < needle_len)
return NULL;
point = *tail++;
for (; begin <= last_possible; begin++) {
if (*begin == point && !memcmp(begin + 1, tail, needle_len - 1))
return (void *)begin;
}
return NULL;
}

2543
third_party/git/compat/mingw.c vendored Normal file

File diff suppressed because it is too large Load diff

583
third_party/git/compat/mingw.h vendored Normal file
View file

@ -0,0 +1,583 @@
#ifdef __MINGW64_VERSION_MAJOR
#include <stdint.h>
#include <wchar.h>
typedef _sigset_t sigset_t;
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
/* MinGW-w64 reports to have flockfile, but it does not actually have it. */
#ifdef __MINGW64_VERSION_MAJOR
#undef _POSIX_THREAD_SAFE_FUNCTIONS
#endif
extern int mingw_core_config(const char *var, const char *value, void *cb);
#define platform_core_config mingw_core_config
/*
* things that are not available in header files
*/
typedef int uid_t;
typedef int socklen_t;
#ifndef __MINGW64_VERSION_MAJOR
typedef int pid_t;
#define hstrerror strerror
#endif
#define S_IFLNK 0120000 /* Symbolic link */
#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(x) 0
#ifndef S_IRWXG
#define S_IRGRP 0
#define S_IWGRP 0
#define S_IXGRP 0
#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
#endif
#ifndef S_IRWXO
#define S_IROTH 0
#define S_IWOTH 0
#define S_IXOTH 0
#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
#endif
#define S_ISUID 0004000
#define S_ISGID 0002000
#define S_ISVTX 0001000
#define WIFEXITED(x) 1
#define WIFSIGNALED(x) 0
#define WEXITSTATUS(x) ((x) & 0xff)
#define WTERMSIG(x) SIGTERM
#ifndef EWOULDBLOCK
#define EWOULDBLOCK EAGAIN
#endif
#ifndef ELOOP
#define ELOOP EMLINK
#endif
#define SHUT_WR SD_SEND
#define SIGHUP 1
#define SIGQUIT 3
#define SIGKILL 9
#define SIGPIPE 13
#define SIGALRM 14
#define SIGCHLD 17
#define F_GETFD 1
#define F_SETFD 2
#define FD_CLOEXEC 0x1
#if !defined O_CLOEXEC && defined O_NOINHERIT
#define O_CLOEXEC O_NOINHERIT
#endif
#ifndef EAFNOSUPPORT
#define EAFNOSUPPORT WSAEAFNOSUPPORT
#endif
#ifndef ECONNABORTED
#define ECONNABORTED WSAECONNABORTED
#endif
#ifndef ENOTSOCK
#define ENOTSOCK WSAENOTSOCK
#endif
struct passwd {
char *pw_name;
char *pw_gecos;
char *pw_dir;
};
typedef void (__cdecl *sig_handler_t)(int);
struct sigaction {
sig_handler_t sa_handler;
unsigned sa_flags;
};
#define SA_RESTART 0
struct itimerval {
struct timeval it_value, it_interval;
};
#define ITIMER_REAL 0
struct utsname {
char sysname[16];
char nodename[1];
char release[16];
char version[16];
char machine[1];
};
/*
* sanitize preprocessor namespace polluted by Windows headers defining
* macros which collide with git local versions
*/
#undef HELP_COMMAND /* from winuser.h */
/*
* 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 fchmod(int fildes, mode_t mode)
{ errno = ENOSYS; return -1; }
#ifndef __MINGW64_VERSION_MAJOR
static inline pid_t fork(void)
{ errno = ENOSYS; return -1; }
#endif
static inline unsigned int alarm(unsigned int seconds)
{ return 0; }
static inline int fsync(int fd)
{ return _commit(fd); }
static inline void sync(void)
{}
static inline uid_t getuid(void)
{ return 1; }
static inline struct passwd *getpwnam(const char *name)
{ return NULL; }
static inline int fcntl(int fd, int cmd, ...)
{
if (cmd == F_GETFD || cmd == F_SETFD)
return 0;
errno = EINVAL;
return -1;
}
#define sigemptyset(x) (void)0
static inline int sigaddset(sigset_t *set, int signum)
{ return 0; }
#define SIG_BLOCK 0
#define SIG_UNBLOCK 0
static inline int sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
{ return 0; }
static inline pid_t getppid(void)
{ return 1; }
static inline pid_t getpgid(pid_t pid)
{ return pid == 0 ? getpid() : pid; }
static inline pid_t tcgetpgrp(int fd)
{ return getpid(); }
/*
* simple adaptors
*/
int mingw_mkdir(const char *path, int mode);
#define mkdir mingw_mkdir
#define WNOHANG 1
pid_t waitpid(pid_t pid, int *status, int options);
#define kill mingw_kill
int mingw_kill(pid_t pid, int sig);
#ifndef NO_OPENSSL
#include <openssl/ssl.h>
static inline int mingw_SSL_set_fd(SSL *ssl, int fd)
{
return SSL_set_fd(ssl, _get_osfhandle(fd));
}
#define SSL_set_fd mingw_SSL_set_fd
static inline int mingw_SSL_set_rfd(SSL *ssl, int fd)
{
return SSL_set_rfd(ssl, _get_osfhandle(fd));
}
#define SSL_set_rfd mingw_SSL_set_rfd
static inline int mingw_SSL_set_wfd(SSL *ssl, int fd)
{
return SSL_set_wfd(ssl, _get_osfhandle(fd));
}
#define SSL_set_wfd mingw_SSL_set_wfd
#endif
/*
* 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);
#ifndef __MINGW64_VERSION_MAJOR
struct tm *gmtime_r(const time_t *timep, struct tm *result);
struct tm *localtime_r(const time_t *timep, struct tm *result);
#endif
int getpagesize(void); /* defined in MinGW's libgcc.a */
struct passwd *getpwuid(uid_t uid);
int setitimer(int type, struct itimerval *in, struct itimerval *out);
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
int link(const char *oldpath, const char *newpath);
int uname(struct utsname *buf);
/*
* replacements of existing functions
*/
int mingw_unlink(const char *pathname);
#define unlink mingw_unlink
int mingw_rmdir(const char *path);
#define rmdir mingw_rmdir
int mingw_open (const char *filename, int oflags, ...);
#define open mingw_open
int mingw_fgetc(FILE *stream);
#define fgetc mingw_fgetc
FILE *mingw_fopen (const char *filename, const char *otype);
#define fopen mingw_fopen
FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
#define freopen mingw_freopen
int mingw_fflush(FILE *stream);
#define fflush mingw_fflush
ssize_t mingw_write(int fd, const void *buf, size_t len);
#define write mingw_write
int mingw_access(const char *filename, int mode);
#undef access
#define access mingw_access
int mingw_chdir(const char *dirname);
#define chdir mingw_chdir
int mingw_chmod(const char *filename, int mode);
#define chmod mingw_chmod
char *mingw_mktemp(char *template);
#define mktemp mingw_mktemp
char *mingw_getcwd(char *pointer, int len);
#define getcwd mingw_getcwd
#ifdef NO_UNSETENV
#error "NO_UNSETENV is incompatible with the Windows-specific startup code!"
#endif
/*
* We bind *env() routines (even the mingw_ ones) to private mingw_ versions.
* These talk to the CRT using UNICODE/wchar_t, but maintain the original
* narrow-char API.
*
* Note that the MSCRT maintains both ANSI (getenv()) and UNICODE (_wgetenv())
* routines and stores both versions of each environment variable in parallel
* (and secretly updates both when you set one or the other), but it uses CP_ACP
* to do the conversion rather than CP_UTF8.
*
* Since everything in the git code base is UTF8, we define the mingw_ routines
* to access the CRT using the UNICODE routines and manually convert them to
* UTF8. This also avoids round-trip problems.
*
* This also helps with our linkage, since "_wenviron" is publicly exported
* from the CRT. But to access "_environ" we would have to statically link
* to the CRT (/MT).
*
* We require NO_SETENV (and let gitsetenv() call our mingw_putenv).
*/
#define getenv mingw_getenv
#define putenv mingw_putenv
#define unsetenv mingw_putenv
char *mingw_getenv(const char *name);
int mingw_putenv(const char *name);
int mingw_gethostname(char *host, int namelen);
#define gethostname mingw_gethostname
struct hostent *mingw_gethostbyname(const char *host);
#define gethostbyname mingw_gethostbyname
int mingw_getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res);
#define getaddrinfo mingw_getaddrinfo
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_bind(int sockfd, struct sockaddr *sa, size_t sz);
#define bind mingw_bind
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen);
#define setsockopt mingw_setsockopt
int mingw_shutdown(int sockfd, int how);
#define shutdown mingw_shutdown
int mingw_listen(int sockfd, int backlog);
#define listen mingw_listen
int mingw_accept(int sockfd, struct sockaddr *sa, socklen_t *sz);
#define accept mingw_accept
int mingw_rename(const char*, const char*);
#define rename mingw_rename
#if defined(USE_WIN32_MMAP) || defined(_MSC_VER)
int mingw_getpagesize(void);
#define getpagesize mingw_getpagesize
#endif
struct rlimit {
unsigned int rlim_cur;
};
#define RLIMIT_NOFILE 0
static inline int getrlimit(int resource, struct rlimit *rlp)
{
if (resource != RLIMIT_NOFILE) {
errno = EINVAL;
return -1;
}
rlp->rlim_cur = 2048;
return 0;
}
/*
* Use mingw specific stat()/lstat()/fstat() implementations on Windows,
* including our own struct stat with 64 bit st_size and nanosecond-precision
* file times.
*/
#ifndef __MINGW64_VERSION_MAJOR
#define off_t off64_t
#define lseek _lseeki64
#ifndef _MSC_VER
struct timespec {
time_t tv_sec;
long tv_nsec;
};
#endif
#endif
struct mingw_stat {
_dev_t st_dev;
_ino_t st_ino;
_mode_t st_mode;
short st_nlink;
short st_uid;
short st_gid;
_dev_t st_rdev;
off64_t st_size;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
};
#define st_atime st_atim.tv_sec
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
#ifdef stat
#undef stat
#endif
#define stat mingw_stat
int mingw_lstat(const char *file_name, struct stat *buf);
int mingw_stat(const char *file_name, struct stat *buf);
int mingw_fstat(int fd, struct stat *buf);
#ifdef fstat
#undef fstat
#endif
#define fstat mingw_fstat
#ifdef lstat
#undef lstat
#endif
#define lstat mingw_lstat
int mingw_utime(const char *file_name, const struct utimbuf *times);
#define utime mingw_utime
size_t mingw_strftime(char *s, size_t max,
const char *format, const struct tm *tm);
#define strftime mingw_strftime
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
const char *dir,
int fhin, int fhout, int fherr);
int mingw_execvp(const char *cmd, char *const *argv);
#define execvp mingw_execvp
int mingw_execv(const char *cmd, char *const *argv);
#define execv mingw_execv
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
int mingw_raise(int sig);
#define raise mingw_raise
/*
* ANSI emulation wrappers
*/
int winansi_isatty(int fd);
#define isatty winansi_isatty
int winansi_dup2(int oldfd, int newfd);
#define dup2 winansi_dup2
void winansi_init(void);
HANDLE winansi_get_osfhandle(int fd);
/*
* git specific compatibility
*/
static inline void convert_slashes(char *path)
{
for (; *path; path++)
if (*path == '\\')
*path = '/';
}
#define PATH_SEP ';'
extern char *mingw_query_user_email(void);
#define query_user_email mingw_query_user_email
#if !defined(__MINGW64_VERSION_MAJOR) && (!defined(_MSC_VER) || _MSC_VER < 1800)
#define PRIuMAX "I64u"
#define PRId64 "I64d"
#else
#include <inttypes.h>
#endif
/**
* Converts UTF-8 encoded string to UTF-16LE.
*
* To support repositories with legacy-encoded file names, invalid UTF-8 bytes
* 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 -
* \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable
* Unicode) are converted to hex-code.
*
* Lead-bytes not followed by an appropriate number of trail-bytes, over-long
* encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8.
*
* Maximum space requirement for the target buffer is two wide chars per UTF-8
* char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]).
*
* The maximum space is needed only if the entire input string consists of
* invalid UTF-8 bytes in range 0x80-0x9f, as per the following table:
*
* | | UTF-8 | UTF-16 |
* Code point | UTF-8 sequence | bytes | words | ratio
* --------------+-------------------+-------+--------+-------
* 000000-00007f | 0-7f | 1 | 1 | 1
* 000080-0007ff | c2-df + 80-bf | 2 | 1 | 0.5
* 000800-00ffff | e0-ef + 2 * 80-bf | 3 | 1 | 0.33
* 010000-10ffff | f0-f4 + 3 * 80-bf | 4 | 2 (a) | 0.5
* invalid | 80-9f | 1 | 2 (b) | 2
* invalid | a0-ff | 1 | 1 | 1
*
* (a) encoded as UTF-16 surrogate pair
* (b) encoded as two hex digits
*
* Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte
* or even indefinite-byte sequences, the largest valid code point \u10ffff
* encodes as only 4 UTF-8 bytes.
*
* Parameters:
* wcs: wide char target buffer
* utf: string to convert
* wcslen: size of target buffer (in wchar_t's)
* utflen: size of string to convert, or -1 if 0-terminated
*
* Returns:
* length of converted string (_wcslen(wcs)), or -1 on failure
*
* Errors:
* EINVAL: one of the input parameters is invalid (e.g. NULL)
* ERANGE: the output buffer is too small
*/
int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen);
/**
* Simplified variant of xutftowcsn, assumes input string is \0-terminated.
*/
static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen)
{
return xutftowcsn(wcs, utf, wcslen, -1);
}
/**
* Simplified file system specific variant of xutftowcsn, assumes output
* buffer size is MAX_PATH wide chars and input string is \0-terminated,
* fails with ENAMETOOLONG if input string is too long.
*/
static inline int xutftowcs_path(wchar_t *wcs, const char *utf)
{
int result = xutftowcsn(wcs, utf, MAX_PATH, -1);
if (result < 0 && errno == ERANGE)
errno = ENAMETOOLONG;
return result;
}
/**
* Converts UTF-16LE encoded string to UTF-8.
*
* Maximum space requirement for the target buffer is three UTF-8 chars per
* wide char ((_wcslen(wcs) * 3) + 1).
*
* The maximum space is needed only if the entire input string consists of
* UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff
* modulo surrogate pairs), as per the following table:
*
* | | UTF-16 | UTF-8 |
* Code point | UTF-16 sequence | words | bytes | ratio
* --------------+-----------------------+--------+-------+-------
* 000000-00007f | 0000-007f | 1 | 1 | 1
* 000080-0007ff | 0080-07ff | 1 | 2 | 2
* 000800-00ffff | 0800-d7ff / e000-ffff | 1 | 3 | 3
* 010000-10ffff | d800-dbff + dc00-dfff | 2 | 4 | 2
*
* Note that invalid code points > 10ffff cannot be represented in UTF-16.
*
* Parameters:
* utf: target buffer
* wcs: wide string to convert
* utflen: size of target buffer
*
* Returns:
* length of converted string, or -1 on failure
*
* Errors:
* EINVAL: one of the input parameters is invalid (e.g. NULL)
* ERANGE: the output buffer is too small
*/
int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
/*
* A critical section used in the implementation of the spawn
* functions (mingw_spawnv[p]e()) and waitpid(). Intialised in
* the replacement main() macro below.
*/
extern CRITICAL_SECTION pinfo_cs;
/*
* Git, like most portable C applications, implements a main() function. On
* Windows, this main() function would receive parameters encoded in the
* current locale, but Git for Windows would prefer UTF-8 encoded parameters.
*
* To make that happen, we still declare main() here, and then declare and
* implement wmain() (which is the Unicode variant of main()) and compile with
* -municode. This wmain() function reencodes the parameters from UTF-16 to
* UTF-8 format, sets up a couple of other things as required on Windows, and
* then hands off to the main() function.
*/
int wmain(int argc, const wchar_t **w_argv);
int main(int argc, const char **argv);
/*
* Used by Pthread API implementation for Windows
*/
extern int err_win_to_posix(DWORD winerr);

24
third_party/git/compat/mkdir.c vendored Normal file
View file

@ -0,0 +1,24 @@
#include "../git-compat-util.h"
#undef mkdir
/* for platforms that can't deal with a trailing '/' */
int compat_mkdir_wo_trailing_slash(const char *dir, mode_t mode)
{
int retval;
char *tmp_dir = NULL;
size_t len = strlen(dir);
if (len && dir[len-1] == '/') {
if ((tmp_dir = strdup(dir)) == NULL)
return -1;
tmp_dir[len-1] = '\0';
}
else
tmp_dir = (char *)dir;
retval = mkdir(tmp_dir, mode);
if (tmp_dir != dir)
free(tmp_dir);
return retval;
}

8
third_party/git/compat/mkdtemp.c vendored Normal file
View file

@ -0,0 +1,8 @@
#include "../git-compat-util.h"
char *gitmkdtemp(char *template)
{
if (!*mktemp(template) || mkdir(template, 0700))
return NULL;
return template;
}

40
third_party/git/compat/mmap.c vendored Normal file
View file

@ -0,0 +1,40 @@
#include "../git-compat-util.h"
void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
{
size_t n = 0;
if (start != NULL || flags != MAP_PRIVATE || prot != PROT_READ)
die("Invalid usage of mmap when built with NO_MMAP");
start = xmalloc(length);
if (start == NULL) {
errno = ENOMEM;
return MAP_FAILED;
}
while (n < length) {
ssize_t count = xpread(fd, (char *)start + n, length - n, offset + n);
if (count == 0) {
memset((char *)start+n, 0, length-n);
break;
}
if (count < 0) {
free(start);
errno = EACCES;
return MAP_FAILED;
}
n += count;
}
return start;
}
int git_munmap(void *start, size_t length)
{
free(start);
return 0;
}

6
third_party/git/compat/msvc.c vendored Normal file
View file

@ -0,0 +1,6 @@
#include "../git-compat-util.h"
#include "win32.h"
#include <conio.h>
#include "../strbuf.h"
#include "mingw.c"

33
third_party/git/compat/msvc.h vendored Normal file
View file

@ -0,0 +1,33 @@
#ifndef __MSVC__HEAD
#define __MSVC__HEAD
#include <direct.h>
#include <process.h>
#include <malloc.h>
#include <io.h>
#pragma warning(disable: 4018) /* signed/unsigned comparison */
#pragma warning(disable: 4244) /* type conversion, possible loss of data */
#pragma warning(disable: 4090) /* 'function' : different 'const' qualifiers (ALLOC_GROW etc.)*/
/* porting function */
#define inline __inline
#define __inline__ __inline
#define __attribute__(x)
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#define ftruncate _chsize
#define strtoull _strtoui64
#define strtoll _strtoi64
#undef ERROR
#define ftello _ftelli64
typedef int sigset_t;
/* open for reading, writing, or both (not in fcntl.h) */
#define O_ACCMODE (_O_RDONLY | _O_WRONLY | _O_RDWR)
#include "compat/mingw.h"
#endif

View file

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,136 @@
nedalloc v1.05 15th June 2008:
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
by Niall Douglas (http://www.nedprod.com/programs/portable/nedmalloc/)
Enclosed is nedalloc, an alternative malloc implementation for multiple
threads without lock contention based on dlmalloc v2.8.4. It is more
or less a newer implementation of ptmalloc2, the standard allocator in
Linux (which is based on dlmalloc v2.7.0) but also contains a per-thread
cache for maximum CPU scalability.
It is licensed under the Boost Software License which basically means
you can do anything you like with it. This does not apply to the malloc.c.h
file which remains copyright to others.
It has been tested on win32 (x86), win64 (x64), Linux (x64), FreeBSD (x64)
and Apple MacOS X (x86). It works very well on all of these and is very
significantly faster than the system allocator on all of these platforms.
By literally dropping in this allocator as a replacement for your system
allocator, you can see real world improvements of up to three times in normal
code!
To use:
-=-=-=-
Drop in nedmalloc.h, nedmalloc.c and malloc.c.h into your project.
Configure using the instructions in nedmalloc.h. Run and enjoy.
To test, compile test.c. It will run a comparison between your system
allocator and nedalloc and tell you how much faster nedalloc is. It also
serves as an example of usage.
Notes:
-=-=-=
If you want the very latest version of this allocator, get it from the
TnFOX SVN repository at svn://svn.berlios.de/viewcvs/tnfox/trunk/src/nedmalloc
Because of how nedalloc allocates an mspace per thread, it can cause
severe bloating of memory usage under certain allocation patterns.
You can substantially reduce this wastage by setting MAXTHREADSINPOOL
or the threads parameter to nedcreatepool() to a fraction of the number of
threads which would normally be in a pool at once. This will reduce
bloating at the cost of an increase in lock contention. If allocated size
is less than THREADCACHEMAX, locking is avoided 90-99% of the time and
if most of your allocations are below this value, you can safely set
MAXTHREADSINPOOL to one.
You will suffer memory leakage unless you call neddisablethreadcache()
per pool for every thread which exits. This is because nedalloc cannot
portably know when a thread exits and thus when its thread cache can
be returned for use by other code. Don't forget pool zero, the system pool.
For C++ type allocation patterns (where the same sizes of memory are
regularly allocated and deallocated as objects are created and destroyed),
the threadcache always benefits performance. If however your allocation
patterns are different, searching the threadcache may significantly slow
down your code - as a rule of thumb, if cache utilisation is below 80%
(see the source for neddisablethreadcache() for how to enable debug
printing in release mode) then you should disable the thread cache for
that thread. You can compile out the threadcache code by setting
THREADCACHEMAX to zero.
Speed comparisons:
-=-=-=-=-=-=-=-=-=
See Benchmarks.xls for details.
The enclosed test.c can do two things: it can be a torture test or a speed
test. The speed test is designed to be a representative synthetic
memory allocator test. It works by randomly mixing allocations with frees
with half of the allocation sizes being a two power multiple less than
512 bytes (to mimic C++ stack instantiated objects) and the other half
being a simple random value less than 16Kb.
The real world code results are from Tn's TestIO benchmark. This is a
heavily multithreaded and memory intensive benchmark with a lot of branching
and other stuff modern processors don't like so much. As you'll note, the
test doesn't show the benefits of the threadcache mostly due to the saturation
of the memory bus being the limiting factor.
ChangeLog:
-=-=-=-=-=
v1.05 15th June 2008:
* { 1042 } Added error check for TLSSET() and TLSFREE() macros. Thanks to
Markus Elfring for reporting this.
* { 1043 } Fixed a segfault when freeing memory allocated using
nedindependent_comalloc(). Thanks to Pavel Vozenilek for reporting this.
v1.04 14th July 2007:
* Fixed a bug with the new optimised implementation that failed to lock
on a realloc under certain conditions.
* Fixed lack of thread synchronisation in InitPool() causing pool corruption
* Fixed a memory leak of thread cache contents on disabling. Thanks to Earl
Chew for reporting this.
* Added a sanity check for freed blocks being valid.
* Reworked test.c into being a torture test.
* Fixed GCC assembler optimisation misspecification
v1.04alpha_svn915 7th October 2006:
* Fixed failure to unlock thread cache list if allocating a new list failed.
Thanks to Dmitry Chichkov for reporting this. Further thanks to Aleksey Sanin.
* Fixed realloc(0, <size>) segfaulting. Thanks to Dmitry Chichkov for
reporting this.
* Made config defines #ifndef so they can be overridden by the build system.
Thanks to Aleksey Sanin for suggesting this.
* Fixed deadlock in nedprealloc() due to unnecessary locking of preferred
thread mspace when mspace_realloc() always uses the original block's mspace
anyway. Thanks to Aleksey Sanin for reporting this.
* Made some speed improvements by hacking mspace_malloc() to no longer lock
its mspace, thus allowing the recursive mutex implementation to be removed
with an associated speed increase. Thanks to Aleksey Sanin for suggesting this.
* Fixed a bug where allocating mspaces overran its max limit. Thanks to
Aleksey Sanin for reporting this.
v1.03 10th July 2006:
* Fixed memory corruption bug in threadcache code which only appeared with >4
threads and in heavy use of the threadcache.
v1.02 15th May 2006:
* Integrated dlmalloc v2.8.4, fixing the win32 memory release problem and
improving performance still further. Speed is now up to twice the speed of v1.01
(average is 67% faster).
* Fixed win32 critical section implementation. Thanks to Pavel Kuznetsov
for reporting this.
* Wasn't locking mspace if all mspaces were locked. Thanks to Pavel Kuznetsov
for reporting this.
* Added Apple Mac OS X support.
v1.01 24th February 2006:
* Fixed multiprocessor scaling problems by removing sources of cache sloshing
* Earl Chew <earl_chew <at> agilent <dot> com> sent patches for the following:
1. size2binidx() wasn't working for default code path (non x86)
2. Fixed failure to release mspace lock under certain circumstances which
caused a deadlock
v1.00 1st January 2006:
* First release

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,953 @@
/* Alternative malloc implementation for multiple threads without
lock contention based on dlmalloc. (C) 2005-2006 Niall Douglas
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifdef _MSC_VER
/* Enable full aliasing on MSVC */
/*#pragma optimize("a", on)*/
#endif
/*#define FULLSANITYCHECKS*/
#include "nedmalloc.h"
#if defined(WIN32)
#include <malloc.h>
#endif
#define MSPACES 1
#define ONLY_MSPACES 1
#ifndef USE_LOCKS
#define USE_LOCKS 1
#endif
#define FOOTERS 1 /* Need to enable footers so frees lock the right mspace */
#undef DEBUG /* dlmalloc wants DEBUG either 0 or 1 */
#ifdef _DEBUG
#define DEBUG 1
#else
#define DEBUG 0
#endif
#ifdef NDEBUG /* Disable assert checking on release builds */
#undef DEBUG
#endif
/* The default of 64Kb means we spend too much time kernel-side */
#ifndef DEFAULT_GRANULARITY
#define DEFAULT_GRANULARITY (1*1024*1024)
#endif
/*#define USE_SPIN_LOCKS 0*/
/*#define FORCEINLINE*/
#include "malloc.c.h"
#ifdef NDEBUG /* Disable assert checking on release builds */
#undef DEBUG
#endif
/* The maximum concurrent threads in a pool possible */
#ifndef MAXTHREADSINPOOL
#define MAXTHREADSINPOOL 16
#endif
/* The maximum number of threadcaches which can be allocated */
#ifndef THREADCACHEMAXCACHES
#define THREADCACHEMAXCACHES 256
#endif
/* The maximum size to be allocated from the thread cache */
#ifndef THREADCACHEMAX
#define THREADCACHEMAX 8192
#endif
#if 0
/* The number of cache entries for finer grained bins. This is (topbitpos(THREADCACHEMAX)-4)*2 */
#define THREADCACHEMAXBINS ((13-4)*2)
#else
/* The number of cache entries. This is (topbitpos(THREADCACHEMAX)-4) */
#define THREADCACHEMAXBINS (13-4)
#endif
/* Point at which the free space in a thread cache is garbage collected */
#ifndef THREADCACHEMAXFREESPACE
#define THREADCACHEMAXFREESPACE (512*1024)
#endif
#ifdef WIN32
#define TLSVAR DWORD
#define TLSALLOC(k) (*(k)=TlsAlloc(), TLS_OUT_OF_INDEXES==*(k))
#define TLSFREE(k) (!TlsFree(k))
#define TLSGET(k) TlsGetValue(k)
#define TLSSET(k, a) (!TlsSetValue(k, a))
#ifdef DEBUG
static LPVOID ChkedTlsGetValue(DWORD idx)
{
LPVOID ret=TlsGetValue(idx);
assert(S_OK==GetLastError());
return ret;
}
#undef TLSGET
#define TLSGET(k) ChkedTlsGetValue(k)
#endif
#else
#define TLSVAR pthread_key_t
#define TLSALLOC(k) pthread_key_create(k, 0)
#define TLSFREE(k) pthread_key_delete(k)
#define TLSGET(k) pthread_getspecific(k)
#define TLSSET(k, a) pthread_setspecific(k, a)
#endif
#if 0
/* Only enable if testing with valgrind. Causes misoperation */
#define mspace_malloc(p, s) malloc(s)
#define mspace_realloc(p, m, s) realloc(m, s)
#define mspace_calloc(p, n, s) calloc(n, s)
#define mspace_free(p, m) free(m)
#endif
#if defined(__cplusplus)
#if !defined(NO_NED_NAMESPACE)
namespace nedalloc {
#else
extern "C" {
#endif
#endif
size_t nedblksize(void *mem) THROWSPEC
{
#if 0
/* Only enable if testing with valgrind. Causes misoperation */
return THREADCACHEMAX;
#else
if(mem)
{
mchunkptr p=mem2chunk(mem);
assert(cinuse(p)); /* If this fails, someone tried to free a block twice */
if(cinuse(p))
return chunksize(p)-overhead_for(p);
}
return 0;
#endif
}
void nedsetvalue(void *v) THROWSPEC { nedpsetvalue(0, v); }
void * nedmalloc(size_t size) THROWSPEC { return nedpmalloc(0, size); }
void * nedcalloc(size_t no, size_t size) THROWSPEC { return nedpcalloc(0, no, size); }
void * nedrealloc(void *mem, size_t size) THROWSPEC { return nedprealloc(0, mem, size); }
void nedfree(void *mem) THROWSPEC { nedpfree(0, mem); }
void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC { return nedpmemalign(0, alignment, bytes); }
#if !NO_MALLINFO
struct mallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo(0); }
#endif
int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt(0, parno, value); }
int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim(0, pad); }
void nedmalloc_stats(void) THROWSPEC { nedpmalloc_stats(0); }
size_t nedmalloc_footprint(void) THROWSPEC { return nedpmalloc_footprint(0); }
void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc(0, elemsno, elemsize, chunks); }
void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc(0, elems, sizes, chunks); }
struct threadcacheblk_t;
typedef struct threadcacheblk_t threadcacheblk;
struct threadcacheblk_t
{ /* Keep less than 16 bytes on 32 bit systems and 32 bytes on 64 bit systems */
#ifdef FULLSANITYCHECKS
unsigned int magic;
#endif
unsigned int lastUsed, size;
threadcacheblk *next, *prev;
};
typedef struct threadcache_t
{
#ifdef FULLSANITYCHECKS
unsigned int magic1;
#endif
int mymspace; /* Last mspace entry this thread used */
long threadid;
unsigned int mallocs, frees, successes;
size_t freeInCache; /* How much free space is stored in this cache */
threadcacheblk *bins[(THREADCACHEMAXBINS+1)*2];
#ifdef FULLSANITYCHECKS
unsigned int magic2;
#endif
} threadcache;
struct nedpool_t
{
MLOCK_T mutex;
void *uservalue;
int threads; /* Max entries in m to use */
threadcache *caches[THREADCACHEMAXCACHES];
TLSVAR mycache; /* Thread cache for this thread. 0 for unset, negative for use mspace-1 directly, otherwise is cache-1 */
mstate m[MAXTHREADSINPOOL+1]; /* mspace entries for this pool */
};
static nedpool syspool;
static FORCEINLINE unsigned int size2binidx(size_t _size) THROWSPEC
{ /* 8=1000 16=10000 20=10100 24=11000 32=100000 48=110000 4096=1000000000000 */
unsigned int topbit, size=(unsigned int)(_size>>4);
/* 16=1 20=1 24=1 32=10 48=11 64=100 96=110 128=1000 4096=100000000 */
#if defined(__GNUC__)
topbit = sizeof(size)*__CHAR_BIT__ - 1 - __builtin_clz(size);
#elif defined(_MSC_VER) && _MSC_VER>=1300
{
unsigned long bsrTopBit;
_BitScanReverse(&bsrTopBit, size);
topbit = bsrTopBit;
}
#else
#if 0
union {
unsigned asInt[2];
double asDouble;
};
int n;
asDouble = (double)size + 0.5;
topbit = (asInt[!FOX_BIGENDIAN] >> 20) - 1023;
#else
{
unsigned int x=size;
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >>16);
x = ~x;
x = x - ((x >> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
x = (x + (x >> 4)) & 0x0F0F0F0F;
x = x + (x << 8);
x = x + (x << 16);
topbit=31 - (x >> 24);
}
#endif
#endif
return topbit;
}
#ifdef FULLSANITYCHECKS
static void tcsanitycheck(threadcacheblk **ptr) THROWSPEC
{
assert((ptr[0] && ptr[1]) || (!ptr[0] && !ptr[1]));
if(ptr[0] && ptr[1])
{
assert(nedblksize(ptr[0])>=sizeof(threadcacheblk));
assert(nedblksize(ptr[1])>=sizeof(threadcacheblk));
assert(*(unsigned int *) "NEDN"==ptr[0]->magic);
assert(*(unsigned int *) "NEDN"==ptr[1]->magic);
assert(!ptr[0]->prev);
assert(!ptr[1]->next);
if(ptr[0]==ptr[1])
{
assert(!ptr[0]->next);
assert(!ptr[1]->prev);
}
}
}
static void tcfullsanitycheck(threadcache *tc) THROWSPEC
{
threadcacheblk **tcbptr=tc->bins;
int n;
for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2)
{
threadcacheblk *b, *ob=0;
tcsanitycheck(tcbptr);
for(b=tcbptr[0]; b; ob=b, b=b->next)
{
assert(*(unsigned int *) "NEDN"==b->magic);
assert(!ob || ob->next==b);
assert(!ob || b->prev==ob);
}
}
}
#endif
static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned int age) THROWSPEC
{
#ifdef FULLSANITYCHECKS
tcfullsanitycheck(tc);
#endif
if(tc->freeInCache)
{
threadcacheblk **tcbptr=tc->bins;
int n;
for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2)
{
threadcacheblk **tcb=tcbptr+1; /* come from oldest end of list */
/*tcsanitycheck(tcbptr);*/
for(; *tcb && tc->frees-(*tcb)->lastUsed>=age; )
{
threadcacheblk *f=*tcb;
size_t blksize=f->size; /*nedblksize(f);*/
assert(blksize<=nedblksize(f));
assert(blksize);
#ifdef FULLSANITYCHECKS
assert(*(unsigned int *) "NEDN"==(*tcb)->magic);
#endif
*tcb=(*tcb)->prev;
if(*tcb)
(*tcb)->next=0;
else
*tcbptr=0;
tc->freeInCache-=blksize;
assert((long) tc->freeInCache>=0);
mspace_free(0, f);
/*tcsanitycheck(tcbptr);*/
}
}
}
#ifdef FULLSANITYCHECKS
tcfullsanitycheck(tc);
#endif
}
static void DestroyCaches(nedpool *p) THROWSPEC
{
if(p->caches)
{
threadcache *tc;
int n;
for(n=0; n<THREADCACHEMAXCACHES; n++)
{
if((tc=p->caches[n]))
{
tc->frees++;
RemoveCacheEntries(p, tc, 0);
assert(!tc->freeInCache);
tc->mymspace=-1;
tc->threadid=0;
mspace_free(0, tc);
p->caches[n]=0;
}
}
}
}
static NOINLINE threadcache *AllocCache(nedpool *p) THROWSPEC
{
threadcache *tc=0;
int n, end;
ACQUIRE_LOCK(&p->mutex);
for(n=0; n<THREADCACHEMAXCACHES && p->caches[n]; n++);
if(THREADCACHEMAXCACHES==n)
{ /* List exhausted, so disable for this thread */
RELEASE_LOCK(&p->mutex);
return 0;
}
tc=p->caches[n]=(threadcache *) mspace_calloc(p->m[0], 1, sizeof(threadcache));
if(!tc)
{
RELEASE_LOCK(&p->mutex);
return 0;
}
#ifdef FULLSANITYCHECKS
tc->magic1=*(unsigned int *)"NEDMALC1";
tc->magic2=*(unsigned int *)"NEDMALC2";
#endif
tc->threadid=(long)(size_t)CURRENT_THREAD;
for(end=0; p->m[end]; end++);
tc->mymspace=tc->threadid % end;
RELEASE_LOCK(&p->mutex);
if(TLSSET(p->mycache, (void *)(size_t)(n+1))) abort();
return tc;
}
static void *threadcache_malloc(nedpool *p, threadcache *tc, size_t *size) THROWSPEC
{
void *ret=0;
unsigned int bestsize;
unsigned int idx=size2binidx(*size);
size_t blksize=0;
threadcacheblk *blk, **binsptr;
#ifdef FULLSANITYCHECKS
tcfullsanitycheck(tc);
#endif
/* Calculate best fit bin size */
bestsize=1<<(idx+4);
#if 0
/* Finer grained bin fit */
idx<<=1;
if(*size>bestsize)
{
idx++;
bestsize+=bestsize>>1;
}
if(*size>bestsize)
{
idx++;
bestsize=1<<(4+(idx>>1));
}
#else
if(*size>bestsize)
{
idx++;
bestsize<<=1;
}
#endif
assert(bestsize>=*size);
if(*size<bestsize) *size=bestsize;
assert(*size<=THREADCACHEMAX);
assert(idx<=THREADCACHEMAXBINS);
binsptr=&tc->bins[idx*2];
/* Try to match close, but move up a bin if necessary */
blk=*binsptr;
if(!blk || blk->size<*size)
{ /* Bump it up a bin */
if(idx<THREADCACHEMAXBINS)
{
idx++;
binsptr+=2;
blk=*binsptr;
}
}
if(blk)
{
blksize=blk->size; /*nedblksize(blk);*/
assert(nedblksize(blk)>=blksize);
assert(blksize>=*size);
if(blk->next)
blk->next->prev=0;
*binsptr=blk->next;
if(!*binsptr)
binsptr[1]=0;
#ifdef FULLSANITYCHECKS
blk->magic=0;
#endif
assert(binsptr[0]!=blk && binsptr[1]!=blk);
assert(nedblksize(blk)>=sizeof(threadcacheblk) && nedblksize(blk)<=THREADCACHEMAX+CHUNK_OVERHEAD);
/*printf("malloc: %p, %p, %p, %lu\n", p, tc, blk, (long) size);*/
ret=(void *) blk;
}
++tc->mallocs;
if(ret)
{
assert(blksize>=*size);
++tc->successes;
tc->freeInCache-=blksize;
assert((long) tc->freeInCache>=0);
}
#if defined(DEBUG) && 0
if(!(tc->mallocs & 0xfff))
{
printf("*** threadcache=%u, mallocs=%u (%f), free=%u (%f), freeInCache=%u\n", (unsigned int) tc->threadid, tc->mallocs,
(float) tc->successes/tc->mallocs, tc->frees, (float) tc->successes/tc->frees, (unsigned int) tc->freeInCache);
}
#endif
#ifdef FULLSANITYCHECKS
tcfullsanitycheck(tc);
#endif
return ret;
}
static NOINLINE void ReleaseFreeInCache(nedpool *p, threadcache *tc, int mymspace) THROWSPEC
{
unsigned int age=THREADCACHEMAXFREESPACE/8192;
/*ACQUIRE_LOCK(&p->m[mymspace]->mutex);*/
while(age && tc->freeInCache>=THREADCACHEMAXFREESPACE)
{
RemoveCacheEntries(p, tc, age);
/*printf("*** Removing cache entries older than %u (%u)\n", age, (unsigned int) tc->freeInCache);*/
age>>=1;
}
/*RELEASE_LOCK(&p->m[mymspace]->mutex);*/
}
static void threadcache_free(nedpool *p, threadcache *tc, int mymspace, void *mem, size_t size) THROWSPEC
{
unsigned int bestsize;
unsigned int idx=size2binidx(size);
threadcacheblk **binsptr, *tck=(threadcacheblk *) mem;
assert(size>=sizeof(threadcacheblk) && size<=THREADCACHEMAX+CHUNK_OVERHEAD);
#ifdef DEBUG
{ /* Make sure this is a valid memory block */
mchunkptr p = mem2chunk(mem);
mstate fm = get_mstate_for(p);
if (!ok_magic(fm)) {
USAGE_ERROR_ACTION(fm, p);
return;
}
}
#endif
#ifdef FULLSANITYCHECKS
tcfullsanitycheck(tc);
#endif
/* Calculate best fit bin size */
bestsize=1<<(idx+4);
#if 0
/* Finer grained bin fit */
idx<<=1;
if(size>bestsize)
{
unsigned int biggerbestsize=bestsize+bestsize<<1;
if(size>=biggerbestsize)
{
idx++;
bestsize=biggerbestsize;
}
}
#endif
if(bestsize!=size) /* dlmalloc can round up, so we round down to preserve indexing */
size=bestsize;
binsptr=&tc->bins[idx*2];
assert(idx<=THREADCACHEMAXBINS);
if(tck==*binsptr)
{
fprintf(stderr, "Attempt to free already freed memory block %p - aborting!\n", tck);
abort();
}
#ifdef FULLSANITYCHECKS
tck->magic=*(unsigned int *) "NEDN";
#endif
tck->lastUsed=++tc->frees;
tck->size=(unsigned int) size;
tck->next=*binsptr;
tck->prev=0;
if(tck->next)
tck->next->prev=tck;
else
binsptr[1]=tck;
assert(!*binsptr || (*binsptr)->size==tck->size);
*binsptr=tck;
assert(tck==tc->bins[idx*2]);
assert(tc->bins[idx*2+1]==tck || binsptr[0]->next->prev==tck);
/*printf("free: %p, %p, %p, %lu\n", p, tc, mem, (long) size);*/
tc->freeInCache+=size;
#ifdef FULLSANITYCHECKS
tcfullsanitycheck(tc);
#endif
#if 1
if(tc->freeInCache>=THREADCACHEMAXFREESPACE)
ReleaseFreeInCache(p, tc, mymspace);
#endif
}
static NOINLINE int InitPool(nedpool *p, size_t capacity, int threads) THROWSPEC
{ /* threads is -1 for system pool */
ensure_initialization();
ACQUIRE_MALLOC_GLOBAL_LOCK();
if(p->threads) goto done;
if(INITIAL_LOCK(&p->mutex)) goto err;
if(TLSALLOC(&p->mycache)) goto err;
if(!(p->m[0]=(mstate) create_mspace(capacity, 1))) goto err;
p->m[0]->extp=p;
p->threads=(threads<1 || threads>MAXTHREADSINPOOL) ? MAXTHREADSINPOOL : threads;
done:
RELEASE_MALLOC_GLOBAL_LOCK();
return 1;
err:
if(threads<0)
abort(); /* If you can't allocate for system pool, we're screwed */
DestroyCaches(p);
if(p->m[0])
{
destroy_mspace(p->m[0]);
p->m[0]=0;
}
if(p->mycache)
{
if(TLSFREE(p->mycache)) abort();
p->mycache=0;
}
RELEASE_MALLOC_GLOBAL_LOCK();
return 0;
}
static NOINLINE mstate FindMSpace(nedpool *p, threadcache *tc, int *lastUsed, size_t size) THROWSPEC
{ /* Gets called when thread's last used mspace is in use. The strategy
is to run through the list of all available mspaces looking for an
unlocked one and if we fail, we create a new one so long as we don't
exceed p->threads */
int n, end;
for(n=end=*lastUsed+1; p->m[n]; end=++n)
{
if(TRY_LOCK(&p->m[n]->mutex)) goto found;
}
for(n=0; n<*lastUsed && p->m[n]; n++)
{
if(TRY_LOCK(&p->m[n]->mutex)) goto found;
}
if(end<p->threads)
{
mstate temp;
if(!(temp=(mstate) create_mspace(size, 1)))
goto badexit;
/* Now we're ready to modify the lists, we lock */
ACQUIRE_LOCK(&p->mutex);
while(p->m[end] && end<p->threads)
end++;
if(end>=p->threads)
{ /* Drat, must destroy it now */
RELEASE_LOCK(&p->mutex);
destroy_mspace((mspace) temp);
goto badexit;
}
/* We really want to make sure this goes into memory now but we
have to be careful of breaking aliasing rules, so write it twice */
{
volatile struct malloc_state **_m=(volatile struct malloc_state **) &p->m[end];
*_m=(p->m[end]=temp);
}
ACQUIRE_LOCK(&p->m[end]->mutex);
/*printf("Created mspace idx %d\n", end);*/
RELEASE_LOCK(&p->mutex);
n=end;
goto found;
}
/* Let it lock on the last one it used */
badexit:
ACQUIRE_LOCK(&p->m[*lastUsed]->mutex);
return p->m[*lastUsed];
found:
*lastUsed=n;
if(tc)
tc->mymspace=n;
else
{
if(TLSSET(p->mycache, (void *)(size_t)(-(n+1)))) abort();
}
return p->m[n];
}
nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC
{
nedpool *ret;
if(!(ret=(nedpool *) nedpcalloc(0, 1, sizeof(nedpool)))) return 0;
if(!InitPool(ret, capacity, threads))
{
nedpfree(0, ret);
return 0;
}
return ret;
}
void neddestroypool(nedpool *p) THROWSPEC
{
int n;
ACQUIRE_LOCK(&p->mutex);
DestroyCaches(p);
for(n=0; p->m[n]; n++)
{
destroy_mspace(p->m[n]);
p->m[n]=0;
}
RELEASE_LOCK(&p->mutex);
if(TLSFREE(p->mycache)) abort();
nedpfree(0, p);
}
void nedpsetvalue(nedpool *p, void *v) THROWSPEC
{
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
p->uservalue=v;
}
void *nedgetvalue(nedpool **p, void *mem) THROWSPEC
{
nedpool *np=0;
mchunkptr mcp=mem2chunk(mem);
mstate fm;
if(!(is_aligned(chunk2mem(mcp))) && mcp->head != FENCEPOST_HEAD) return 0;
if(!cinuse(mcp)) return 0;
if(!next_pinuse(mcp)) return 0;
if(!is_mmapped(mcp) && !pinuse(mcp))
{
if(next_chunk(prev_chunk(mcp))!=mcp) return 0;
}
fm=get_mstate_for(mcp);
if(!ok_magic(fm)) return 0;
if(!ok_address(fm, mcp)) return 0;
if(!fm->extp) return 0;
np=(nedpool *) fm->extp;
if(p) *p=np;
return np->uservalue;
}
void neddisablethreadcache(nedpool *p) THROWSPEC
{
int mycache;
if(!p)
{
p=&syspool;
if(!syspool.threads) InitPool(&syspool, 0, -1);
}
mycache=(int)(size_t) TLSGET(p->mycache);
if(!mycache)
{ /* Set to mspace 0 */
if(TLSSET(p->mycache, (void *)-1)) abort();
}
else if(mycache>0)
{ /* Set to last used mspace */
threadcache *tc=p->caches[mycache-1];
#if defined(DEBUG)
printf("Threadcache utilisation: %lf%% in cache with %lf%% lost to other threads\n",
100.0*tc->successes/tc->mallocs, 100.0*((double) tc->mallocs-tc->frees)/tc->mallocs);
#endif
if(TLSSET(p->mycache, (void *)(size_t)(-tc->mymspace))) abort();
tc->frees++;
RemoveCacheEntries(p, tc, 0);
assert(!tc->freeInCache);
tc->mymspace=-1;
tc->threadid=0;
mspace_free(0, p->caches[mycache-1]);
p->caches[mycache-1]=0;
}
}
#define GETMSPACE(m,p,tc,ms,s,action) \
do \
{ \
mstate m = GetMSpace((p),(tc),(ms),(s)); \
action; \
RELEASE_LOCK(&m->mutex); \
} while (0)
static FORCEINLINE mstate GetMSpace(nedpool *p, threadcache *tc, int mymspace, size_t size) THROWSPEC
{ /* Returns a locked and ready for use mspace */
mstate m=p->m[mymspace];
assert(m);
if(!TRY_LOCK(&p->m[mymspace]->mutex)) m=FindMSpace(p, tc, &mymspace, size);\
/*assert(IS_LOCKED(&p->m[mymspace]->mutex));*/
return m;
}
static FORCEINLINE void GetThreadCache(nedpool **p, threadcache **tc, int *mymspace, size_t *size) THROWSPEC
{
int mycache;
if(size && *size<sizeof(threadcacheblk)) *size=sizeof(threadcacheblk);
if(!*p)
{
*p=&syspool;
if(!syspool.threads) InitPool(&syspool, 0, -1);
}
mycache=(int)(size_t) TLSGET((*p)->mycache);
if(mycache>0)
{
*tc=(*p)->caches[mycache-1];
*mymspace=(*tc)->mymspace;
}
else if(!mycache)
{
*tc=AllocCache(*p);
if(!*tc)
{ /* Disable */
if(TLSSET((*p)->mycache, (void *)-1)) abort();
*mymspace=0;
}
else
*mymspace=(*tc)->mymspace;
}
else
{
*tc=0;
*mymspace=-mycache-1;
}
assert(*mymspace>=0);
assert((long)(size_t)CURRENT_THREAD==(*tc)->threadid);
#ifdef FULLSANITYCHECKS
if(*tc)
{
if(*(unsigned int *)"NEDMALC1"!=(*tc)->magic1 || *(unsigned int *)"NEDMALC2"!=(*tc)->magic2)
{
abort();
}
}
#endif
}
void * nedpmalloc(nedpool *p, size_t size) THROWSPEC
{
void *ret=0;
threadcache *tc;
int mymspace;
GetThreadCache(&p, &tc, &mymspace, &size);
#if THREADCACHEMAX
if(tc && size<=THREADCACHEMAX)
{ /* Use the thread cache */
ret=threadcache_malloc(p, tc, &size);
}
#endif
if(!ret)
{ /* Use this thread's mspace */
GETMSPACE(m, p, tc, mymspace, size,
ret=mspace_malloc(m, size));
}
return ret;
}
void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC
{
size_t rsize=size*no;
void *ret=0;
threadcache *tc;
int mymspace;
GetThreadCache(&p, &tc, &mymspace, &rsize);
#if THREADCACHEMAX
if(tc && rsize<=THREADCACHEMAX)
{ /* Use the thread cache */
if((ret=threadcache_malloc(p, tc, &rsize)))
memset(ret, 0, rsize);
}
#endif
if(!ret)
{ /* Use this thread's mspace */
GETMSPACE(m, p, tc, mymspace, rsize,
ret=mspace_calloc(m, 1, rsize));
}
return ret;
}
void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC
{
void *ret=0;
threadcache *tc;
int mymspace;
if(!mem) return nedpmalloc(p, size);
GetThreadCache(&p, &tc, &mymspace, &size);
#if THREADCACHEMAX
if(tc && size && size<=THREADCACHEMAX)
{ /* Use the thread cache */
size_t memsize=nedblksize(mem);
assert(memsize);
if((ret=threadcache_malloc(p, tc, &size)))
{
memcpy(ret, mem, memsize<size ? memsize : size);
if(memsize<=THREADCACHEMAX)
threadcache_free(p, tc, mymspace, mem, memsize);
else
mspace_free(0, mem);
}
}
#endif
if(!ret)
{ /* Reallocs always happen in the mspace they happened in, so skip
locking the preferred mspace for this thread */
ret=mspace_realloc(0, mem, size);
}
return ret;
}
void nedpfree(nedpool *p, void *mem) THROWSPEC
{ /* Frees always happen in the mspace they happened in, so skip
locking the preferred mspace for this thread */
threadcache *tc;
int mymspace;
size_t memsize;
assert(mem);
GetThreadCache(&p, &tc, &mymspace, 0);
#if THREADCACHEMAX
memsize=nedblksize(mem);
assert(memsize);
if(mem && tc && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD))
threadcache_free(p, tc, mymspace, mem, memsize);
else
#endif
mspace_free(0, mem);
}
void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC
{
void *ret;
threadcache *tc;
int mymspace;
GetThreadCache(&p, &tc, &mymspace, &bytes);
{ /* Use this thread's mspace */
GETMSPACE(m, p, tc, mymspace, bytes,
ret=mspace_memalign(m, alignment, bytes));
}
return ret;
}
#if !NO_MALLINFO
struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC
{
int n;
struct mallinfo ret={0};
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
for(n=0; p->m[n]; n++)
{
struct mallinfo t=mspace_mallinfo(p->m[n]);
ret.arena+=t.arena;
ret.ordblks+=t.ordblks;
ret.hblkhd+=t.hblkhd;
ret.usmblks+=t.usmblks;
ret.uordblks+=t.uordblks;
ret.fordblks+=t.fordblks;
ret.keepcost+=t.keepcost;
}
return ret;
}
#endif
int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC
{
return mspace_mallopt(parno, value);
}
int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC
{
int n, ret=0;
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
for(n=0; p->m[n]; n++)
{
ret+=mspace_trim(p->m[n], pad);
}
return ret;
}
void nedpmalloc_stats(nedpool *p) THROWSPEC
{
int n;
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
for(n=0; p->m[n]; n++)
{
mspace_malloc_stats(p->m[n]);
}
}
size_t nedpmalloc_footprint(nedpool *p) THROWSPEC
{
size_t ret=0;
int n;
if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
for(n=0; p->m[n]; n++)
{
ret+=mspace_footprint(p->m[n]);
}
return ret;
}
void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC
{
void **ret;
threadcache *tc;
int mymspace;
GetThreadCache(&p, &tc, &mymspace, &elemsize);
GETMSPACE(m, p, tc, mymspace, elemsno*elemsize,
ret=mspace_independent_calloc(m, elemsno, elemsize, chunks));
return ret;
}
void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC
{
void **ret;
threadcache *tc;
int mymspace;
size_t i, *adjustedsizes=(size_t *) alloca(elems*sizeof(size_t));
if(!adjustedsizes) return 0;
for(i=0; i<elems; i++)
adjustedsizes[i]=sizes[i]<sizeof(threadcacheblk) ? sizeof(threadcacheblk) : sizes[i];
GetThreadCache(&p, &tc, &mymspace, 0);
GETMSPACE(m, p, tc, mymspace, 0,
ret=mspace_independent_comalloc(m, elems, adjustedsizes, chunks));
return ret;
}
#if defined(__cplusplus)
}
#endif

View file

@ -0,0 +1,180 @@
/* nedalloc, an alternative malloc implementation for multiple threads without
lock contention based on dlmalloc v2.8.3. (C) 2005 Niall Douglas
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef NEDMALLOC_H
#define NEDMALLOC_H
/* See malloc.c.h for what each function does.
REPLACE_SYSTEM_ALLOCATOR causes nedalloc's functions to be called malloc,
free etc. instead of nedmalloc, nedfree etc. You may or may not want this.
NO_NED_NAMESPACE prevents the functions from being defined in the nedalloc
namespace when in C++ (uses the global namespace instead).
EXTSPEC can be defined to be __declspec(dllexport) or
__attribute__ ((visibility("default"))) or whatever you like. It defaults
to extern.
USE_LOCKS can be 2 if you want to define your own MLOCK_T, INITIAL_LOCK,
ACQUIRE_LOCK, RELEASE_LOCK, TRY_LOCK, IS_LOCKED and NULL_LOCK_INITIALIZER.
*/
#include <stddef.h> /* for size_t */
#ifndef EXTSPEC
#define EXTSPEC extern
#endif
#if defined(_MSC_VER) && _MSC_VER>=1400
#define MALLOCATTR __declspec(restrict)
#endif
#ifdef __GNUC__
#define MALLOCATTR __attribute__ ((malloc))
#endif
#ifndef MALLOCATTR
#define MALLOCATTR
#endif
#ifdef REPLACE_SYSTEM_ALLOCATOR
#define nedmalloc malloc
#define nedcalloc calloc
#define nedrealloc realloc
#define nedfree free
#define nedmemalign memalign
#define nedmallinfo mallinfo
#define nedmallopt mallopt
#define nedmalloc_trim malloc_trim
#define nedmalloc_stats malloc_stats
#define nedmalloc_footprint malloc_footprint
#define nedindependent_calloc independent_calloc
#define nedindependent_comalloc independent_comalloc
#ifdef _MSC_VER
#define nedblksize _msize
#endif
#endif
#ifndef NO_MALLINFO
#define NO_MALLINFO 0
#endif
#if !NO_MALLINFO
struct mallinfo;
#endif
#if defined(__cplusplus)
#if !defined(NO_NED_NAMESPACE)
namespace nedalloc {
#else
extern "C" {
#endif
#define THROWSPEC throw()
#else
#define THROWSPEC
#endif
/* These are the global functions */
/* Gets the usable size of an allocated block. Note this will always be bigger than what was
asked for due to rounding etc.
*/
EXTSPEC size_t nedblksize(void *mem) THROWSPEC;
EXTSPEC void nedsetvalue(void *v) THROWSPEC;
EXTSPEC MALLOCATTR void * nedmalloc(size_t size) THROWSPEC;
EXTSPEC MALLOCATTR void * nedcalloc(size_t no, size_t size) THROWSPEC;
EXTSPEC MALLOCATTR void * nedrealloc(void *mem, size_t size) THROWSPEC;
EXTSPEC void nedfree(void *mem) THROWSPEC;
EXTSPEC MALLOCATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC;
#if !NO_MALLINFO
EXTSPEC struct mallinfo nedmallinfo(void) THROWSPEC;
#endif
EXTSPEC int nedmallopt(int parno, int value) THROWSPEC;
EXTSPEC int nedmalloc_trim(size_t pad) THROWSPEC;
EXTSPEC void nedmalloc_stats(void) THROWSPEC;
EXTSPEC size_t nedmalloc_footprint(void) THROWSPEC;
EXTSPEC MALLOCATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
EXTSPEC MALLOCATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC;
/* These are the pool functions */
struct nedpool_t;
typedef struct nedpool_t nedpool;
/* Creates a memory pool for use with the nedp* functions below.
Capacity is how much to allocate immediately (if you know you'll be allocating a lot
of memory very soon) which you can leave at zero. Threads specifies how many threads
will *normally* be accessing the pool concurrently. Setting this to zero means it
extends on demand, but be careful of this as it can rapidly consume system resources
where bursts of concurrent threads use a pool at once.
*/
EXTSPEC MALLOCATTR nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC;
/* Destroys a memory pool previously created by nedcreatepool().
*/
EXTSPEC void neddestroypool(nedpool *p) THROWSPEC;
/* Sets a value to be associated with a pool. You can retrieve this value by passing
any memory block allocated from that pool.
*/
EXTSPEC void nedpsetvalue(nedpool *p, void *v) THROWSPEC;
/* Gets a previously set value using nedpsetvalue() or zero if memory is unknown.
Optionally can also retrieve pool.
*/
EXTSPEC void *nedgetvalue(nedpool **p, void *mem) THROWSPEC;
/* Disables the thread cache for the calling thread, returning any existing cache
data to the central pool.
*/
EXTSPEC void neddisablethreadcache(nedpool *p) THROWSPEC;
EXTSPEC MALLOCATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC;
EXTSPEC MALLOCATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC;
EXTSPEC MALLOCATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC;
EXTSPEC void nedpfree(nedpool *p, void *mem) THROWSPEC;
EXTSPEC MALLOCATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC;
#if !NO_MALLINFO
EXTSPEC struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC;
#endif
EXTSPEC int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC;
EXTSPEC int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC;
EXTSPEC void nedpmalloc_stats(nedpool *p) THROWSPEC;
EXTSPEC size_t nedpmalloc_footprint(nedpool *p) THROWSPEC;
EXTSPEC MALLOCATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
EXTSPEC MALLOCATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC;
#if defined(__cplusplus)
}
#endif
#undef MALLOCATTR
#undef EXTSPEC
#endif

413
third_party/git/compat/obstack.c vendored Normal file
View file

@ -0,0 +1,413 @@
/* obstack.c - subroutines used implicitly by object stack macros
Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005 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 Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include "git-compat-util.h"
#include <gettext.h>
#include "obstack.h"
/* NOTE BEFORE MODIFYING THIS FILE: This version number must be
incremented whenever callers compiled using an old obstack.h can no
longer properly call the functions in this obstack.c. */
#define OBSTACK_INTERFACE_VERSION 1
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself, and the installed library
supports the same library interface we do. 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. */
#include <stdio.h> /* Random thing to get __GNU_LIBRARY__. */
#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
# include <gnu-versions.h>
# if _GNU_OBSTACK_INTERFACE_VERSION == OBSTACK_INTERFACE_VERSION
# define ELIDE_CODE
# endif
#endif
#include <stddef.h>
#ifndef ELIDE_CODE
# if HAVE_INTTYPES_H
# include <inttypes.h>
# endif
# if HAVE_STDINT_H || defined _LIBC
# include <stdint.h>
# endif
/* Determine default alignment. */
union fooround
{
uintmax_t i;
long double d;
void *p;
};
struct fooalign
{
char c;
union fooround u;
};
/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
But in fact it might be less smart and round addresses to as much as
DEFAULT_ROUNDING. So we prepare for it to do that. */
enum
{
DEFAULT_ALIGNMENT = offsetof (struct fooalign, u),
DEFAULT_ROUNDING = sizeof (union fooround)
};
/* When we copy a long block of data, this is the unit to do it with.
On some machines, copying successive ints does not work;
in such a case, redefine COPYING_UNIT to `long' (if that works)
or `char' as a last resort. */
# ifndef COPYING_UNIT
# define COPYING_UNIT int
# endif
/* The functions allocating more room by calling `obstack_chunk_alloc'
jump to the handler pointed to by `obstack_alloc_failed_handler'.
This can be set to a user defined function which should either
abort gracefully or use longjump - but shouldn't return. This
variable by default points to the internal function
`print_and_abort'. */
static void print_and_abort (void);
void (*obstack_alloc_failed_handler) (void) = print_and_abort;
# ifdef _LIBC
# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
/* A looong time ago (before 1994, anyway; we're not sure) this global variable
was used by non-GNU-C macros to avoid multiple evaluation. The GNU C
library still exports it because somebody might use it. */
struct obstack *_obstack_compat;
compat_symbol (libc, _obstack_compat, _obstack, GLIBC_2_0);
# endif
# endif
/* Define a macro that either calls functions with the traditional malloc/free
calling interface, or calls functions with the mmalloc/mfree interface
(that adds an extra first argument), based on the state of use_extra_arg.
For free, do not use ?:, since some compilers, like the MIPS compilers,
do not allow (expr) ? void : void. */
# define CALL_CHUNKFUN(h, size) \
(((h) -> use_extra_arg) \
? (*(h)->chunkfun.extra) ((h)->extra_arg, (size)) \
: (*(h)->chunkfun.plain) ((size)))
# define CALL_FREEFUN(h, old_chunk) \
do { \
if ((h) -> use_extra_arg) \
(*(h)->freefun.extra) ((h)->extra_arg, (old_chunk)); \
else \
(*(h)->freefun.plain) ((old_chunk)); \
} while (0)
/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
Objects start on multiples of ALIGNMENT (0 means use default).
CHUNKFUN is the function to use to allocate chunks,
and FREEFUN the function to free them.
Return nonzero if successful, calls obstack_alloc_failed_handler if
allocation fails. */
int
_obstack_begin (struct obstack *h,
int size, int alignment,
void *(*chunkfun) (long),
void (*freefun) (void *))
{
register struct _obstack_chunk *chunk; /* points to new chunk */
if (alignment == 0)
alignment = DEFAULT_ALIGNMENT;
if (size == 0)
/* Default size is what GNU malloc can fit in a 4096-byte block. */
{
/* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
Use the values for range checking, because if range checking is off,
the extra bytes won't be missed terribly, but if range checking is on
and we used a larger request, a whole extra 4096 bytes would be
allocated.
These number are irrelevant to the new GNU malloc. I suspect it is
less sensitive to the size of the request. */
int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ 4 + DEFAULT_ROUNDING - 1)
& ~(DEFAULT_ROUNDING - 1));
size = 4096 - extra;
}
h->chunkfun.plain = chunkfun;
h->freefun.plain = freefun;
h->chunk_size = size;
h->alignment_mask = alignment - 1;
h->use_extra_arg = 0;
chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
if (!chunk)
(*obstack_alloc_failed_handler) ();
h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
alignment - 1);
h->chunk_limit = chunk->limit
= (char *) chunk + h->chunk_size;
chunk->prev = NULL;
/* The initial chunk now contains no empty object. */
h->maybe_empty_object = 0;
h->alloc_failed = 0;
return 1;
}
int
_obstack_begin_1 (struct obstack *h, int size, int alignment,
void *(*chunkfun) (void *, long),
void (*freefun) (void *, void *),
void *arg)
{
register struct _obstack_chunk *chunk; /* points to new chunk */
if (alignment == 0)
alignment = DEFAULT_ALIGNMENT;
if (size == 0)
/* Default size is what GNU malloc can fit in a 4096-byte block. */
{
/* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
Use the values for range checking, because if range checking is off,
the extra bytes won't be missed terribly, but if range checking is on
and we used a larger request, a whole extra 4096 bytes would be
allocated.
These number are irrelevant to the new GNU malloc. I suspect it is
less sensitive to the size of the request. */
int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ 4 + DEFAULT_ROUNDING - 1)
& ~(DEFAULT_ROUNDING - 1));
size = 4096 - extra;
}
h->chunkfun.extra = (struct _obstack_chunk * (*)(void *,long)) chunkfun;
h->freefun.extra = (void (*) (void *, struct _obstack_chunk *)) freefun;
h->chunk_size = size;
h->alignment_mask = alignment - 1;
h->extra_arg = arg;
h->use_extra_arg = 1;
chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
if (!chunk)
(*obstack_alloc_failed_handler) ();
h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
alignment - 1);
h->chunk_limit = chunk->limit
= (char *) chunk + h->chunk_size;
chunk->prev = NULL;
/* The initial chunk now contains no empty object. */
h->maybe_empty_object = 0;
h->alloc_failed = 0;
return 1;
}
/* Allocate a new current chunk for the obstack *H
on the assumption that LENGTH bytes need to be added
to the current object, or a new object of length LENGTH allocated.
Copies any partial object from the end of the old chunk
to the beginning of the new one. */
void
_obstack_newchunk (struct obstack *h, int length)
{
register struct _obstack_chunk *old_chunk = h->chunk;
register struct _obstack_chunk *new_chunk;
register long new_size;
register long obj_size = h->next_free - h->object_base;
register long i;
long already;
char *object_base;
/* Compute size for new chunk. */
new_size = (obj_size + length) + (obj_size >> 3) + h->alignment_mask + 100;
if (new_size < h->chunk_size)
new_size = h->chunk_size;
/* Allocate and initialize the new chunk. */
new_chunk = CALL_CHUNKFUN (h, new_size);
if (!new_chunk)
(*obstack_alloc_failed_handler) ();
h->chunk = new_chunk;
new_chunk->prev = old_chunk;
new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
/* Compute an aligned object_base in the new chunk */
object_base =
__PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask);
/* Move the existing object to the new chunk.
Word at a time is fast and is safe if the object
is sufficiently aligned. */
if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
{
for (i = obj_size / sizeof (COPYING_UNIT) - 1;
i >= 0; i--)
((COPYING_UNIT *)object_base)[i]
= ((COPYING_UNIT *)h->object_base)[i];
/* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
but that can cross a page boundary on a machine
which does not do strict alignment for COPYING_UNITS. */
already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
}
else
already = 0;
/* Copy remaining bytes one by one. */
for (i = already; i < obj_size; i++)
object_base[i] = h->object_base[i];
/* If the object just copied was the only data in OLD_CHUNK,
free that chunk and remove it from the chain.
But not if that chunk might contain an empty object. */
if (! h->maybe_empty_object
&& (h->object_base
== __PTR_ALIGN ((char *) old_chunk, old_chunk->contents,
h->alignment_mask)))
{
new_chunk->prev = old_chunk->prev;
CALL_FREEFUN (h, old_chunk);
}
h->object_base = object_base;
h->next_free = h->object_base + obj_size;
/* The new chunk certainly contains no empty object yet. */
h->maybe_empty_object = 0;
}
# ifdef _LIBC
libc_hidden_def (_obstack_newchunk)
# endif
/* Return nonzero if object OBJ has been allocated from obstack H.
This is here for debugging.
If you use it in a program, you are probably losing. */
/* Suppress -Wmissing-prototypes warning. We don't want to declare this in
obstack.h because it is just for debugging. */
int _obstack_allocated_p (struct obstack *h, void *obj);
int
_obstack_allocated_p (struct obstack *h, void *obj)
{
register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
register struct _obstack_chunk *plp; /* point to previous chunk if any */
lp = (h)->chunk;
/* We use >= rather than > since the object cannot be exactly at
the beginning of the chunk but might be an empty object exactly
at the end of an adjacent chunk. */
while (lp != NULL && ((void *) lp >= obj || (void *) (lp)->limit < obj))
{
plp = lp->prev;
lp = plp;
}
return lp != NULL;
}
/* Free objects in obstack H, including OBJ and everything allocate
more recently than OBJ. If OBJ is zero, free everything in H. */
# undef obstack_free
void
obstack_free (struct obstack *h, void *obj)
{
register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
register struct _obstack_chunk *plp; /* point to previous chunk if any */
lp = h->chunk;
/* We use >= because there cannot be an object at the beginning of a chunk.
But there can be an empty object at that address
at the end of another chunk. */
while (lp != NULL && ((void *) lp >= obj || (void *) (lp)->limit < obj))
{
plp = lp->prev;
CALL_FREEFUN (h, lp);
lp = plp;
/* If we switch chunks, we can't tell whether the new current
chunk contains an empty object, so assume that it may. */
h->maybe_empty_object = 1;
}
if (lp)
{
h->object_base = h->next_free = (char *) (obj);
h->chunk_limit = lp->limit;
h->chunk = lp;
}
else if (obj != NULL)
/* obj is not in any of the chunks! */
abort ();
}
# ifdef _LIBC
/* Older versions of libc used a function _obstack_free intended to be
called by non-GCC compilers. */
strong_alias (obstack_free, _obstack_free)
# endif
int
_obstack_memory_used (struct obstack *h)
{
register struct _obstack_chunk* lp;
register int nbytes = 0;
for (lp = h->chunk; lp != NULL; lp = lp->prev)
{
nbytes += lp->limit - (char *) lp;
}
return nbytes;
}
# ifdef _LIBC
# include <libio/iolibio.h>
# endif
# ifndef __attribute__
/* This feature is available in gcc versions 2.5 and later. */
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
# define __attribute__(Spec) /* empty */
# endif
# endif
static void
print_and_abort (void)
{
/* Don't change any of these strings. Yes, it would be possible to add
the newline to the string and use fputs or so. But this must not
happen because the "memory exhausted" message appears in other places
like this and the translation should be reused instead of creating
a very similar string which requires a separate translation. */
# ifdef _LIBC
(void) __fxprintf (NULL, "%s\n", _("memory exhausted"));
# else
fprintf (stderr, "%s\n", _("memory exhausted"));
# endif
exit (1);
}
#endif /* !ELIDE_CODE */

509
third_party/git/compat/obstack.h vendored Normal file
View file

@ -0,0 +1,509 @@
/* obstack.h - object stack macros
Copyright (C) 1988-1994,1996-1999,2003,2004,2005,2009
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 Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* Summary:
All the apparent functions defined here are macros. The idea
is that you would use these pre-tested macros to solve a
very specific set of problems, and they would run fast.
Caution: no side-effects in arguments please!! They may be
evaluated MANY times!!
These macros operate a stack of objects. Each object starts life
small, and may grow to maturity. (Consider building a word syllable
by syllable.) An object can move while it is growing. Once it has
been "finished" it never changes address again. So the "top of the
stack" is typically an immature growing object, while the rest of the
stack is of mature, fixed size and fixed address objects.
These routines grab large chunks of memory, using a function you
supply, called `obstack_chunk_alloc'. On occasion, they free chunks,
by calling `obstack_chunk_free'. You must define them and declare
them before using any obstack macros.
Each independent stack is represented by a `struct obstack'.
Each of the obstack macros expects a pointer to such a structure
as the first argument.
One motivation for this package is the problem of growing char strings
in symbol tables. Unless you are "fascist pig with a read-only mind"
--Gosper's immortal quote from HAKMEM item 154, out of context--you
would not like to put any arbitrary upper limit on the length of your
symbols.
In practice this often means you will build many short symbols and a
few long symbols. At the time you are reading a symbol you don't know
how long it is. One traditional method is to read a symbol into a
buffer, realloc()ating the buffer every time you try to read a symbol
that is longer than the buffer. This is beaut, but you still will
want to copy the symbol from the buffer to a more permanent
symbol-table entry say about half the time.
With obstacks, you can work differently. Use one obstack for all symbol
names. As you read a symbol, grow the name in the obstack gradually.
When the name is complete, finalize it. Then, if the symbol exists already,
free the newly read name.
The way we do this is to take a large chunk, allocating memory from
low addresses. When you want to build a symbol in the chunk you just
add chars above the current "high water mark" in the chunk. When you
have finished adding chars, because you got to the end of the symbol,
you know how long the chars are, and you can create a new object.
Mostly the chars will not burst over the highest address of the chunk,
because you would typically expect a chunk to be (say) 100 times as
long as an average object.
In case that isn't clear, when we have enough chars to make up
the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
so we just point to it where it lies. No moving of chars is
needed and this is the second win: potentially long strings need
never be explicitly shuffled. Once an object is formed, it does not
change its address during its lifetime.
When the chars burst over a chunk boundary, we allocate a larger
chunk, and then copy the partly formed object from the end of the old
chunk to the beginning of the new larger chunk. We then carry on
accreting characters to the end of the object as we normally would.
A special macro is provided to add a single char at a time to a
growing object. This allows the use of register variables, which
break the ordinary 'growth' macro.
Summary:
We allocate large chunks.
We carve out one object at a time from the current chunk.
Once carved, an object never moves.
We are free to append data of any size to the currently
growing object.
Exactly one object is growing in an obstack at any one time.
You can run one obstack per control block.
You may have as many control blocks as you dare.
Because of the way we do it, you can `unwind' an obstack
back to a previous state. (You may remove objects much
as you would with a stack.)
*/
/* Don't do the contents of this file more than once. */
#ifndef _OBSTACK_H
#define _OBSTACK_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* We need the type of a pointer subtraction. If __PTRDIFF_TYPE__ is
defined, as with GNU C, use that; that way we don't pollute the
namespace with <stddef.h>'s symbols. Otherwise, include <stddef.h>
and use ptrdiff_t. */
#ifdef __PTRDIFF_TYPE__
# define PTR_INT_TYPE __PTRDIFF_TYPE__
#else
# include <stddef.h>
# define PTR_INT_TYPE ptrdiff_t
#endif
/* If B is the base of an object addressed by P, return the result of
aligning P to the next multiple of A + 1. B and P must be of type
char *. A + 1 must be a power of 2. */
#define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A)))
/* Similar to _BPTR_ALIGN (B, P, A), except optimize the common case
where pointers can be converted to integers, aligned as integers,
and converted back again. If PTR_INT_TYPE is narrower than a
pointer (e.g., the AS/400), play it safe and compute the alignment
relative to B. Otherwise, use the faster strategy of computing the
alignment relative to 0. */
#define __PTR_ALIGN(B, P, A) \
__BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \
P, A)
#include <string.h>
struct _obstack_chunk /* Lives at front of each chunk. */
{
char *limit; /* 1 past end of this chunk */
struct _obstack_chunk *prev; /* address of prior chunk or NULL */
char contents[4]; /* objects begin here */
};
struct obstack /* control current object in current chunk */
{
long chunk_size; /* preferred size to allocate chunks in */
struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */
char *object_base; /* address of object we are building */
char *next_free; /* where to add next char to current object */
char *chunk_limit; /* address of char after current chunk */
union
{
PTR_INT_TYPE tempint;
void *tempptr;
} temp; /* Temporary for some macros. */
int alignment_mask; /* Mask of alignment for each object. */
/* These prototypes vary based on `use_extra_arg'. */
union {
void *(*plain) (long);
struct _obstack_chunk *(*extra) (void *, long);
} chunkfun;
union {
void (*plain) (void *);
void (*extra) (void *, struct _obstack_chunk *);
} freefun;
void *extra_arg; /* first arg for chunk alloc/dealloc funcs */
unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */
unsigned maybe_empty_object:1;/* There is a possibility that the current
chunk contains a zero-length object. This
prevents freeing the chunk if we allocate
a bigger chunk to replace it. */
unsigned alloc_failed:1; /* No longer used, as we now call the failed
handler on error, but retained for binary
compatibility. */
};
/* Declare the external functions we use; they are in obstack.c. */
extern void _obstack_newchunk (struct obstack *, int);
extern int _obstack_begin (struct obstack *, int, int,
void *(*) (long), void (*) (void *));
extern int _obstack_begin_1 (struct obstack *, int, int,
void *(*) (void *, long),
void (*) (void *, void *), void *);
extern int _obstack_memory_used (struct obstack *);
void obstack_free (struct obstack *, void *);
/* Error handler called when `obstack_chunk_alloc' failed to allocate
more memory. This can be set to a user defined function which
should either abort gracefully or use longjump - but shouldn't
return. The default action is to print a message and abort. */
extern void (*obstack_alloc_failed_handler) (void);
/* Pointer to beginning of object being allocated or to be allocated next.
Note that this might not be the final address of the object
because a new chunk might be needed to hold the final size. */
#define obstack_base(h) ((void *) (h)->object_base)
/* Size for allocating ordinary chunks. */
#define obstack_chunk_size(h) ((h)->chunk_size)
/* Pointer to next byte not yet allocated in current chunk. */
#define obstack_next_free(h) ((h)->next_free)
/* Mask specifying low bits that should be clear in address of an object. */
#define obstack_alignment_mask(h) ((h)->alignment_mask)
/* To prevent prototype warnings provide complete argument list. */
#define obstack_init(h) \
_obstack_begin ((h), 0, 0, \
(void *(*) (long)) obstack_chunk_alloc, \
(void (*) (void *)) obstack_chunk_free)
#define obstack_begin(h, size) \
_obstack_begin ((h), (size), 0, \
(void *(*) (long)) obstack_chunk_alloc, \
(void (*) (void *)) obstack_chunk_free)
#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
_obstack_begin ((h), (size), (alignment), \
(void *(*) (long)) (chunkfun), \
(void (*) (void *)) (freefun))
#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
_obstack_begin_1 ((h), (size), (alignment), \
(void *(*) (void *, long)) (chunkfun), \
(void (*) (void *, void *)) (freefun), (arg))
#define obstack_chunkfun(h, newchunkfun) \
((h)->chunkfun.extra = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun))
#define obstack_freefun(h, newfreefun) \
((h)->freefun.extra = (void (*)(void *, struct _obstack_chunk *)) (newfreefun))
#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = (achar))
#define obstack_blank_fast(h,n) ((h)->next_free += (n))
#define obstack_memory_used(h) _obstack_memory_used (h)
#if defined __GNUC__ && defined __STDC__ && __STDC__
/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and
does not implement __extension__. But that compiler doesn't define
__GNUC_MINOR__. */
# if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
# define __extension__
# endif
/* For GNU C, if not -traditional,
we can define these macros to compute all args only once
without using a global variable.
Also, we can avoid using the `temp' slot, to make faster code. */
# define obstack_object_size(OBSTACK) \
__extension__ \
({ struct obstack const *__o = (OBSTACK); \
(unsigned) (__o->next_free - __o->object_base); })
# define obstack_room(OBSTACK) \
__extension__ \
({ struct obstack const *__o = (OBSTACK); \
(unsigned) (__o->chunk_limit - __o->next_free); })
# define obstack_make_room(OBSTACK,length) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
int __len = (length); \
if (__o->chunk_limit - __o->next_free < __len) \
_obstack_newchunk (__o, __len); \
(void) 0; })
# define obstack_empty_p(OBSTACK) \
__extension__ \
({ struct obstack const *__o = (OBSTACK); \
(__o->chunk->prev == 0 \
&& __o->next_free == __PTR_ALIGN ((char *) __o->chunk, \
__o->chunk->contents, \
__o->alignment_mask)); })
# define obstack_grow(OBSTACK,where,length) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
int __len = (length); \
if (__o->next_free + __len > __o->chunk_limit) \
_obstack_newchunk (__o, __len); \
memcpy (__o->next_free, where, __len); \
__o->next_free += __len; \
(void) 0; })
# define obstack_grow0(OBSTACK,where,length) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
int __len = (length); \
if (__o->next_free + __len + 1 > __o->chunk_limit) \
_obstack_newchunk (__o, __len + 1); \
memcpy (__o->next_free, where, __len); \
__o->next_free += __len; \
*(__o->next_free)++ = 0; \
(void) 0; })
# define obstack_1grow(OBSTACK,datum) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
if (__o->next_free + 1 > __o->chunk_limit) \
_obstack_newchunk (__o, 1); \
obstack_1grow_fast (__o, datum); \
(void) 0; })
/* These assume that the obstack alignment is good enough for pointers
or ints, and that the data added so far to the current object
shares that much alignment. */
# define obstack_ptr_grow(OBSTACK,datum) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
if (__o->next_free + sizeof (void *) > __o->chunk_limit) \
_obstack_newchunk (__o, sizeof (void *)); \
obstack_ptr_grow_fast (__o, datum); }) \
# define obstack_int_grow(OBSTACK,datum) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
if (__o->next_free + sizeof (int) > __o->chunk_limit) \
_obstack_newchunk (__o, sizeof (int)); \
obstack_int_grow_fast (__o, datum); })
# define obstack_ptr_grow_fast(OBSTACK,aptr) \
__extension__ \
({ struct obstack *__o1 = (OBSTACK); \
*(const void **) __o1->next_free = (aptr); \
__o1->next_free += sizeof (const void *); \
(void) 0; })
# define obstack_int_grow_fast(OBSTACK,aint) \
__extension__ \
({ struct obstack *__o1 = (OBSTACK); \
*(int *) __o1->next_free = (aint); \
__o1->next_free += sizeof (int); \
(void) 0; })
# define obstack_blank(OBSTACK,length) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
int __len = (length); \
if (__o->chunk_limit - __o->next_free < __len) \
_obstack_newchunk (__o, __len); \
obstack_blank_fast (__o, __len); \
(void) 0; })
# define obstack_alloc(OBSTACK,length) \
__extension__ \
({ struct obstack *__h = (OBSTACK); \
obstack_blank (__h, (length)); \
obstack_finish (__h); })
# define obstack_copy(OBSTACK,where,length) \
__extension__ \
({ struct obstack *__h = (OBSTACK); \
obstack_grow (__h, (where), (length)); \
obstack_finish (__h); })
# define obstack_copy0(OBSTACK,where,length) \
__extension__ \
({ struct obstack *__h = (OBSTACK); \
obstack_grow0 (__h, (where), (length)); \
obstack_finish (__h); })
/* The local variable is named __o1 to avoid a name conflict
when obstack_blank is called. */
# define obstack_finish(OBSTACK) \
__extension__ \
({ struct obstack *__o1 = (OBSTACK); \
void *__value = (void *) __o1->object_base; \
if (__o1->next_free == __value) \
__o1->maybe_empty_object = 1; \
__o1->next_free \
= __PTR_ALIGN (__o1->object_base, __o1->next_free, \
__o1->alignment_mask); \
if (__o1->next_free - (char *)__o1->chunk \
> __o1->chunk_limit - (char *)__o1->chunk) \
__o1->next_free = __o1->chunk_limit; \
__o1->object_base = __o1->next_free; \
__value; })
# define obstack_free(OBSTACK, OBJ) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
void *__obj = (OBJ); \
if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \
__o->next_free = __o->object_base = (char *)__obj; \
else (obstack_free) (__o, __obj); })
#else /* not __GNUC__ or not __STDC__ */
# define obstack_object_size(h) \
(unsigned) ((h)->next_free - (h)->object_base)
# define obstack_room(h) \
(unsigned) ((h)->chunk_limit - (h)->next_free)
# define obstack_empty_p(h) \
((h)->chunk->prev == 0 \
&& (h)->next_free == __PTR_ALIGN ((char *) (h)->chunk, \
(h)->chunk->contents, \
(h)->alignment_mask))
/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
so that we can avoid having void expressions
in the arms of the conditional expression.
Casting the third operand to void was tried before,
but some compilers won't accept it. */
# define obstack_make_room(h,length) \
( (h)->temp.tempint = (length), \
(((h)->next_free + (h)->temp.tempint > (h)->chunk_limit) \
? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0))
# define obstack_grow(h,where,length) \
( (h)->temp.tempint = (length), \
(((h)->next_free + (h)->temp.tempint > (h)->chunk_limit) \
? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0), \
memcpy ((h)->next_free, where, (h)->temp.tempint), \
(h)->next_free += (h)->temp.tempint)
# define obstack_grow0(h,where,length) \
( (h)->temp.tempint = (length), \
(((h)->next_free + (h)->temp.tempint + 1 > (h)->chunk_limit) \
? (_obstack_newchunk ((h), (h)->temp.tempint + 1), 0) : 0), \
memcpy ((h)->next_free, where, (h)->temp.tempint), \
(h)->next_free += (h)->temp.tempint, \
*((h)->next_free)++ = 0)
# define obstack_1grow(h,datum) \
( (((h)->next_free + 1 > (h)->chunk_limit) \
? (_obstack_newchunk ((h), 1), 0) : 0), \
obstack_1grow_fast (h, datum))
# define obstack_ptr_grow(h,datum) \
( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \
? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \
obstack_ptr_grow_fast (h, datum))
# define obstack_int_grow(h,datum) \
( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \
? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \
obstack_int_grow_fast (h, datum))
# define obstack_ptr_grow_fast(h,aptr) \
(((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr))
# define obstack_int_grow_fast(h,aint) \
(((int *) ((h)->next_free += sizeof (int)))[-1] = (aint))
# define obstack_blank(h,length) \
( (h)->temp.tempint = (length), \
(((h)->chunk_limit - (h)->next_free < (h)->temp.tempint) \
? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0), \
obstack_blank_fast (h, (h)->temp.tempint))
# define obstack_alloc(h,length) \
(obstack_blank ((h), (length)), obstack_finish ((h)))
# define obstack_copy(h,where,length) \
(obstack_grow ((h), (where), (length)), obstack_finish ((h)))
# define obstack_copy0(h,where,length) \
(obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
# define obstack_finish(h) \
( ((h)->next_free == (h)->object_base \
? (((h)->maybe_empty_object = 1), 0) \
: 0), \
(h)->temp.tempptr = (h)->object_base, \
(h)->next_free \
= __PTR_ALIGN ((h)->object_base, (h)->next_free, \
(h)->alignment_mask), \
(((h)->next_free - (char *) (h)->chunk \
> (h)->chunk_limit - (char *) (h)->chunk) \
? ((h)->next_free = (h)->chunk_limit) : 0), \
(h)->object_base = (h)->next_free, \
(h)->temp.tempptr)
# define obstack_free(h,obj) \
( (h)->temp.tempint = (char *) (obj) - (char *) (h)->chunk, \
((((h)->temp.tempint > 0 \
&& (h)->temp.tempint < (h)->chunk_limit - (char *) (h)->chunk)) \
? (ptrdiff_t) ((h)->next_free = (h)->object_base \
= (h)->temp.tempint + (char *) (h)->chunk) \
: (((obstack_free) ((h), (h)->temp.tempint + (char *) (h)->chunk), 0), 0)))
#endif /* not __GNUC__ or not __STDC__ */
#ifdef __cplusplus
} /* C++ */
#endif
#endif /* obstack.h */

633
third_party/git/compat/poll/poll.c vendored Normal file
View file

@ -0,0 +1,633 @@
/* Emulation for poll(2)
Contributed by Paolo Bonzini.
Copyright 2001-2003, 2006-2011 Free Software Foundation, Inc.
This file is part of gnulib.
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, see <http://www.gnu.org/licenses/>. */
/* To bump the minimum Windows version to Windows Vista */
#include "git-compat-util.h"
/* Tell gcc not to warn about the (nfd < 0) tests, below. */
#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
# pragma GCC diagnostic ignored "-Wtype-limits"
#endif
#if defined(WIN32)
# include <malloc.h>
#endif
#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#include <assert.h>
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
# define WIN32_NATIVE
# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0502
# endif
# include <winsock2.h>
# include <windows.h>
# include <io.h>
# include <stdio.h>
# include <conio.h>
#else
# include <sys/time.h>
# include <sys/socket.h>
# ifndef NO_SYS_SELECT_H
# include <sys/select.h>
# endif
# include <unistd.h>
#endif
/* Specification. */
#include "poll.h"
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
#include <time.h>
#ifndef INFTIM
# define INFTIM (-1)
#endif
/* BeOS does not have MSG_PEEK. */
#ifndef MSG_PEEK
# define MSG_PEEK 0
#endif
#ifdef WIN32_NATIVE
#define IsConsoleHandle(h) (((long) (intptr_t) (h) & 3) == 3)
static BOOL
IsSocketHandle (HANDLE h)
{
WSANETWORKEVENTS ev;
if (IsConsoleHandle (h))
return FALSE;
/* Under Wine, it seems that getsockopt returns 0 for pipes too.
WSAEnumNetworkEvents instead distinguishes the two correctly. */
ev.lNetworkEvents = 0xDEADBEEF;
WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
return ev.lNetworkEvents != 0xDEADBEEF;
}
/* Declare data structures for ntdll functions. */
typedef struct _FILE_PIPE_LOCAL_INFORMATION {
ULONG NamedPipeType;
ULONG NamedPipeConfiguration;
ULONG MaximumInstances;
ULONG CurrentInstances;
ULONG InboundQuota;
ULONG ReadDataAvailable;
ULONG OutboundQuota;
ULONG WriteQuotaAvailable;
ULONG NamedPipeState;
ULONG NamedPipeEnd;
} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
typedef struct _IO_STATUS_BLOCK
{
union {
DWORD Status;
PVOID Pointer;
} u;
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
typedef enum _FILE_INFORMATION_CLASS {
FilePipeLocalInformation = 24
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
typedef DWORD (WINAPI *PNtQueryInformationFile)
(HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
# ifndef PIPE_BUF
# define PIPE_BUF 512
# endif
/* Compute revents values for file handle H. If some events cannot happen
for the handle, eliminate them from *P_SOUGHT. */
static int
win32_compute_revents (HANDLE h, int *p_sought)
{
int i, ret, happened;
INPUT_RECORD *irbuffer;
DWORD avail, nbuffer;
BOOL bRet;
IO_STATUS_BLOCK iosb;
FILE_PIPE_LOCAL_INFORMATION fpli;
static PNtQueryInformationFile NtQueryInformationFile;
static BOOL once_only;
switch (GetFileType (h))
{
case FILE_TYPE_PIPE:
if (!once_only)
{
NtQueryInformationFile = (PNtQueryInformationFile)(void (*)(void))
GetProcAddress (GetModuleHandleW (L"ntdll.dll"),
"NtQueryInformationFile");
once_only = TRUE;
}
happened = 0;
if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
{
if (avail)
happened |= *p_sought & (POLLIN | POLLRDNORM);
}
else if (GetLastError () == ERROR_BROKEN_PIPE)
happened |= POLLHUP;
else
{
/* It was the write-end of the pipe. Check if it is writable.
If NtQueryInformationFile fails, optimistically assume the pipe is
writable. This could happen on Win9x, where NtQueryInformationFile
is not available, or if we inherit a pipe that doesn't permit
FILE_READ_ATTRIBUTES access on the write end (I think this should
not happen since WinXP SP2; WINE seems fine too). Otherwise,
ensure that enough space is available for atomic writes. */
memset (&iosb, 0, sizeof (iosb));
memset (&fpli, 0, sizeof (fpli));
if (!NtQueryInformationFile
|| NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
FilePipeLocalInformation)
|| fpli.WriteQuotaAvailable >= PIPE_BUF
|| (fpli.OutboundQuota < PIPE_BUF &&
fpli.WriteQuotaAvailable == fpli.OutboundQuota))
happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
}
return happened;
case FILE_TYPE_CHAR:
ret = WaitForSingleObject (h, 0);
if (!IsConsoleHandle (h))
return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
nbuffer = avail = 0;
bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
if (bRet)
{
/* Input buffer. */
*p_sought &= POLLIN | POLLRDNORM;
if (nbuffer == 0)
return POLLHUP;
if (!*p_sought)
return 0;
irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
if (!bRet || avail == 0)
return POLLHUP;
for (i = 0; i < avail; i++)
if (irbuffer[i].EventType == KEY_EVENT)
return *p_sought;
return 0;
}
else
{
/* Screen buffer. */
*p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
return *p_sought;
}
default:
ret = WaitForSingleObject (h, 0);
if (ret == WAIT_OBJECT_0)
return *p_sought & ~(POLLPRI | POLLRDBAND);
return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
}
}
/* Convert fd_sets returned by select into revents values. */
static int
win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
{
int happened = 0;
if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
happened |= (POLLIN | POLLRDNORM) & sought;
else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
{
int r, error;
char data[64];
WSASetLastError (0);
r = recv (h, data, sizeof (data), MSG_PEEK);
error = WSAGetLastError ();
WSASetLastError (0);
if (r > 0 || error == WSAENOTCONN)
happened |= (POLLIN | POLLRDNORM) & sought;
/* Distinguish hung-up sockets from other errors. */
else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
|| error == WSAECONNABORTED || error == WSAENETRESET)
happened |= POLLHUP;
else
happened |= POLLERR;
}
if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
if (lNetworkEvents & FD_OOB)
happened |= (POLLPRI | POLLRDBAND) & sought;
return happened;
}
#else /* !MinGW */
/* Convert select(2) returned fd_sets into poll(2) revents values. */
static int
compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
{
int happened = 0;
if (FD_ISSET (fd, rfds))
{
int r;
int socket_errno;
# if defined __MACH__ && defined __APPLE__
/* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
for some kinds of descriptors. Detect if this descriptor is a
connected socket, a server socket, or something else using a
0-byte recv, and use ioctl(2) to detect POLLHUP. */
r = recv (fd, NULL, 0, MSG_PEEK);
socket_errno = (r < 0) ? errno : 0;
if (r == 0 || socket_errno == ENOTSOCK)
ioctl (fd, FIONREAD, &r);
# else
char data[64];
r = recv (fd, data, sizeof (data), MSG_PEEK);
socket_errno = (r < 0) ? errno : 0;
# endif
if (r == 0)
happened |= POLLHUP;
/* If the event happened on an unconnected server socket,
that's fine. */
else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
happened |= (POLLIN | POLLRDNORM) & sought;
/* Distinguish hung-up sockets from other errors. */
else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
|| socket_errno == ECONNABORTED || socket_errno == ENETRESET)
happened |= POLLHUP;
/* some systems can't use recv() on non-socket, including HP NonStop */
else if (/* (r == -1) && */ socket_errno == ENOTSOCK)
happened |= (POLLIN | POLLRDNORM) & sought;
else
happened |= POLLERR;
}
if (FD_ISSET (fd, wfds))
happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
if (FD_ISSET (fd, efds))
happened |= (POLLPRI | POLLRDBAND) & sought;
return happened;
}
#endif /* !MinGW */
int
poll (struct pollfd *pfd, nfds_t nfd, int timeout)
{
#ifndef WIN32_NATIVE
fd_set rfds, wfds, efds;
struct timeval tv;
struct timeval *ptv;
int maxfd, rc;
nfds_t i;
# ifdef _SC_OPEN_MAX
static int sc_open_max = -1;
if (nfd < 0
|| (nfd > sc_open_max
&& (sc_open_max != -1
|| nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
{
errno = EINVAL;
return -1;
}
# else /* !_SC_OPEN_MAX */
# ifdef OPEN_MAX
if (nfd < 0 || nfd > OPEN_MAX)
{
errno = EINVAL;
return -1;
}
# endif /* OPEN_MAX -- else, no check is needed */
# endif /* !_SC_OPEN_MAX */
/* EFAULT is not necessary to implement, but let's do it in the
simplest case. */
if (!pfd && nfd)
{
errno = EFAULT;
return -1;
}
/* convert timeout number into a timeval structure */
if (timeout == 0)
{
ptv = &tv;
ptv->tv_sec = 0;
ptv->tv_usec = 0;
}
else if (timeout > 0)
{
ptv = &tv;
ptv->tv_sec = timeout / 1000;
ptv->tv_usec = (timeout % 1000) * 1000;
}
else if (timeout == INFTIM)
/* wait forever */
ptv = NULL;
else
{
errno = EINVAL;
return -1;
}
/* create fd sets and determine max fd */
maxfd = -1;
FD_ZERO (&rfds);
FD_ZERO (&wfds);
FD_ZERO (&efds);
for (i = 0; i < nfd; i++)
{
if (pfd[i].fd < 0)
continue;
if (pfd[i].events & (POLLIN | POLLRDNORM))
FD_SET (pfd[i].fd, &rfds);
/* see select(2): "the only exceptional condition detectable
is out-of-band data received on a socket", hence we push
POLLWRBAND events onto wfds instead of efds. */
if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
FD_SET (pfd[i].fd, &wfds);
if (pfd[i].events & (POLLPRI | POLLRDBAND))
FD_SET (pfd[i].fd, &efds);
if (pfd[i].fd >= maxfd
&& (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
| POLLRDNORM | POLLRDBAND
| POLLWRNORM | POLLWRBAND)))
{
maxfd = pfd[i].fd;
if (maxfd > FD_SETSIZE)
{
errno = EOVERFLOW;
return -1;
}
}
}
/* examine fd sets */
rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
if (rc < 0)
return rc;
/* establish results */
rc = 0;
for (i = 0; i < nfd; i++)
if (pfd[i].fd < 0)
pfd[i].revents = 0;
else
{
int happened = compute_revents (pfd[i].fd, pfd[i].events,
&rfds, &wfds, &efds);
if (happened)
{
pfd[i].revents = happened;
rc++;
}
else
{
pfd[i].revents = 0;
}
}
return rc;
#else
static struct timeval tv0;
static HANDLE hEvent;
WSANETWORKEVENTS ev;
HANDLE h, handle_array[FD_SETSIZE + 2];
DWORD ret, wait_timeout, nhandles, orig_timeout = 0;
ULONGLONG start = 0;
fd_set rfds, wfds, xfds;
BOOL poll_again;
MSG msg;
int rc = 0;
nfds_t i;
if (nfd < 0 || timeout < -1)
{
errno = EINVAL;
return -1;
}
if (timeout != INFTIM)
{
orig_timeout = timeout;
start = GetTickCount64();
}
if (!hEvent)
hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
restart:
handle_array[0] = hEvent;
nhandles = 1;
FD_ZERO (&rfds);
FD_ZERO (&wfds);
FD_ZERO (&xfds);
/* Classify socket handles and create fd sets. */
for (i = 0; i < nfd; i++)
{
int sought = pfd[i].events;
pfd[i].revents = 0;
if (pfd[i].fd < 0)
continue;
if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
| POLLPRI | POLLRDBAND)))
continue;
h = (HANDLE) _get_osfhandle (pfd[i].fd);
assert (h != NULL);
if (IsSocketHandle (h))
{
int requested = FD_CLOSE;
/* see above; socket handles are mapped onto select. */
if (sought & (POLLIN | POLLRDNORM))
{
requested |= FD_READ | FD_ACCEPT;
FD_SET ((SOCKET) h, &rfds);
}
if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
{
requested |= FD_WRITE | FD_CONNECT;
FD_SET ((SOCKET) h, &wfds);
}
if (sought & (POLLPRI | POLLRDBAND))
{
requested |= FD_OOB;
FD_SET ((SOCKET) h, &xfds);
}
if (requested)
WSAEventSelect ((SOCKET) h, hEvent, requested);
}
else
{
/* Poll now. If we get an event, do not poll again. Also,
screen buffer handles are waitable, and they'll block until
a character is available. win32_compute_revents eliminates
bits for the "wrong" direction. */
pfd[i].revents = win32_compute_revents (h, &sought);
if (sought)
handle_array[nhandles++] = h;
if (pfd[i].revents)
timeout = 0;
}
}
if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
{
/* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
no need to call select again. */
poll_again = FALSE;
wait_timeout = 0;
}
else
{
poll_again = TRUE;
if (timeout == INFTIM)
wait_timeout = INFINITE;
else
wait_timeout = timeout;
}
for (;;)
{
ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
wait_timeout, QS_ALLINPUT);
if (ret == WAIT_OBJECT_0 + nhandles)
{
/* new input of some other kind */
BOOL bRet;
while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
else
break;
}
if (poll_again)
select (0, &rfds, &wfds, &xfds, &tv0);
/* Place a sentinel at the end of the array. */
handle_array[nhandles] = NULL;
nhandles = 1;
for (i = 0; i < nfd; i++)
{
int happened;
if (pfd[i].fd < 0)
continue;
if (!(pfd[i].events & (POLLIN | POLLRDNORM |
POLLOUT | POLLWRNORM | POLLWRBAND)))
continue;
h = (HANDLE) _get_osfhandle (pfd[i].fd);
if (h != handle_array[nhandles])
{
/* It's a socket. */
WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
WSAEventSelect ((SOCKET) h, NULL, 0);
/* If we're lucky, WSAEnumNetworkEvents already provided a way
to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
if (FD_ISSET ((SOCKET) h, &rfds)
&& !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
if (FD_ISSET ((SOCKET) h, &wfds))
ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
if (FD_ISSET ((SOCKET) h, &xfds))
ev.lNetworkEvents |= FD_OOB;
happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
ev.lNetworkEvents);
}
else
{
/* Not a socket. */
int sought = pfd[i].events;
happened = win32_compute_revents (h, &sought);
nhandles++;
}
if ((pfd[i].revents |= happened) != 0)
rc++;
}
if (!rc && orig_timeout && timeout != INFTIM)
{
ULONGLONG elapsed = GetTickCount64() - start;
timeout = elapsed >= orig_timeout ? 0 : (int)(orig_timeout - elapsed);
}
if (!rc && timeout)
{
SleepEx (1, TRUE);
goto restart;
}
return rc;
#endif
}

67
third_party/git/compat/poll/poll.h vendored Normal file
View file

@ -0,0 +1,67 @@
/* Header for poll(2) emulation
Contributed by Paolo Bonzini.
Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc.
This file is part of gnulib.
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, see <http://www.gnu.org/licenses/>. */
#ifndef _GL_POLL_H
#define _GL_POLL_H
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
/* Vista has its own, socket-only poll() */
#undef POLLIN
#undef POLLPRI
#undef POLLOUT
#undef POLLERR
#undef POLLHUP
#undef POLLNVAL
#undef POLLRDNORM
#undef POLLRDBAND
#undef POLLWRNORM
#undef POLLWRBAND
#define pollfd compat_pollfd
#endif
/* fake a poll(2) environment */
#define POLLIN 0x0001 /* any readable data available */
#define POLLPRI 0x0002 /* OOB/Urgent readable data */
#define POLLOUT 0x0004 /* file descriptor is writeable */
#define POLLERR 0x0008 /* some poll error occurred */
#define POLLHUP 0x0010 /* file descriptor was "hung up" */
#define POLLNVAL 0x0020 /* requested events "invalid" */
#define POLLRDNORM 0x0040
#define POLLRDBAND 0x0080
#define POLLWRNORM 0x0100
#define POLLWRBAND 0x0200
struct pollfd
{
int fd; /* which file descriptor to poll */
short events; /* events we are interested in */
short revents; /* events found on return */
};
typedef unsigned long nfds_t;
extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout);
/* Define INFTIM only if doing so conforms to POSIX. */
#if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE)
#define INFTIM (-1)
#endif
#endif /* _GL_POLL_H */

18
third_party/git/compat/pread.c vendored Normal file
View file

@ -0,0 +1,18 @@
#include "../git-compat-util.h"
ssize_t git_pread(int fd, void *buf, size_t count, off_t offset)
{
off_t current_offset;
ssize_t rc;
current_offset = lseek(fd, 0, SEEK_CUR);
if (lseek(fd, offset, SEEK_SET) < 0)
return -1;
rc = read_in_full(fd, buf, count);
if (current_offset != lseek(fd, current_offset, SEEK_SET))
return -1;
return rc;
}

184
third_party/git/compat/precompose_utf8.c vendored Normal file
View file

@ -0,0 +1,184 @@
/*
* Converts filenames from decomposed unicode into precomposed unicode.
* Used on MacOS X.
*/
#define PRECOMPOSE_UNICODE_C
#include "cache.h"
#include "config.h"
#include "utf8.h"
#include "precompose_utf8.h"
typedef char *iconv_ibp;
static const char *repo_encoding = "UTF-8";
static const char *path_encoding = "UTF-8-MAC";
static size_t has_non_ascii(const char *s, size_t maxlen, size_t *strlen_c)
{
const uint8_t *ptr = (const uint8_t *)s;
size_t strlen_chars = 0;
size_t ret = 0;
if (!ptr || !*ptr)
return 0;
while (*ptr && maxlen) {
if (*ptr & 0x80)
ret++;
strlen_chars++;
ptr++;
maxlen--;
}
if (strlen_c)
*strlen_c = strlen_chars;
return ret;
}
void probe_utf8_pathname_composition(void)
{
struct strbuf path = STRBUF_INIT;
static const char *auml_nfc = "\xc3\xa4";
static const char *auml_nfd = "\x61\xcc\x88";
int output_fd;
if (precomposed_unicode != -1)
return; /* We found it defined in the global config, respect it */
git_path_buf(&path, "%s", auml_nfc);
output_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600);
if (output_fd >= 0) {
close(output_fd);
git_path_buf(&path, "%s", auml_nfd);
precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;
git_config_set("core.precomposeunicode",
precomposed_unicode ? "true" : "false");
git_path_buf(&path, "%s", auml_nfc);
if (unlink(path.buf))
die_errno(_("failed to unlink '%s'"), path.buf);
}
strbuf_release(&path);
}
void precompose_argv(int argc, const char **argv)
{
int i = 0;
const char *oldarg;
char *newarg;
iconv_t ic_precompose;
if (precomposed_unicode != 1)
return;
ic_precompose = iconv_open(repo_encoding, path_encoding);
if (ic_precompose == (iconv_t) -1)
return;
while (i < argc) {
size_t namelen;
oldarg = argv[i];
if (has_non_ascii(oldarg, (size_t)-1, &namelen)) {
newarg = reencode_string_iconv(oldarg, namelen, ic_precompose, 0, NULL);
if (newarg)
argv[i] = newarg;
}
i++;
}
iconv_close(ic_precompose);
}
PREC_DIR *precompose_utf8_opendir(const char *dirname)
{
PREC_DIR *prec_dir = xmalloc(sizeof(PREC_DIR));
prec_dir->dirent_nfc = xmalloc(sizeof(dirent_prec_psx));
prec_dir->dirent_nfc->max_name_len = sizeof(prec_dir->dirent_nfc->d_name);
prec_dir->dirp = opendir(dirname);
if (!prec_dir->dirp) {
free(prec_dir->dirent_nfc);
free(prec_dir);
return NULL;
} else {
int ret_errno = errno;
prec_dir->ic_precompose = iconv_open(repo_encoding, path_encoding);
/* if iconv_open() fails, die() in readdir() if needed */
errno = ret_errno;
}
return prec_dir;
}
struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)
{
struct dirent *res;
res = readdir(prec_dir->dirp);
if (res) {
size_t namelenz = strlen(res->d_name) + 1; /* \0 */
size_t new_maxlen = namelenz;
int ret_errno = errno;
if (new_maxlen > prec_dir->dirent_nfc->max_name_len) {
size_t new_len = sizeof(dirent_prec_psx) + new_maxlen -
sizeof(prec_dir->dirent_nfc->d_name);
prec_dir->dirent_nfc = xrealloc(prec_dir->dirent_nfc, new_len);
prec_dir->dirent_nfc->max_name_len = new_maxlen;
}
prec_dir->dirent_nfc->d_ino = res->d_ino;
prec_dir->dirent_nfc->d_type = res->d_type;
if ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {
if (prec_dir->ic_precompose == (iconv_t)-1) {
die("iconv_open(%s,%s) failed, but needed:\n"
" precomposed unicode is not supported.\n"
" If you want to use decomposed unicode, run\n"
" \"git config core.precomposeunicode false\"\n",
repo_encoding, path_encoding);
} else {
iconv_ibp cp = (iconv_ibp)res->d_name;
size_t inleft = namelenz;
char *outpos = &prec_dir->dirent_nfc->d_name[0];
size_t outsz = prec_dir->dirent_nfc->max_name_len;
errno = 0;
iconv(prec_dir->ic_precompose, &cp, &inleft, &outpos, &outsz);
if (errno || inleft) {
/*
* iconv() failed and errno could be E2BIG, EILSEQ, EINVAL, EBADF
* MacOS X avoids illegal byte sequences.
* If they occur on a mounted drive (e.g. NFS) it is not worth to
* die() for that, but rather let the user see the original name
*/
namelenz = 0; /* trigger strlcpy */
}
}
} else
namelenz = 0;
if (!namelenz)
strlcpy(prec_dir->dirent_nfc->d_name, res->d_name,
prec_dir->dirent_nfc->max_name_len);
errno = ret_errno;
return prec_dir->dirent_nfc;
}
return NULL;
}
int precompose_utf8_closedir(PREC_DIR *prec_dir)
{
int ret_value;
int ret_errno;
ret_value = closedir(prec_dir->dirp);
ret_errno = errno;
if (prec_dir->ic_precompose != (iconv_t)-1)
iconv_close(prec_dir->ic_precompose);
free(prec_dir->dirent_nfc);
free(prec_dir);
errno = ret_errno;
return ret_value;
}

View file

@ -0,0 +1,46 @@
#ifndef PRECOMPOSE_UNICODE_H
#define PRECOMPOSE_UNICODE_H
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <iconv.h>
typedef struct dirent_prec_psx {
ino_t d_ino; /* Posix */
size_t max_name_len; /* See below */
unsigned char d_type; /* available on all systems git runs on */
/*
* See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html
* NAME_MAX + 1 should be enough, but some systems have
* NAME_MAX=255 and strlen(d_name) may return 508 or 510
* Solution: allocate more when needed, see precompose_utf8_readdir()
*/
char d_name[NAME_MAX+1];
} dirent_prec_psx;
typedef struct {
iconv_t ic_precompose;
DIR *dirp;
struct dirent_prec_psx *dirent_nfc;
} PREC_DIR;
void precompose_argv(int argc, const char **argv);
void probe_utf8_pathname_composition(void);
PREC_DIR *precompose_utf8_opendir(const char *dirname);
struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *dirp);
int precompose_utf8_closedir(PREC_DIR *dirp);
#ifndef PRECOMPOSE_UNICODE_C
#define dirent dirent_prec_psx
#define opendir(n) precompose_utf8_opendir(n)
#define readdir(d) precompose_utf8_readdir(d)
#define closedir(d) precompose_utf8_closedir(d)
#define DIR PREC_DIR
#endif /* PRECOMPOSE_UNICODE_C */
#endif /* PRECOMPOSE_UNICODE_H */

62
third_party/git/compat/qsort.c vendored Normal file
View file

@ -0,0 +1,62 @@
#include "../git-compat-util.h"
/*
* A merge sort implementation, simplified from the qsort implementation
* by Mike Haertel, which is a part of the GNU C Library.
*/
static void msort_with_tmp(void *b, size_t n, size_t s,
int (*cmp)(const void *, const void *),
char *t)
{
char *tmp;
char *b1, *b2;
size_t n1, n2;
if (n <= 1)
return;
n1 = n / 2;
n2 = n - n1;
b1 = b;
b2 = (char *)b + (n1 * s);
msort_with_tmp(b1, n1, s, cmp, t);
msort_with_tmp(b2, n2, s, cmp, t);
tmp = t;
while (n1 > 0 && n2 > 0) {
if (cmp(b1, b2) <= 0) {
memcpy(tmp, b1, s);
tmp += s;
b1 += s;
--n1;
} else {
memcpy(tmp, b2, s);
tmp += s;
b2 += s;
--n2;
}
}
if (n1 > 0)
memcpy(tmp, b1, n1 * s);
memcpy(b, t, (n - n2) * s);
}
void git_qsort(void *b, size_t n, size_t s,
int (*cmp)(const void *, const void *))
{
const size_t size = st_mult(n, s);
char buf[1024];
if (size < sizeof(buf)) {
/* The temporary array fits on the small on-stack buffer. */
msort_with_tmp(b, n, s, cmp, buf);
} else {
/* It's somewhat large, so malloc it. */
char *tmp = xmalloc(size);
msort_with_tmp(b, n, s, cmp, tmp);
free(tmp);
}
}

69
third_party/git/compat/qsort_s.c vendored Normal file
View file

@ -0,0 +1,69 @@
#include "../git-compat-util.h"
/*
* A merge sort implementation, simplified from the qsort implementation
* by Mike Haertel, which is a part of the GNU C Library.
* Added context pointer, safety checks and return value.
*/
static void msort_with_tmp(void *b, size_t n, size_t s,
int (*cmp)(const void *, const void *, void *),
char *t, void *ctx)
{
char *tmp;
char *b1, *b2;
size_t n1, n2;
if (n <= 1)
return;
n1 = n / 2;
n2 = n - n1;
b1 = b;
b2 = (char *)b + (n1 * s);
msort_with_tmp(b1, n1, s, cmp, t, ctx);
msort_with_tmp(b2, n2, s, cmp, t, ctx);
tmp = t;
while (n1 > 0 && n2 > 0) {
if (cmp(b1, b2, ctx) <= 0) {
memcpy(tmp, b1, s);
tmp += s;
b1 += s;
--n1;
} else {
memcpy(tmp, b2, s);
tmp += s;
b2 += s;
--n2;
}
}
if (n1 > 0)
memcpy(tmp, b1, n1 * s);
memcpy(b, t, (n - n2) * s);
}
int git_qsort_s(void *b, size_t n, size_t s,
int (*cmp)(const void *, const void *, void *), void *ctx)
{
const size_t size = st_mult(n, s);
char buf[1024];
if (!n)
return 0;
if (!b || !cmp)
return -1;
if (size < sizeof(buf)) {
/* The temporary array fits on the small on-stack buffer. */
msort_with_tmp(b, n, s, cmp, buf, ctx);
} else {
/* It's somewhat large, so malloc it. */
char *tmp = xmalloc(size);
msort_with_tmp(b, n, s, cmp, tmp, ctx);
free(tmp);
}
return 0;
}

3891
third_party/git/compat/regex/regcomp.c vendored Normal file

File diff suppressed because it is too large Load diff

87
third_party/git/compat/regex/regex.c vendored Normal file
View file

@ -0,0 +1,87 @@
/* Extended regular expression matching and search library.
Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* Make sure no one compiles this code with a C++ compiler. */
#ifdef __cplusplus
# error "This is C code, use a C compiler"
#endif
#ifdef _LIBC
/* We have to keep the namespace clean. */
# define regfree(preg) __regfree (preg)
# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
# define regerror(errcode, preg, errbuf, errbuf_size) \
__regerror(errcode, preg, errbuf, errbuf_size)
# define re_set_registers(bu, re, nu, st, en) \
__re_set_registers (bu, re, nu, st, en)
# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
__re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
# define re_match(bufp, string, size, pos, regs) \
__re_match (bufp, string, size, pos, regs)
# define re_search(bufp, string, size, startpos, range, regs) \
__re_search (bufp, string, size, startpos, range, regs)
# define re_compile_pattern(pattern, length, bufp) \
__re_compile_pattern (pattern, length, bufp)
# define re_set_syntax(syntax) __re_set_syntax (syntax)
# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
__re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
# include "../locale/localeinfo.h"
#endif
#if defined (_MSC_VER)
#include <stdio.h> /* for size_t */
#endif
/* On some systems, limits.h sets RE_DUP_MAX to a lower value than
GNU regex allows. Include it before <regex.h>, which correctly
#undefs RE_DUP_MAX and sets it to the right value. */
#include <limits.h>
#include <stdint.h>
#ifdef GAWK
#undef alloca
#define alloca alloca_is_bad_you_should_never_use_it
#endif
#include <regex.h>
#include "regex_internal.h"
#include "regex_internal.c"
#ifdef GAWK
#define bool int
#define true (1)
#define false (0)
#endif
#include "regcomp.c"
#include "regexec.c"
/* Binary backward compatibility. */
#if _LIBC
# include <shlib-compat.h>
# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.")
int re_max_failures = 2000;
# endif
#endif

581
third_party/git/compat/regex/regex.h vendored Normal file
View file

@ -0,0 +1,581 @@
#include <stdio.h>
#include <stddef.h>
/* Definitions for data structures and routines for the regular
expression library.
Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005,2006,2008
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 Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#ifndef _REGEX_H
#define _REGEX_H 1
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifndef _LIBC
#define __USE_GNU 1
#endif
/* Allow the use in C++ code. */
#ifdef __cplusplus
extern "C" {
#endif
/* The following two types have to be signed and unsigned integer type
wide enough to hold a value of a pointer. For most ANSI compilers
ptrdiff_t and size_t should be likely OK. Still size of these two
types is 2 for Microsoft C. Ugh... */
typedef long int s_reg_t;
typedef unsigned long int active_reg_t;
/* 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 long int reg_syntax_t;
#ifdef __USE_GNU
/* 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 ((unsigned long int) 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)
/* If this bit is set, succeed as soon as we match the whole pattern,
without further backtracking. */
# define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
/* If this bit is set, do not process the GNU regex operators.
If not set, then the GNU regex operators are recognized. */
# define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
/* If this bit is set, a syntactically invalid interval is treated as
a string of ordinary characters. For example, the ERE 'a{1' is
treated as 'a\{1'. */
# define RE_INVALID_INTERVAL_ORD (RE_NO_GNU_OPS << 1)
/* If this bit is set, then ignore case when matching.
If not set, then case is significant. */
# define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only
for ^, because it is difficult to scan the regex backwards to find
whether ^ should be special. */
# define RE_CARET_ANCHORS_HERE (RE_ICASE << 1)
/* If this bit is set, then \{ cannot be first in an bre or
immediately after an alternation or begin-group operator. */
# define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1)
/* If this bit is set, then no_sub will be set to 1 during
re_compile_pattern. */
#define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1)
#endif
/* 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;
#ifdef __USE_GNU
/* 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_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \
| RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
#define RE_SYNTAX_GNU_AWK \
((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
| RE_INVALID_INTERVAL_ORD) \
& ~(RE_DOT_NOT_NULL | RE_CONTEXT_INDEP_OPS \
| RE_CONTEXT_INVALID_OPS ))
#define RE_SYNTAX_POSIX_AWK \
(RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
| RE_INTERVALS | RE_NO_GNU_OPS \
| RE_INVALID_INTERVAL_ORD)
#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 \
| RE_INVALID_INTERVAL_ORD)
/* 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 | RE_CONTEXT_INVALID_DUP)
/* 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_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD)
/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is
removed 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
/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */
# define RE_DUP_MAX (0x7fff)
#endif
/* 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)
/* Use PMATCH[0] to delimit the start and end of the search in the
buffer. */
#define REG_STARTEND (1 << 2)
/* If any error codes are removed, changed, or added, update the
`re_error_msg' table in regex.c. */
typedef enum
{
#if defined _XOPEN_SOURCE || defined __USE_XOPEN2K
REG_ENOSYS = -1, /* This will never happen for this implementation. */
#endif
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, /* Inalid collating element. */
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. */
#ifndef RE_TRANSLATE_TYPE
# define __RE_TRANSLATE_TYPE unsigned char *
# ifdef __USE_GNU
# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE
# endif
#endif
#ifdef __USE_GNU
# define __REPB_PREFIX(name) name
#else
# define __REPB_PREFIX(name) __##name
#endif
struct re_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 *__REPB_PREFIX(buffer);
/* Number of bytes to which `buffer' points. */
unsigned long int __REPB_PREFIX(allocated);
/* Number of bytes actually used in `buffer'. */
unsigned long int __REPB_PREFIX(used);
/* Syntax setting with which the pattern was compiled. */
reg_syntax_t __REPB_PREFIX(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 *__REPB_PREFIX(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. */
__RE_TRANSLATE_TYPE __REPB_PREFIX(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 __REPB_PREFIX(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. */
#ifdef __USE_GNU
# define REGS_UNALLOCATED 0
# define REGS_REALLOCATE 1
# define REGS_FIXED 2
#endif
unsigned __REPB_PREFIX(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 __REPB_PREFIX(fastmap_accurate) : 1;
/* If set, `re_match_2' does not return information about
subexpressions. */
unsigned __REPB_PREFIX(no_sub) : 1;
/* If set, a beginning-of-line anchor doesn't match at the beginning
of the string. */
unsigned __REPB_PREFIX(not_bol) : 1;
/* Similarly for an end-of-line anchor. */
unsigned __REPB_PREFIX(not_eol) : 1;
/* If true, an anchor at a newline matches. */
unsigned __REPB_PREFIX(newline_anchor) : 1;
};
typedef struct re_pattern_buffer regex_t;
/* Type for byte offsets within the string. POSIX mandates this. */
typedef int regoff_t;
#ifdef __USE_GNU
/* 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
#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. */
#ifdef __USE_GNU
/* 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 (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 (const char *__pattern, size_t __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 (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 (struct re_pattern_buffer *__buffer, const char *__cstring,
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 (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 (struct re_pattern_buffer *__buffer, const char *__cstring,
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 (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 (struct re_pattern_buffer *__buffer,
struct re_registers *__regs,
unsigned int __num_regs,
regoff_t *__starts, regoff_t *__ends);
#endif /* Use GNU */
#if defined _REGEX_RE_COMP || (defined _LIBC && defined __USE_BSD)
# ifndef _CRAY
/* 4.2 bsd compatibility. */
extern char *re_comp (const char *);
extern int re_exec (const char *);
# endif
#endif
/* GCC 2.95 and later have "__restrict"; C99 compilers have
"restrict", and "configure" may have defined "restrict". */
#ifndef __restrict
# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__))
# if defined restrict || 199901L <= __STDC_VERSION__
# define __restrict restrict
# else
# define __restrict
# endif
# endif
#endif
/* gcc 3.1 and up support the [restrict] syntax. */
#ifndef __restrict_arr
# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) \
&& !defined __GNUG__
# define __restrict_arr __restrict
# else
# define __restrict_arr
# endif
#endif
/* POSIX compatibility. */
extern int regcomp (regex_t *__restrict __preg,
const char *__restrict __pattern,
int __cflags);
extern int regexec (const regex_t *__restrict __preg,
const char *__restrict __cstring, size_t __nmatch,
regmatch_t __pmatch[__restrict_arr],
int __eflags);
extern size_t regerror (int __errcode, const regex_t *__restrict __preg,
char *__restrict __errbuf, size_t __errbuf_size);
extern void regfree (regex_t *__preg);
#ifdef __cplusplus
}
#endif /* C++ */
#endif /* regex.h */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,809 @@
/* Extended regular expression matching and search library.
Copyright (C) 2002-2005, 2007, 2008, 2010 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#ifndef _REGEX_INTERNAL_H
#define _REGEX_INTERNAL_H 1
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC
# include <langinfo.h>
#endif
#if defined HAVE_LOCALE_H || defined _LIBC
# include <locale.h>
#endif
#if defined HAVE_WCHAR_H || defined _LIBC
# include <wchar.h>
#endif /* HAVE_WCHAR_H || _LIBC */
#if defined HAVE_WCTYPE_H || defined _LIBC
# include <wctype.h>
#endif /* HAVE_WCTYPE_H || _LIBC */
#if defined HAVE_STDBOOL_H || defined _LIBC
# include <stdbool.h>
#endif /* HAVE_STDBOOL_H || _LIBC */
#if !defined(ZOS_USS)
#if defined HAVE_STDINT_H || defined _LIBC
# include <stdint.h>
#endif /* HAVE_STDINT_H || _LIBC */
#endif /* !ZOS_USS */
#if defined _LIBC
# include <bits/libc-lock.h>
#else
# define __libc_lock_define(CLASS,NAME)
# define __libc_lock_init(NAME) do { } while (0)
# define __libc_lock_lock(NAME) do { } while (0)
# define __libc_lock_unlock(NAME) do { } while (0)
#endif
#ifndef GAWK
/* In case that the system doesn't have isblank(). */
#if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank
# define isblank(ch) ((ch) == ' ' || (ch) == '\t')
#endif
#else /* GAWK */
/*
* This is a freaking mess. On glibc systems you have to define
* a magic constant to get isblank() out of <ctype.h>, since it's
* a C99 function. To heck with all that and borrow a page from
* dfa.c's book.
*/
static int
is_blank (int c)
{
return (c == ' ' || c == '\t');
}
#endif /* GAWK */
#ifdef _LIBC
# ifndef _RE_DEFINE_LOCALE_FUNCTIONS
# define _RE_DEFINE_LOCALE_FUNCTIONS 1
# include <locale/localeinfo.h>
# include <locale/elem-hash.h>
# include <locale/coll-lookup.h>
# endif
#endif
/* This is for other GNU distributions with internationalized messages. */
#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
# include <libintl.h>
# ifdef _LIBC
# undef gettext
# define gettext(msgid) \
INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES)
# endif
#else
# define gettext(msgid) (msgid)
#endif
#ifndef gettext_noop
/* This define is so xgettext can find the internationalizable
strings. */
# define gettext_noop(String) String
#endif
/* For loser systems without the definition. */
#ifndef SIZE_MAX
# define SIZE_MAX ((size_t) -1)
#endif
#ifndef NO_MBSUPPORT
#include "mbsupport.h" /* gawk */
#endif
#ifndef MB_CUR_MAX
#define MB_CUR_MAX 1
#endif
#if (defined MBS_SUPPORT) || _LIBC
# define RE_ENABLE_I18N
#endif
#if __GNUC__ >= 3
# define BE(expr, val) __builtin_expect (expr, val)
#else
# define BE(expr, val) (expr)
# ifdef inline
# undef inline
# endif
# define inline
#endif
/* Number of single byte character. */
#define SBC_MAX 256
#define COLL_ELEM_LEN_MAX 8
/* The character which represents newline. */
#define NEWLINE_CHAR '\n'
#define WIDE_NEWLINE_CHAR L'\n'
/* Rename to standard API for using out of glibc. */
#ifndef _LIBC
# ifdef __wctype
# undef __wctype
# endif
# define __wctype wctype
# ifdef __iswctype
# undef __iswctype
# endif
# define __iswctype iswctype
# define __btowc btowc
# define __mbrtowc mbrtowc
#undef __mempcpy /* GAWK */
# define __mempcpy mempcpy
# define __wcrtomb wcrtomb
# define __regfree regfree
# define attribute_hidden
#endif /* not _LIBC */
#ifdef __GNUC__
# define __attribute(arg) __attribute__ (arg)
#else
# define __attribute(arg)
#endif
extern const char __re_error_msgid[] attribute_hidden;
extern const size_t __re_error_msgid_idx[] attribute_hidden;
/* An integer used to represent a set of bits. It must be unsigned,
and must be at least as wide as unsigned int. */
typedef unsigned long int bitset_word_t;
/* All bits set in a bitset_word_t. */
#define BITSET_WORD_MAX ULONG_MAX
/* Number of bits in a bitset_word_t. */
#define BITSET_WORD_BITS (sizeof (bitset_word_t) * CHAR_BIT)
/* Number of bitset_word_t in a bit_set. */
#define BITSET_WORDS (SBC_MAX / BITSET_WORD_BITS)
typedef bitset_word_t bitset_t[BITSET_WORDS];
typedef bitset_word_t *re_bitset_ptr_t;
typedef const bitset_word_t *re_const_bitset_ptr_t;
#define bitset_set(set,i) \
(set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS)
#define bitset_clear(set,i) \
(set[i / BITSET_WORD_BITS] &= ~((bitset_word_t) 1 << i % BITSET_WORD_BITS))
#define bitset_contain(set,i) \
(set[i / BITSET_WORD_BITS] & ((bitset_word_t) 1 << i % BITSET_WORD_BITS))
#define bitset_empty(set) memset (set, '\0', sizeof (bitset_t))
#define bitset_set_all(set) memset (set, '\xff', sizeof (bitset_t))
#define bitset_copy(dest,src) memcpy (dest, src, sizeof (bitset_t))
#define PREV_WORD_CONSTRAINT 0x0001
#define PREV_NOTWORD_CONSTRAINT 0x0002
#define NEXT_WORD_CONSTRAINT 0x0004
#define NEXT_NOTWORD_CONSTRAINT 0x0008
#define PREV_NEWLINE_CONSTRAINT 0x0010
#define NEXT_NEWLINE_CONSTRAINT 0x0020
#define PREV_BEGBUF_CONSTRAINT 0x0040
#define NEXT_ENDBUF_CONSTRAINT 0x0080
#define WORD_DELIM_CONSTRAINT 0x0100
#define NOT_WORD_DELIM_CONSTRAINT 0x0200
typedef enum
{
INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
LINE_FIRST = PREV_NEWLINE_CONSTRAINT,
LINE_LAST = NEXT_NEWLINE_CONSTRAINT,
BUF_FIRST = PREV_BEGBUF_CONSTRAINT,
BUF_LAST = NEXT_ENDBUF_CONSTRAINT,
WORD_DELIM = WORD_DELIM_CONSTRAINT,
NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT
} re_context_type;
typedef struct
{
int alloc;
int nelem;
int *elems;
} re_node_set;
typedef enum
{
NON_TYPE = 0,
/* Node type, These are used by token, node, tree. */
CHARACTER = 1,
END_OF_RE = 2,
SIMPLE_BRACKET = 3,
OP_BACK_REF = 4,
OP_PERIOD = 5,
#ifdef RE_ENABLE_I18N
COMPLEX_BRACKET = 6,
OP_UTF8_PERIOD = 7,
#endif /* RE_ENABLE_I18N */
/* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used
when the debugger shows values of this enum type. */
#define EPSILON_BIT 8
OP_OPEN_SUBEXP = EPSILON_BIT | 0,
OP_CLOSE_SUBEXP = EPSILON_BIT | 1,
OP_ALT = EPSILON_BIT | 2,
OP_DUP_ASTERISK = EPSILON_BIT | 3,
ANCHOR = EPSILON_BIT | 4,
/* Tree type, these are used only by tree. */
CONCAT = 16,
SUBEXP = 17,
/* Token type, these are used only by token. */
OP_DUP_PLUS = 18,
OP_DUP_QUESTION,
OP_OPEN_BRACKET,
OP_CLOSE_BRACKET,
OP_CHARSET_RANGE,
OP_OPEN_DUP_NUM,
OP_CLOSE_DUP_NUM,
OP_NON_MATCH_LIST,
OP_OPEN_COLL_ELEM,
OP_CLOSE_COLL_ELEM,
OP_OPEN_EQUIV_CLASS,
OP_CLOSE_EQUIV_CLASS,
OP_OPEN_CHAR_CLASS,
OP_CLOSE_CHAR_CLASS,
OP_WORD,
OP_NOTWORD,
OP_SPACE,
OP_NOTSPACE,
BACK_SLASH
} re_token_type_t;
#ifdef RE_ENABLE_I18N
typedef struct
{
/* Multibyte characters. */
wchar_t *mbchars;
/* Collating symbols. */
# ifdef _LIBC
int32_t *coll_syms;
# endif
/* Equivalence classes. */
# ifdef _LIBC
int32_t *equiv_classes;
# endif
/* Range expressions. */
# ifdef _LIBC
uint32_t *range_starts;
uint32_t *range_ends;
# else /* not _LIBC */
wchar_t *range_starts;
wchar_t *range_ends;
# endif /* not _LIBC */
/* Character classes. */
wctype_t *char_classes;
/* If this character set is the non-matching list. */
unsigned int non_match : 1;
/* # of multibyte characters. */
int nmbchars;
/* # of collating symbols. */
int ncoll_syms;
/* # of equivalence classes. */
int nequiv_classes;
/* # of range expressions. */
int nranges;
/* # of character classes. */
int nchar_classes;
} re_charset_t;
#endif /* RE_ENABLE_I18N */
typedef struct
{
union
{
unsigned char c; /* for CHARACTER */
re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */
#ifdef RE_ENABLE_I18N
re_charset_t *mbcset; /* for COMPLEX_BRACKET */
#endif /* RE_ENABLE_I18N */
int idx; /* for BACK_REF */
re_context_type ctx_type; /* for ANCHOR */
} opr;
#if __GNUC__ >= 2
re_token_type_t type : 8;
#else
re_token_type_t type;
#endif
unsigned int constraint : 10; /* context constraint */
unsigned int duplicated : 1;
unsigned int opt_subexp : 1;
#ifdef RE_ENABLE_I18N
unsigned int accept_mb : 1;
/* These 2 bits can be moved into the union if needed (e.g. if running out
of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */
unsigned int mb_partial : 1;
#endif
unsigned int word_char : 1;
} re_token_t;
#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT)
struct re_string_t
{
/* Indicate the raw buffer which is the original string passed as an
argument of regexec(), re_search(), etc.. */
const unsigned char *raw_mbs;
/* Store the multibyte string. In case of "case insensitive mode" like
REG_ICASE, upper cases of the string are stored, otherwise MBS points
the same address that RAW_MBS points. */
unsigned char *mbs;
#ifdef RE_ENABLE_I18N
/* Store the wide character string which is corresponding to MBS. */
wint_t *wcs;
int *offsets;
mbstate_t cur_state;
#endif
/* Index in RAW_MBS. Each character mbs[i] corresponds to
raw_mbs[raw_mbs_idx + i]. */
int raw_mbs_idx;
/* The length of the valid characters in the buffers. */
int valid_len;
/* The corresponding number of bytes in raw_mbs array. */
int valid_raw_len;
/* The length of the buffers MBS and WCS. */
int bufs_len;
/* The index in MBS, which is updated by re_string_fetch_byte. */
int cur_idx;
/* length of RAW_MBS array. */
int raw_len;
/* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */
int len;
/* End of the buffer may be shorter than its length in the cases such
as re_match_2, re_search_2. Then, we use STOP for end of the buffer
instead of LEN. */
int raw_stop;
/* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */
int stop;
/* The context of mbs[0]. We store the context independently, since
the context of mbs[0] may be different from raw_mbs[0], which is
the beginning of the input string. */
unsigned int tip_context;
/* The translation passed as a part of an argument of re_compile_pattern. */
RE_TRANSLATE_TYPE trans;
/* Copy of re_dfa_t's word_char. */
re_const_bitset_ptr_t word_char;
/* 1 if REG_ICASE. */
unsigned char icase;
unsigned char is_utf8;
unsigned char map_notascii;
unsigned char mbs_allocated;
unsigned char offsets_needed;
unsigned char newline_anchor;
unsigned char word_ops_used;
int mb_cur_max;
};
typedef struct re_string_t re_string_t;
struct re_dfa_t;
typedef struct re_dfa_t re_dfa_t;
#ifndef _LIBC
# ifdef __i386__
# define internal_function __attribute ((regparm (3), stdcall))
# else
# define internal_function
# endif
#endif
#ifndef NOT_IN_libc
static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr,
int new_buf_len)
internal_function;
# ifdef RE_ENABLE_I18N
static void build_wcs_buffer (re_string_t *pstr) internal_function;
static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr)
internal_function;
# endif /* RE_ENABLE_I18N */
static void build_upper_buffer (re_string_t *pstr) internal_function;
static void re_string_translate_buffer (re_string_t *pstr) internal_function;
static unsigned int re_string_context_at (const re_string_t *input, int idx,
int eflags)
internal_function __attribute ((pure));
#endif
#define re_string_peek_byte(pstr, offset) \
((pstr)->mbs[(pstr)->cur_idx + offset])
#define re_string_fetch_byte(pstr) \
((pstr)->mbs[(pstr)->cur_idx++])
#define re_string_first_byte(pstr, idx) \
((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF)
#define re_string_is_single_byte_char(pstr, idx) \
((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \
|| (pstr)->wcs[(idx) + 1] != WEOF))
#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx)
#define re_string_cur_idx(pstr) ((pstr)->cur_idx)
#define re_string_get_buffer(pstr) ((pstr)->mbs)
#define re_string_length(pstr) ((pstr)->len)
#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx])
#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx))
#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx))
#ifndef _LIBC
# if HAVE_ALLOCA
# if (_MSC_VER)
# include <malloc.h>
# define __libc_use_alloca(n) 0
# else
# include <alloca.h>
/* The OS usually guarantees only one guard page at the bottom of the stack,
and a page size can be as small as 4096 bytes. So we cannot safely
allocate anything larger than 4096 bytes. Also care for the possibility
of a few compiler-allocated temporary stack slots. */
# define __libc_use_alloca(n) ((n) < 4032)
# endif
# else
/* alloca is implemented with malloc, so just use malloc. */
# define __libc_use_alloca(n) 0
# endif
#endif
#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t)))
/* SunOS 4.1.x realloc doesn't accept null pointers: pre-Standard C. Sigh. */
#define re_realloc(p,t,n) ((p != NULL) ? (t *) realloc (p,(n)*sizeof(t)) : (t *) calloc(n,sizeof(t)))
#define re_free(p) free (p)
struct bin_tree_t
{
struct bin_tree_t *parent;
struct bin_tree_t *left;
struct bin_tree_t *right;
struct bin_tree_t *first;
struct bin_tree_t *next;
re_token_t token;
/* `node_idx' is the index in dfa->nodes, if `type' == 0.
Otherwise `type' indicate the type of this node. */
int node_idx;
};
typedef struct bin_tree_t bin_tree_t;
#define BIN_TREE_STORAGE_SIZE \
((1024 - sizeof (void *)) / sizeof (bin_tree_t))
struct bin_tree_storage_t
{
struct bin_tree_storage_t *next;
bin_tree_t data[BIN_TREE_STORAGE_SIZE];
};
typedef struct bin_tree_storage_t bin_tree_storage_t;
#define CONTEXT_WORD 1
#define CONTEXT_NEWLINE (CONTEXT_WORD << 1)
#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1)
#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1)
#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD)
#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE)
#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF)
#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF)
#define IS_ORDINARY_CONTEXT(c) ((c) == 0)
#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_')
#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR)
#define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_')
#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR)
#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \
((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
|| ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
|| ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\
|| ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context)))
#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \
((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
|| (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
|| (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \
|| (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context)))
struct re_dfastate_t
{
unsigned int hash;
re_node_set nodes;
re_node_set non_eps_nodes;
re_node_set inveclosure;
re_node_set *entrance_nodes;
struct re_dfastate_t **trtable, **word_trtable;
unsigned int context : 4;
unsigned int halt : 1;
/* If this state can accept `multi byte'.
Note that we refer to multibyte characters, and multi character
collating elements as `multi byte'. */
unsigned int accept_mb : 1;
/* If this state has backreference node(s). */
unsigned int has_backref : 1;
unsigned int has_constraint : 1;
};
typedef struct re_dfastate_t re_dfastate_t;
struct re_state_table_entry
{
int num;
int alloc;
re_dfastate_t **array;
};
/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */
typedef struct
{
int next_idx;
int alloc;
re_dfastate_t **array;
} state_array_t;
/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */
typedef struct
{
int node;
int str_idx; /* The position NODE match at. */
state_array_t path;
} re_sub_match_last_t;
/* Store information about the node NODE whose type is OP_OPEN_SUBEXP.
And information about the node, whose type is OP_CLOSE_SUBEXP,
corresponding to NODE is stored in LASTS. */
typedef struct
{
int str_idx;
int node;
state_array_t *path;
int alasts; /* Allocation size of LASTS. */
int nlasts; /* The number of LASTS. */
re_sub_match_last_t **lasts;
} re_sub_match_top_t;
struct re_backref_cache_entry
{
int node;
int str_idx;
int subexp_from;
int subexp_to;
char more;
char unused;
unsigned short int eps_reachable_subexps_map;
};
typedef struct
{
/* The string object corresponding to the input string. */
re_string_t input;
#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
const re_dfa_t *const dfa;
#else
const re_dfa_t *dfa;
#endif
/* EFLAGS of the argument of regexec. */
int eflags;
/* Where the matching ends. */
int match_last;
int last_node;
/* The state log used by the matcher. */
re_dfastate_t **state_log;
int state_log_top;
/* Back reference cache. */
int nbkref_ents;
int abkref_ents;
struct re_backref_cache_entry *bkref_ents;
int max_mb_elem_len;
int nsub_tops;
int asub_tops;
re_sub_match_top_t **sub_tops;
} re_match_context_t;
typedef struct
{
re_dfastate_t **sifted_states;
re_dfastate_t **limited_states;
int last_node;
int last_str_idx;
re_node_set limits;
} re_sift_context_t;
struct re_fail_stack_ent_t
{
int idx;
int node;
regmatch_t *regs;
re_node_set eps_via_nodes;
};
struct re_fail_stack_t
{
int num;
int alloc;
struct re_fail_stack_ent_t *stack;
};
struct re_dfa_t
{
re_token_t *nodes;
size_t nodes_alloc;
size_t nodes_len;
int *nexts;
int *org_indices;
re_node_set *edests;
re_node_set *eclosures;
re_node_set *inveclosures;
struct re_state_table_entry *state_table;
re_dfastate_t *init_state;
re_dfastate_t *init_state_word;
re_dfastate_t *init_state_nl;
re_dfastate_t *init_state_begbuf;
bin_tree_t *str_tree;
bin_tree_storage_t *str_tree_storage;
re_bitset_ptr_t sb_char;
int str_tree_storage_idx;
/* number of subexpressions `re_nsub' is in regex_t. */
unsigned int state_hash_mask;
int init_node;
int nbackref; /* The number of backreference in this dfa. */
/* Bitmap expressing which backreference is used. */
bitset_word_t used_bkref_map;
bitset_word_t completed_bkref_map;
unsigned int has_plural_match : 1;
/* If this dfa has "multibyte node", which is a backreference or
a node which can accept multibyte character or multi character
collating element. */
unsigned int has_mb_node : 1;
unsigned int is_utf8 : 1;
unsigned int map_notascii : 1;
unsigned int word_ops_used : 1;
int mb_cur_max;
bitset_t word_char;
reg_syntax_t syntax;
int *subexp_map;
#ifdef DEBUG
char* re_str;
#endif
#if defined _LIBC
__libc_lock_define (, lock)
#endif
};
#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set))
#define re_node_set_remove(set,id) \
(re_node_set_remove_at (set, re_node_set_contains (set, id) - 1))
#define re_node_set_empty(p) ((p)->nelem = 0)
#define re_node_set_free(set) re_free ((set)->elems)
typedef enum
{
SB_CHAR,
MB_CHAR,
EQUIV_CLASS,
COLL_SYM,
CHAR_CLASS
} bracket_elem_type;
typedef struct
{
bracket_elem_type type;
union
{
unsigned char ch;
unsigned char *name;
wchar_t wch;
} opr;
} bracket_elem_t;
/* Inline functions for bitset operation. */
static inline void
bitset_not (bitset_t set)
{
int bitset_i;
for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
set[bitset_i] = ~set[bitset_i];
}
static inline void
bitset_merge (bitset_t dest, const bitset_t src)
{
int bitset_i;
for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
dest[bitset_i] |= src[bitset_i];
}
static inline void
bitset_mask (bitset_t dest, const bitset_t src)
{
int bitset_i;
for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
dest[bitset_i] &= src[bitset_i];
}
#ifdef RE_ENABLE_I18N
/* Inline functions for re_string. */
static inline int
internal_function __attribute ((pure))
re_string_char_size_at (const re_string_t *pstr, int idx)
{
int byte_idx;
if (pstr->mb_cur_max == 1)
return 1;
for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
if (pstr->wcs[idx + byte_idx] != WEOF)
break;
return byte_idx;
}
static inline wint_t
internal_function __attribute ((pure))
re_string_wchar_at (const re_string_t *pstr, int idx)
{
if (pstr->mb_cur_max == 1)
return (wint_t) pstr->mbs[idx];
return (wint_t) pstr->wcs[idx];
}
# ifndef NOT_IN_libc
static int
internal_function __attribute ((pure))
re_string_elem_size_at (const re_string_t *pstr, int idx)
{
# ifdef _LIBC
const unsigned char *p, *extra;
const int32_t *table, *indirect;
int32_t tmp;
# include <locale/weight.h>
uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
if (nrules != 0)
{
table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
extra = (const unsigned char *)
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
_NL_COLLATE_INDIRECTMB);
p = pstr->mbs + idx;
tmp = findidx (&p);
return p - pstr->mbs - idx;
}
else
# endif /* _LIBC */
return 1;
}
# endif
#endif /* RE_ENABLE_I18N */
#endif /* _REGEX_INTERNAL_H */

4368
third_party/git/compat/regex/regexec.c vendored Normal file

File diff suppressed because it is too large Load diff

40
third_party/git/compat/setenv.c vendored Normal file
View file

@ -0,0 +1,40 @@
#include "../git-compat-util.h"
int gitsetenv(const char *name, const char *value, int replace)
{
int out;
size_t namelen, valuelen;
char *envstr;
if (!name || strchr(name, '=') || !value) {
errno = EINVAL;
return -1;
}
if (!replace) {
char *oldval = NULL;
oldval = getenv(name);
if (oldval) return 0;
}
namelen = strlen(name);
valuelen = strlen(value);
envstr = malloc(st_add3(namelen, valuelen, 2));
if (!envstr) {
errno = ENOMEM;
return -1;
}
memcpy(envstr, name, namelen);
envstr[namelen] = '=';
memcpy(envstr + namelen + 1, value, valuelen);
envstr[namelen + valuelen + 1] = 0;
out = putenv(envstr);
/* putenv(3) makes the argument string part of the environment,
* and changing that string modifies the environment --- which
* means we do not own that storage anymore. Do not free
* envstr.
*/
return out;
}

19
third_party/git/compat/sha1-chunked.c vendored Normal file
View file

@ -0,0 +1,19 @@
#include "cache.h"
int git_SHA1_Update_Chunked(platform_SHA_CTX *c, const void *data, size_t len)
{
size_t nr;
size_t total = 0;
const char *cdata = (const char*)data;
while (len) {
nr = len;
if (nr > SHA1_MAX_BLOCK_SIZE)
nr = SHA1_MAX_BLOCK_SIZE;
platform_SHA1_Update(c, cdata, nr);
total += nr;
cdata += nr;
len -= nr;
}
return total;
}

2
third_party/git/compat/sha1-chunked.h vendored Normal file
View file

@ -0,0 +1,2 @@
int git_SHA1_Update_Chunked(platform_SHA_CTX *c, const void *data, size_t len);

69
third_party/git/compat/snprintf.c vendored Normal file
View file

@ -0,0 +1,69 @@
#include "../git-compat-util.h"
/*
* The size parameter specifies the available space, i.e. includes
* the trailing NUL byte; but Windows's vsnprintf uses the entire
* buffer and avoids the trailing NUL, should the buffer be exactly
* big enough for the result. Defining SNPRINTF_SIZE_CORR to 1 will
* therefore remove 1 byte from the reported buffer size, so we
* always have room for a trailing NUL byte.
*/
#ifndef SNPRINTF_SIZE_CORR
#if defined(WIN32) && (!defined(__GNUC__) || __GNUC__ < 4) && (!defined(_MSC_VER) || _MSC_VER < 1900)
#define SNPRINTF_SIZE_CORR 1
#else
#define SNPRINTF_SIZE_CORR 0
#endif
#endif
#undef vsnprintf
int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
{
va_list cp;
char *s;
int ret = -1;
if (maxsize > 0) {
va_copy(cp, ap);
ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp);
va_end(cp);
if (ret == maxsize-1)
ret = -1;
/* Windows does not NUL-terminate if result fills buffer */
str[maxsize-1] = 0;
}
if (ret != -1)
return ret;
s = NULL;
if (maxsize < 128)
maxsize = 128;
while (ret == -1) {
maxsize *= 4;
str = realloc(s, maxsize);
if (! str)
break;
s = str;
va_copy(cp, ap);
ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp);
va_end(cp);
if (ret == maxsize-1)
ret = -1;
}
free(s);
return ret;
}
int git_snprintf(char *str, size_t maxsize, const char *format, ...)
{
va_list ap;
int ret;
va_start(ap, format);
ret = git_vsnprintf(str, maxsize, format, ap);
va_end(ap);
return ret;
}

48
third_party/git/compat/stat.c vendored Normal file
View file

@ -0,0 +1,48 @@
#define _POSIX_C_SOURCE 200112L
#include <sys/stat.h> /* *stat, S_IS* */
#include <sys/types.h> /* mode_t */
static inline mode_t mode_native_to_git(mode_t native_mode)
{
mode_t perm_bits = native_mode & 07777;
if (S_ISREG(native_mode))
return 0100000 | perm_bits;
if (S_ISDIR(native_mode))
return 0040000 | perm_bits;
if (S_ISLNK(native_mode))
return 0120000 | perm_bits;
if (S_ISBLK(native_mode))
return 0060000 | perm_bits;
if (S_ISCHR(native_mode))
return 0020000 | perm_bits;
if (S_ISFIFO(native_mode))
return 0010000 | perm_bits;
if (S_ISSOCK(native_mode))
return 0140000 | perm_bits;
/* Non-standard type bits were given. */
return perm_bits;
}
int git_stat(const char *path, struct stat *buf)
{
int rc = stat(path, buf);
if (rc == 0)
buf->st_mode = mode_native_to_git(buf->st_mode);
return rc;
}
int git_fstat(int fd, struct stat *buf)
{
int rc = fstat(fd, buf);
if (rc == 0)
buf->st_mode = mode_native_to_git(buf->st_mode);
return rc;
}
int git_lstat(const char *path, struct stat *buf)
{
int rc = lstat(path, buf);
if (rc == 0)
buf->st_mode = mode_native_to_git(buf->st_mode);
return rc;
}

22
third_party/git/compat/strcasestr.c vendored Normal file
View file

@ -0,0 +1,22 @@
#include "../git-compat-util.h"
char *gitstrcasestr(const char *haystack, const char *needle)
{
int nlen = strlen(needle);
int hlen = strlen(haystack) - nlen + 1;
int i;
for (i = 0; i < hlen; i++) {
int j;
for (j = 0; j < nlen; j++) {
unsigned char c1 = haystack[i+j];
unsigned char c2 = needle[j];
if (toupper(c1) != toupper(c2))
goto next;
}
return (char *) haystack + i;
next:
;
}
return NULL;
}

11
third_party/git/compat/strdup.c vendored Normal file
View file

@ -0,0 +1,11 @@
#include "../git-compat-util.h"
char *gitstrdup(const char *s1)
{
size_t len = strlen(s1) + 1;
char *s2 = malloc(len);
if (s2)
memcpy(s2, s1, len);
return s2;
}

13
third_party/git/compat/strlcpy.c vendored Normal file
View file

@ -0,0 +1,13 @@
#include "../git-compat-util.h"
size_t gitstrlcpy(char *dest, const char *src, size_t size)
{
size_t ret = strlen(src);
if (size) {
size_t len = (ret >= size) ? size - 1 : ret;
memcpy(dest, src, len);
dest[len] = '\0';
}
return ret;
}

10
third_party/git/compat/strtoimax.c vendored Normal file
View file

@ -0,0 +1,10 @@
#include "../git-compat-util.h"
intmax_t gitstrtoimax (const char *nptr, char **endptr, int base)
{
#if defined(NO_STRTOULL)
return strtol(nptr, endptr, base);
#else
return strtoll(nptr, endptr, base);
#endif
}

10
third_party/git/compat/strtoumax.c vendored Normal file
View file

@ -0,0 +1,10 @@
#include "../git-compat-util.h"
uintmax_t gitstrtoumax (const char *nptr, char **endptr, int base)
{
#if defined(NO_STRTOULL)
return strtoul(nptr, endptr, base);
#else
return strtoull(nptr, endptr, base);
#endif
}

147
third_party/git/compat/terminal.c vendored Normal file
View file

@ -0,0 +1,147 @@
#include "git-compat-util.h"
#include "compat/terminal.h"
#include "sigchain.h"
#include "strbuf.h"
#if defined(HAVE_DEV_TTY) || defined(GIT_WINDOWS_NATIVE)
static void restore_term(void);
static void restore_term_on_signal(int sig)
{
restore_term();
sigchain_pop(sig);
raise(sig);
}
#ifdef HAVE_DEV_TTY
#define INPUT_PATH "/dev/tty"
#define OUTPUT_PATH "/dev/tty"
static int term_fd = -1;
static struct termios old_term;
static void restore_term(void)
{
if (term_fd < 0)
return;
tcsetattr(term_fd, TCSAFLUSH, &old_term);
close(term_fd);
term_fd = -1;
}
static int disable_echo(void)
{
struct termios t;
term_fd = open("/dev/tty", O_RDWR);
if (tcgetattr(term_fd, &t) < 0)
goto error;
old_term = t;
sigchain_push_common(restore_term_on_signal);
t.c_lflag &= ~ECHO;
if (!tcsetattr(term_fd, TCSAFLUSH, &t))
return 0;
error:
close(term_fd);
term_fd = -1;
return -1;
}
#elif defined(GIT_WINDOWS_NATIVE)
#define INPUT_PATH "CONIN$"
#define OUTPUT_PATH "CONOUT$"
#define FORCE_TEXT "t"
static HANDLE hconin = INVALID_HANDLE_VALUE;
static DWORD cmode;
static void restore_term(void)
{
if (hconin == INVALID_HANDLE_VALUE)
return;
SetConsoleMode(hconin, cmode);
CloseHandle(hconin);
hconin = INVALID_HANDLE_VALUE;
}
static int disable_echo(void)
{
hconin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hconin == INVALID_HANDLE_VALUE)
return -1;
GetConsoleMode(hconin, &cmode);
sigchain_push_common(restore_term_on_signal);
if (!SetConsoleMode(hconin, cmode & (~ENABLE_ECHO_INPUT))) {
CloseHandle(hconin);
hconin = INVALID_HANDLE_VALUE;
return -1;
}
return 0;
}
#endif
#ifndef FORCE_TEXT
#define FORCE_TEXT
#endif
char *git_terminal_prompt(const char *prompt, int echo)
{
static struct strbuf buf = STRBUF_INIT;
int r;
FILE *input_fh, *output_fh;
input_fh = fopen(INPUT_PATH, "r" FORCE_TEXT);
if (!input_fh)
return NULL;
output_fh = fopen(OUTPUT_PATH, "w" FORCE_TEXT);
if (!output_fh) {
fclose(input_fh);
return NULL;
}
if (!echo && disable_echo()) {
fclose(input_fh);
fclose(output_fh);
return NULL;
}
fputs(prompt, output_fh);
fflush(output_fh);
r = strbuf_getline_lf(&buf, input_fh);
if (!echo) {
putc('\n', output_fh);
fflush(output_fh);
}
restore_term();
fclose(input_fh);
fclose(output_fh);
if (r == EOF)
return NULL;
return buf.buf;
}
#else
char *git_terminal_prompt(const char *prompt, int echo)
{
return getpass(prompt);
}
#endif

6
third_party/git/compat/terminal.h vendored Normal file
View file

@ -0,0 +1,6 @@
#ifndef COMPAT_TERMINAL_H
#define COMPAT_TERMINAL_H
char *git_terminal_prompt(const char *prompt, int echo);
#endif /* COMPAT_TERMINAL_H */

27
third_party/git/compat/unsetenv.c vendored Normal file
View file

@ -0,0 +1,27 @@
#include "../git-compat-util.h"
void gitunsetenv (const char *name)
{
#if !defined(__MINGW32__)
extern char **environ;
#endif
int src, dst;
size_t nmln;
nmln = strlen(name);
for (src = dst = 0; environ[src]; ++src) {
size_t enln;
enln = strlen(environ[src]);
if (enln > nmln) {
/* might match, and can test for '=' safely */
if (0 == strncmp (environ[src], name, nmln)
&& '=' == environ[src][nmln])
/* matches, so skip */
continue;
}
environ[dst] = environ[src];
++dst;
}
environ[dst] = NULL;
}

View file

@ -0,0 +1,3 @@
/vcpkg/
/MSVC-DEFS-GEN
/VCPKG-DEFS

112
third_party/git/compat/vcbuild/README vendored Normal file
View file

@ -0,0 +1,112 @@
The Steps to Build Git with VS2015 or VS2017 from the command line.
1. Install the "vcpkg" open source package manager and build essential
third-party libraries. The steps for this have been captured in a
set of convenience scripts. These can be run from a stock Command
Prompt or from an SDK bash window:
$ cd <repo_root>
$ ./compat/vcbuild/vcpkg_install.bat
The vcpkg tools and all of the third-party sources will be installed
in this folder:
<repo_root>/compat/vcbuild/vcpkg/
A file will be created with a set of Makefile macros pointing to a
unified "include", "lib", and "bin" directory (release and debug) for
all of the required packages. This file will be included by the main
Makefile:
<repo_root>/compat/vcbuild/MSVC-DEFS-GEN
2. OPTIONALLY copy the third-party *.dll and *.pdb files into the repo
root to make it easier to run and debug git.exe without having to
manipulate your PATH. This is especially true for debug sessions in
Visual Studio.
Use ONE of the following forms which should match how you want to
compile git.exe.
$ ./compat/vcbuild/vcpkg_copy_packages.bat debug
$ ./compat/vcbuild/vcpkg_copy_packages.bat release
3. Build git using MSVC from an SDK bash window using one of the
following commands:
$ make MSVC=1
$ make MSVC=1 DEBUG=1
================================================================
Alternatively, run `make vcxproj` and then load the generated `git.sln` in
Visual Studio. The initial build will install the vcpkg system and build the
dependencies automatically. This will take a while.
Instead of generating the `git.sln` file yourself (which requires a full Git
for Windows SDK), you may want to consider fetching the `vs/master` branch of
https://github.com/git-for-windows/git instead (which is updated automatically
via CI running `make vcxproj`). The `vs/master` branch does not require a Git
for Windows to build, but you can run the test scripts in a regular Git Bash.
Note that `make vcxproj` will automatically add and commit the generated `.sln`
and `.vcxproj` files to the repo. This is necessary to allow building a
fully-testable Git in Visual Studio, where a regular Git Bash can be used to
run the test scripts (as opposed to a full Git for Windows SDK): a number of
build targets, such as Git commands implemented as Unix shell scripts (where
`@@SHELL_PATH@@` and other placeholders are interpolated) require a full-blown
Git for Windows SDK (which is about 10x the size of a regular Git for Windows
installation).
If your plan is to open a Pull Request with Git for Windows, it is a good idea
to drop this commit before submitting.
================================================================
The Steps of Build Git with VS2008
1. You need the build environment, which contains the Git dependencies
to be able to compile, link and run Git with MSVC.
You can either use the binary repository:
WWW: http://repo.or.cz/w/msvcgit.git
Git: git clone git://repo.or.cz/msvcgit.git
Zip: http://repo.or.cz/w/msvcgit.git?a=snapshot;h=master;sf=zip
and call the setup_32bit_env.cmd batch script before compiling Git,
(see repo/package README for details), or the source repository:
WWW: http://repo.or.cz/w/gitbuild.git
Git: git clone git://repo.or.cz/gitbuild.git
Zip: (None, as it's a project with submodules)
and build the support libs as instructed in that repo/package.
2. Ensure you have the msysgit environment in your path, so you have
GNU Make, bash and perl available.
WWW: http://repo.or.cz/w/msysgit.git
Git: git clone git://repo.or.cz/msysgit.git
Zip: http://repo.or.cz/w/msysgit.git?a=snapshot;h=master;sf=zip
This environment is also needed when you use the resulting
executables, since Git might need to run scripts which are part of
the git operations.
3. Inside Git's directory run the command:
make command-list.h
to generate the command-list.h file needed to compile git.
4. Then either build Git with the GNU Make Makefile in the Git projects
root
make MSVC=1
or generate Visual Studio solution/projects (.sln/.vcproj) with the
command
perl contrib/buildsystems/generate -g Vcproj
and open and build the solution with the IDE
devenv git.sln /useenv
or build with the IDE build engine directly from the command line
devenv git.sln /useenv /build "Release|Win32"
The /useenv option is required, so Visual Studio picks up the
environment variables for the support libraries required to build
Git, which you set up in step 1.
Done!

View file

@ -0,0 +1,168 @@
@ECHO OFF
REM ================================================================
REM You can use either GCC (the default) or MSVC to build git
REM using the GIT-SDK command line tools.
REM $ make
REM $ make MSVC=1
REM
REM GIT-SDK BASH windows inherit environment variables with all of
REM the bin/lib/include paths for GCC. It DOES NOT inherit values
REM for the corresponding MSVC tools.
REM
REM During normal (non-git) Windows development, you launch one
REM of the provided "developer command prompts" to set environment
REM variables for the MSVC tools.
REM
REM Therefore, to allow MSVC command line builds of git from BASH
REM and MAKE, we must blend these two different worlds. This script
REM attempts to do that.
REM ================================================================
REM This BAT file starts in a plain (non-developer) command prompt,
REM searches for the "best" commmand prompt setup script, installs
REM it into the current CMD process, and exports the various MSVC
REM environment variables for use by MAKE.
REM
REM The output of this script should be written to a make "include
REM file" and referenced by the top-level Makefile.
REM
REM See "config.mak.uname" (look for compat/vcbuild/MSVC-DEFS-GEN).
REM ================================================================
REM The provided command prompts are custom to each VS release and
REM filled with lots of internal knowledge (such as Registry settings);
REM even their names vary by release, so it is not appropriate for us
REM to look inside them. Rather, just run them in a subordinate
REM process and extract the settings we need.
REM ================================================================
REM
REM Current (VS2017 and beyond)
REM -------------------
REM Visual Studio 2017 introduced a new installation layout and
REM support for side-by-side installation of multiple versions of
REM VS2017. Furthermore, these can all coexist with installations
REM of previous versions of VS (which have a completely different
REM layout on disk).
REM
REM VS2017 Update 2 introduced a "vswhere.exe" command:
REM https://github.com/Microsoft/vswhere
REM https://blogs.msdn.microsoft.com/heaths/2017/02/25/vswhere-available/
REM https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/
REM
REM VS2015
REM ------
REM Visual Studio 2015 uses the traditional VcVarsAll.
REM
REM Earlier Versions
REM ----------------
REM Currently unsupported.
REM
REM ================================================================
REM Note: Throughout this script we use "dir <path> && <cmd>" rather
REM than "if exist <path>" because of script problems with pathnames
REM containing spaces.
REM ================================================================
REM Sanitize PATH to prevent git-sdk paths from confusing "wmic.exe"
REM (called internally in some of the system BAT files).
SET PATH=%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;
REM ================================================================
:current
SET vs_where=C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe
dir "%vs_where%" >nul 2>nul && GOTO have_vs_where
GOTO not_2017
:have_vs_where
REM Try to use VsWhere to get the location of VsDevCmd.
REM Keep VsDevCmd from cd'ing away.
SET VSCMD_START_DIR=.
REM Get the root of the VS product installation.
FOR /F "usebackq tokens=*" %%i IN (`"%vs_where%" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath`) DO @SET vs_ip=%%i
SET vs_devcmd=%vs_ip%\Common7\Tools\VsDevCmd.bat
dir "%vs_devcmd%" >nul 2>nul && GOTO have_vs_devcmd
GOTO not_2017
:have_vs_devcmd
REM Use VsDevCmd to setup the environment of this process.
REM Setup CL for building 64-bit apps using 64-bit tools.
@call "%vs_devcmd%" -no_logo -arch=x64 -host_arch=x64
SET tgt=%VSCMD_ARG_TGT_ARCH%
SET mn=%VCToolsInstallDir%
SET msvc_includes=-I"%mn%INCLUDE"
SET msvc_libs=-L"%mn%lib\%tgt%"
SET msvc_bin_dir=%mn%bin\Host%VSCMD_ARG_HOST_ARCH%\%tgt%
SET sdk_dir=%WindowsSdkDir%
SET sdk_ver=%WindowsSDKVersion%
SET si=%sdk_dir%Include\%sdk_ver%
SET sdk_includes=-I"%si%ucrt" -I"%si%um" -I"%si%shared"
SET sl=%sdk_dir%lib\%sdk_ver%
SET sdk_libs=-L"%sl%ucrt\%tgt%" -L"%sl%um\%tgt%"
SET vs_ver=%VisualStudioVersion%
GOTO print_vars
REM ================================================================
:not_2017
REM See if VS2015 is installed.
SET vs_2015_bat=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
dir "%vs_2015_bat%" >nul 2>nul && GOTO have_vs_2015
GOTO not_2015
:have_vs_2015
REM Use VcVarsAll like the "x64 Native" command prompt.
REM Setup CL for building 64-bit apps using 64-bit tools.
@call "%vs_2015_bat%" amd64
REM Note that in VS2015 they use "x64" in some contexts and "amd64" in others.
SET mn=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\
SET msvc_includes=-I"%mn%INCLUDE"
SET msvc_libs=-L"%mn%lib\amd64"
SET msvc_bin_dir=%mn%bin\amd64
SET sdk_dir=%WindowsSdkDir%
SET sdk_ver=%WindowsSDKVersion%
SET si=%sdk_dir%Include\%sdk_ver%
SET sdk_includes=-I"%si%ucrt" -I"%si%um" -I"%si%shared" -I"%si%winrt"
SET sl=%sdk_dir%lib\%sdk_ver%
SET sdk_libs=-L"%sl%ucrt\x64" -L"%sl%um\x64"
SET vs_ver=%VisualStudioVersion%
GOTO print_vars
REM ================================================================
:not_2015
echo "ERROR: unsupported VS version (older than VS2015)" >&2
EXIT /B 1
REM ================================================================
:print_vars
REM Dump the essential vars to stdout to allow the main
REM Makefile to include it. See config.mak.uname.
REM Include DOS-style and BASH-style path for bin dir.
echo msvc_bin_dir=%msvc_bin_dir%
SET X1=%msvc_bin_dir:C:=/C%
SET X2=%X1:\=/%
echo msvc_bin_dir_msys=%X2%
echo msvc_includes=%msvc_includes%
echo msvc_libs=%msvc_libs%
echo sdk_includes=%sdk_includes%
echo sdk_libs=%sdk_libs%
echo vs_ver=%vs_ver%
EXIT /B 0

View file

@ -0,0 +1 @@
/* Intentionally empty file to support building git with MSVC */

View file

@ -0,0 +1 @@
/* Intentionally empty file to support building git with MSVC */

View file

@ -0,0 +1,34 @@
#ifndef _UTIME_H_
#define _UTIME_H_
/*
* UTIME.H
* This file has no copyright assigned and is placed in the Public Domain.
* This file is a part of the mingw-runtime package.
*
* The mingw-runtime package and its code is distributed in the hope that it
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* You are free to use this package and its code without limitation.
*/
/*
* Structure used by _utime function.
*/
struct _utimbuf
{
time_t actime; /* Access time */
time_t modtime; /* Modification time */
};
#ifndef _NO_OLDNAMES
/* NOTE: Must be the same as _utimbuf above. */
struct utimbuf
{
time_t actime;
time_t modtime;
};
#endif /* Not _NO_OLDNAMES */
#endif

View file

@ -0,0 +1,103 @@
#ifndef _UNISTD_
#define _UNISTD_
/* Win32 define for porting git*/
#ifndef _MODE_T_
#define _MODE_T_
typedef unsigned short _mode_t;
#ifndef _NO_OLDNAMES
typedef _mode_t mode_t;
#endif
#endif /* Not _MODE_T_ */
#ifndef _SSIZE_T_
#define _SSIZE_T_
typedef long _ssize_t;
#ifndef _OFF_T_
#define _OFF_T_
typedef long _off_t;
#ifndef _NO_OLDNAMES
typedef _off_t off_t;
#endif
#endif /* Not _OFF_T_ */
#ifndef _NO_OLDNAMES
typedef _ssize_t ssize_t;
#endif
#endif /* Not _SSIZE_T_ */
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
typedef long long intmax_t;
typedef unsigned long long uintmax_t;
typedef int64_t off64_t;
#if !defined(_MSC_VER) || _MSC_VER < 1600
#define INTMAX_MIN _I64_MIN
#define INTMAX_MAX _I64_MAX
#define UINTMAX_MAX _UI64_MAX
#define UINT32_MAX 0xffffffff /* 4294967295U */
#else
#include <stdint.h>
#endif
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
/* Some defines for _access nAccessMode (MS doesn't define them, but
* it doesn't seem to hurt to add them). */
#define F_OK 0 /* Check for file existence */
/* Well maybe it does hurt. On newer versions of MSVCRT, an access mode
of 1 causes invalid parameter error. */
#define X_OK 0 /* MS access() doesn't check for execute permission. */
#define W_OK 2 /* Check for write permission */
#define R_OK 4 /* Check for read permission */
#define _S_IFIFO 0x1000 /* FIFO */
#define _S_IFCHR 0x2000 /* Character */
#define _S_IFBLK 0x3000 /* Block: Is this ever set under w32? */
#define _S_IFDIR 0x4000 /* Directory */
#define _S_IFREG 0x8000 /* Regular */
#define _S_IFMT 0xF000 /* File type mask */
#define _S_IXUSR _S_IEXEC
#define _S_IWUSR _S_IWRITE
#define _S_IRUSR _S_IREAD
#define _S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
#define S_IFIFO _S_IFIFO
#define S_IFCHR _S_IFCHR
#define S_IFBLK _S_IFBLK
#define S_IFDIR _S_IFDIR
#define S_IFREG _S_IFREG
#define S_IFMT _S_IFMT
#define S_IEXEC _S_IEXEC
#define S_IWRITE _S_IWRITE
#define S_IREAD _S_IREAD
#define S_IRWXU _S_IRWXU
#define S_IXUSR _S_IXUSR
#define S_IWUSR _S_IWUSR
#define S_IRUSR _S_IRUSR
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
#endif

View file

@ -0,0 +1 @@
#include <sys/utime.h>

View file

@ -0,0 +1,85 @@
#!/usr/bin/perl -w
######################################################################
# Compiles or links files
#
# This is a wrapper to facilitate the compilation of Git with MSVC
# using GNU Make as the build system. So, instead of manipulating the
# Makefile into something nasty, just to support non-space arguments
# etc, we use this wrapper to fix the command line options
#
# Copyright (C) 2009 Marius Storm-Olsen <mstormo@gmail.com>
######################################################################
use strict;
my @args = ();
my @cflags = ();
my @lflags = ();
my $is_linking = 0;
my $is_debug = 0;
while (@ARGV) {
my $arg = shift @ARGV;
if ("$arg" eq "-DDEBUG") {
# Some vcpkg-based libraries have different names for release
# and debug versions. This hack assumes that -DDEBUG comes
# before any "-l*" flags.
$is_debug = 1;
}
if ("$arg" =~ /^-[DIMGOZ]/) {
push(@cflags, $arg);
} elsif ("$arg" eq "-o") {
my $file_out = shift @ARGV;
if ("$file_out" =~ /exe$/) {
$is_linking = 1;
# Create foo.exe and foo.pdb
push(@args, "-OUT:$file_out");
} else {
# Create foo.o and foo.o.pdb
push(@args, "-Fo$file_out");
push(@args, "-Fd$file_out.pdb");
}
} elsif ("$arg" eq "-lz") {
if ($is_debug) {
push(@args, "zlibd.lib");
} else{
push(@args, "zlib.lib");
}
} elsif ("$arg" eq "-liconv") {
push(@args, "libiconv.lib");
} elsif ("$arg" eq "-lcrypto") {
push(@args, "libeay32.lib");
} elsif ("$arg" eq "-lssl") {
push(@args, "ssleay32.lib");
} elsif ("$arg" eq "-lcurl") {
my $lib = "";
# Newer vcpkg definitions call this libcurl_imp.lib; Do we
# need to use that instead?
foreach my $flag (@lflags) {
if ($flag =~ /^-LIBPATH:(.*)/) {
foreach my $l ("libcurl_imp.lib", "libcurl.lib") {
if (-f "$1/$l") {
$lib = $l;
last;
}
}
}
}
push(@args, $lib);
} elsif ("$arg" eq "-lexpat") {
push(@args, "expat.lib");
} elsif ("$arg" =~ /^-L/ && "$arg" ne "-LTCG") {
$arg =~ s/^-L/-LIBPATH:/;
push(@lflags, $arg);
} elsif ("$arg" =~ /^-R/) {
# eat
} else {
push(@args, $arg);
}
}
if ($is_linking) {
push(@args, @lflags);
unshift(@args, "link.exe");
} else {
unshift(@args, "cl.exe");
push(@args, @cflags);
}
printf(STDERR "**** @args\n\n\n") if (!defined($ENV{'QUIET_GEN'}));
exit (system(@args) != 0);

26
third_party/git/compat/vcbuild/scripts/lib.pl vendored Executable file
View file

@ -0,0 +1,26 @@
#!/usr/bin/perl -w
######################################################################
# Libifies files on Windows
#
# This is a wrapper to facilitate the compilation of Git with MSVC
# using GNU Make as the build system. So, instead of manipulating the
# Makefile into something nasty, just to support non-space arguments
# etc, we use this wrapper to fix the command line options
#
# Copyright (C) 2009 Marius Storm-Olsen <mstormo@gmail.com>
######################################################################
use strict;
my @args = ();
while (@ARGV) {
my $arg = shift @ARGV;
if ("$arg" eq "rcs") {
# Consume the rcs option
} elsif ("$arg" =~ /\.a$/) {
push(@args, "-OUT:$arg");
} else {
push(@args, $arg);
}
}
unshift(@args, "lib.exe");
# printf("**** @args\n");
exit (system(@args) != 0);

View file

@ -0,0 +1,39 @@
@ECHO OFF
REM ================================================================
REM This script is an optional step. It copies the *.dll and *.pdb
REM files (created by vcpkg_install.bat) into the top-level directory
REM of the repo so that you can type "./git.exe" and find them without
REM having to fixup your PATH.
REM
REM NOTE: Because the names of some DLL files change between DEBUG and
REM NOTE: RELEASE builds when built using "vcpkg.exe", you will need
REM NOTE: to copy up the corresponding version.
REM ================================================================
SETLOCAL EnableDelayedExpansion
@FOR /F "delims=" %%D IN ("%~dp0") DO @SET cwd=%%~fD
cd %cwd%
SET arch=x64-windows
SET inst=%cwd%vcpkg\installed\%arch%
IF [%1]==[release] (
echo Copying RELEASE mode DLLs to repo root...
) ELSE IF [%1]==[debug] (
SET inst=%inst%\debug
echo Copying DEBUG mode DLLs to repo root...
) ELSE (
echo ERROR: Invalid argument.
echo Usage: %~0 release
echo Usage: %~0 debug
EXIT /B 1
)
xcopy /e/s/v/y %inst%\bin\*.dll ..\..\
xcopy /e/s/v/y %inst%\bin\*.pdb ..\..\
xcopy /e/s/v/y %inst%\bin\*.dll ..\..\t\helper\
xcopy /e/s/v/y %inst%\bin\*.pdb ..\..\t\helper\
EXIT /B 0

View file

@ -0,0 +1,80 @@
@ECHO OFF
REM ================================================================
REM This script installs the "vcpkg" source package manager and uses
REM it to build the third-party libraries that git requires when it
REM is built using MSVC.
REM
REM [1] Install VCPKG.
REM [a] Create <root>/compat/vcbuild/vcpkg/
REM [b] Download "vcpkg".
REM [c] Compile using the currently installed version of VS.
REM [d] Create <root>/compat/vcbuild/vcpkg/vcpkg.exe
REM
REM [2] Install third-party libraries.
REM [a] Download each (which may also install CMAKE).
REM [b] Compile in RELEASE mode and install in:
REM vcpkg/installed/<arch>/{bin,lib}
REM [c] Compile in DEBUG mode and install in:
REM vcpkg/installed/<arch>/debug/{bin,lib}
REM [d] Install headers in:
REM vcpkg/installed/<arch>/include
REM
REM [3] Create a set of MAKE definitions for the top-level
REM Makefile to allow "make MSVC=1" to find the above
REM third-party libraries.
REM [a] Write vcpkg/VCPGK-DEFS
REM
REM https://blogs.msdn.microsoft.com/vcblog/2016/09/19/vcpkg-a-tool-to-acquire-and-build-c-open-source-libraries-on-windows/
REM https://github.com/Microsoft/vcpkg
REM https://vcpkg.readthedocs.io/en/latest/
REM ================================================================
SETLOCAL EnableDelayedExpansion
@FOR /F "delims=" %%D IN ("%~dp0") DO @SET cwd=%%~fD
cd %cwd%
dir vcpkg\vcpkg.exe >nul 2>nul && GOTO :install_libraries
echo Fetching vcpkg in %cwd%vcpkg
git.exe clone https://github.com/Microsoft/vcpkg vcpkg
IF ERRORLEVEL 1 ( EXIT /B 1 )
cd vcpkg
echo Building vcpkg
powershell -exec bypass scripts\bootstrap.ps1
IF ERRORLEVEL 1 ( EXIT /B 1 )
echo Successfully installed %cwd%vcpkg\vcpkg.exe
:install_libraries
SET arch=x64-windows
echo Installing third-party libraries...
FOR %%i IN (zlib expat libiconv openssl libssh2 curl) DO (
cd %cwd%vcpkg
IF NOT EXIST "packages\%%i_%arch%" CALL :sub__install_one %%i
IF ERRORLEVEL 1 ( EXIT /B 1 )
)
:install_defines
cd %cwd%
SET inst=%cwd%vcpkg\installed\%arch%
echo vcpkg_inc=-I"%inst%\include">VCPKG-DEFS
echo vcpkg_rel_lib=-L"%inst%\lib">>VCPKG-DEFS
echo vcpkg_rel_bin="%inst%\bin">>VCPKG-DEFS
echo vcpkg_dbg_lib=-L"%inst%\debug\lib">>VCPKG-DEFS
echo vcpkg_dbg_bin="%inst%\debug\bin">>VCPKG-DEFS
EXIT /B 0
:sub__install_one
echo Installing package %1...
.\vcpkg.exe install %1:%arch%
IF ERRORLEVEL 1 ( EXIT /B 1 )
echo Finished %1
goto :EOF

41
third_party/git/compat/win32.h vendored Normal file
View file

@ -0,0 +1,41 @@
#ifndef WIN32_H
#define WIN32_H
/* common Win32 functions for MinGW and Cygwin */
#ifndef GIT_WINDOWS_NATIVE /* Not defined for Cygwin */
#include <windows.h>
#endif
static inline int file_attr_to_st_mode (DWORD attr)
{
int fMode = S_IREAD;
if (attr & FILE_ATTRIBUTE_DIRECTORY)
fMode |= S_IFDIR;
else
fMode |= S_IFREG;
if (!(attr & FILE_ATTRIBUTE_READONLY))
fMode |= S_IWRITE;
return fMode;
}
static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
{
if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata))
return 0;
switch (GetLastError()) {
case ERROR_ACCESS_DENIED:
case ERROR_SHARING_VIOLATION:
case ERROR_LOCK_VIOLATION:
case ERROR_SHARING_BUFFER_EXCEEDED:
return EACCES;
case ERROR_BUFFER_OVERFLOW:
return ENAMETOOLONG;
case ERROR_NOT_ENOUGH_MEMORY:
return ENOMEM;
default:
return ENOENT;
}
}
#endif

1
third_party/git/compat/win32/alloca.h vendored Normal file
View file

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

92
third_party/git/compat/win32/dirent.c vendored Normal file
View file

@ -0,0 +1,92 @@
#include "../../git-compat-util.h"
struct DIR {
struct dirent dd_dir; /* includes d_type */
HANDLE dd_handle; /* FindFirstFile handle */
int dd_stat; /* 0-based index */
};
static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
{
/* convert UTF-16 name to UTF-8 */
xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
/* Set file type, based on WIN32_FIND_DATA */
if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
ent->d_type = DT_DIR;
else
ent->d_type = DT_REG;
}
DIR *opendir(const char *name)
{
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
WIN32_FIND_DATAW fdata;
HANDLE h;
int len;
DIR *dir;
/* convert name to UTF-16 and check length < MAX_PATH */
if ((len = xutftowcs_path(pattern, name)) < 0)
return NULL;
/* append optional '/' and wildcard '*' */
if (len && !is_dir_sep(pattern[len - 1]))
pattern[len++] = '/';
pattern[len++] = '*';
pattern[len] = 0;
/* open find handle */
h = FindFirstFileW(pattern, &fdata);
if (h == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
return NULL;
}
/* initialize DIR structure and copy first dir entry */
dir = xmalloc(sizeof(DIR));
dir->dd_handle = h;
dir->dd_stat = 0;
finddata2dirent(&dir->dd_dir, &fdata);
return dir;
}
struct dirent *readdir(DIR *dir)
{
if (!dir) {
errno = EBADF; /* No set_errno for mingw */
return NULL;
}
/* if first entry, dirent has already been set up by opendir */
if (dir->dd_stat) {
/* get next entry and convert from WIN32_FIND_DATA to dirent */
WIN32_FIND_DATAW fdata;
if (FindNextFileW(dir->dd_handle, &fdata)) {
finddata2dirent(&dir->dd_dir, &fdata);
} else {
DWORD lasterr = GetLastError();
/* POSIX says you shouldn't set errno when readdir can't
find any more files; so, if another error we leave it set. */
if (lasterr != ERROR_NO_MORE_FILES)
errno = err_win_to_posix(lasterr);
return NULL;
}
}
++dir->dd_stat;
return &dir->dd_dir;
}
int closedir(DIR *dir)
{
if (!dir) {
errno = EBADF;
return -1;
}
FindClose(dir->dd_handle);
free(dir);
return 0;
}

20
third_party/git/compat/win32/dirent.h vendored Normal file
View file

@ -0,0 +1,20 @@
#ifndef DIRENT_H
#define DIRENT_H
typedef struct DIR DIR;
#define DT_UNKNOWN 0
#define DT_DIR 1
#define DT_REG 2
#define DT_LNK 3
struct dirent {
unsigned char d_type; /* file type to prevent lstat after readdir */
char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
};
DIR *opendir(const char *dirname);
struct dirent *readdir(DIR *dir);
int closedir(DIR *dir);
#endif /* DIRENT_H */

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="Git" version="0.0.0.1" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>

57
third_party/git/compat/win32/lazyload.h vendored Normal file
View file

@ -0,0 +1,57 @@
#ifndef LAZYLOAD_H
#define LAZYLOAD_H
/*
* A pair of macros to simplify loading of DLL functions. Example:
*
* DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateHardLinkW,
* LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
*
* if (!INIT_PROC_ADDR(CreateHardLinkW))
* return error("Could not find CreateHardLinkW() function";
*
* if (!CreateHardLinkW(source, target, NULL))
* return error("could not create hardlink from %S to %S",
* source, target);
*/
struct proc_addr {
const char *const dll;
const char *const function;
FARPROC pfunction;
unsigned initialized : 1;
};
/* Declares a function to be loaded dynamically from a DLL. */
#define DECLARE_PROC_ADDR(dll, rettype, function, ...) \
static struct proc_addr proc_addr_##function = \
{ #dll, #function, NULL, 0 }; \
static rettype (WINAPI *function)(__VA_ARGS__)
/*
* Loads a function from a DLL (once-only).
* Returns non-NULL function pointer on success.
* Returns NULL + errno == ENOSYS on failure.
* This function is not thread-safe.
*/
#define INIT_PROC_ADDR(function) \
(function = get_proc_addr(&proc_addr_##function))
static inline void *get_proc_addr(struct proc_addr *proc)
{
/* only do this once */
if (!proc->initialized) {
HANDLE hnd;
proc->initialized = 1;
hnd = LoadLibraryExA(proc->dll, NULL,
LOAD_LIBRARY_SEARCH_SYSTEM32);
if (hnd)
proc->pfunction = GetProcAddress(hnd, proc->function);
}
/* set ENOSYS if DLL or function was not found */
if (!proc->pfunction)
errno = ENOSYS;
return proc->pfunction;
}
#endif

View file

@ -0,0 +1,28 @@
#include "../../git-compat-util.h"
int win32_skip_dos_drive_prefix(char **path)
{
int ret = has_dos_drive_prefix(*path);
*path += ret;
return ret;
}
int win32_offset_1st_component(const char *path)
{
char *pos = (char *)path;
/* unc paths */
if (!skip_dos_drive_prefix(&pos) &&
is_dir_sep(pos[0]) && is_dir_sep(pos[1])) {
/* skip server name */
pos = strpbrk(pos + 2, "\\/");
if (!pos)
return 0; /* Error: malformed unc path */
do {
pos++;
} while (*pos && !is_dir_sep(*pos));
}
return pos + is_dir_sep(*pos) - path;
}

View file

@ -0,0 +1,20 @@
#define has_dos_drive_prefix(path) \
(isalpha(*(path)) && (path)[1] == ':' ? 2 : 0)
int win32_skip_dos_drive_prefix(char **path);
#define skip_dos_drive_prefix win32_skip_dos_drive_prefix
static inline int win32_is_dir_sep(int c)
{
return c == '/' || c == '\\';
}
#define is_dir_sep win32_is_dir_sep
static inline char *win32_find_last_dir_sep(const char *path)
{
char *ret = NULL;
for (; *path; ++path)
if (is_dir_sep(*path))
ret = (char *)path;
return ret;
}
#define find_last_dir_sep win32_find_last_dir_sep
int win32_offset_1st_component(const char *path);
#define offset_1st_component win32_offset_1st_component

58
third_party/git/compat/win32/pthread.c vendored Normal file
View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com>
*
* DISCLAIMER: The implementation is Git-specific, it is subset of original
* Pthreads API, without lots of other features that Git doesn't use.
* Git also makes sure that the passed arguments are valid, so there's
* no need for double-checking.
*/
#include "../../git-compat-util.h"
#include "pthread.h"
#include <errno.h>
#include <limits.h>
static unsigned __stdcall win32_start_routine(void *arg)
{
pthread_t *thread = arg;
thread->tid = GetCurrentThreadId();
thread->arg = thread->start_routine(thread->arg);
return 0;
}
int pthread_create(pthread_t *thread, const void *unused,
void *(*start_routine)(void*), void *arg)
{
thread->arg = arg;
thread->start_routine = start_routine;
thread->handle = (HANDLE)
_beginthreadex(NULL, 0, win32_start_routine, thread, 0, NULL);
if (!thread->handle)
return errno;
else
return 0;
}
int win32_pthread_join(pthread_t *thread, void **value_ptr)
{
DWORD result = WaitForSingleObject(thread->handle, INFINITE);
switch (result) {
case WAIT_OBJECT_0:
if (value_ptr)
*value_ptr = thread->arg;
return 0;
case WAIT_ABANDONED:
return EINVAL;
default:
return err_win_to_posix(GetLastError());
}
}
pthread_t pthread_self(void)
{
pthread_t t = { NULL };
t.tid = GetCurrentThreadId();
return t;
}

100
third_party/git/compat/win32/pthread.h vendored Normal file
View file

@ -0,0 +1,100 @@
/*
* Header used to adapt pthread-based POSIX code to Windows API threads.
*
* Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com>
*/
#ifndef PTHREAD_H
#define PTHREAD_H
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
/*
* Defines that adapt Windows API threads to pthreads API
*/
#define pthread_mutex_t CRITICAL_SECTION
static inline int return_0(int i) {
return 0;
}
#define pthread_mutex_init(a,b) return_0((InitializeCriticalSection((a)), 0))
#define pthread_mutex_destroy(a) DeleteCriticalSection((a))
#define pthread_mutex_lock EnterCriticalSection
#define pthread_mutex_unlock LeaveCriticalSection
typedef int pthread_mutexattr_t;
#define pthread_mutexattr_init(a) (*(a) = 0)
#define pthread_mutexattr_destroy(a) do {} while (0)
#define pthread_mutexattr_settype(a, t) 0
#define PTHREAD_MUTEX_RECURSIVE 0
#define pthread_cond_t CONDITION_VARIABLE
#define pthread_cond_init(a,b) InitializeConditionVariable((a))
#define pthread_cond_destroy(a) do {} while (0)
#define pthread_cond_wait(a,b) return_0(SleepConditionVariableCS((a), (b), INFINITE))
#define pthread_cond_signal WakeConditionVariable
#define pthread_cond_broadcast WakeAllConditionVariable
/*
* Simple thread creation implementation using pthread API
*/
typedef struct {
HANDLE handle;
void *(*start_routine)(void*);
void *arg;
DWORD tid;
} pthread_t;
extern int pthread_create(pthread_t *thread, const void *unused,
void *(*start_routine)(void*), void *arg);
/*
* To avoid the need of copying a struct, we use small macro wrapper to pass
* pointer to win32_pthread_join instead.
*/
#define pthread_join(a, b) win32_pthread_join(&(a), (b))
extern int win32_pthread_join(pthread_t *thread, void **value_ptr);
#define pthread_equal(t1, t2) ((t1).tid == (t2).tid)
extern pthread_t pthread_self(void);
static inline void NORETURN pthread_exit(void *ret)
{
ExitThread((DWORD)(intptr_t)ret);
}
typedef DWORD pthread_key_t;
static inline int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *value))
{
return (*keyp = TlsAlloc()) == TLS_OUT_OF_INDEXES ? EAGAIN : 0;
}
static inline int pthread_key_delete(pthread_key_t key)
{
return TlsFree(key) ? 0 : EINVAL;
}
static inline int pthread_setspecific(pthread_key_t key, const void *value)
{
return TlsSetValue(key, (void *)value) ? 0 : EINVAL;
}
static inline void *pthread_getspecific(pthread_key_t key)
{
return TlsGetValue(key);
}
#ifndef __MINGW64_VERSION_MAJOR
static inline int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
{
return 0;
}
#endif
#endif /* PTHREAD_H */

80
third_party/git/compat/win32/syslog.c vendored Normal file
View file

@ -0,0 +1,80 @@
#include "../../git-compat-util.h"
static HANDLE ms_eventlog;
void openlog(const char *ident, int logopt, int facility)
{
if (ms_eventlog)
return;
ms_eventlog = RegisterEventSourceA(NULL, ident);
if (!ms_eventlog)
warning("RegisterEventSource() failed: %lu", GetLastError());
}
void syslog(int priority, const char *fmt, ...)
{
WORD logtype;
char *str, *pos;
int str_len;
va_list ap;
if (!ms_eventlog)
return;
va_start(ap, fmt);
str_len = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
if (str_len < 0) {
warning_errno("vsnprintf failed");
return;
}
str = malloc(st_add(str_len, 1));
if (!str) {
warning_errno("malloc failed");
return;
}
va_start(ap, fmt);
vsnprintf(str, str_len + 1, fmt, ap);
va_end(ap);
while ((pos = strstr(str, "%1")) != NULL) {
char *oldstr = str;
str = realloc(str, st_add(++str_len, 1));
if (!str) {
free(oldstr);
warning_errno("realloc failed");
return;
}
memmove(pos + 2, pos + 1, strlen(pos));
pos[1] = ' ';
}
switch (priority) {
case LOG_EMERG:
case LOG_ALERT:
case LOG_CRIT:
case LOG_ERR:
logtype = EVENTLOG_ERROR_TYPE;
break;
case LOG_WARNING:
logtype = EVENTLOG_WARNING_TYPE;
break;
case LOG_NOTICE:
case LOG_INFO:
case LOG_DEBUG:
default:
logtype = EVENTLOG_INFORMATION_TYPE;
break;
}
ReportEventA(ms_eventlog, logtype, 0, 0, NULL, 1, 0,
(const char **)&str, NULL);
free(str);
}

20
third_party/git/compat/win32/syslog.h vendored Normal file
View file

@ -0,0 +1,20 @@
#ifndef SYSLOG_H
#define SYSLOG_H
#define LOG_PID 0x01
#define LOG_EMERG 0
#define LOG_ALERT 1
#define LOG_CRIT 2
#define LOG_ERR 3
#define LOG_WARNING 4
#define LOG_NOTICE 5
#define LOG_INFO 6
#define LOG_DEBUG 7
#define LOG_DAEMON (3<<3)
void openlog(const char *ident, int logopt, int facility);
void syslog(int priority, const char *fmt, ...);
#endif /* SYSLOG_H */

View file

@ -0,0 +1,191 @@
#include "../../cache.h"
#include "../../json-writer.h"
#include "lazyload.h"
#include <Psapi.h>
#include <tlHelp32.h>
/*
* An arbitrarily chosen value to limit the size of the ancestor
* array built in git_processes().
*/
#define NR_PIDS_LIMIT 10
/*
* Find the process data for the given PID in the given snapshot
* and update the PROCESSENTRY32 data.
*/
static int find_pid(DWORD pid, HANDLE hSnapshot, PROCESSENTRY32 *pe32)
{
pe32->dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, pe32)) {
do {
if (pe32->th32ProcessID == pid)
return 1;
} while (Process32Next(hSnapshot, pe32));
}
return 0;
}
/*
* Accumulate JSON array of our parent processes:
* [
* exe-name-parent,
* exe-name-grand-parent,
* ...
* ]
*
* Note: we only report the filename of the process executable; the
* only way to get its full pathname is to use OpenProcess()
* and GetModuleFileNameEx() or QueryfullProcessImageName()
* and that seems rather expensive (on top of the cost of
* getting the snapshot).
*
* Note: we compute the set of parent processes by walking the PPID
* link in each visited PROCESSENTRY32 record. This search
* stops when an ancestor process is not found in the snapshot
* (because it exited before the current or intermediate parent
* process exited).
*
* This search may compute an incorrect result if the PPID link
* refers to the PID of an exited parent and that PID has been
* recycled and given to a new unrelated process.
*
* Worse, it is possible for a child or descendant of the
* current process to be given the recycled PID and cause a
* PPID-cycle. This would cause an infinite loop building our
* parent process array.
*
* Note: for completeness, the "System Idle" process has PID=0 and
* PPID=0 and could cause another PPID-cycle. We don't expect
* Git to be a descendant of the idle process, but because of
* PID recycling, it might be possible to get a PPID link value
* of 0. This too would cause an infinite loop.
*
* Therefore, we keep an array of the visited PPIDs to guard against
* cycles.
*
* We use a fixed-size array rather than ALLOC_GROW to keep things
* simple and avoid the alloc/realloc overhead. It is OK if we
* truncate the search and return a partial answer.
*/
static void get_processes(struct json_writer *jw, HANDLE hSnapshot)
{
PROCESSENTRY32 pe32;
DWORD pid;
DWORD pid_list[NR_PIDS_LIMIT];
int k, nr_pids = 0;
pid = GetCurrentProcessId();
while (find_pid(pid, hSnapshot, &pe32)) {
/* Only report parents. Omit self from the JSON output. */
if (nr_pids)
jw_array_string(jw, pe32.szExeFile);
/* Check for cycle in snapshot. (Yes, it happened.) */
for (k = 0; k < nr_pids; k++)
if (pid == pid_list[k]) {
jw_array_string(jw, "(cycle)");
return;
}
if (nr_pids == NR_PIDS_LIMIT) {
jw_array_string(jw, "(truncated)");
return;
}
pid_list[nr_pids++] = pid;
pid = pe32.th32ParentProcessID;
}
}
/*
* Emit JSON data for the current and parent processes. Individual
* trace2 targets can decide how to actually print it.
*/
static void get_ancestry(void)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE) {
struct json_writer jw = JSON_WRITER_INIT;
jw_array_begin(&jw, 0);
get_processes(&jw, hSnapshot);
jw_end(&jw);
trace2_data_json("process", the_repository, "windows/ancestry",
&jw);
jw_release(&jw);
CloseHandle(hSnapshot);
}
}
/*
* Is a debugger attached to the current process?
*
* This will catch debug runs (where the debugger started the process).
* This is the normal case. Since this code is called during our startup,
* it will not report instances where a debugger is attached dynamically
* to a running git process, but that is relatively rare.
*/
static void get_is_being_debugged(void)
{
if (IsDebuggerPresent())
trace2_data_intmax("process", the_repository,
"windows/debugger_present", 1);
}
/*
* Emit JSON data with the peak memory usage of the current process.
*/
static void get_peak_memory_info(void)
{
DECLARE_PROC_ADDR(psapi.dll, BOOL, GetProcessMemoryInfo, HANDLE,
PPROCESS_MEMORY_COUNTERS, DWORD);
if (INIT_PROC_ADDR(GetProcessMemoryInfo)) {
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc,
sizeof(pmc))) {
struct json_writer jw = JSON_WRITER_INIT;
jw_object_begin(&jw, 0);
#define KV(kv) #kv, (intmax_t)pmc.kv
jw_object_intmax(&jw, KV(PageFaultCount));
jw_object_intmax(&jw, KV(PeakWorkingSetSize));
jw_object_intmax(&jw, KV(PeakPagefileUsage));
jw_end(&jw);
trace2_data_json("process", the_repository,
"windows/memory", &jw);
jw_release(&jw);
}
}
}
void trace2_collect_process_info(enum trace2_process_info_reason reason)
{
if (!trace2_is_enabled())
return;
switch (reason) {
case TRACE2_PROCESS_INFO_STARTUP:
get_is_being_debugged();
get_ancestry();
return;
case TRACE2_PROCESS_INFO_EXIT:
get_peak_memory_info();
return;
default:
BUG("trace2_collect_process_info: unknown reason '%d'", reason);
}
}

46
third_party/git/compat/win32mmap.c vendored Normal file
View file

@ -0,0 +1,46 @@
#include "../git-compat-util.h"
void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
{
HANDLE osfhandle, hmap;
void *temp;
LARGE_INTEGER len;
uint64_t o = offset;
uint32_t l = o & 0xFFFFFFFF;
uint32_t h = (o >> 32) & 0xFFFFFFFF;
osfhandle = (HANDLE)_get_osfhandle(fd);
if (!GetFileSizeEx(osfhandle, &len))
die("mmap: could not determine filesize");
if ((length + offset) > len.QuadPart)
length = xsize_t(len.QuadPart - offset);
if (!(flags & MAP_PRIVATE))
die("Invalid usage of mmap when built with USE_WIN32_MMAP");
hmap = CreateFileMapping(osfhandle, NULL,
prot == PROT_READ ? PAGE_READONLY : PAGE_WRITECOPY, 0, 0, NULL);
if (!hmap) {
errno = EINVAL;
return MAP_FAILED;
}
temp = MapViewOfFileEx(hmap, prot == PROT_READ ?
FILE_MAP_READ : FILE_MAP_COPY, h, l, length, start);
if (!CloseHandle(hmap))
warning("unable to close file mapping handle");
if (temp)
return temp;
errno = GetLastError() == ERROR_COMMITMENT_LIMIT ? EFBIG : EINVAL;
return MAP_FAILED;
}
int git_munmap(void *start, size_t length)
{
return !UnmapViewOfFile(start);
}

671
third_party/git/compat/winansi.c vendored Normal file
View file

@ -0,0 +1,671 @@
/*
* Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
*/
#undef NOGDI
#include "../git-compat-util.h"
#include <wingdi.h>
#include <winreg.h>
#include "win32.h"
#include "win32/lazyload.h"
static int fd_is_interactive[3] = { 0, 0, 0 };
#define FD_CONSOLE 0x1
#define FD_SWAPPED 0x2
#define FD_MSYS 0x4
/*
ANSI codes used by git: m, K
This file is git-specific. Therefore, this file does not attempt
to implement any codes that are not used by git.
*/
static HANDLE console;
static WORD plain_attr;
static WORD attr;
static int negative;
static int non_ascii_used = 0;
static HANDLE hthread, hread, hwrite;
static HANDLE hconsole1, hconsole2;
#ifdef __MINGW32__
#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 5
typedef struct _CONSOLE_FONT_INFOEX {
ULONG cbSize;
DWORD nFont;
COORD dwFontSize;
UINT FontFamily;
UINT FontWeight;
WCHAR FaceName[LF_FACESIZE];
} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
#endif
#endif
static void warn_if_raster_font(void)
{
DWORD fontFamily = 0;
DECLARE_PROC_ADDR(kernel32.dll, BOOL, GetCurrentConsoleFontEx,
HANDLE, BOOL, PCONSOLE_FONT_INFOEX);
/* don't bother if output was ascii only */
if (!non_ascii_used)
return;
/* GetCurrentConsoleFontEx is available since Vista */
if (INIT_PROC_ADDR(GetCurrentConsoleFontEx)) {
CONSOLE_FONT_INFOEX cfi;
cfi.cbSize = sizeof(cfi);
if (GetCurrentConsoleFontEx(console, 0, &cfi))
fontFamily = cfi.FontFamily;
} else {
/* pre-Vista: check default console font in registry */
HKEY hkey;
if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
0, KEY_READ, &hkey)) {
DWORD size = sizeof(fontFamily);
RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
(LPVOID) &fontFamily, &size);
RegCloseKey(hkey);
}
}
if (!(fontFamily & TMPF_TRUETYPE)) {
const wchar_t *msg = L"\nWarning: Your console font probably "
L"doesn\'t support Unicode. If you experience strange "
L"characters in the output, consider switching to a "
L"TrueType font such as Consolas!\n";
DWORD dummy;
WriteConsoleW(console, msg, wcslen(msg), &dummy, NULL);
}
}
static int is_console(int fd)
{
CONSOLE_SCREEN_BUFFER_INFO sbi;
DWORD mode;
HANDLE hcon;
static int initialized = 0;
/* get OS handle of the file descriptor */
hcon = (HANDLE) _get_osfhandle(fd);
if (hcon == INVALID_HANDLE_VALUE)
return 0;
/* check if its a device (i.e. console, printer, serial port) */
if (GetFileType(hcon) != FILE_TYPE_CHAR)
return 0;
/* check if its a handle to a console output screen buffer */
if (!fd) {
if (!GetConsoleMode(hcon, &mode))
return 0;
/*
* This code path is only reached if there is no console
* attached to stdout/stderr, i.e. we will not need to output
* any text to any console, therefore we might just as well
* use black as foreground color.
*/
sbi.wAttributes = 0;
} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
return 0;
if (fd >= 0 && fd <= 2)
fd_is_interactive[fd] |= FD_CONSOLE;
/* initialize attributes */
if (!initialized) {
console = hcon;
attr = plain_attr = sbi.wAttributes;
negative = 0;
initialized = 1;
}
return 1;
}
#define BUFFER_SIZE 4096
#define MAX_PARAMS 16
static void write_console(unsigned char *str, size_t len)
{
/* only called from console_thread, so a static buffer will do */
static wchar_t wbuf[2 * BUFFER_SIZE + 1];
DWORD dummy;
/* convert utf-8 to utf-16 */
int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
if (wlen < 0) {
wchar_t *err = L"[invalid]";
WriteConsoleW(console, err, wcslen(err), &dummy, NULL);
return;
}
/* write directly to console */
WriteConsoleW(console, wbuf, wlen, &dummy, NULL);
/* remember if non-ascii characters are printed */
if (wlen != len)
non_ascii_used = 1;
}
#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
static void set_console_attr(void)
{
WORD attributes = attr;
if (negative) {
attributes &= ~FOREGROUND_ALL;
attributes &= ~BACKGROUND_ALL;
/* This could probably use a bitmask
instead of a series of ifs */
if (attr & FOREGROUND_RED)
attributes |= BACKGROUND_RED;
if (attr & FOREGROUND_GREEN)
attributes |= BACKGROUND_GREEN;
if (attr & FOREGROUND_BLUE)
attributes |= BACKGROUND_BLUE;
if (attr & BACKGROUND_RED)
attributes |= FOREGROUND_RED;
if (attr & BACKGROUND_GREEN)
attributes |= FOREGROUND_GREEN;
if (attr & BACKGROUND_BLUE)
attributes |= FOREGROUND_BLUE;
}
SetConsoleTextAttribute(console, attributes);
}
static void erase_in_line(void)
{
CONSOLE_SCREEN_BUFFER_INFO sbi;
DWORD dummy; /* Needed for Windows 7 (or Vista) regression */
if (!console)
return;
GetConsoleScreenBufferInfo(console, &sbi);
FillConsoleOutputCharacterA(console, ' ',
sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
&dummy);
}
static void set_attr(char func, const int *params, int paramlen)
{
int i;
switch (func) {
case 'm':
for (i = 0; i < paramlen; i++) {
switch (params[i]) {
case 0: /* reset */
attr = plain_attr;
negative = 0;
break;
case 1: /* bold */
attr |= FOREGROUND_INTENSITY;
break;
case 2: /* faint */
case 22: /* normal */
attr &= ~FOREGROUND_INTENSITY;
break;
case 3: /* italic */
/* Unsupported */
break;
case 4: /* underline */
case 21: /* double underline */
/* Wikipedia says this flag does nothing */
/* Furthermore, mingw doesn't define this flag
attr |= COMMON_LVB_UNDERSCORE; */
break;
case 24: /* no underline */
/* attr &= ~COMMON_LVB_UNDERSCORE; */
break;
case 5: /* slow blink */
case 6: /* fast blink */
/* We don't have blink, but we do have
background intensity */
attr |= BACKGROUND_INTENSITY;
break;
case 25: /* no blink */
attr &= ~BACKGROUND_INTENSITY;
break;
case 7: /* negative */
negative = 1;
break;
case 27: /* positive */
negative = 0;
break;
case 8: /* conceal */
case 28: /* reveal */
/* Unsupported */
break;
case 30: /* Black */
attr &= ~FOREGROUND_ALL;
break;
case 31: /* Red */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_RED;
break;
case 32: /* Green */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_GREEN;
break;
case 33: /* Yellow */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_RED | FOREGROUND_GREEN;
break;
case 34: /* Blue */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_BLUE;
break;
case 35: /* Magenta */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_RED | FOREGROUND_BLUE;
break;
case 36: /* Cyan */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
break;
case 37: /* White */
attr |= FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE;
break;
case 38: /* Unknown */
break;
case 39: /* reset */
attr &= ~FOREGROUND_ALL;
attr |= (plain_attr & FOREGROUND_ALL);
break;
case 40: /* Black */
attr &= ~BACKGROUND_ALL;
break;
case 41: /* Red */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_RED;
break;
case 42: /* Green */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_GREEN;
break;
case 43: /* Yellow */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_RED | BACKGROUND_GREEN;
break;
case 44: /* Blue */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_BLUE;
break;
case 45: /* Magenta */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_RED | BACKGROUND_BLUE;
break;
case 46: /* Cyan */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
break;
case 47: /* White */
attr |= BACKGROUND_RED |
BACKGROUND_GREEN |
BACKGROUND_BLUE;
break;
case 48: /* Unknown */
break;
case 49: /* reset */
attr &= ~BACKGROUND_ALL;
attr |= (plain_attr & BACKGROUND_ALL);
break;
default:
/* Unsupported code */
break;
}
}
set_console_attr();
break;
case 'K':
erase_in_line();
break;
default:
/* Unsupported code */
break;
}
}
enum {
TEXT = 0, ESCAPE = 033, BRACKET = '['
};
static DWORD WINAPI console_thread(LPVOID unused)
{
unsigned char buffer[BUFFER_SIZE];
DWORD bytes;
int start, end = 0, c, parampos = 0, state = TEXT;
int params[MAX_PARAMS];
while (1) {
/* read next chunk of bytes from the pipe */
if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes,
NULL)) {
/* exit if pipe has been closed or disconnected */
if (GetLastError() == ERROR_PIPE_NOT_CONNECTED ||
GetLastError() == ERROR_BROKEN_PIPE)
break;
/* ignore other errors */
continue;
}
/* scan the bytes and handle ANSI control codes */
bytes += end;
start = end = 0;
while (end < bytes) {
c = buffer[end++];
switch (state) {
case TEXT:
if (c == ESCAPE) {
/* print text seen so far */
if (end - 1 > start)
write_console(buffer + start,
end - 1 - start);
/* then start parsing escape sequence */
start = end - 1;
memset(params, 0, sizeof(params));
parampos = 0;
state = ESCAPE;
}
break;
case ESCAPE:
/* continue if "\033[", otherwise bail out */
state = (c == BRACKET) ? BRACKET : TEXT;
break;
case BRACKET:
/* parse [0-9;]* into array of parameters */
if (c >= '0' && c <= '9') {
params[parampos] *= 10;
params[parampos] += c - '0';
} else if (c == ';') {
/*
* next parameter, bail out if out of
* bounds
*/
parampos++;
if (parampos >= MAX_PARAMS)
state = TEXT;
} else {
/*
* end of escape sequence, change
* console attributes
*/
set_attr(c, params, parampos + 1);
start = end;
state = TEXT;
}
break;
}
}
/* print remaining text unless parsing an escape sequence */
if (state == TEXT && end > start) {
/* check for incomplete UTF-8 sequences and fix end */
if (buffer[end - 1] >= 0x80) {
if (buffer[end -1] >= 0xc0)
end--;
else if (end - 1 > start &&
buffer[end - 2] >= 0xe0)
end -= 2;
else if (end - 2 > start &&
buffer[end - 3] >= 0xf0)
end -= 3;
}
/* print remaining complete UTF-8 sequences */
if (end > start)
write_console(buffer + start, end - start);
/* move remaining bytes to the front */
if (end < bytes)
memmove(buffer, buffer + end, bytes - end);
end = bytes - end;
} else {
/* all data has been consumed, mark buffer empty */
end = 0;
}
}
/* check if the console font supports unicode */
warn_if_raster_font();
CloseHandle(hread);
return 0;
}
static void winansi_exit(void)
{
/* flush all streams */
_flushall();
/* signal console thread to exit */
FlushFileBuffers(hwrite);
DisconnectNamedPipe(hwrite);
/* wait for console thread to copy remaining data */
WaitForSingleObject(hthread, INFINITE);
/* cleanup handles... */
CloseHandle(hwrite);
CloseHandle(hthread);
}
static void die_lasterr(const char *fmt, ...)
{
va_list params;
va_start(params, fmt);
errno = err_win_to_posix(GetLastError());
die_errno(fmt, params);
va_end(params);
}
#undef dup2
int winansi_dup2(int oldfd, int newfd)
{
int ret = dup2(oldfd, newfd);
if (!ret && newfd >= 0 && newfd <= 2)
fd_is_interactive[newfd] = oldfd < 0 || oldfd > 2 ?
0 : fd_is_interactive[oldfd];
return ret;
}
static HANDLE duplicate_handle(HANDLE hnd)
{
HANDLE hresult, hproc = GetCurrentProcess();
if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE,
DUPLICATE_SAME_ACCESS))
die_lasterr("DuplicateHandle(%li) failed",
(long) (intptr_t) hnd);
return hresult;
}
static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
{
/*
* Create a copy of the original handle associated with fd
* because the original will get closed when we dup2().
*/
HANDLE handle = (HANDLE)_get_osfhandle(fd);
HANDLE duplicate = duplicate_handle(handle);
/* Create a temp fd associated with the already open "new_handle". */
int new_fd = _open_osfhandle((intptr_t)new_handle, O_BINARY);
assert((fd == 1) || (fd == 2));
/*
* Use stock dup2() to re-bind fd to the new handle. Note that
* this will implicitly close(1) and close both fd=1 and the
* originally associated handle. It will open a new fd=1 and
* call DuplicateHandle() on the handle associated with new_fd.
* It is because of this implicit close() that we created the
* copy of the original.
*
* Note that we need to update the cached console handle to the
* duplicated one because the dup2() call will implicitly close
* the original one.
*
* Note that dup2() when given target := {0,1,2} will also
* call SetStdHandle(), so we don't need to worry about that.
*/
if (console == handle)
console = duplicate;
dup2(new_fd, fd);
/* Close the temp fd. This explicitly closes "new_handle"
* (because it has been associated with it).
*/
close(new_fd);
if (fd == 2)
setvbuf(stderr, NULL, _IONBF, BUFSIZ);
fd_is_interactive[fd] |= FD_SWAPPED;
return duplicate;
}
#ifdef DETECT_MSYS_TTY
#include <winternl.h>
#if defined(_MSC_VER)
typedef struct _OBJECT_NAME_INFORMATION
{
UNICODE_STRING Name;
WCHAR NameBuffer[0];
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
#define ObjectNameInformation 1
#else
#include <ntstatus.h>
#endif
static void detect_msys_tty(int fd)
{
ULONG result;
BYTE buffer[1024];
POBJECT_NAME_INFORMATION nameinfo = (POBJECT_NAME_INFORMATION) buffer;
PWSTR name;
/* check if fd is a pipe */
HANDLE h = (HANDLE) _get_osfhandle(fd);
if (GetFileType(h) != FILE_TYPE_PIPE)
return;
/* get pipe name */
if (!NT_SUCCESS(NtQueryObject(h, ObjectNameInformation,
buffer, sizeof(buffer) - 2, &result)))
return;
name = nameinfo->Name.Buffer;
name[nameinfo->Name.Length / sizeof(*name)] = 0;
/*
* Check if this could be a MSYS2 pty pipe ('msys-XXXX-ptyN-XX')
* or a cygwin pty pipe ('cygwin-XXXX-ptyN-XX')
*/
if ((!wcsstr(name, L"msys-") && !wcsstr(name, L"cygwin-")) ||
!wcsstr(name, L"-pty"))
return;
if (fd == 2)
setvbuf(stderr, NULL, _IONBF, BUFSIZ);
fd_is_interactive[fd] |= FD_MSYS;
}
#endif
/*
* Wrapper for isatty(). Most calls in the main git code
* call isatty(1 or 2) to see if the instance is interactive
* and should: be colored, show progress, paginate output.
* We lie and give results for what the descriptor WAS at
* startup (and ignore any pipe redirection we internally
* do).
*/
#undef isatty
int winansi_isatty(int fd)
{
if (fd >= 0 && fd <= 2)
return fd_is_interactive[fd] != 0;
return isatty(fd);
}
void winansi_init(void)
{
int con1, con2;
wchar_t name[32];
/* check if either stdout or stderr is a console output screen buffer */
con1 = is_console(1);
con2 = is_console(2);
/* Also compute console bit for fd 0 even though we don't need the result here. */
is_console(0);
if (!con1 && !con2) {
#ifdef DETECT_MSYS_TTY
/* check if stdin / stdout / stderr are MSYS2 pty pipes */
detect_msys_tty(0);
detect_msys_tty(1);
detect_msys_tty(2);
#endif
return;
}
/* create a named pipe to communicate with the console thread */
if (swprintf(name, ARRAY_SIZE(name) - 1, L"\\\\.\\pipe\\winansi%lu",
GetCurrentProcessId()) < 0)
die("Could not initialize winansi pipe name");
hwrite = CreateNamedPipeW(name, PIPE_ACCESS_OUTBOUND,
PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL);
if (hwrite == INVALID_HANDLE_VALUE)
die_lasterr("CreateNamedPipe failed");
hread = CreateFileW(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hread == INVALID_HANDLE_VALUE)
die_lasterr("CreateFile for named pipe failed");
/* start console spool thread on the pipe's read end */
hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
if (hthread == INVALID_HANDLE_VALUE)
die_lasterr("CreateThread(console_thread) failed");
/* schedule cleanup routine */
if (atexit(winansi_exit))
die_errno("atexit(winansi_exit) failed");
/* redirect stdout / stderr to the pipe */
if (con1)
hconsole1 = swap_osfhnd(1, duplicate_handle(hwrite));
if (con2)
hconsole2 = swap_osfhnd(2, duplicate_handle(hwrite));
}
/*
* Returns the real console handle if stdout / stderr is a pipe redirecting
* to the console. Allows spawn / exec to pass the console to the next process.
*/
HANDLE winansi_get_osfhandle(int fd)
{
if (fd == 1 && (fd_is_interactive[1] & FD_SWAPPED))
return hconsole1;
if (fd == 2 && (fd_is_interactive[2] & FD_SWAPPED))
return hconsole2;
return (HANDLE)_get_osfhandle(fd);
}