#ifndef SCULBLOG_XDIFF_GIT_COMPAT_UTIL_H
#define SCULBLOG_XDIFF_GIT_COMPAT_UTIL_H

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <regex.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(__GNUC__) || defined(__clang__)
#define UNUSED __attribute__((unused))
#define NORETURN __attribute__((noreturn))
#else
#define UNUSED
#define NORETURN
#endif

#define bitsizeof(x)  (CHAR_BIT * sizeof(x))
#define maximum_signed_value_of_type(a) \
    (INTMAX_MAX >> (bitsizeof(intmax_t) - bitsizeof(a)))
#define signed_add_overflows(a, b) \
    ((b) > maximum_signed_value_of_type(a) - (a))

extern int BUG_exit_code;
extern int bug_called_must_BUG;

void *xmalloc(size_t size);
void *xcalloc(size_t nmemb, size_t size);
void *xrealloc(void *ptr, size_t size);
NORETURN void BUG_fl(const char *file, int line, const char *fmt, ...);

#define BUG(...) BUG_fl(__FILE__, __LINE__, __VA_ARGS__)

#ifndef REG_STARTEND
#error "Git xdiff requires REG_STARTEND support"
#endif

static inline int regexec_buf(const regex_t *preg, const char *buf, size_t size,
                              size_t nmatch, regmatch_t pmatch[], int eflags)
{
    assert(nmatch > 0 && pmatch);
    pmatch[0].rm_so = 0;
    pmatch[0].rm_eo = size;
    return regexec(preg, buf, nmatch, pmatch, eflags | REG_STARTEND);
}

#endif
