util.h 11.2 KB
Newer Older
Vicent Marti committed
1
/*
Edward Thomson committed
2
 * Copyright (C) the libgit2 contributors. All rights reserved.
Vicent Marti committed
3 4 5 6
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */
7 8 9
#ifndef INCLUDE_util_h__
#define INCLUDE_util_h__

10 11
#include "common.h"

12 13 14 15
#ifndef GIT_WIN32
# include <ctype.h>
#endif

16 17
#include "git2/buffer.h"

18
#include "buffer.h"
19
#include "common.h"
20
#include "strnlen.h"
21
#include "thread-utils.h"
22

23
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
Vicent Marti committed
24
#define bitsizeof(x) (CHAR_BIT * sizeof(x))
Vicent Marti committed
25
#define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits))))
26 27 28
#ifndef min
# define min(a,b) ((a) < (b) ? (a) : (b))
#endif
29 30 31
#ifndef max
# define max(a,b) ((a) > (b) ? (a) : (b))
#endif
32

33 34
#define GIT_DATE_RFC2822_SZ  32

35 36 37 38 39 40 41 42 43
/**
 * Return the length of a constant string.
 * We are aware that `strlen` performs the same task and is usually
 * optimized away by the compiler, whilst being safer because it returns
 * valid values when passed a pointer instead of a constant string; however
 * this macro will transparently work with wide-char and single-char strings.
 */
#define CONST_STRLEN(x) ((sizeof(x)/sizeof(x[0])) - 1)

44 45 46 47 48 49
#define STRCMP_CASESELECT(IGNORE_CASE, STR1, STR2) \
	((IGNORE_CASE) ? strcasecmp((STR1), (STR2)) : strcmp((STR1), (STR2)))

#define CASESELECT(IGNORE_CASE, ICASE, CASE) \
	((IGNORE_CASE) ? (ICASE) : (CASE))

50
extern int git__prefixcmp(const char *str, const char *prefix);
51
extern int git__prefixcmp_icase(const char *str, const char *prefix);
52
extern int git__prefixncmp(const char *str, size_t str_n, const char *prefix);
53
extern int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix);
54
extern int git__suffixcmp(const char *str, const char *suffix);
55

56 57 58 59 60
GIT_INLINE(int) git__signum(int val)
{
	return ((val > 0) - (val < 0));
}

61 62 63
extern int git__strntol32(int32_t *n, const char *buff, size_t buff_len, const char **end_buf, int base);
extern int git__strntol64(int64_t *n, const char *buff, size_t buff_len, const char **end_buf, int base);

64

65
extern void git__hexdump(const char *buffer, size_t n);
66 67 68 69 70 71 72 73 74
extern uint32_t git__hash(const void *key, int len, uint32_t seed);

/* 32-bit cross-platform rotl */
#ifdef _MSC_VER /* use built-in method in MSVC */
#	define git__rotl(v, s) (uint32_t)_rotl(v, s)
#else /* use bitops in GCC; with o2 this gets optimized to a rotl instruction */
#	define git__rotl(v, s) (uint32_t)(((uint32_t)(v) << (s)) | ((uint32_t)(v) >> (32 - (s))))
#endif

75
extern char *git__strtok(char **end, const char *sep);
76
extern char *git__strsep(char **end, const char *sep);
77

78
extern void git__strntolower(char *str, size_t len);
79 80
extern void git__strtolower(char *str);

81 82 83 84 85 86 87 88 89
#ifdef GIT_WIN32
GIT_INLINE(int) git__tolower(int c)
{
	return (c >= 'A' && c <= 'Z') ? (c + 32) : c;
}
#else
# define git__tolower(a) tolower(a)
#endif

90 91
extern size_t git__linenlen(const char *buffer, size_t buffer_len);

92 93 94
GIT_INLINE(const char *) git__next_line(const char *s)
{
	while (*s && *s != '\n') s++;
Russell Belfer committed
95
	while (*s == '\n' || *s == '\r') s++;
96 97 98
	return s;
}

99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
GIT_INLINE(const void *) git__memrchr(const void *s, int c, size_t n)
{
	const unsigned char *cp;

	if (n != 0) {
		cp = (unsigned char *)s + n;
		do {
			if (*(--cp) == (unsigned char)c)
				return cp;
		} while (--n != 0);
	}

	return NULL;
}

114 115 116
extern const void * git__memmem(const void *haystack, size_t haystacklen,
				const void *needle, size_t needlelen);

117 118 119 120
typedef int (*git__tsort_cmp)(const void *a, const void *b);

extern void git__tsort(void **dst, size_t size, git__tsort_cmp cmp);

