merge(third_party/git): Merge squashed git subtree at v2.23.0
Merge commit '1b593e1ea4' as 'third_party/git'
This commit is contained in:
commit
7ef0d62730
3629 changed files with 1139935 additions and 0 deletions
31
third_party/git/compat/access.c
vendored
Normal file
31
third_party/git/compat/access.c
vendored
Normal 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;
|
||||
}
|
||||
96
third_party/git/compat/apple-common-crypto.h
vendored
Normal file
96
third_party/git/compat/apple-common-crypto.h
vendored
Normal 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
71
third_party/git/compat/basename.c
vendored
Normal 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
217
third_party/git/compat/bswap.h
vendored
Normal 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
7
third_party/git/compat/fileno.c
vendored
Normal 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
37
third_party/git/compat/fopen.c
vendored
Normal 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
29
third_party/git/compat/gmtime.c
vendored
Normal 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
21
third_party/git/compat/hstrerror.c
vendored
Normal 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
185
third_party/git/compat/inet_ntop.c
vendored
Normal 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
215
third_party/git/compat/inet_pton.c
vendored
Normal 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
32
third_party/git/compat/memmem.c
vendored
Normal 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
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
583
third_party/git/compat/mingw.h
vendored
Normal 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
24
third_party/git/compat/mkdir.c
vendored
Normal 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
8
third_party/git/compat/mkdtemp.c
vendored
Normal 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
40
third_party/git/compat/mmap.c
vendored
Normal 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
6
third_party/git/compat/msvc.c
vendored
Normal 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
33
third_party/git/compat/msvc.h
vendored
Normal 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
|
||||
23
third_party/git/compat/nedmalloc/License.txt
vendored
Normal file
23
third_party/git/compat/nedmalloc/License.txt
vendored
Normal 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.
|
||||
136
third_party/git/compat/nedmalloc/Readme.txt
vendored
Normal file
136
third_party/git/compat/nedmalloc/Readme.txt
vendored
Normal 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
|
||||
5761
third_party/git/compat/nedmalloc/malloc.c.h
vendored
Normal file
5761
third_party/git/compat/nedmalloc/malloc.c.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
953
third_party/git/compat/nedmalloc/nedmalloc.c
vendored
Normal file
953
third_party/git/compat/nedmalloc/nedmalloc.c
vendored
Normal 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
|
||||
180
third_party/git/compat/nedmalloc/nedmalloc.h
vendored
Normal file
180
third_party/git/compat/nedmalloc/nedmalloc.h
vendored
Normal 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
413
third_party/git/compat/obstack.c
vendored
Normal 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
509
third_party/git/compat/obstack.h
vendored
Normal 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
633
third_party/git/compat/poll/poll.c
vendored
Normal 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
67
third_party/git/compat/poll/poll.h
vendored
Normal 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
18
third_party/git/compat/pread.c
vendored
Normal 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
184
third_party/git/compat/precompose_utf8.c
vendored
Normal 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;
|
||||
}
|
||||
46
third_party/git/compat/precompose_utf8.h
vendored
Normal file
46
third_party/git/compat/precompose_utf8.h
vendored
Normal 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
62
third_party/git/compat/qsort.c
vendored
Normal 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
69
third_party/git/compat/qsort_s.c
vendored
Normal 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
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
87
third_party/git/compat/regex/regex.c
vendored
Normal 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
581
third_party/git/compat/regex/regex.h
vendored
Normal 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 */
|
||||
1743
third_party/git/compat/regex/regex_internal.c
vendored
Normal file
1743
third_party/git/compat/regex/regex_internal.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
809
third_party/git/compat/regex/regex_internal.h
vendored
Normal file
809
third_party/git/compat/regex/regex_internal.h
vendored
Normal 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
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
40
third_party/git/compat/setenv.c
vendored
Normal 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
19
third_party/git/compat/sha1-chunked.c
vendored
Normal 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
2
third_party/git/compat/sha1-chunked.h
vendored
Normal 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
69
third_party/git/compat/snprintf.c
vendored
Normal 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
48
third_party/git/compat/stat.c
vendored
Normal 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
22
third_party/git/compat/strcasestr.c
vendored
Normal 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
11
third_party/git/compat/strdup.c
vendored
Normal 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
13
third_party/git/compat/strlcpy.c
vendored
Normal 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
10
third_party/git/compat/strtoimax.c
vendored
Normal 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
10
third_party/git/compat/strtoumax.c
vendored
Normal 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
147
third_party/git/compat/terminal.c
vendored
Normal 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
6
third_party/git/compat/terminal.h
vendored
Normal 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
27
third_party/git/compat/unsetenv.c
vendored
Normal 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;
|
||||
}
|
||||
3
third_party/git/compat/vcbuild/.gitignore
vendored
Normal file
3
third_party/git/compat/vcbuild/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/vcpkg/
|
||||
/MSVC-DEFS-GEN
|
||||
/VCPKG-DEFS
|
||||
112
third_party/git/compat/vcbuild/README
vendored
Normal file
112
third_party/git/compat/vcbuild/README
vendored
Normal 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!
|
||||
168
third_party/git/compat/vcbuild/find_vs_env.bat
vendored
Normal file
168
third_party/git/compat/vcbuild/find_vs_env.bat
vendored
Normal 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
|
||||
1
third_party/git/compat/vcbuild/include/sys/param.h
vendored
Normal file
1
third_party/git/compat/vcbuild/include/sys/param.h
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/* Intentionally empty file to support building git with MSVC */
|
||||
1
third_party/git/compat/vcbuild/include/sys/time.h
vendored
Normal file
1
third_party/git/compat/vcbuild/include/sys/time.h
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/* Intentionally empty file to support building git with MSVC */
|
||||
34
third_party/git/compat/vcbuild/include/sys/utime.h
vendored
Normal file
34
third_party/git/compat/vcbuild/include/sys/utime.h
vendored
Normal 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
|
||||
103
third_party/git/compat/vcbuild/include/unistd.h
vendored
Normal file
103
third_party/git/compat/vcbuild/include/unistd.h
vendored
Normal 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
|
||||
1
third_party/git/compat/vcbuild/include/utime.h
vendored
Normal file
1
third_party/git/compat/vcbuild/include/utime.h
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include <sys/utime.h>
|
||||
85
third_party/git/compat/vcbuild/scripts/clink.pl
vendored
Executable file
85
third_party/git/compat/vcbuild/scripts/clink.pl
vendored
Executable 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
26
third_party/git/compat/vcbuild/scripts/lib.pl
vendored
Executable 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);
|
||||
39
third_party/git/compat/vcbuild/vcpkg_copy_dlls.bat
vendored
Normal file
39
third_party/git/compat/vcbuild/vcpkg_copy_dlls.bat
vendored
Normal 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
|
||||
80
third_party/git/compat/vcbuild/vcpkg_install.bat
vendored
Normal file
80
third_party/git/compat/vcbuild/vcpkg_install.bat
vendored
Normal 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
41
third_party/git/compat/win32.h
vendored
Normal 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
1
third_party/git/compat/win32/alloca.h
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include <malloc.h>
|
||||
92
third_party/git/compat/win32/dirent.c
vendored
Normal file
92
third_party/git/compat/win32/dirent.c
vendored
Normal 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
20
third_party/git/compat/win32/dirent.h
vendored
Normal 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 */
|
||||
25
third_party/git/compat/win32/git.manifest
vendored
Normal file
25
third_party/git/compat/win32/git.manifest
vendored
Normal 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
57
third_party/git/compat/win32/lazyload.h
vendored
Normal 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
|
||||
28
third_party/git/compat/win32/path-utils.c
vendored
Normal file
28
third_party/git/compat/win32/path-utils.c
vendored
Normal 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;
|
||||
}
|
||||
20
third_party/git/compat/win32/path-utils.h
vendored
Normal file
20
third_party/git/compat/win32/path-utils.h
vendored
Normal 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
58
third_party/git/compat/win32/pthread.c
vendored
Normal 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
100
third_party/git/compat/win32/pthread.h
vendored
Normal 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
80
third_party/git/compat/win32/syslog.c
vendored
Normal 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
20
third_party/git/compat/win32/syslog.h
vendored
Normal 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 */
|
||||
191
third_party/git/compat/win32/trace2_win32_process_info.c
vendored
Normal file
191
third_party/git/compat/win32/trace2_win32_process_info.c
vendored
Normal 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
46
third_party/git/compat/win32mmap.c
vendored
Normal 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
671
third_party/git/compat/winansi.c
vendored
Normal 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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue