summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2019-05-21 14:59:55 +0200
committerGitHub <noreply@github.com>2019-05-21 14:59:55 +0200
commit3d9e82fdd5619985b56ca25fb1f89de3dfabc029 (patch)
tree689c3f2a148574fdaeb48f8d04648707c61230ed /src
parent954f5357282233ecdfea226c819f3f3884949cdb (diff)
parentafb04a95af939295d9baebac5bea72c070001d9e (diff)
downloadlibgit2-3d9e82fdd5619985b56ca25fb1f89de3dfabc029.tar.gz
Merge pull request #4935 from libgit2/ethomson/pcre
Use PCRE for our fallback regex engine when regcomp_l is unavailable
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt67
-rw-r--r--src/common.h79
-rw-r--r--src/config.c28
-rw-r--r--src/config_file.c21
-rw-r--r--src/diff_driver.c33
-rw-r--r--src/errors.c6
-rw-r--r--src/errors.h88
-rw-r--r--src/features.h.in7
-rw-r--r--src/posix_regex.h73
-rw-r--r--src/revparse.c28
-rw-r--r--src/unix/posix.h10
-rw-r--r--src/userdiff.h2
-rw-r--r--src/win32/path_w32.h29
-rw-r--r--src/win32/posix.h3
-rw-r--r--src/win32/precompiled.h2
-rw-r--r--src/win32/w32_common.h39
16 files changed, 322 insertions, 193 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 00021b828..bf51c45bd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -48,23 +48,6 @@ IF (ENABLE_TRACE STREQUAL "ON")
ENDIF()
ADD_FEATURE_INFO(tracing GIT_TRACE "tracing support")
-# Use `regcomp_l` if available
-CHECK_SYMBOL_EXISTS(regcomp_l "regex.h;xlocale.h" HAVE_REGCOMP_L)
-IF (HAVE_REGCOMP_L)
- SET(GIT_USE_REGCOMP_L 1)
-ENDIF ()
-
-# Otherwise, we either want to use system's `regcomp` or our
-# bundled regcomp code, if system doesn't provide `regcomp`.
-IF(NOT HAVE_REGCOMP_L)
- CHECK_FUNCTION_EXISTS(regcomp HAVE_REGCOMP)
- IF(NOT HAVE_REGCOMP)
- ADD_SUBDIRECTORY("${libgit2_SOURCE_DIR}/deps/regex" "${libgit2_BINARY_DIR}/deps/regex")
- LIST(APPEND LIBGIT2_INCLUDES "${libgit2_SOURCE_DIR}/deps/regex")
- LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:regex>)
- ENDIF()
-ENDIF()
-
CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS)
IF (HAVE_FUTIMENS)
SET(GIT_USE_FUTIMENS 1)
@@ -306,6 +289,56 @@ ELSE()
MESSAGE(FATAL_ERROR "Asked for unknown SHA1 backend ${SHA1_BACKEND}")
ENDIF()
+# Specify regular expression implementation
+FIND_PACKAGE(PCRE)
+
+IF(REGEX_BACKEND STREQUAL "")
+ CHECK_SYMBOL_EXISTS(regcomp_l "regex.h;xlocale.h" HAVE_REGCOMP_L)
+
+ IF(HAVE_REGCOMP_L)
+ SET(REGEX_BACKEND "regcomp_l")
+ ELSEIF(PCRE_FOUND)
+ SET(REGEX_BACKEND "pcre")
+ ELSE()
+ SET(REGEX_BACKEND "builtin")
+ ENDIF()
+ENDIF()
+
+IF(REGEX_BACKEND STREQUAL "regcomp_l")
+ ADD_FEATURE_INFO(regex ON "using system regcomp_l")
+ SET(GIT_REGEX_REGCOMP_L 1)
+ELSEIF(REGEX_BACKEND STREQUAL "pcre2")
+ FIND_PACKAGE(PCRE2)
+
+ IF(NOT PCRE2_FOUND)
+ MESSAGE(FATAL_ERROR "PCRE2 support was requested but not found")
+ ENDIF()
+
+ ADD_FEATURE_INFO(regex ON "using system PCRE2")
+ SET(GIT_REGEX_PCRE2 1)
+
+ LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${PCRE2_INCLUDE_DIRS})
+ LIST(APPEND LIBGIT2_LIBS ${PCRE2_LIBRARIES})
+ELSEIF(REGEX_BACKEND STREQUAL "pcre")
+ ADD_FEATURE_INFO(regex ON "using system PCRE")
+ SET(GIT_REGEX_PCRE 1)
+
+ LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${PCRE_INCLUDE_DIRS})
+ LIST(APPEND LIBGIT2_LIBS ${PCRE_LIBRARIES})
+ELSEIF(REGEX_BACKEND STREQUAL "regcomp")
+ ADD_FEATURE_INFO(regex ON "using system regcomp")
+ SET(GIT_REGEX_REGCOMP 1)
+ELSEIF(REGEX_BACKEND STREQUAL "builtin")
+ ADD_FEATURE_INFO(regex ON "using bundled PCRE")
+ SET(GIT_REGEX_BUILTIN 1)
+
+ ADD_SUBDIRECTORY("${libgit2_SOURCE_DIR}/deps/pcre" "${libgit2_BINARY_DIR}/deps/pcre")
+ LIST(APPEND LIBGIT2_INCLUDES "${libgit2_SOURCE_DIR}/deps/pcre")
+ LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:pcre>)
+ELSE()
+ MESSAGE(FATAL_ERROR "The REGEX_BACKEND option provided is not supported")
+ENDIF()
+
# Optional external dependency: http-parser
FIND_PACKAGE(HTTP_Parser)
IF (USE_EXT_HTTP_PARSER AND HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2)
diff --git a/src/common.h b/src/common.h
index 18ba72dd1..8a5761abc 100644
--- a/src/common.h
+++ b/src/common.h
@@ -47,6 +47,7 @@
# include <ws2tcpip.h>
# include "win32/msvc-compat.h"
# include "win32/mingw-compat.h"
+# include "win32/w32_common.h"
# include "win32/win32-compat.h"
# include "win32/error.h"
# include "win32/version.h"
@@ -76,6 +77,7 @@
#include "git2/types.h"
#include "git2/errors.h"
+#include "errors.h"
#include "thread-utils.h"
#include "integer.h"
@@ -85,7 +87,8 @@
*/
#include "git2/deprecated.h"
-#include <regex.h>
+#include "posix.h"
+#include "posix_regex.h"
#define DEFAULT_BUFSIZE 65536
#define FILEIO_BUFSIZE DEFAULT_BUFSIZE
@@ -109,80 +112,6 @@
do { int _err = (code); if (_err) return _err; } while (0)
/**
- * Set the error message for this thread, formatting as needed.
- */
-
-void git_error_set(int error_class, const char *string, ...) GIT_FORMAT_PRINTF(2, 3);
-
-/**
- * Set the error message for a regex failure, using the internal regex
- * error code lookup and return a libgit error code.
- */
-int git_error_set_regex(const regex_t *regex, int error_code);
-
-/**
- * Set error message for user callback if needed.
- *
- * If the error code in non-zero and no error message is set, this
- * sets a generic error message.
- *
- * @return This always returns the `error_code` parameter.
- */
-GIT_INLINE(int) git_error_set_after_callback_function(
- int error_code, const char *action)
-{
- if (error_code) {
- const git_error *e = git_error_last();
- if (!e || !e->message)
- git_error_set(e ? e->klass : GIT_ERROR_CALLBACK,
- "%s callback returned %d", action, error_code);
- }
- return error_code;
-}
-
-#ifdef GIT_WIN32
-#define git_error_set_after_callback(code) \
- git_error_set_after_callback_function((code), __FUNCTION__)
-#else
-#define git_error_set_after_callback(code) \
- git_error_set_after_callback_function((code), __func__)
-#endif
-
-/**
- * Gets the system error code for this thread.
- */
-int git_error_system_last(void);
-
-/**
- * Sets the system error code for this thread.
- */
-void git_error_system_set(int code);
-
-/**
- * Structure to preserve libgit2 error state
- */
-typedef struct {
- int error_code;
- unsigned int oom : 1;
- git_error error_msg;
-} git_error_state;
-
-/**
- * Capture current error state to restore later, returning error code.
- * If `error_code` is zero, this does not clear the current error state.
- * You must either restore this error state, or free it.
- */
-extern int git_error_state_capture(git_error_state *state, int error_code);
-
-/**
- * Restore error state to a previous value, returning saved error code.
- */
-extern int git_error_state_restore(git_error_state *state);
-
-/** Free an error state. */
-extern void git_error_state_free(git_error_state *state);
-
-/**
* Check a versioned structure for validity
*/
GIT_INLINE(int) git_error__check_version(const void *structure, unsigned int expected_max, const char *name)
diff --git a/src/config.c b/src/config.c
index fce1aad3b..5519fe19c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -345,7 +345,7 @@ typedef struct {
git_config_iterator parent;
git_config_iterator *current;
const git_config *cfg;
- regex_t regex;
+ p_regex_t regex;
size_t i;
} all_iter;
@@ -423,7 +423,7 @@ static int all_iter_glob_next(git_config_entry **entry, git_config_iterator *_it
*/
while ((error = all_iter_next(entry, _iter)) == 0) {
/* skip non-matching keys if regexp was provided */
- if (regexec(&iter->regex, (*entry)->name, 0, NULL, 0) != 0)
+ if (p_regexec(&iter->regex, (*entry)->name, 0, NULL, 0) != 0)
continue;
/* and simply return if we like the entry's name */
@@ -447,7 +447,7 @@ static void all_iter_glob_free(git_config_iterator *_iter)
{
all_iter *iter = (all_iter *) _iter;
- regfree(&iter->regex);
+ p_regfree(&iter->regex);
all_iter_free(_iter);
}
@@ -480,7 +480,7 @@ int git_config_iterator_glob_new(git_config_iterator **out, const git_config *cf
iter = git__calloc(1, sizeof(all_iter));
GIT_ERROR_CHECK_ALLOC(iter);
- if ((result = p_regcomp(&iter->regex, regexp, REG_EXTENDED)) != 0) {
+ if ((result = p_regcomp(&iter->regex, regexp, P_REG_EXTENDED)) != 0) {
git_error_set_regex(&iter->regex, result);
git__free(iter);
return -1;
@@ -510,15 +510,15 @@ int git_config_backend_foreach_match(
{
git_config_entry *entry;
git_config_iterator* iter;
- regex_t regex;
+ p_regex_t regex;
int error = 0;
assert(backend && cb);
if (regexp != NULL) {
- if ((error = p_regcomp(&regex, regexp, REG_EXTENDED)) != 0) {
+ if ((error = p_regcomp(&regex, regexp, P_REG_EXTENDED)) != 0) {
git_error_set_regex(&regex, error);
- regfree(&regex);
+ p_regfree(&regex);
return -1;
}
}
@@ -530,7 +530,7 @@ int git_config_backend_foreach_match(
while (!(iter->next(&entry, iter) < 0)) {
/* skip non-matching keys if regexp was provided */
- if (regexp && regexec(&regex, entry->name, 0, NULL, 0) != 0)
+ if (regexp && p_regexec(&regex, entry->name, 0, NULL, 0) != 0)
continue;
/* abort iterator on non-zero return value */
@@ -541,7 +541,7 @@ int git_config_backend_foreach_match(
}
if (regexp != NULL)
- regfree(&regex);
+ p_regfree(&regex);
iter->free(iter);
@@ -981,7 +981,7 @@ typedef struct {
git_config_iterator parent;
git_config_iterator *iter;
char *name;
- regex_t regex;
+ p_regex_t regex;
int have_regex;
} multivar_iter;
@@ -997,7 +997,7 @@ static int multivar_iter_next(git_config_entry **entry, git_config_iterator *_it
if (!iter->have_regex)
return 0;
- if (regexec(&iter->regex, (*entry)->value, 0, NULL, 0) == 0)
+ if (p_regexec(&iter->regex, (*entry)->value, 0, NULL, 0) == 0)
return 0;
}
@@ -1012,7 +1012,7 @@ void multivar_iter_free(git_config_iterator *_iter)
git__free(iter->name);
if (iter->have_regex)
- regfree(&iter->regex);
+ p_regfree(&iter->regex);
git__free(iter);
}
@@ -1032,11 +1032,11 @@ int git_config_multivar_iterator_new(git_config_iterator **out, const git_config
goto on_error;
if (regexp != NULL) {
- error = p_regcomp(&iter->regex, regexp, REG_EXTENDED);
+ error = p_regcomp(&iter->regex, regexp, P_REG_EXTENDED);
if (error != 0) {
git_error_set_regex(&iter->regex, error);
error = -1;
- regfree(&iter->regex);
+ p_regfree(&iter->regex);
goto on_error;
}
diff --git a/src/config_file.c b/src/config_file.c
index 48a9a26d4..716205851 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -21,7 +21,6 @@
#include <ctype.h>
#include <sys/types.h>
-#include <regex.h>
/* Max depth for [include] directives */
#define MAX_INCLUDE_DEPTH 10
@@ -62,7 +61,7 @@ typedef struct {
} diskfile_parse_state;
static int config_read(git_config_entries *entries, const git_repository *repo, git_config_file *file, git_config_level_t level, int depth);
-static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const regex_t *preg, const char *value);
+static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const p_regex_t *preg, const char *value);
static char *escape_value(const char *ptr);
static int config_snapshot(git_config_backend **out, git_config_backend *in);
@@ -329,7 +328,7 @@ static int config_set_multivar(
{
diskfile_backend *b = (diskfile_backend *)cfg;
char *key;
- regex_t preg;
+ p_regex_t preg;
int result;
assert(regexp);
@@ -337,7 +336,7 @@ static int config_set_multivar(
if ((result = git_config__normalize_name(name, &key)) < 0)
return result;
- result = p_regcomp(&preg, regexp, REG_EXTENDED);
+ result = p_regcomp(&preg, regexp, P_REG_EXTENDED);
if (result != 0) {
git_error_set_regex(&preg, result);
result = -1;
@@ -352,7 +351,7 @@ static int config_set_multivar(
out:
git__free(key);
- regfree(&preg);
+ p_regfree(&preg);
return result;
}
@@ -395,7 +394,7 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con
diskfile_backend *b = (diskfile_backend *)cfg;
git_config_entries *entries = NULL;
git_config_entry *entry = NULL;
- regex_t preg = { 0 };
+ p_regex_t preg = { 0 };
char *key = NULL;
int result;
@@ -413,7 +412,7 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con
goto out;
}
- if ((result = p_regcomp(&preg, regexp, REG_EXTENDED)) != 0) {
+ if ((result = p_regcomp(&preg, regexp, P_REG_EXTENDED)) != 0) {
git_error_set_regex(&preg, result);
result = -1;
goto out;
@@ -428,7 +427,7 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con
out:
git_config_entries_free(entries);
git__free(key);
- regfree(&preg);
+ p_regfree(&preg);
return result;
}
@@ -954,7 +953,7 @@ struct write_data {
const char *section;
const char *orig_name;
const char *name;
- const regex_t *preg;
+ const p_regex_t *preg;
const char *value;
};
@@ -1059,7 +1058,7 @@ static int write_on_variable(
/* If we have a regex to match the value, see if it matches */
if (has_matched && write_data->preg != NULL)
- has_matched = (regexec(write_data->preg, var_value, 0, NULL, 0) == 0);
+ has_matched = (p_regexec(write_data->preg, var_value, 0, NULL, 0) == 0);
/* If this isn't the name/value we're looking for, simply dump the
* existing data back out and continue on.
@@ -1120,7 +1119,7 @@ static int write_on_eof(
/*
* This is pretty much the parsing, except we write out anything we don't have
*/
-static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const regex_t *preg, const char* value)
+static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const p_regex_t *preg, const char* value)
{
int result;
char *orig_section, *section, *orig_name, *name, *ldot;
diff --git a/src/diff_driver.c b/src/diff_driver.c
index 959cf6258..740b5c9a3 100644
--- a/src/diff_driver.c
+++ b/src/diff_driver.c
@@ -9,6 +9,7 @@
#include "git2/attr.h"
+#include "common.h"
#include "diff.h"
#include "strmap.h"
#include "map.h"
@@ -24,7 +25,7 @@ typedef enum {
} git_diff_driver_t;
typedef struct {
- regex_t re;
+ p_regex_t re;
int flags;
} git_diff_driver_pattern;
@@ -38,7 +39,7 @@ struct git_diff_driver {
uint32_t binary_flags;
uint32_t other_flags;
git_array_t(git_diff_driver_pattern) fn_patterns;
- regex_t word_pattern;
+ p_regex_t word_pattern;
char name[GIT_FLEX_ARRAY];
};
@@ -129,7 +130,7 @@ static int diff_driver_add_patterns(
static int diff_driver_xfuncname(const git_config_entry *entry, void *payload)
{
- return diff_driver_add_patterns(payload, entry->value, REG_EXTENDED);
+ return diff_driver_add_patterns(payload, entry->value, P_REG_EXTENDED);
}
static int diff_driver_funcname(const git_config_entry *entry, void *payload)
@@ -204,12 +205,12 @@ static int git_diff_driver_builtin(
if (ddef->fns &&
(error = diff_driver_add_patterns(
- drv, ddef->fns, ddef->flags | REG_EXTENDED)) < 0)
+ drv, ddef->fns, ddef->flags | P_REG_EXTENDED)) < 0)
goto done;
if (ddef->words &&
(error = p_regcomp(
- &drv->word_pattern, ddef->words, ddef->flags | REG_EXTENDED)))
+ &drv->word_pattern, ddef->words, ddef->flags | P_REG_EXTENDED)))
{
error = git_error_set_regex(&drv->word_pattern, error);
goto done;
@@ -280,7 +281,9 @@ static int git_diff_driver_load(
/* TODO: warn if diff.<name>.command or diff.<name>.textconv are set */
git_buf_truncate(&name, namelen + strlen("diff.."));
- git_buf_put(&name, "xfuncname", strlen("xfuncname"));
+ if ((error = git_buf_PUTS(&name, "xfuncname")) < 0)
+ goto done;
+
if ((error = git_config_get_multivar_foreach(
cfg, name.ptr, NULL, diff_driver_xfuncname, drv)) < 0) {
if (error != GIT_ENOTFOUND)
@@ -289,7 +292,9 @@ static int git_diff_driver_load(
}
git_buf_truncate(&name, namelen + strlen("diff.."));
- git_buf_put(&name, "funcname", strlen("funcname"));
+ if ((error = git_buf_PUTS(&name, "funcname")) < 0)
+ goto done;
+
if ((error = git_config_get_multivar_foreach(
cfg, name.ptr, NULL, diff_driver_funcname, drv)) < 0) {
if (error != GIT_ENOTFOUND)
@@ -304,12 +309,14 @@ static int git_diff_driver_load(
}
git_buf_truncate(&name, namelen + strlen("diff.."));
- git_buf_put(&name, "wordregex", strlen("wordregex"));
+ if ((error = git_buf_PUTS(&name, "wordregex")) < 0)
+ goto done;
+
if ((error = git_config__lookup_entry(&ce, cfg, name.ptr, false)) < 0)
goto done;
if (!ce || !ce->value)
/* no diff.<driver>.wordregex, so just continue */;
- else if (!(error = p_regcomp(&drv->word_pattern, ce->value, REG_EXTENDED)))
+ else if (!(error = p_regcomp(&drv->word_pattern, ce->value, P_REG_EXTENDED)))
found_driver = true;
else {
/* TODO: warn about bad regex instead of failure */
@@ -393,10 +400,10 @@ void git_diff_driver_free(git_diff_driver *driver)
return;
for (i = 0; i < git_array_size(driver->fn_patterns); ++i)
- regfree(& git_array_get(driver->fn_patterns, i)->re);
+ p_regfree(& git_array_get(driver->fn_patterns, i)->re);
git_array_clear(driver->fn_patterns);
- regfree(&driver->word_pattern);
+ p_regfree(&driver->word_pattern);
git__free(driver);
}
@@ -444,12 +451,12 @@ static int diff_context_line__pattern_match(
git_diff_driver *driver, git_buf *line)
{
size_t i, maxi = git_array_size(driver->fn_patterns);
- regmatch_t pmatch[2];
+ p_regmatch_t pmatch[2];
for (i = 0; i < maxi; ++i) {
git_diff_driver_pattern *pat = git_array_get(driver->fn_patterns, i);
- if (!regexec(&pat->re, line->ptr, 2, pmatch, 0)) {
+ if (!p_regexec(&pat->re, line->ptr, 2, pmatch, 0)) {
if (pat->flags & REG_NEGATE)
return false;
diff --git a/src/errors.c b/src/errors.c
index afa340936..8ef491916 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -105,16 +105,16 @@ void git_error_set_str(int error_class, const char *string)
set_error_from_buffer(error_class);
}
-int git_error_set_regex(const regex_t *regex, int error_code)
+int git_error_set_regex(const p_regex_t *regex, int error_code)
{
char error_buf[1024];
assert(error_code);
- regerror(error_code, regex, error_buf, sizeof(error_buf));
+ p_regerror(error_code, regex, error_buf, sizeof(error_buf));
git_error_set_str(GIT_ERROR_REGEX, error_buf);
- if (error_code == REG_NOMATCH)
+ if (error_code == P_REG_NOMATCH)
return GIT_ENOTFOUND;
return GIT_EINVALIDSPEC;
diff --git a/src/errors.h b/src/errors.h
new file mode 100644
index 000000000..f2af1e37d
--- /dev/null
+++ b/src/errors.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_errors_h__
+#define INCLUDE_errors_h__
+
+#include "posix_regex.h"
+#include "common.h"
+
+/*
+ * Set the error message for this thread, formatting as needed.
+ */
+
+void git_error_set(int error_class, const char *string, ...) GIT_FORMAT_PRINTF(2, 3);
+
+/**
+ * Set the error message for a regex failure, using the internal regex
+ * error code lookup and return a libgit error code.
+ */
+int git_error_set_regex(const p_regex_t *regex, int error_code);
+
+/**
+ * Set error message for user callback if needed.
+ *
+ * If the error code in non-zero and no error message is set, this
+ * sets a generic error message.
+ *
+ * @return This always returns the `error_code` parameter.
+ */
+GIT_INLINE(int) git_error_set_after_callback_function(
+ int error_code, const char *action)
+{
+ if (error_code) {
+ const git_error *e = git_error_last();
+ if (!e || !e->message)
+ git_error_set(e ? e->klass : GIT_ERROR_CALLBACK,
+ "%s callback returned %d", action, error_code);
+ }
+ return error_code;
+}
+
+#ifdef GIT_WIN32
+#define git_error_set_after_callback(code) \
+ git_error_set_after_callback_function((code), __FUNCTION__)
+#else
+#define git_error_set_after_callback(code) \
+ git_error_set_after_callback_function((code), __func__)
+#endif
+
+/**
+ * Gets the system error code for this thread.
+ */
+int git_error_system_last(void);
+
+/**
+ * Sets the system error code for this thread.
+ */
+void git_error_system_set(int code);
+
+/**
+ * Structure to preserve libgit2 error state
+ */
+typedef struct {
+ int error_code;
+ unsigned int oom : 1;
+ git_error error_msg;
+} git_error_state;
+
+/**
+ * Capture current error state to restore later, returning error code.
+ * If `error_code` is zero, this does not clear the current error state.
+ * You must either restore this error state, or free it.
+ */
+extern int git_error_state_capture(git_error_state *state, int error_code);
+
+/**
+ * Restore error state to a previous value, returning saved error code.
+ */
+extern int git_error_state_restore(git_error_state *state);
+
+/** Free an error state. */
+extern void git_error_state_free(git_error_state *state);
+
+#endif
diff --git a/src/features.h.in b/src/features.h.in
index 694a61c02..4090fadb5 100644
--- a/src/features.h.in
+++ b/src/features.h.in
@@ -15,7 +15,12 @@
#cmakedefine GIT_USE_STAT_MTIMESPEC 1
#cmakedefine GIT_USE_STAT_MTIME_NSEC 1
#cmakedefine GIT_USE_FUTIMENS 1
-#cmakedefine GIT_USE_REGCOMP_L 1
+
+#cmakedefine GIT_REGEX_REGCOMP_L
+#cmakedefine GIT_REGEX_REGCOMP
+#cmakedefine GIT_REGEX_PCRE
+#cmakedefine GIT_REGEX_PCRE2
+#cmakedefine GIT_REGEX_BUILTIN 1
#cmakedefine GIT_SSH 1
#cmakedefine GIT_SSH_MEMORY_CREDENTIALS 1
diff --git a/src/posix_regex.h b/src/posix_regex.h
new file mode 100644
index 000000000..421ffeba1
--- /dev/null
+++ b/src/posix_regex.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_posix_regex_h__
+#define INCLUDE_posix_regex_h__
+
+#include "common.h"
+
+/*
+ * Regular expressions: if we were asked to use PCRE (either our
+ * bundled version or a system version) then use their regcomp
+ * compatible implementation.
+ */
+
+#ifdef GIT_REGEX_BUILTIN
+
+# include "pcreposix.h"
+
+# define P_REG_EXTENDED PCRE_REG_EXTENDED
+# define P_REG_ICASE PCRE_REG_ICASE
+# define P_REG_NOMATCH PCRE_REG_NOMATCH
+
+# define p_regex_t pcre_regex_t
+# define p_regmatch_t pcre_regmatch_t
+# define p_regcomp pcre_regcomp
+# define p_regerror pcre_regerror
+# define p_regexec pcre_regexec
+# define p_regfree pcre_regfree
+
+/*
+ * Use the system-provided `regex` routines, whether that's via the
+ * PCRE emulation layer, or libc, preferring `regcomp_l` it's available.
+ */
+
+#else
+
+# if defined(GIT_REGEX_PCRE2)
+# include <pcre2posix.h>
+# elif defined(GIT_REGEX_PCRE)
+# include <pcreposix.h>
+# else
+# include <regex.h>
+# endif
+
+# define P_REG_EXTENDED REG_EXTENDED
+# define P_REG_ICASE REG_ICASE
+# define P_REG_NOMATCH REG_NOMATCH
+
+# define p_regex_t regex_t
+# define p_regmatch_t regmatch_t
+
+# define p_regerror regerror
+# define p_regexec regexec
+# define p_regfree regfree
+
+# ifdef GIT_REGEX_REGCOMP_L
+# include <xlocale.h>
+
+GIT_INLINE(int) p_regcomp(p_regex_t *preg, const char *pattern, int cflags)
+{
+ return regcomp_l(preg, pattern, cflags, (locale_t) 0);
+}
+
+# else
+# define p_regcomp regcomp
+# endif /* GIT_REGEX_REGCOMP_L */
+
+#endif
+
+#endif
diff --git a/src/revparse.c b/src/revparse.c
index 50ee31ca0..4bde0d7f2 100644
--- a/src/revparse.c
+++ b/src/revparse.c
@@ -42,7 +42,7 @@ static int maybe_abbrev(git_object** out, git_repository *repo, const char *spec
return maybe_sha_or_abbrev(out, repo, spec, speclen);
}
-static int build_regex(regex_t *regex, const char *pattern)
+static int build_regex(p_regex_t *regex, const char *pattern)
{
int error;
@@ -51,13 +51,13 @@ static int build_regex(regex_t *regex, const char *pattern)
return GIT_EINVALIDSPEC;
}
- error = p_regcomp(regex, pattern, REG_EXTENDED);
+ error = p_regcomp(regex, pattern, P_REG_EXTENDED);
if (!error)
return 0;
error = git_error_set_regex(regex, error);
- regfree(regex);
+ p_regfree(regex);
return error;
}
@@ -66,7 +66,7 @@ static int maybe_describe(git_object**out, git_repository *repo, const char *spe
{
const char *substr;
int error;
- regex_t regex;
+ p_regex_t regex;
substr = strstr(spec, "-g");
@@ -76,8 +76,8 @@ static int maybe_describe(git_object**out, git_repository *repo, const char *spe
if (build_regex(&regex, ".+-[0-9]+-g[0-9a-fA-F]+") < 0)
return -1;
- error = regexec(&regex, spec, 0, NULL, 0);
- regfree(&regex);
+ error = p_regexec(&regex, spec, 0, NULL, 0);
+ p_regfree(&regex);
if (error)
return GIT_ENOTFOUND;
@@ -143,12 +143,12 @@ static int retrieve_previously_checked_out_branch_or_revision(git_object **out,
{
git_reference *ref = NULL;
git_reflog *reflog = NULL;
- regex_t preg;
+ p_regex_t preg;
int error = -1;
size_t i, numentries, cur;
const git_reflog_entry *entry;
const char *msg;
- regmatch_t regexmatches[2];
+ p_regmatch_t regexmatches[2];
git_buf buf = GIT_BUF_INIT;
cur = position;
@@ -173,7 +173,7 @@ static int retrieve_previously_checked_out_branch_or_revision(git_object **out,
if (!msg)
continue;
- if (regexec(&preg, msg, 2, regexmatches, 0))
+ if (p_regexec(&preg, msg, 2, regexmatches, 0))
continue;
cur--;
@@ -199,7 +199,7 @@ static int retrieve_previously_checked_out_branch_or_revision(git_object **out,
cleanup:
git_reference_free(ref);
git_buf_dispose(&buf);
- regfree(&preg);
+ p_regfree(&preg);
git_reflog_free(reflog);
return error;
}
@@ -448,7 +448,7 @@ cleanup:
return error;
}
-static int walk_and_search(git_object **out, git_revwalk *walk, regex_t *regex)
+static int walk_and_search(git_object **out, git_revwalk *walk, p_regex_t *regex)
{
int error;
git_oid oid;
@@ -460,7 +460,7 @@ static int walk_and_search(git_object **out, git_revwalk *walk, regex_t *regex)
if ((error < 0) && (error != GIT_ENOTFOUND))
return -1;
- if (!regexec(regex, git_commit_message((git_commit*)obj), 0, NULL, 0)) {
+ if (!p_regexec(regex, git_commit_message((git_commit*)obj), 0, NULL, 0)) {
*out = obj;
return 0;
}
@@ -476,7 +476,7 @@ static int walk_and_search(git_object **out, git_revwalk *walk, regex_t *regex)
static int handle_grep_syntax(git_object **out, git_repository *repo, const git_oid *spec_oid, const char *pattern)
{
- regex_t preg;
+ p_regex_t preg;
git_revwalk *walk = NULL;
int error;
@@ -497,7 +497,7 @@ static int handle_grep_syntax(git_object **out, git_repository *repo, const git_
error = walk_and_search(out, walk, &preg);
cleanup:
- regfree(&preg);
+ p_regfree(&preg);
git_revwalk_free(walk);
return error;
diff --git a/src/unix/posix.h b/src/unix/posix.h
index f2fffd5c9..f969f8362 100644
--- a/src/unix/posix.h
+++ b/src/unix/posix.h
@@ -89,14 +89,4 @@ GIT_INLINE(int) p_futimes(int f, const struct p_timeval t[2])
# define p_futimes futimes
#endif
-#ifdef GIT_USE_REGCOMP_L
-#include <xlocale.h>
-GIT_INLINE(int) p_regcomp(regex_t *preg, const char *pattern, int cflags)
-{
- return regcomp_l(preg, pattern, cflags, (locale_t) 0);
-}
-#else
-# define p_regcomp regcomp
-#endif
-
#endif
diff --git a/src/userdiff.h b/src/userdiff.h
index 91c1f42dc..8bde6303f 100644
--- a/src/userdiff.h
+++ b/src/userdiff.h
@@ -29,7 +29,7 @@ typedef struct {
#define PATTERNS(NAME, FN_PATS, WORD_PAT) \
{ NAME, FN_PATS, WORD_PAT WORD_DEFAULT, 0 }
#define IPATTERN(NAME, FN_PATS, WORD_PAT) \
- { NAME, FN_PATS, WORD_PAT WORD_DEFAULT, REG_ICASE }
+ { NAME, FN_PATS, WORD_PAT WORD_DEFAULT, P_REG_ICASE }
/*
* The table of diff driver patterns
diff --git a/src/win32/path_w32.h b/src/win32/path_w32.h
index facbced81..afd0aa155 100644
--- a/src/win32/path_w32.h
+++ b/src/win32/path_w32.h
@@ -8,37 +8,8 @@
#define INCLUDE_win32_path_w32_h__
#include "common.h"
-
#include "vector.h"
-/*
- * Provides a large enough buffer to support Windows paths: MAX_PATH is
- * 260, corresponding to a maximum path length of 259 characters plus a
- * NULL terminator. Prefixing with "\\?\" adds 4 characters, but if the
- * original was a UNC path, then we turn "\\server\share" into
- * "\\?\UNC\server\share". So we replace the first two characters with
- * 8 characters, a net gain of 6, so the maximum length is MAX_PATH+6.
- */
-#define GIT_WIN_PATH_UTF16 MAX_PATH+6
-
-/* Maximum size of a UTF-8 Win32 path. We remove the "\\?\" or "\\?\UNC\"
- * prefixes for presentation, bringing us back to 259 (non-NULL)
- * characters. UTF-8 does have 4-byte sequences, but they are encoded in
- * UTF-16 using surrogate pairs, which takes up the space of two characters.
- * Two characters in the range U+0800 -> U+FFFF take up more space in UTF-8
- * (6 bytes) than one surrogate pair (4 bytes).
- */
-#define GIT_WIN_PATH_UTF8 (259 * 3 + 1)
-
-/*
- * The length of a Windows "shortname", for 8.3 compatibility.
- */
-#define GIT_WIN_PATH_SHORTNAME 13
-
-/* Win32 path types */
-typedef wchar_t git_win32_path[GIT_WIN_PATH_UTF16];
-typedef char git_win32_utf8_path[GIT_WIN_PATH_UTF8];
-
/**
* Create a Win32 path (in UCS-2 format) from a UTF-8 string.
*
diff --git a/src/win32/posix.h b/src/win32/posix.h
index d5ab2e8f5..e427d64c3 100644
--- a/src/win32/posix.h
+++ b/src/win32/posix.h
@@ -60,7 +60,4 @@ extern int p_lstat_posixly(const char *filename, struct stat *buf);
extern struct tm * p_localtime_r(const time_t *timer, struct tm *result);
extern struct tm * p_gmtime_r(const time_t *timer, struct tm *result);
-/* Use the bundled regcomp */
-#define p_regcomp regcomp
-
#endif
diff --git a/src/win32/precompiled.h b/src/win32/precompiled.h
index 851a083d5..314383d31 100644
--- a/src/win32/precompiled.h
+++ b/src/win32/precompiled.h
@@ -13,8 +13,6 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <regex.h>
-
#include <io.h>
#include <direct.h>
#ifdef GIT_THREADS
diff --git a/src/win32/w32_common.h b/src/win32/w32_common.h
new file mode 100644
index 000000000..f9e74b947
--- /dev/null
+++ b/src/win32/w32_common.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_win32_w32_common_h__
+#define INCLUDE_win32_w32_common_h__
+
+/*
+ * Provides a large enough buffer to support Windows paths: MAX_PATH is
+ * 260, corresponding to a maximum path length of 259 characters plus a
+ * NULL terminator. Prefixing with "\\?\" adds 4 characters, but if the
+ * original was a UNC path, then we turn "\\server\share" into
+ * "\\?\UNC\server\share". So we replace the first two characters with
+ * 8 characters, a net gain of 6, so the maximum length is MAX_PATH+6.
+ */
+#define GIT_WIN_PATH_UTF16 MAX_PATH+6
+
+/* Maximum size of a UTF-8 Win32 path. We remove the "\\?\" or "\\?\UNC\"
+ * prefixes for presentation, bringing us back to 259 (non-NULL)
+ * characters. UTF-8 does have 4-byte sequences, but they are encoded in
+ * UTF-16 using surrogate pairs, which takes up the space of two characters.
+ * Two characters in the range U+0800 -> U+FFFF take up more space in UTF-8
+ * (6 bytes) than one surrogate pair (4 bytes).
+ */
+#define GIT_WIN_PATH_UTF8 (259 * 3 + 1)
+
+/*
+ * The length of a Windows "shortname", for 8.3 compatibility.
+ */
+#define GIT_WIN_PATH_SHORTNAME 13
+
+/* Win32 path types */
+typedef wchar_t git_win32_path[GIT_WIN_PATH_UTF16];
+typedef char git_win32_utf8_path[GIT_WIN_PATH_UTF8];
+
+#endif