121
typedef int (*git__sort_r_cmp)(const void *a, const void *b, void *payload);
122 123

extern void git__tsort_r(
124
	void **dst, size_t size, git__sort_r_cmp cmp, void *payload);
125 126

extern void git__qsort_r(
127 128 129 130 131
	void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload);

extern void git__insertsort_r(
	void *els, size_t nel, size_t elsize, void *swapel,
	git__sort_r_cmp cmp, void *payload);
132

133 134 135
/**
 * @param position If non-NULL, this will be set to the position where the
 * 		element is or would be inserted if not found.
136
 * @return 0 if found; GIT_ENOTFOUND if not found
137
 */
138 139 140 141
extern int git__bsearch(
	void **array,
	size_t array_len,
	const void *key,
142 143 144 145 146 147 148 149 150
	int (*compare)(const void *key, const void *element),
	size_t *position);

extern int git__bsearch_r(
	void **array,
	size_t array_len,
	const void *key,
	int (*compare_r)(const void *key, const void *element, void *payload),
	void *payload,
151
	size_t *position);
152

153
extern int git__strcmp_cb(const void *a, const void *b);
154
extern int git__strcasecmp_cb(const void *a, const void *b);
155

156 157 158 159 160
extern int git__strcmp(const char *a, const char *b);
extern int git__strcasecmp(const char *a, const char *b);
extern int git__strncmp(const char *a, const char *b, size_t sz);
extern int git__strncasecmp(const char *a, const char *b, size_t sz);

161 162
extern int git__strcasesort_cmp(const char *a, const char *b);

163
typedef struct {
164
	git_atomic refcount;
165 166 167 168 169 170
	void *owner;
} git_refcount;

typedef void (*git_refcount_freeptr)(void *r);

#define GIT_REFCOUNT_INC(r) { \
171
	git_atomic_inc(&(r)->rc.refcount);	\
172 173 174
}

#define GIT_REFCOUNT_DEC(_r, do_free) { \
175
	git_refcount *r = &(_r)->rc; \
176 177
	int val = git_atomic_dec(&r->refcount); \
	if (val <= 0 && r->owner == NULL) { do_free(_r); } \
178 179 180
}

#define GIT_REFCOUNT_OWN(r, o) { \
181
	(r)->rc.owner = o; \
182 183
}

184
#define GIT_REFCOUNT_OWNER(r) ((r)->rc.owner)
185

186
#define GIT_REFCOUNT_VAL(r) git_atomic_get((r)->rc.refcount)
187 188


nulltoken committed
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
static signed char from_hex[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 20 */
 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 30 */
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 40 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 50 */
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 60 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* f0 */
};

GIT_INLINE(int) git__fromhex(char h)
{
	return from_hex[(unsigned char) h];
}
212

schu committed
213 214 215
GIT_INLINE(int) git__ishex(const char *str)
{
	unsigned i;
216
	for (i=0; str[i] != '\0'; i++)
schu committed
217 218 219 220 221
		if (git__fromhex(str[i]) < 0)
			return 0;
	return 1;
}

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
GIT_INLINE(size_t) git__size_t_bitmask(size_t v)
{
	v--;
	v |= v >> 1;
	v |= v >> 2;
	v |= v >> 4;
	v |= v >> 8;
	v |= v >> 16;

	return v;
}

GIT_INLINE(size_t) git__size_t_powerof2(size_t v)
{
	return git__size_t_bitmask(v) + 1;
}

239 240
GIT_INLINE(bool) git__isupper(int c)
{
Linquize committed
241
	return (c >= 'A' && c <= 'Z');
242 243 244 245
}

GIT_INLINE(bool) git__isalpha(int c)
{
Linquize committed
246
	return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
247 248
}

nulltoken committed
249 250
GIT_INLINE(bool) git__isdigit(int c)
{
Linquize committed
251
	return (c >= '0' && c <= '9');
nulltoken committed
252 253
}

254 255
GIT_INLINE(bool) git__isspace(int c)
{
256
	return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v');
257 258
}

259 260
GIT_INLINE(bool) git__isspace_nonlf(int c)
{
261
	return (c == ' ' || c == '\t' || c == '\f' || c == '\r' || c == '\v');
262 263
}

264 265 266 267 268
GIT_INLINE(bool) git__iswildcard(int c)
{
	return (c == '*' || c == '?' || c == '[');
}

269 270 271 272 273
GIT_INLINE(bool) git__isxdigit(int c)
{
	return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}

274
/*
275
 * Parse a string value as a boolean, just like Core Git does.
276 277 278 279 280 281
 *
 * Valid values for true are: 'true', 'yes', 'on'
 * Valid values for false are: 'false', 'no', 'off'
 */
extern int git__parse_bool(int *out, const char *value);

282 283 284 285 286 287 288 289
/*
 * Parse a string into a value as a git_time_t.
 *
 * Sample valid input:
 * - "yesterday"
 * - "July 17, 2003"
 * - "2003-7-17 08:23"
 */
290
extern int git__date_parse(git_time_t *out, const char *date);
291

292
/*
293 294 295 296 297 298 299 300 301 302
 * Format a git_time as a RFC2822 string
 *
 * @param out buffer to store formatted date; a '\\0' terminator will automatically be added.
 * @param len size of the buffer; should be atleast `GIT_DATE_RFC2822_SZ` in size;
 * @param date the date to be formatted
 * @return 0 if successful; -1 on error
 */
extern int git__date_rfc2822_fmt(char *out, size_t len, const git_time *date);

/*
303
 * Unescapes a string in-place.
Russell Belfer committed
304
 *
305 306 307 308 309 310
 * Edge cases behavior:
 * - "jackie\" -> "jacky\"
 * - "chan\\" -> "chan\"
 */
extern size_t git__unescape(char *str);

311
/*
312 313 314 315 316 317 318 319 320 321 322
 * Iterate through an UTF-8 string, yielding one
 * codepoint at a time.
 *
 * @param str current position in the string
 * @param str_len size left in the string; -1 if the string is NULL-terminated
 * @param dst pointer where to store the current codepoint
 * @return length in bytes of the read codepoint; -1 if the codepoint was invalid
 */
extern int git__utf8_iterate(const uint8_t *str, int str_len, int32_t *dst);

/*
323 324 325 326 327 328 329 330 331 332
 * Iterate through an UTF-8 string and stops after finding any invalid UTF-8
 * codepoints.
 *
 * @param str string to scan
 * @param str_len size of the string
 * @return length in bytes of the string that contains valid data
 */
extern size_t git__utf8_valid_buf_length(const uint8_t *str, size_t str_len);

/*
333 334
 * Safely zero-out memory, making sure that the compiler
 * doesn't optimize away the operation.
335
 */
yorah committed
336 337 338 339 340 341 342 343 344 345 346
GIT_INLINE(void) git__memzero(void *data, size_t size)
{
#ifdef _MSC_VER
	SecureZeroMemory((PVOID)data, size);
#else
	volatile uint8_t *scan = (volatile uint8_t *)data;

	while (size--)
		*scan++ = 0x0;
#endif
}
347

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
#ifdef GIT_WIN32

GIT_INLINE(double) git__timer(void)
{
	/* We need the initial tick count to detect if the tick
	 * count has rolled over. */
	static DWORD initial_tick_count = 0;

	/* GetTickCount returns the number of milliseconds that have
	 * elapsed since the system was started. */
	DWORD count = GetTickCount();

	if(initial_tick_count == 0) {
		initial_tick_count = count;
	} else if (count < initial_tick_count) {
		/* The tick count has rolled over - adjust for it. */
		count = (0xFFFFFFFF - initial_tick_count) + count;
	}

	return (double) count / (double) 1000;
}

#elif __APPLE__

#include <mach/mach_time.h>

374
GIT_INLINE(double) git__timer(void)
375 376 377 378 379 380 381 382 383 384
{
   uint64_t time = mach_absolute_time();
   static double scaling_factor = 0;

   if (scaling_factor == 0) {
       mach_timebase_info_data_t info;
       (void)mach_timebase_info(&info);
       scaling_factor = (double)info.numer / (double)info.denom;
   }

385
   return (double)time * scaling_factor / 1.0E9;
386 387
}

388 389 390 391 392 393 394 395 396 397 398
#elif defined(AMIGA)

#include <proto/timer.h>

GIT_INLINE(double) git__timer(void)
{
	struct TimeVal tv;
	ITimer->GetUpTime(&tv);
	return (double)tv.Seconds + (double)tv.Microseconds / 1.0E6;
}

399 400 401 402 403 404 405 406 407
#else

#include <sys/time.h>

GIT_INLINE(double) git__timer(void)
{
	struct timespec tp;

	if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
408
		return (double) tp.tv_sec + (double) tp.tv_nsec / 1.0E9;
409 410 411 412 413
	} else {
		/* Fall back to using gettimeofday */
		struct timeval tv;
		struct timezone tz;
		gettimeofday(&tv, &tz);
414
		return (double)tv.tv_sec + (double)tv.tv_usec / 1.0E6;
415 416 417 418 419
	}
}

#endif

420 421
extern int git__getenv(git_buf *out, const char *name);

422 423
#include "alloc.h"

424
#endif